1 <?xml version="1.0" encoding="utf-8"?>
\r
3 xmlns:mx="http://www.adobe.com/2006/mxml"
\r
4 layout="absolute" creationComplete="{this.init();}">
\r
7 import com.google.zxing.common.BitMatrix;
\r
11 Thank you for your interest in the AS3 implementation of the zxing library.
\r
12 This Actionscript (AS3) code needs Flash player version 10 to run.
\r
13 This file is a very basic example how to use the zxing library to
\r
14 scan various barcodes with a standard webcam.
\r
15 This conversion is based on the zxing Java library, checked out from the SVN on August 7th 2009 (SVN revision ???)
\r
16 All additions and bugfixes added after this date have not yet been implemented in this version.
\r
17 This AS3 implementation has roughly the same recognition rate as revision ??? of Java implementation.
\r
19 How to build this example in FlexBuilder:
\r
20 - import this project (File->Import->Flex Project : select the 'client' folder)
\r
21 - uncheck 'Use default location' and press Finish
\r
22 - import the zxing library project (File->Import->FlexProject : select the 'core' folder)
\r
23 - uncheck 'Use default location' and press Finish
\r
24 - Right click the 'zxing client' project to select Properties
\r
25 - goto the 'Flex Build Path' section and select the 'Source path' tabsheet
\r
26 - click the 'Add Folder' button and select the 'src' directory in the 'core' project folder
\r
27 Now the client will use the zxing source files directly to build the application.
\r
28 Any updates in the library will then automatically be used by the client
\r
29 An an alternative would be to generate a SWC library file for the zxing.
\r
31 For more details, join the zxing project and please commit your bugfixes to the zxing repository.
\r
32 http://zxing.google.com
\r
37 - This project should compile with Flexbuilder 3.0 in combination with Flash10.
\r
38 If you do not need access to the local filesystem, Flash 9 should be sufficient to run this application.
\r
39 - I have omitted some very specific settings in this example application (e.g. the extended mode for code39/128 barcodes).
\r
40 The zxing library does handle these barcodes correctly if you set these modes correctly.
\r
41 - Actionscript is not very good at handling character sets with various encodings (used in e.g. in QRCodes).
\r
42 UTF8 and ShiftJIS encodings seem to work but I have not been able to test other character encodings.
\r
44 - Great performance improvements can be made but this needs quite some altering of the
\r
46 In order to keep the library as much in line with the original library for future updates and bugfixes,
\r
47 I have choosen not to implement those improvements here. I believe maintainability has a higher priority
\r
48 than performance at this moment
\r
49 I have introduced some extra classes in the
\r
50 com/google/zxing/common/flexdatatypes folder that match some of the default Java classes.
\r
51 - If you encounter bugs (and hopefully solutions) please join the zxing project and commit your fixes to
\r
52 the repository. Zxing project members are always willing to assist you if you're not familiar with repositories.
\r
53 - The Zxing project files are licensed under the Apache License, Version 2.0 (the "License");
\r
54 You may not use this file except in compliance with the License. You may obtain a copy of the License at
\r
55 http://www.apache.org/licenses/LICENSE-2.0
\r
56 - When using a webcam make sure you set the resolution to at least 300x300 with the setMode method of the Camera object.
\r
57 The default 160x120 resolution is too low for recognition of most barcodes.
\r
60 import mx.core.BitmapAsset;
\r
61 import com.google.zxing.common.flexdatatypes.HashTable;
\r
62 import flash.net.FileReference;
\r
63 import flash.display.Bitmap;
\r
64 import flash.display.*;
\r
65 import flash.net.URLRequest;
\r
66 import flash.events.Event;
\r
67 import mx.controls.Alert;
\r
69 import com.google.zxing.common.GlobalHistogramBinarizer;
\r
70 import com.google.zxing.common.ByteMatrix;
\r
71 import com.google.zxing.client.result.ParsedResult;
\r
72 import com.google.zxing.client.result.ResultParser;
\r
73 import com.google.zxing.DecodeHintType;
\r
74 import com.google.zxing.BarcodeFormat;
\r
75 import com.google.zxing.BinaryBitmap;
\r
76 import com.google.zxing.BufferedImageLuminanceSource;
\r
77 import com.google.zxing.MultiFormatReader;
\r
78 import com.google.zxing.MultiFormatWriter;
\r
79 import com.google.zxing.Result;
\r
81 private var fileRef:FileReference;
\r
82 private var myReader:MultiFormatReader;
\r
83 private var hints:HashTable;
\r
84 private var myWriter:MultiFormatWriter;
\r
86 public function init():void
\r
88 // initialise the generic reader
\r
89 myReader = new MultiFormatReader();
\r
92 public function decodeImage():void
\r
94 // did the user select an image?
\r
95 if (this.img.source != "")
\r
97 // show a message we are decoding
\r
98 this.resulttextarea.text = "*** decoding ***"
\r
101 // is the image valid?
\r
102 if (img.content != null)
\r
104 // try to decode the image
\r
105 this.decodeBitmapData((img.content as Bitmap).bitmapData,img.contentWidth, img.contentHeight);
\r
110 this.resulttextarea.text = "no image selected";
\r
115 this.resulttextarea.text = "*** Error in image data***"
\r
120 public function decodeBitmapData(bmpd:BitmapData, width:int, height:int):void
\r
122 // create the container to store the image data in
\r
123 var lsource:BufferedImageLuminanceSource = new BufferedImageLuminanceSource(bmpd);
\r
124 // convert it to a binary bitmap
\r
125 var bitmap:BinaryBitmap = new BinaryBitmap(new GlobalHistogramBinarizer(lsource));
\r
126 // get all the hints
\r
127 var ht:HashTable = null;
\r
128 ht = this.getAllHints()
\r
129 var res:Result = null;
\r
132 // try to decode the image
\r
133 res = myReader.decode(bitmap,ht);
\r
140 // did we find something?
\r
143 // no : we could not detect a valid barcode in the image
\r
144 this.resulttextarea.text = "<<No decoder could read the barcode>>";
\r
145 if (!this.bc_tryharder.selected)
\r
147 this.resulttextarea.text = "<<No decoder could read the barcode : Retry with the 'Try Harder' setting>>";
\r
152 // yes : parse the result
\r
153 var parsedResult:ParsedResult = ResultParser.parseResult(res);
\r
154 // get a formatted string and display it in our textarea
\r
155 this.resulttextarea.text = parsedResult.getDisplayResult();
\r
160 public function getAllHints():HashTable
\r
162 // get all hints from the user
\r
163 var ht:HashTable = new HashTable();
\r
164 if (this.bc_QR_CODE.selected) { ht.Add(DecodeHintType.POSSIBLE_FORMATS,BarcodeFormat.QR_CODE); }
\r
165 if (this.bc_DATAMATRIX.selected) { ht.Add(DecodeHintType.POSSIBLE_FORMATS,BarcodeFormat.DATAMATRIX); }
\r
166 if (this.bc_UPC_E.selected) { ht.Add(DecodeHintType.POSSIBLE_FORMATS,BarcodeFormat.UPC_E); }
\r
167 if (this.bc_UPC_A.selected) { ht.Add(DecodeHintType.POSSIBLE_FORMATS,BarcodeFormat.UPC_A); }
\r
168 if (this.bc_EAN_8.selected) { ht.Add(DecodeHintType.POSSIBLE_FORMATS,BarcodeFormat.EAN_8); }
\r
169 if (this.bc_EAN_13.selected) { ht.Add(DecodeHintType.POSSIBLE_FORMATS,BarcodeFormat.EAN_13); }
\r
170 if (this.bc_CODE_39.selected) { ht.Add(DecodeHintType.POSSIBLE_FORMATS,BarcodeFormat.CODE_39);}
\r
171 if (this.bc_CODE_128.selected) { ht.Add(DecodeHintType.POSSIBLE_FORMATS,BarcodeFormat.CODE_128); }
\r
172 if (this.bc_PDF417.selected) { ht.Add(DecodeHintType.POSSIBLE_FORMATS,BarcodeFormat.PDF417); }
\r
173 if (this.bc_ITF.selected) { ht.Add(DecodeHintType.POSSIBLE_FORMATS,BarcodeFormat.ITF); }
\r
174 if (this.bc_tryharder.selected) { ht.Add(DecodeHintType.TRY_HARDER,true); }
\r
179 public function clearImage():void
\r
181 // remove the image
\r
182 this.img.source = null;
\r
183 this.resulttextarea.text = "";
\r
186 public function selectFile():void
\r
189 fileRef = new FileReference();
\r
190 var fileFilter4:FileFilter = new FileFilter('JPG','*.jpg');
\r
191 var fileFilter1:FileFilter = new FileFilter('PNG','*.png');
\r
192 var fileFilter2:FileFilter = new FileFilter('GIF','*.gif');
\r
193 var fileFilter3:FileFilter = new FileFilter('All files','*.*');
\r
194 fileRef.addEventListener(Event.SELECT, selectHandler);
\r
195 fileRef.addEventListener(Event.COMPLETE,completeHandler);
\r
196 fileRef.browse([fileFilter4,
\r
202 public function selectHandler(event:Event):void
\r
204 // try to load the image
\r
205 fileRef.removeEventListener(Event.SELECT, selectHandler);
\r
209 public function completeHandler(event:Event):void
\r
211 // image loaded succesfully
\r
212 fileRef.removeEventListener(Event.COMPLETE,completeHandler);
\r
213 img.load(fileRef.data);
\r
216 public function selectNone():void
\r
218 // remove all hints (except the try harder hint)
\r
219 this.bc_QR_CODE.selected = false;
\r
220 this.bc_DATAMATRIX.selected = false;
\r
221 this.bc_UPC_E.selected = false;
\r
222 this.bc_UPC_A.selected = false;
\r
223 this.bc_EAN_8.selected = false;
\r
224 this.bc_EAN_13.selected = false;
\r
225 this.bc_CODE_128.selected = false;
\r
226 this.bc_CODE_39.selected = false;
\r
227 this.bc_ITF.selected = false;
\r
230 private function videoDisplay_creationComplete():void
\r
232 // try to attach the webcam to the videoDisplay
\r
233 var camera:Camera = Camera.getCamera();
\r
236 if ((camera.width == -1) && ( camera.height == -1))
\r
238 // no webcam seems to be attached -> hide videoDisplay
\r
239 videoDisplay.width = 0;
\r
240 videoDisplay.height = 0;
\r
241 this.videoDisplayLabel.visible = true;
\r
242 this.buttonBox.visible = false;
\r
248 // change the default mode of the webcam
\r
249 camera.setMode(350,350,5,true);
\r
250 videoDisplay.width = camera.width;
\r
251 videoDisplay.height = camera.height;
\r
252 this.videoDisplayLabel.visible = false;
\r
253 this.buttonBox.visible = true;
\r
255 videoDisplay.attachCamera(camera);
\r
258 Alert.show("You don't seem to have a webcam.");
\r
262 private function decodeSnapshot():void
\r
264 // try to decode the current snapshpt
\r
265 var bmd:BitmapData = new BitmapData(this.videoDisplay.width, this.videoDisplay.height);
\r
266 bmd.draw(videoDisplay);
\r
267 this.decodeBitmapData(bmd, this.videoDisplay.width, this.videoDisplay.height);
\r
271 public function generateQRCode():void
\r
273 // read input string
\r
274 var contents:String = this.QRINput.text;
\r
275 myWriter = new MultiFormatWriter();
\r
278 // try to encode the string
\r
279 var result:ByteMatrix = (myWriter.encode(contents,BarcodeFormat.QR_CODE,300,300)) as ByteMatrix;
\r
283 Alert.show('An error occurred during the encoding process');
\r
286 // try to generate an image with the result data
\r
287 var bmpd:BitmapData = new BitmapData(300, 300, false, 0x009900);
\r
288 var bmp:Bitmap = new Bitmap(bmpd);
\r
289 this.QRImage.source = bmp;
\r
290 for (var h:int=0;h<300;h++)
\r
292 for (var w:int=0;w<300;w++)
\r
294 if (result._get(w,h) == 0)
\r
296 bmpd.setPixel(w,h, 0);
\r
300 bmpd.setPixel(w,h, 0xFFFFFF);
\r
307 public function generateEANBarcode():void
\r
309 var name:String = "";
\r
310 var barcodeType:BarcodeFormat = null;
\r
311 var inputlength:int = 0;
\r
312 // set the correct parameters
\r
313 if (this.EAN8.selected)
\r
316 barcodeType = BarcodeFormat.EAN_8;
\r
322 barcodeType = BarcodeFormat.EAN_13;
\r
327 var resultBits:Array = null;
\r
328 var contents:String = this.EANINput.text;
\r
329 // do some checking
\r
330 if (contents.length > inputlength)
\r
332 Alert.show(name+' can only contain '+inputlength+' digits');
\r
336 while(counter < contents.length)
\r
339 var cc:int = contents.charCodeAt(counter);
\r
340 if ((cc<0x30) || (cc>0x39))
\r
342 Alert.show("EAN barcodes can only contain digits");
\r
347 while (contents.length < inputlength) { contents = "0" + contents; }
\r
348 this.EANINput.text = contents;
\r
349 myWriter = new MultiFormatWriter();
\r
352 // try to generate the data for the barcode
\r
353 var result:ByteMatrix = myWriter.encode(contents,barcodeType) as ByteMatrix;
\r
357 Alert.show("An error occured when making the barcode");
\r
359 resultBits = new Array(result.height());
\r
360 for (var i:int=0;i<result.height();i++)
\r
362 resultBits[i] = result._get(i,0);
\r
365 // generate an image
\r
366 var bmpd:BitmapData = new BitmapData(this.EANImage.width, this.EANImage.height, false, 0x009900);
\r
367 var bmp:Bitmap = new Bitmap(bmpd);
\r
368 this.EANImage.source = bmp;
\r
369 for (var h:int=0;h<bmpd.height;h++)
\r
371 var bmpdwidth:int = bmpd.width;
\r
372 for (var w:int=0;w<bmpdwidth;w++)
\r
374 if (resultBits[Math.round(w*(resultBits.length/bmpdwidth))] == 0)
\r
376 bmpd.setPixel(w,h, 0);
\r
380 bmpd.setPixel(w,h, 0xFFFFFF);
\r
390 <mx:Label text="Example for reading and creating barcodes with the ZXing library by Bas Vijfwinkel" fontWeight="bold" />
\r
392 <mx:HBox label="Read a barcode">
\r
393 <mx:VBox width="300">
\r
395 <mx:Button label="Select image" click="selectFile()" x="10" y="318"/>
\r
396 <mx:Button label="Decode!" click="decodeImage()" x="117" y="318"/>
\r
397 <mx:Button label="Clear" click="clearImage()" x="198" y="318"/>
\r
399 <mx:Canvas width="300" height="300" backgroundColor="white">
\r
400 <mx:Image id="img" width="300" height="300"/>
\r
402 <mx:Label text="Result :"/>
\r
403 <mx:TextArea id="resulttextarea" width="300" height="100" />
\r
406 <mx:VideoDisplay id="videoDisplay"
\r
407 creationComplete="videoDisplay_creationComplete();"
\r
410 <mx:Label id="videoDisplayLabel" text="Camera not attached" visible="false"/>
\r
411 <mx:HBox id="buttonBox" visible="true">
\r
412 <mx:Button id="button"
\r
413 label="Reload Camera"
\r
414 click="videoDisplay_creationComplete();" />
\r
415 <mx:Button id="snapshot"
\r
416 label = "Decode Snapshot"
\r
417 click ="decodeSnapshot();"
\r
420 <mx:HBox x="320" y="10">
\r
422 <mx:CheckBox id="bc_QR_CODE" label="QR_CODE" />
\r
423 <mx:CheckBox id="bc_DATAMATRIX" label="DATAMATRIX" />
\r
424 <mx:CheckBox id="bc_UPC_E" label="UPC_E" />
\r
425 <mx:CheckBox id="bc_UPC_A" label="UPC_A" />
\r
426 <mx:CheckBox id="bc_EAN_8" label="EAN_8" />
\r
427 <mx:CheckBox id="bc_EAN_13" label="EAN_13" />
\r
430 <mx:CheckBox id="bc_CODE_128" label="CODE_128" />
\r
431 <mx:CheckBox id="bc_CODE_39" label="CODE_39" />
\r
432 <mx:CheckBox id="bc_PDF417" label="PDF417" />
\r
433 <mx:CheckBox id="bc_ITF" label="ITF" />
\r
434 <mx:CheckBox id="bc_tryharder" label="Try Harder" />
\r
435 <mx:Button label="Select None" click="selectNone()" />
\r
440 <mx:TabNavigator label="Create a barcode">
\r
441 <mx:VBox label="EAN">
\r
442 <mx:Label text="Generate an EAN barcode"/>
\r
443 <mx:TextInput id="EANINput" text="type the digits here"/>
\r
444 <mx:RadioButton groupName="EANRB" id="EAN8" label="EAN8" selected="true"/>
\r
445 <mx:RadioButton groupName="EANRB" id="EAN13" label="EAN13" selected="false"/>
\r
446 <mx:Button label="Generate" buttonDown="{this.generateEANBarcode();}"/>
\r
447 <mx:Image id="EANImage" width="300" height="100" />
\r
449 <mx:VBox label="QRCode">
\r
450 <mx:Label text="Generate a QRCode"/>
\r
451 <mx:TextInput id="QRINput" text="type text here"/>
\r
452 <mx:Button label="Generate" buttonDown="{this.generateQRCode();}"/>
\r
453 <mx:Image id="QRImage" width="300" height="300" />
\r