Added simplistic ability to rotate an LCDUI image (once), to help out some devices...
[zxing.git] / actionscript / zxing client / src / zxing_client.mxml
1 <?xml version="1.0" encoding="utf-8"?>\r
2 <mx:Application \r
3         xmlns:mx="http://www.adobe.com/2006/mxml" \r
4         layout="absolute" creationComplete="{this.init();}">\r
5             <mx:Script>\r
6     <![CDATA[\r
7         import com.google.zxing.common.BitMatrix;\r
8     /*\r
9         Dear developer,\r
10         \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
18         \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
30         \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
33         \r
34         Bas Vijfwinkel\r
35          \r
36         Notes : \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
43                    \r
44                 - Great performance improvements can be made but this needs quite some altering of the \r
45                   current library.\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
58     \r
59     */\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
68         \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
80         \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
85 \r
86         public function init():void\r
87         {\r
88                 // initialise the generic reader\r
89                 myReader = new MultiFormatReader();\r
90         }\r
91         \r
92         public function decodeImage():void\r
93         {\r
94                 // did the user select an image?\r
95                 if (this.img.source != "")\r
96                 {\r
97                         // show a message we are decoding\r
98                         this.resulttextarea.text = "*** decoding ***"\r
99                         try\r
100                         {\r
101                                 // is the image valid?\r
102                                 if (img.content != null)\r
103                                 {\r
104                                         // try to decode the image\r
105                                                 this.decodeBitmapData((img.content as Bitmap).bitmapData,img.contentWidth, img.contentHeight);\r
106                                 }\r
107                                 else\r
108                                 {\r
109                                         // invalid image\r
110                                         this.resulttextarea.text = "no image selected";\r
111                                 }\r
112                         }\r
113                         catch(E:Error)\r
114                         {\r
115                                 this.resulttextarea.text = "*** Error in image data***"\r
116                         }\r
117                 }\r
118         }\r
119         \r
120         public function decodeBitmapData(bmpd:BitmapData, width:int, height:int):void\r
121         {\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
130                 try\r
131                 {\r
132                         // try to decode the image\r
133                         res = myReader.decode(bitmap,ht);\r
134                 }\r
135                 catch(e:Error) \r
136                 {\r
137                         // failed\r
138                 }\r
139                 \r
140                 // did we find something?\r
141                 if (res == null)\r
142                 {\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
146                         {\r
147                                 this.resulttextarea.text = "<<No decoder could read the barcode : Retry with the 'Try Harder' setting>>";\r
148                         }\r
149                 }\r
150                 else\r
151                 {\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
156                 }\r
157     }\r
158             \r
159             \r
160             public function getAllHints():HashTable\r
161             {\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
175                         return ht;\r
176             }\r
177             \r
178         \r
179         public function clearImage():void\r
180         {\r
181                 // remove the image\r
182                 this.img.source = null;\r
183                 this.resulttextarea.text = "";\r
184         }\r
185         \r
186         public function selectFile():void\r
187         {\r
188                 // file open menu\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
197                                                 fileFilter1,\r
198                                                 fileFilter2,\r
199                                                 fileFilter3]);\r
200         }\r
201 \r
202                 public function selectHandler(event:Event):void\r
203                 {\r
204                         // try to load the image\r
205                         fileRef.removeEventListener(Event.SELECT, selectHandler);\r
206                         fileRef.load();\r
207                 }\r
208                 \r
209                 public function completeHandler(event:Event):void\r
210                 {\r
211                         // image loaded succesfully\r
212                         fileRef.removeEventListener(Event.COMPLETE,completeHandler);\r
213                         img.load(fileRef.data);\r
214                 }\r
215                 \r
216                 public function selectNone():void\r
217                 {\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
228                 }\r
229 \r
230         private function videoDisplay_creationComplete():void \r
231         {\r
232                 // try to attach the webcam to the videoDisplay\r
233                 var camera:Camera = Camera.getCamera();\r
234                 if (camera) \r
235                 {\r
236                         if ((camera.width == -1) && ( camera.height == -1))\r
237                         {\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
243                         }\r
244                         else\r
245                         {\r
246                                 // webcam detected\r
247                                 \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
254 \r
255                         videoDisplay.attachCamera(camera);\r
256                         }\r
257                 } else {\r
258                     Alert.show("You don't seem to have a webcam.");\r
259                 }\r
260             }\r
261             \r
262             private function decodeSnapshot():void\r
263             {\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
268                 \r
269             }\r
270 \r
271             public function generateQRCode():void\r
272             {\r
273                 // read input string\r
274                 var contents:String = this.QRINput.text;\r
275                 myWriter = new MultiFormatWriter();\r
276                 try\r
277                 {\r
278                         // try to encode the string\r
279                         var result:ByteMatrix = (myWriter.encode(contents,BarcodeFormat.QR_CODE,300,300)) as ByteMatrix;\r
280                 }\r
281                 catch (e:Error)\r
282                 {\r
283                         Alert.show('An error occurred during the encoding process');\r
284                         return;\r
285                 }\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
291                 {\r
292                         for (var w:int=0;w<300;w++)\r
293                         {\r
294                                 if (result._get(w,h) == 0)\r
295                                 {\r
296                                         bmpd.setPixel(w,h, 0);\r
297                                 }\r
298                                 else\r
299                                 {\r
300                                         bmpd.setPixel(w,h, 0xFFFFFF);\r
301                                 }               \r
302                         }\r
303                 }\r
304 \r
305             } \r
306             \r
307             public function generateEANBarcode():void\r
308             {\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
314                 {\r
315                         name       = "EAN8";\r
316                         barcodeType = BarcodeFormat.EAN_8;\r
317                         inputlength = 8;\r
318                 }\r
319                 else\r
320                 {\r
321                         name       = "EAN13";\r
322                         barcodeType = BarcodeFormat.EAN_13;\r
323                         inputlength = 13;\r
324 \r
325 \r
326                 }\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
331                     {\r
332                         Alert.show(name+' can only contain '+inputlength+' digits');\r
333                         return;\r
334                     }\r
335                     var counter:int=0;\r
336                     while(counter < contents.length)\r
337                     {\r
338                         \r
339                         var cc:int = contents.charCodeAt(counter);\r
340                         if ((cc<0x30) || (cc>0x39)) \r
341                         {\r
342                                  Alert.show("EAN barcodes can only contain digits"); \r
343                                  return;\r
344                         }\r
345                         counter++;\r
346                     }\r
347                     while (contents.length < inputlength) { contents = "0" + contents; }\r
348                     this.EANINput.text = contents;\r
349                 myWriter = new MultiFormatWriter();\r
350                 try\r
351                 {\r
352                         // try to generate the data for the barcode\r
353                         var result:ByteMatrix = myWriter.encode(contents,barcodeType) as ByteMatrix;\r
354                 }\r
355                 catch (e:Error)\r
356                 {\r
357                         Alert.show("An error occured when making the barcode");\r
358                 }\r
359                 resultBits = new Array(result.height());\r
360                 for (var i:int=0;i<result.height();i++)\r
361                 {\r
362                         resultBits[i] = result._get(i,0);\r
363                 }\r
364 \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
370                 {\r
371                         var bmpdwidth:int = bmpd.width; \r
372                         for (var w:int=0;w<bmpdwidth;w++)\r
373                         {\r
374                                 if (resultBits[Math.round(w*(resultBits.length/bmpdwidth))] == 0)\r
375                                 {\r
376                                         bmpd.setPixel(w,h, 0);\r
377                                 }\r
378                                 else\r
379                                 {\r
380                                         bmpd.setPixel(w,h, 0xFFFFFF);\r
381                                 }               \r
382                         }\r
383                 }\r
384             }\r
385             \r
386                 \r
387     ]]>\r
388     </mx:Script>\r
389     <mx:VBox>\r
390         <mx:Label text="Example for reading and creating barcodes with the ZXing library       by Bas Vijfwinkel" fontWeight="bold" />\r
391             <mx:TabNavigator>\r
392                     <mx:HBox label="Read a barcode">\r
393                                 <mx:VBox width="300">\r
394                                         <mx:HBox>\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
398                                         </mx:HBox>\r
399                                         <mx:Canvas width="300" height="300" backgroundColor="white">\r
400                                                 <mx:Image id="img" width="300" height="300"/>   \r
401                                         </mx:Canvas>\r
402                                         <mx:Label text="Result :"/>\r
403                                         <mx:TextArea id="resulttextarea" width="300" height="100" />\r
404                                 </mx:VBox>\r
405                                         <mx:VBox>\r
406                                             <mx:VideoDisplay id="videoDisplay"\r
407                                                                 creationComplete="videoDisplay_creationComplete();"\r
408                                                                 width="300"\r
409                                                                 height="300" />\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
418                                                            />\r
419                                             </mx:HBox>\r
420                                             <mx:HBox  x="320" y="10">\r
421                                                         <mx:VBox>\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
428                                                         </mx:VBox>\r
429                                                         <mx:VBox>\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
436                                                         </mx:VBox>              \r
437                                                 </mx:HBox>\r
438                                         </mx:VBox>\r
439                         </mx:HBox>\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
448                                 </mx:VBox>\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
454                                         \r
455                                         \r
456                                 </mx:VBox>\r
457                         </mx:TabNavigator>\r
458             </mx:TabNavigator>\r
459         </mx:VBox>\r
460 </mx:Application>\r