惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
Scott Helme
Scott Helme
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Stack Overflow Blog
Stack Overflow Blog
Forbes - Security
Forbes - Security
T
The Blog of Author Tim Ferriss
Y
Y Combinator Blog
S
Schneier on Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Cisco Talos Blog
Cisco Talos Blog
N
News | PayPal Newsroom
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Project Zero
Project Zero
Cyberwarzone
Cyberwarzone
Vercel News
Vercel News
M
MIT News - Artificial intelligence
云风的 BLOG
云风的 BLOG
Google Online Security Blog
Google Online Security Blog
Simon Willison's Weblog
Simon Willison's Weblog
MongoDB | Blog
MongoDB | Blog
Martin Fowler
Martin Fowler
T
Tenable Blog
I
InfoQ
W
WeLiveSecurity
Google DeepMind News
Google DeepMind News
G
Google Developers Blog
D
DataBreaches.Net
博客园 - Franky
Know Your Adversary
Know Your Adversary
Spread Privacy
Spread Privacy
S
Security @ Cisco Blogs
Hacker News: Ask HN
Hacker News: Ask HN
J
Java Code Geeks
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
F
Full Disclosure
C
Cisco Blogs
Google DeepMind News
Google DeepMind News
P
Proofpoint News Feed
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Cloudflare Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
I
Intezer
The GitHub Blog
The GitHub Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
F
Fortinet All Blogs
Jina AI
Jina AI
V
Visual Studio Blog
L
LINUX DO - 热门话题
WordPress大学
WordPress大学
aimingoo的专栏
aimingoo的专栏

博客园 - 永不言败

JavaScript 语言基础知识点总结(思维导图) 关于Visual Studio项目系统属性中的宏 MongoDb的相关资料 javascript apply 和call的区别,javascript设计模式 castle 在mvc3如何注入 Castle Automatic Transaction Management python webpy模板介绍 使用 asp.net mvc和 jQuery UI 控件包 webpy demo核心代码 Howto create a System.Linq.Expressions.Expression for Like 实体框架继承关系。很好 淘宝店铺图片数据迁移核心代码 mvc扩展 ASP.NET MVC 2 Templates C#、VB.NET使用HttpWebRequest访问https地址(SSL)的实现 Nhibernate继承 Castle 容器注入学习例子 javaScript 运算符 && 和 || 的返回值 event.x,event.clientX,event.offsetX区别
Adding a QR Code Reader in Flex on Android
永不言败 · 2012-01-12 · via 博客园 - 永不言败

One of the features I commonly see requested for Android applications is QR code reader or barcode scanner integration. Some native Android applications actually use an external application for QR code/barcode scanning. That, as far as I know, is not an option at the moment in AIR on Android. However, thanks to the open source ZXing library, some direction from Amer Dababneh and a blog post by Michael B, I was able to create basic sample Flex-based mobile application that accessed the camera and read QR codes. This blog post will show you how.

For any smart asses out there (yes, I mean you Ray) - yes, I can still code. It’s just been a while since I had something “blogworthy.” :)

Create Your Project
To begin with, of course, you need to create your new Flex mobile project - I used a standard view-based application. I should note that while I only tested this on Android (via my Nexus One), it’s entirely possible that this code will work as is on iOS or Blackberry Tablet OS via the recent Flash Builder 4.5.1 update.

The important thing to note here is that you will need to enable Camera permissions in your app.xml file. This can be done during the new project wizard or by manually adding the below items to your app.xml within the Android “manifestAdditions” section:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.autofocus"/>

In my experience, if you forget to do this or don’t do it properly, the camera will simply fail silently (which can lead to needless debugging frustration - so just don’t forget).

Adding the Camera
Now that we’ve created our new Flex mobile application, we need to lay out our sample application. My sample is very simple with only a home view that contains the camera, a label to display any results and a button to start the process and capture the QR codes. For reference, I borrowed some of the camera placement code from this blog post by Guillaume.

You can see the visual elements of the page laid out below. The SpriteVisualElement is the container that will hold the view to our camera.

<s:VGroup width="100%" horizontalAlign="center" id="vg">
   <s:SpriteVisualElement id="sv" width="360" height="400"/>
   <s:Label id="lbl" text="" />
   <s:Button id="btn" label="Start Camera" width="220" height="93" click="button1_clickHandler(event)"/>
</s:VGroup>

The first time the user clicks the button, it will start the camera. Inside my click handler for the button, I have the following code that first gets an instance of the Camera, attaches it to a VideoDisplay object which is added as a child to our SpriteVisualElement. We also initialize our QRCodeReader class which is from the ZXing library.

if (Camera.isSupported)
{
   camera=Camera.getCamera();
   camera.setMode(360, 360, 24);
                  
   videoDisplay.x = 360;
   sv.addChild(videoDisplay);
   
   videoDisplay.attachCamera(camera);
   videoDisplay.rotation=90;
   qrReader=new QRCodeReader;
   btn.label = "Scan Now";
   lbl.text = "";
   cameraStarted = true;
}
else {
   lbl.text = "no camera found";
}

If you ran your app right now (see the full code at the end of this post for all the necessary variables and imports) you would see a view into your device’s camera appear once you click the button to start - that is if our QRCodeReader wasn’t throwing compile errors. Let’s get those fixed.

Modifying the ZXing Library
Obviously, in order to create this project you must download the ZXing library from Google Code. Simply dump the library into your “src” folder where it should be under a com.google.zxing package. As I noted, you will get some complile errors as soon as you try to use the necessary files for QRCodeScanning. Luckily they are very easy to correct as they all involve unnecessary or missing imports.

Here are the changes required to get this working on our project:

  • In QRCodeMultiReader add import com.google.zxing.BinaryBitmap; (or just press ctrl+space after the BinaryBitmap on the line with the compile error and have Flash Builder add the import for you);
  • In DecoderResult comment out import of mx.controls.List;
  • In BufferedImageLuminanceSource comment out import mx.controls.Image;.

Reading the QR Code
Most of the ZXing library usage code to read the QR code was taken verbatim from the blog post by Michael B referenced above. The decodeSnapshot method, which is triggered when the user presses the button to capture a QR code, gets the bitmap data from the Camera and passes it to the decodeBitmapData method. The decodeBitmapData method mostly handles passing this bitmap data to the ZXing library for decoding and then displaying the result in the label. The getAllHints method actually tells the ZXing library what kind of QR/barcode we are trying to decode. Theoretically, if you wanted to decode other standard barcode types, you would just add those to the hashtable. ZXing supports many types of barcode scanning and if you simply add the other types, it should just work - but I emphasize should because I didn’t test it yet.

public function decodeSnapshot():void
{
   lbl.text="checking...";
   bmd=new BitmapData(300, 300);
   bmd.draw(videoDisplay, null, null, null, null, true);
   videoDisplay.cacheAsBitmap=true;
   videoDisplay.cacheAsBitmapMatrix=new Matrix;
   decodeBitmapData(bmd, 300, 300);
   bmd.dispose();
   bmd=null;
   System.gc();
}
         
public function decodeBitmapData(bmpd:BitmapData, width:int, height:int):void
{
   var lsource:BufferedImageLuminanceSource=new BufferedImageLuminanceSource(bmpd);
   var bitmap:BinaryBitmap=new BinaryBitmap(new GlobalHistogramBinarizer(lsource));

   var ht:HashTable=null;
   ht=this.getAllHints();
            
   var res:Result=null;
   try {
      res=qrReader.decode(bitmap, ht);
   }
   catch (event:Error) {
   }
            
   if (res == null) {
      videoDisplay.clear();
      lbl.text="nothing decoded";
   }
   else {
      var parsedResult:ParsedResult=ResultParser.parseResult(res);
      lbl.text=parsedResult.getDisplayResult();
      sv.removeChild(videoDisplay);
      cameraStarted = false;
      btn.label = "Start Camera";
   }
}
         
public function getAllHints():HashTable
{
   var ht:HashTable=new HashTable;
   ht.Add(DecodeHintType.POSSIBLE_FORMATS, BarcodeFormat.QR_CODE);
   return ht;
}

Testing Your QR Code Reading
For testing, I used this QR Code generator for encode both URL and straight text encoded QR codes. In my tests, not only did the QR code reading work well but it ran pretty fast (and my Nexus One is no powerhouse any longer - if it ever was). One thing I did note though is that it can be pretty picky about where the QR code is placed within the image. It should be centered and should not be so close that it takes up the entire camera. I think this is partly because we are actually passing only a 300x300 bitmap out of our 360x360 camera image to be decoded, so this might be fixable. If that isn’t correctable in that manner than I thought it would be wise to add some guides as an overlay to help the user know where to align the QR code.

The other thing I noticed was that when I created a timer event and tested checked the camera periodically using that (as in the linked sample I sourced), I did get some performance issues where the app periodically became unusable (mostly during debugging mode but it seemed indicative of a problem you’d want to potentially eliminate).

That’s it. Not too complicated eh? For reference, below is the finished Flex Mobile View with all the elements you need to get this sample running. Let me know if this helps you or if you manage to expand upon the example (and feel free to share your code if you do).

P.S. I am not posting an FXP because I am unsure if there are any redistribution restrictions on the license for ZXing.

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx"
      xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView">

   <fx:Declarations>
      <!-- Place non-visual elements (e.g., services, value objects) here -->
   </fx:Declarations>
   <fx:Script>
      <![CDATA[
         import com.google.zxing.BarcodeFormat;
         import com.google.zxing.BinaryBitmap;
         import com.google.zxing.BufferedImageLuminanceSource;
         import com.google.zxing.DecodeHintType;
         import com.google.zxing.Result;
         import com.google.zxing.client.result.ParsedResult;
         import com.google.zxing.client.result.ResultParser;
         import com.google.zxing.common.BitMatrix;
         import com.google.zxing.common.ByteMatrix;
         import com.google.zxing.common.GlobalHistogramBinarizer;
         import com.google.zxing.common.flexdatatypes.HashTable;
         import com.google.zxing.qrcode.QRCodeReader;
         import com.google.zxing.qrcode.detector.Detector;
         
         import spark.events.ViewNavigatorEvent;
         
         protected var camera:Camera;
         private var videoDisplay:Video=new Video(360, 360);
         private var qrReader:QRCodeReader;
         private var bmd:BitmapData;
         private var cameraStarted:Boolean = false;
         
         protected function button1_clickHandler(event:MouseEvent):void
         {
            if (!cameraStarted) {
               if (Camera.isSupported)
               {
                  camera=Camera.getCamera();
                  camera.setMode(360, 360, 24);
                  
                  videoDisplay.x = 360;
                  sv.addChild(videoDisplay);
                  
                  videoDisplay.attachCamera(camera);
                  videoDisplay.rotation=90;
                  qrReader=new QRCodeReader;
                  btn.label = "Scan Now";
                  lbl.text = "";
                  cameraStarted = true;
               }
               else {
                  lbl.text = "no camera found";
               }
            }
            else {
               decodeSnapshot();
            }
         }
         
         public function decodeSnapshot():void
         {
            lbl.text="checking...";
            bmd=new BitmapData(300, 300);
            bmd.draw(videoDisplay, null, null, null, null, true);
            videoDisplay.cacheAsBitmap=true;
            videoDisplay.cacheAsBitmapMatrix=new Matrix;
            decodeBitmapData(bmd, 300, 300);
            bmd.dispose();
            bmd=null;
            System.gc();
         }
         
         public function decodeBitmapData(bmpd:BitmapData, width:int, height:int):void
         {
            var lsource:BufferedImageLuminanceSource=new BufferedImageLuminanceSource(bmpd);
            var bitmap:BinaryBitmap=new BinaryBitmap(new GlobalHistogramBinarizer(lsource));
            
            var ht:HashTable=null;
            ht=this.getAllHints();
            
            var res:Result=null;
            try {
               res=qrReader.decode(bitmap, ht);
            }
            catch (event:Error) {
            }
            
            if (res == null) {
               videoDisplay.clear();
               lbl.text="nothing decoded";
            }
            else {
               var parsedResult:ParsedResult=ResultParser.parseResult(res);
               lbl.text=parsedResult.getDisplayResult();
               sv.removeChild(videoDisplay);
               cameraStarted = false;
               btn.label = "Start Camera";
            }
         }
         
         public function getAllHints():HashTable
         {
            var ht:HashTable=new HashTable;
            ht.Add(DecodeHintType.POSSIBLE_FORMATS, BarcodeFormat.QR_CODE);
            return ht;
         }
         
      ]]>
   </fx:Script>
   <s:VGroup width="100%" horizontalAlign="center" id="vg">
      <s:SpriteVisualElement id="sv" width="360" height="400"/>
      <s:Label id="lbl" text="" />
      <s:Button id="btn" label="Start Camera" width="220" height="93" click="button1_clickHandler(event)"/>
   </s:VGroup>
</s:View>

http://remotesynthesis.com/post.cfm/adding-a-qr-code-reader-in-flex-on-android