Return to Snippet

Revision: 37770
at December 17, 2010 00:32 by adrianparr


Initial Code
// Useful Resources
//
// http://active.tutsplus.com/tutorials/actionscript/quick-tip-using-a-php-proxy-to-load-assets-into-flash/
// http://blog.juanbonfante.com/?p=272
// http://alivepdf.bytearray.org/
// http://blog.unthinkmedia.com/2008/09/05/exporting-pdfs-in-flex-using-alivepdf/
// http://lucamezzalira.com/2009/02/28/create-pdf-in-runtime-with-actionscript-3-alivepdf-zinc-or-air-flex-or-flash/

package 
{
	import flash.display.Loader;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.display.Shape;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.TextEvent;
	import flash.geom.Rectangle;
	import flash.net.URLRequest;
	import flash.display.Bitmap;
	import flash.net.URLVariables;
	import flash.text.TextFormat;
	import flash.text.TextField;
	import flash.text.TextFormatAlign;
	import flash.text.TextFieldAutoSize;
	import flash.net.navigateToURL;
	import flash.system.LoaderContext;
	import flash.system.Security;
	import flash.display.BitmapData;
	import flash.utils.ByteArray;
	import flash.net.URLRequestHeader;
	import flash.net.URLRequestMethod;
	import flash.printing.PrintJob;
	import flash.net.FileReference;
	
	// http://www.minimalcomps.com
	import com.bit101.components.Text;
	import com.bit101.components.HUISlider;
	import com.bit101.components.PushButton;
	import com.bit101.components.Label;

	// https://github.com/mikechambers/as3corelib
	import com.adobe.images.JPGEncoder;
	import com.adobe.images.PNGEncoder;

	// http://alivepdf.bytearray.org/
	import org.alivepdf.pdf.PDF;
	import org.alivepdf.layout.Orientation;
	import org.alivepdf.layout.Size;
	import org.alivepdf.layout.Unit;
	import org.alivepdf.display.Display;
	import org.alivepdf.saving.Method;
	import org.alivepdf.layout.Resize;
	import org.alivepdf.layout.Mode;
	import org.alivepdf.layout.Position;
	
	[SWF(width = '500', height = '500', backgroundColor = '#FFFFFF', frameRate = '25')]

	/**
	 * ...
	 * @author Adrian Parr
	 */
	public class Main extends Sprite 
	{

		[Embed(source="../assets/title.png")]
		private var TitleGraphic:Class;
		
		[Embed(source="../assets/loading_anim.swf")]
		private var LoadingAnim:Class;
		
		private static const _serversideProxyUrl:String = "proxy.php";
		private static const _googleUrl:String = "http://chart.apis.google.com/chart";
		private static const _imageFilename:String = "qr_code";
		private static const _createPngFilePhpUrl:String = "png_encoder_download.php";
		private static const _createJpegFilePhpUrl:String = "jpg_encoder_download.php";
		private static const _pdfFilename:String = "qr_code.pdf";
		private static const _printA4width:int = 580;
		private static const _printA4height:int = 830;
		private static const _pdfA4width:int = 540;
		private static const _pdfA4height:int = 790;
		
		private var _loadingAnim:MovieClip;
		
		private var _border:Shape;
		private var _borderColour:uint = 0x036CB4;
		private var _borderWidth:uint = 1;
		private var _borderAlpha:Number = 1;
		private var _controlsHeight:int = 100;
		private var _controls:Sprite;
		
		private var _qrLoader:Loader;
		private var _urlVars:URLVariables;
		private var _urlRequest:URLRequest;
		private var _url:String = "";
		private var _size:int;
		
		private var _urlText:Text;
		private var _dimensionsSlider:HUISlider;
		private var _generateBtn:PushButton;
		private var _savePngBtn:PushButton;
		private var _saveJpegBtn:PushButton;
		private var _printBtn:PushButton;
		private var _pdfBtn:PushButton;
		private var _defaultSize:int = 200;
		
		private var _qrCodeBitmapData:BitmapData;
		private var _errorTxt:TextField = new TextField();
		private var _printTemplate:Sprite;
		
		
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			
			var bgRect:Shape = new Shape();
			bgRect.graphics.beginFill(0xCCCCCC, 1);
			bgRect.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
			bgRect.graphics.endFill();
			addChild(bgRect);

			createControls();

			_border = new Shape();
			_border = drawBorder(_borderColour, _borderWidth, _borderAlpha);
			addChild(_border);
			
			_qrLoader = new Loader();
			_qrLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onQrLoader_COMPLETE);
			_qrLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onQrLoader_IO_ERROR);
			_qrLoader.contentLoaderInfo.addEventListener(HTTPStatusEvent.HTTP_STATUS, onQrLoader_HTTP_STATUS);
			
			_loadingAnim = new LoadingAnim();
			_loadingAnim.visible = false;
			_loadingAnim.alpha = 0.7;
			_loadingAnim.x = stage.stageWidth / 2 - _loadingAnim.width / 2;
			_loadingAnim.y = ((stage.stageHeight-_controlsHeight) / 2) - (_loadingAnim.height / 2) + _controlsHeight;
			addChild(_loadingAnim);
			
			_printTemplate = new Sprite();
			_printTemplate.graphics.beginFill(0xFFFFFF, 1);
			_printTemplate.graphics.drawRect(0, 0, _printA4width, _printA4height);
			_printTemplate.graphics.endFill();
			
		}
		
		
		private function createControls():void
		{
			_controls = new Sprite();
			
			var bg:Shape = new Shape();
			bg.graphics.beginFill(0x000000, 0.1);
			bg.graphics.drawRect(0, 0, stage.stageWidth, _controlsHeight);
			bg.graphics.endFill();
			_controls.addChild(bg);
			
			var title:Bitmap = new TitleGraphic();
			title.x = 10;
			title.y = 10;
			_controls.addChild(title);
			
			var urlLabel:Label = new Label(_controls, 13, 29, "Message/URL");

			_urlText = new Text(_controls, 80, 28, "");
			_urlText.addEventListener(Event.CHANGE, onUrlText_CHANGE);
			_urlText.textField.multiline = false;
			_urlText.width = 375;
			_urlText.height = 20;

			_dimensionsSlider = new HUISlider(_controls, 10, 50, "Size (in pixels)", onDimensionsSlider);
			_dimensionsSlider.width = 500;
			_dimensionsSlider.minimum = 50;
			_dimensionsSlider.maximum = stage.stageHeight - _controlsHeight;
			_dimensionsSlider.value = _defaultSize;
			_dimensionsSlider.labelPrecision = 0;
			
			_generateBtn = new PushButton(_controls, 80, 69, "Generate", onGenerateBtn);
			_generateBtn.width = 71;
			_generateBtn.enabled = false;
			
			_savePngBtn = new PushButton(_controls, 156, 69, "Save as PNG", onSavePngBtn);
			_savePngBtn.width = 71;
			_savePngBtn.enabled = false;
			
			_saveJpegBtn = new PushButton(_controls, 232, 69, "Save as JPEG", onSaveJpegBtn);
			_saveJpegBtn.width = 71;
			_saveJpegBtn.enabled = false;
			
			_printBtn = new PushButton(_controls, 308, 69, "Print A4", onPrintBtn);
			_printBtn.width = 71;
			_printBtn.enabled = false;
			
			_pdfBtn = new PushButton(_controls, 384, 69, "Create PDF", onPdfBtn);
			_pdfBtn.width = 71;
			_pdfBtn.enabled = false;
			
			addChild(_controls);
		}
		
		
		private function onDimensionsSlider(event:Event):void
		{
			if (_url.length > 0) {
				_generateBtn.enabled = true;
			} else {
				_generateBtn.enabled = false;
			}
			_savePngBtn.enabled = false;
			_saveJpegBtn.enabled = false;
			_printBtn.enabled = false;
			_pdfBtn.enabled = false;
			_qrLoader.visible = false;
		}
		
		
		private function onUrlText_CHANGE(event:Event):void
		{
			//trace("onUrlText()");
			_url = _urlText.text;
			//trace("_url:", _url);
			if (_url.length > 0) {
				_generateBtn.enabled = true;
			} else {
				_generateBtn.enabled = false;
			}
			_savePngBtn.enabled = false;
			_saveJpegBtn.enabled = false;
			_printBtn.enabled = false;
			_pdfBtn.enabled = false;
			_qrLoader.visible = false;
		}
		
		
		private function onGenerateBtn(event:Event):void
		{
			trace("onGenerateBtn()");
			
			_generateBtn.enabled = false;
			
			_qrLoader.visible = false;
			_loadingAnim.visible = true;
			
			_url = _urlText.text;
			_size = _dimensionsSlider.value;
			
			_errorTxt.visible = false;
			
			_urlVars = new URLVariables();
			_urlRequest = new URLRequest();
			
			_urlVars.chs = String(_size + "x" + _size);
			
			if (Security.sandboxType == Security.LOCAL_TRUSTED) {
				// If 'LOCAL_TRUSTED' then load the image from Google directly.
				trace("Security.sandboxType == Security.LOCAL_TRUSTED");
				_urlVars.cht = "qr";
				_urlVars.chl = _url;
				_urlRequest.url = _googleUrl;
			} else {
				// Else, circumvent using a server-side proxy script
				trace("Security.sandboxType != Security.LOCAL_TRUSTED");
				_urlVars.chl = encodeURIComponent(_url);
				_urlVars.googleUrl = _googleUrl;
				_urlRequest.url = _serversideProxyUrl;
			}
			
			_urlRequest.data = _urlVars;
			
			trace("vars.toString():" + _urlVars.toString());
			trace("_urlRequest: ", _urlRequest.url);
			
			_savePngBtn.enabled = false;
			_saveJpegBtn.enabled = false;
			_printBtn.enabled = false;
			_pdfBtn.enabled = false;
			
			var loaderContext:LoaderContext = new LoaderContext ();
			loaderContext.checkPolicyFile = true;
			
			_qrLoader.load(_urlRequest, loaderContext);
		}
		
		
		private function onSavePngBtn(event:Event):void
		{
			trace("onSavePngBtn()");
			
			var qrCodeBitmap:Bitmap = Bitmap(_qrLoader.content);
			_qrCodeBitmapData = qrCodeBitmap.bitmapData;
			
			//var pngEncoder:PNGEncoder = new PNGEncoder(90);
			var imageByteArray:ByteArray = PNGEncoder.encode(_qrCodeBitmapData);
			
			var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");
			var pngURLRequest:URLRequest = new URLRequest(_createPngFilePhpUrl+"?name="+_imageFilename+".png");
			pngURLRequest.requestHeaders.push(header);
			pngURLRequest.method = URLRequestMethod.POST;
			pngURLRequest.data = imageByteArray;
			navigateToURL(pngURLRequest, "_blank");
		}
		
		
		private function onSaveJpegBtn(event:Event):void
		{
			trace("onSaveJpegBtn()");
			//navigateToURL(_urlRequest, "_blank");
			
			var qrCodeBitmap:Bitmap = Bitmap(_qrLoader.content);
			_qrCodeBitmapData = qrCodeBitmap.bitmapData;
			
			var jpgEncoder:JPGEncoder = new JPGEncoder(90);
			var imageByteArray:ByteArray = jpgEncoder.encode(_qrCodeBitmapData);
			
			var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");
			var jpgURLRequest:URLRequest = new URLRequest(_createJpegFilePhpUrl+"?name="+_imageFilename+".jpg");
			jpgURLRequest.requestHeaders.push(header);
			jpgURLRequest.method = URLRequestMethod.POST;
			jpgURLRequest.data = imageByteArray;
			navigateToURL(jpgURLRequest, "_blank");
		}
		
		
		private function onPrintBtn(event:Event):void
		{
			trace("onPrintBtn()");
			var pj:PrintJob = new PrintJob();
			
			if (pj.start()) {
				try {
					var tempBitmapData:BitmapData = new BitmapData( _size, _size);
					tempBitmapData.draw(_qrLoader);
					var qrCodeBitmap:Bitmap = new Bitmap(tempBitmapData);
					
					var qrCodeSprite:Sprite = new Sprite();
					qrCodeSprite.addChild(qrCodeBitmap);
					
					var scale:Number = _printTemplate.width / _size;
					qrCodeSprite.scaleX = qrCodeSprite.scaleY = scale;

					qrCodeSprite.y = (_printTemplate.height / 2) - (qrCodeSprite.height / 2);
					_printTemplate.addChild(qrCodeSprite);

					pj.addPage(_printTemplate);
				}
				catch(error:Error) {
					trace("There was an error with the PrintJob");
				}
				pj.send();
			} else {
				trace("PrintJob was cancelled");
			}

		}
		
		
		private function onPdfBtn(event:Event):void
		{
			trace("onPdfBtn()");
			
			var myPDF:PDF = new PDF(Orientation.PORTRAIT, Unit.MM, Size.A4);
			myPDF.setDisplayMode(Display.FULL_WIDTH); 
			
			myPDF.addPage();
			
			var pdfSheet:Sprite = new Sprite();
			pdfSheet.graphics.beginFill(0xFFFFFF, 1);
			pdfSheet.graphics.drawRect(0, 0, _pdfA4width, _pdfA4height);
			pdfSheet.graphics.endFill();
			
			var tempBitmapData:BitmapData = new BitmapData( _size, _size);
			tempBitmapData.draw(_qrLoader);
			var qrCodeBitmap:Bitmap = new Bitmap(tempBitmapData);
			var qrCodeSprite:Sprite = new Sprite();
			qrCodeSprite.addChild(qrCodeBitmap);
			var scale:Number = pdfSheet.width / _size;
			qrCodeSprite.scaleX = qrCodeSprite.scaleY = scale;
			qrCodeSprite.y = (pdfSheet.height / 2) - (qrCodeSprite.height / 2);
			pdfSheet.addChild(qrCodeSprite);

			myPDF.addImage(pdfSheet);
			
			var fileReference:FileReference = new FileReference();
			var byteArray:ByteArray = myPDF.save(Method.LOCAL);
			fileReference.save(byteArray, _pdfFilename);
			fileReference.addEventListener(IOErrorEvent.IO_ERROR, onFileReference_IO_ERROR);
		}
		
		
		private function onFileReference_IO_ERROR(event:IOErrorEvent):void
		{
			trace("onFileReference_IO_ERROR()");
			
		}
		
		
		private function onQrLoader_COMPLETE(event:Event):void {
			_loadingAnim.visible = false;
			
			_qrLoader.x = stage.stageWidth / 2 - _qrLoader.width / 2;
			_qrLoader.y = ((stage.stageHeight-_controlsHeight) / 2) - (_qrLoader.height / 2) + _controlsHeight;
			_qrLoader.visible = true;
			
			addChild(_qrLoader);
			addChild(_border);
			
			_savePngBtn.enabled = true;
			_saveJpegBtn.enabled = true;
			_printBtn.enabled = true;
			_pdfBtn.enabled = true;
			
			// NOTE: This will fail online because Google Charts
			// doesn't have a crossdomain.xml file.
			// To get around this issue we are using a serverside proxy script using PHP.
			var bmp:Bitmap = _qrLoader.content as Bitmap ;
			bmp.smoothing = true ;
		}
		
		
		private function onQrLoader_IO_ERROR(event:IOErrorEvent):void
		{
			trace("onQrLoader_IO_ERROR()");
			trace("event: " + event);
			_loadingAnim.visible = false;
			var errorMsg:String = "The was an error loading the following url:\n" + _urlRequest.url + "?" + _urlVars.toString();
			displayTextInMiddleOfScreen(errorMsg);
		}
		
		
		private function onQrLoader_HTTP_STATUS(event:HTTPStatusEvent):void
		{
			
			trace("onQrLoader_HTTP_STATUS()");
			trace("event: " + event);
            trace("event.status: " + event.status);
		}
		
		
		private function drawBorder($borderColour:uint = 0x0000, $borderWidth:uint = 1, $borderAlpha:Number = 1):Shape
		{
			var border:Shape = new Shape();
			
			border.graphics.beginFill($borderColour, $borderAlpha);
			border.graphics.drawRect($borderWidth, 0, stage.stageWidth-$borderWidth, $borderWidth);
			border.graphics.endFill();
			
			border.graphics.beginFill($borderColour, $borderAlpha);
			border.graphics.drawRect(stage.stageWidth-$borderWidth, $borderWidth, $borderWidth, stage.stageHeight-$borderWidth);
			border.graphics.endFill();
			
			border.graphics.beginFill($borderColour, $borderAlpha);
			border.graphics.drawRect(0, stage.stageHeight-$borderWidth, stage.stageWidth-$borderWidth, $borderWidth);
			border.graphics.endFill();
			
			border.graphics.beginFill($borderColour, $borderAlpha);
			border.graphics.drawRect(0, 0, $borderWidth, stage.stageHeight-$borderWidth);
			border.graphics.endFill();

			return border;
		}
		
		
		private function displayTextInMiddleOfScreen($msg:String):void
		{
			var tf:TextFormat = new TextFormat();
			tf.align = TextFormatAlign.CENTER;
			tf.size = 10;
			tf.bold = true;
			tf.font = "_sans";
			tf.color = 0x666666;
			
			_errorTxt.text = $msg;
			_errorTxt.border = true;
			_errorTxt.width = 400;
			_errorTxt.wordWrap = true;
			_errorTxt.autoSize = TextFieldAutoSize.CENTER;
			
			_errorTxt.setTextFormat(tf);
			_errorTxt.x = (stage.stageWidth / 2) - (_errorTxt.width / 2);
			_errorTxt.y = ((stage.stageHeight-_controlsHeight) / 2) - (_errorTxt.height / 2) + _controlsHeight - 10;
			
			_errorTxt.visible = true;
			addChild(_errorTxt);
		}
		
	}
	
}

Initial URL
http://www.adrianparr.com/?p=140

Initial Description
This makes use of http://www.minimalcomps.com, https://github.com/mikechambers/as3corelib and http://alivepdf.bytearray.org

Initial Title
AS3 QR Code Generator

Initial Tags
google, code

Initial Language
ActionScript 3