Showing posts with label ZXing. Show all posts
Showing posts with label ZXing. Show all posts

Wednesday, April 21, 2010

ColdFusion: ZXing - Read / Write QRCode Barcode Example

I have been slowly working my way through more of the zxing library. Since I did not find any CF examples in my searches, I am posting some of my code snippets in case it helps someone else.


Generate Barcode
To generate a barcode, I first created an instance of the QRCodeWriter. Then called its encode() method with four settings: the text to encode, barcode type and the desired width and height. The encode() method does it magic and returns a matrix of bytes. Next I used the MatrixToImageWriter class, and its toBufferedImage(), method to convert the matrix into something useful. Not surprisingly, it returns a BufferedImage which is easily converted to a CF image object.

Note: This example uses the JavaLoader.cfc

<!---
    Generate barcode
--->
<cftry>
    <cfset origText = "http://code.google.com/p/zxing/wiki/GettingStarted" />
    <!--- initialize writer and create a new barcode matrix --->
    <cfset BarcodeFormat = loader.create("com.google.zxing.BarcodeFormat") />
    <cfset writer = loader.create("com.google.zxing.qrcode.QRCodeWriter").init() />
    <cfset bitMatrix = writer.encode( origText, BarcodeFormat.QR_CODE, 80, 80 )>
    <!--- render the matrix as a bufferedimage --->
    <cfset converter = loader.create("com.google.zxing.client.j2se.MatrixToImageWriter")>
    <cfset buff = converter.toBufferedImage( bitMatrix ) />
    <!--- convert it to a CF compatible image --->
    <cfset img = ImageNew( buff ) />

    <!--- display results --->
    <b>Original Text = </b> <cfoutput>#origText#</cfoutput>
    <div>
        <cfimage action="writeToBrowser" source="#img#" format="png">
    </div>
    <!--- add real exception handling here ...--->
    <cfcatch>
        ERROR: Unable to generate barcode <cfoutput>#cfcatch.message#</cfoutput>
    </cfcatch>
</cftry>

Read Barcode
Now to read / decode, I passed the BufferedImage into a series of classes that attempt to locate a barcode within an image and essentially extract it into matrix of bits. Finally, I passed the matrix into a QRCodeReader for decoding and voila - it returned the decoded text.

Result:


<!---
    Decode barcode
--->
<cftry>
    <!--- extract the BufferedImage of the current barcode --->
    <cfset buff = ImageGetBufferedImage( img ) />
    <!--- prepare the image for decoding --->
    <cfset source = loader.create("com.google.zxing.client.j2se.BufferedImageLuminanceSource").init( buff ) />
    <cfset binarizer = loader.create("com.google.zxing.common.GlobalHistogramBinarizer").init( source ) />
    <cfset bitmap = loader.create("com.google.zxing.BinaryBitmap").init( binarizer ) />
    <cfset reader = loader.create("com.google.zxing.qrcode.QRCodeReader").init() />
    <!--- decode the barcode. skipping "hints" just for simplicity --->
    <cfset decodedResult = reader.decode( bitmap, javacast("null", "")) />
    
    <!--- display results --->
    <b>Decoded Text = </b> <cfoutput>#decodedResult.getText()#</cfoutput>

    <!--- add real exception handling here ...--->
    <cfcatch>
        ERROR: Unable to generate barcode <cfoutput>#cfcatch.message#</cfoutput>
    </cfcatch>
</cftry>

Related Entries

...Read More

Friday, January 15, 2010

How to Install ZXing in Eclipse (JavaSE Component Only)

Update: Apparently I had a serious concussion when I wrote this, as I completely overlooked the obvious. "Hello, McFly - svn? I hear Google code has it too." So do not bother using these instructions. It is much simpler pull the project from SVN.

When I researched the JavaSE component of ZXing, I compiled the jars I needed with Eclipse 3.4.1 . The set up was relatively simple. But there were several steps needed to get everything up and running properly. So I decided to write up a quick set of instructions.


Note: ZXing contains several components (javase, javame, servlet, android, etcetera). These instructions only cover the JavaSE component. You may notice I imported the full source. But to actually use the other components in the project, additional files are needed. For further instructions see the project's Getting Started section

Instructions

1. Download the latest source and extract the files.
As of this entry, the current version is ZXing-1.4.zip. (Your version may differ.)


2. Create a new project in Eclipse.
  • Use whatever you project name you wish. Example: "ZXing"
  • Make sure the project JVM is 1.5 or higher

3. Import the source files into the project

  • Select File => Import => File System => Next
  • Supply the source and destination
  • 1. Navigate to the extracted files and select the ZXing-1.4 subfolder . 2. In the main window, check the ZXing-1.4 folder, so its contents are imported 3. Select the top level folder of your project (not "src") for Into Folder

  • Make sure Create selected folders only is selected
  • Finally, click Finish to import the files into the project

4. Next Configure the Build Path

After the source files are imported, you need to configure the project build path. Each sub-component in ZXing has its own separate src folder. Each of them must be added to the build path. ZXing also has a few jar dependencies. Those jars must be added to the project build path as well.

You could modify the path using Eclipse's "Configure Build Path" option. But a shortcut
is to modify the project's .classpath file manually.

  • Find and open the project's .classpath file
  • Paste in the new class path entries below and save the file.
  • Close and re-open the project in Eclipse to apply the changes.


New Class Path Entries
<classpathentry kind="src" path="android/src"/>
<classpathentry kind="src" path="bug/src"/>
<classpathentry kind="src" path="core/src"/>
<classpathentry kind="src" path="core/test/src"/>
<classpathentry kind="src" path="javame/src"/>
<classpathentry kind="src" path="javase/src"/>
<classpathentry kind="src" path="rim/src"/>
<classpathentry kind="src" path="zxingorg/src"/>
<classpathentry kind="lib" path="bug/lib/osgi.jar"/>
<classpathentry kind="lib" path="core/lib/junit.jar"/>
<classpathentry kind="lib" path="zxingorg/web/BarcodeReader.jar"/>
<classpathentry kind="lib" path="zxingorg/web/basic/BarcodeReader.jar"/>
<classpathentry kind="lib" path="zxingorg/web/WEB-INF/lib/commons-codec-1.3.jar"/>
<classpathentry kind="lib" path="zxingorg/web/WEB-INF/lib/commons-fileupload-1.2.1.jar"/>
<classpathentry kind="lib" path="zxingorg/web/WEB-INF/lib/commons-io-1.4.jar"/>
<classpathentry kind="lib" path="zxingorg/web/WEB-INF/lib/commons-lang-2.4.jar"/>
<classpathentry kind="lib" path="zxingorg/web/WEB-INF/lib/commons-logging-api-1.1.1.jar"/>
<classpathentry kind="lib" path="zxingorg/web/WEB-INF/lib/httpclient-4.0.jar"/>
<classpathentry kind="lib" path="zxingorg/web/WEB-INF/lib/httpcore-4.0.1.jar"/>
<classpathentry kind="lib" path="zxingorg/web/WEB-INF/lib/httpcore-nio-4.0.1.jar"/>
<classpathentry kind="lib" path="zxingorg/web/WEB-INF/lib/httpmime-4.0.jar"/>
<classpathentry kind="lib" path="zxingorg/web/WEB-INF/lib/mailapi.jar"/>
<classpathentry kind="lib" path="zxingorg/web/WEB-INF/lib/pop3.jar"/>
<classpathentry kind="lib" path="zxingorg/web/WEB-INF/lib/smtp.jar"/>


.ClassPath File


.ClassPath File Contents


You should now be able to run both the core an javase components of the project from Eclipse


Building Jars
The project includes several ant build files to simplify the process of building jars. Again, each component subfolder contains its own separate build file. So you can easily build jars individually. Simply locate the build.xml file for the desired component. Then run the build task to generate the jar.

Example: To build the JavaSE Jar

  1. Locate the javase/build.xml file
  2. Run the build task in ant
  3. Ant will generate a javase.jar file inside the javase/ folder

...Read More

Thursday, November 19, 2009

Seeing Stripes: Experiment with ZXing

I recently took a look at the ZXing Project which is described as "an open-source, multi-format 1D/2D barcode image processing library implemented in Java.". While its primary focus is mobile phones, I decided to look at the javase component of the project. ZXing also comes with a servlet. But I first wanted to see how the lower level components worked.


Setup
Not seeing any pre-compiled jars, I downloaded the latest sources (ZXing-1.4.zip). After loading it into Eclipse, and poked around a bit to figure out how to decode barcode images of different types. Finally, I used the pre-made ant files to create the two jars I needed: core.jar and javase.jar.

Decoding barcode images
While the project has some decent documentation, the developer notes seem to be outdated in a few places. But examining some of the javase classes turned up a convenience class called MultiFormatReader. From what I could tell it provides a simple way to decode barcodes when you may not know the type ahead of time. Obviously if you know the barcode type ahead of time, it is more efficient to use the specific reader for that type. But since I wanted to test all supported types the MultiFormatReader was perfect for my needs.

Now before I could test ZXing, I needed some barcode images. So I used CFBarbecue.cfc to generate a sample of all of the barcodes supported by the Barbecue library. Now ZXing does not support all of them. But there is a good intersection between the two. Once I had my images, I created an instance of MultiFormatReader, using the ever-handy JavaLoader.cfc. I also passed the reader some hints to increase accuracy.

Note: This code is for demonstration purposes only. Normally, the javaLoader should be stored in the server scope to avoid memory leaks.

<cfset paths = [] />
<cfset arrayAppend(paths, expandPath('zxing-1.4/core/core.jar')) />
<cfset arrayAppend(paths, expandPath('zxing-1.4/javase/javase.jar')) />
<cfset loader = createObject("component", "javaloader.JavaLoader").init( paths ) />

<!--- Create hints for the reader. TRY_HARDER increases accuracy --->
<cfset DecodeHintType = loader.create("com.google.zxing.DecodeHintType") />
<cfset hints = loader.create("java.util.Hashtable").init() />
<cfset hints.put(DecodeHintType.TRY_HARDER, javacast("boolean", true)) />

<!--- Since we will be reading multiple images, create one reader and reuse it  --->
<cfset Reader = loader.create("com.google.zxing.MultiFormatReader").init() />
<cfset Reader.setHints(hints) />

Next, I used cfdirectory to grab a list of all of my barcode images. Then looped through the images and attempted to decode each one. Now in order to use the reader's decode method, I needed to convert my image to a compatible format: BinaryBitmap. So I read in each image, extracted the underlying BufferedImage and passed it through a few of the ZXing classes designed to prepare images for decoding.

Finally, I called the reader's decode method to decode the image. If the image was successfully decoded it returns a Result object containing some useful properties like the raw text and barcode type.

One thing to be aware of is that error handling is unlikely to yield any useful information, beyond the fact that an error occurred. From the notes in the current source code, the way in which decoding errors are handled is undergoing a transformation, to increase performance. So for now do not expect much exception information beyond name, rank and serial number.


<!--- read all barcode images in my subdirectory --->
<cfdirectory action="list" directory="#ExpandPath('images')#"
            filter="*.gif"
            name="barcodeImages" />

<!---
    Try and decode each barcode with z-xing.
    Note: Not all codes are supported by z-xing!!!
--->
<cfoutput query="barcodeImages">
    <cfset imagePath = Directory &"/"& name />
    <cftry>

        <!--- display the original image --->
        <strong>Barcode Image</strong> #name# <br />
        <cfimage action="writeToBrowser" source="#imagePath#"><br />

        <!--- extract the BufferedImage of the current barcode --->
        <cfset img = ImageGetBufferedImage(ImageRead(imagePath)) />

        <!--- prepare the image for decoding --->
        <cfset source = loader.create("com.google.zxing.client.j2se.BufferedImageLuminanceSource").init(img) />
        <cfset binarizer = loader.create("com.google.zxing.common.GlobalHistogramBinarizer").init(source) />
        <cfset bitmap = loader.create("com.google.zxing.BinaryBitmap").init(binarizer) />

        <!--- This method reuses the existing settings for decoding multiple images --->
        <cfset decodedResult = Reader.decodeWithState(bitmap) />

        <!--- display the results --->
        <strong>Decoded Text</strong> #decodedResult.getText()# <br />
        <strong>Decoded Format</strong> #decodedResult.getBarcodeFormat()# <br />

        <cfcatch>
            Not supported or unable to decode: #cfcatch.type# #cfcatch.message#
        </cfcatch>
    </cftry>
    <br /><br /><hr />
</cfoutput>




All of my sample images were decoded except:

  • 2of7
  • Codabar
  • Int2of5
  • Monarch
  • NW7
  • PDF417
  • PostNet
  • Std2of5
  • USD4
While I knew some of them are not supported, but I was surprised that the PD417 and Interleaved 2 of 5 samples failed. I am not yet sure why. For now I will assume it was an error on my part. I will have to investigate the individual readers further.

However, I was able to decode a DataMatrix barcode using the DataMatrixReader. (Created using the free servlet at IDAutomation.com). Just be aware the current project documentation lists DataMatrix decoding as "alpha quality". So do not expect miracles.




<cfset imagePath = "c:\barCode_loremIpsum_idAutomation.gif" />

<cfset DecodeHintType = loader.create("com.google.zxing.DecodeHintType") />
<cfset hints = loader.create("java.util.Hashtable").init() />
<cfset hints.put(DecodeHintType.PURE_BARCODE, javacast("boolean", true)) />

<!--- prepare the image for decoding --->
<cfset img = ImageGetBufferedImage(ImageNew(imagePath)) />
<cfset source = loader.create("com.google.zxing.client.j2se.BufferedImageLuminanceSource").init(img) />
<cfset binarizer = loader.create("com.google.zxing.common.GlobalHistogramBinarizer").init(source) />
<cfset bitmap = loader.create("com.google.zxing.BinaryBitmap").init(binarizer) />

<!--- attempt to decode the image --->
<cfset Reader = loader.create("com.google.zxing.datamatrix.DataMatrixReader") />
<cfset decodedResult = Reader.decode( bitmap, hints ) />

<cfoutput>
<!--- display the original image --->
<strong>Barcode Image</strong> #imagePath# <br />
<cfimage action="writeToBrowser" source="#imagePath#"><br />

<!--- display the results --->
<strong>Decoded Result</strong><br />
#decodedResult.getText()# <hr />
</cfoutput>

Other Classes
The j2se component also has a few classes you might find useful for quick tests. The first is GUIRunner. It is a very rudimentary GUI you can use to test a single bar code image. To use it, simply open a command prompt and enter the following. Just modify the "-cp" value (classpath) to point to the location of your jars.

Example:


C:\test\zxing> java -cp c:\test\zxing\core.jar;c:\test\zxing\javase.jar com.google.zxing.client.j2se.GUIRunner


The other class is CommandLineRunner. It can be used to decode a single image, a directory of images or a url. Just supply the locations of your jars and the file/directory/url you wish to decode. The "--try_harder" hint can be used to increase accuracy, and the "--dump_results" option to save the results to a file. Note: The results of each barcode are saved to individual files. So keep that in mind if you are decoding an entire directory.

Example:

C:\test\zxing> java -cp c:\test\zxing\core.jar;c:\test\zxing\javase.jar com.google.zxing.client.j2se.CommandLineRunner c:/test/zxing/barcodeimages --try_harder


Well, that is it for now. I will have to experiment with some lower quality images, to see how the results stack up in a real test. (Once I find a supported phone ...)

...Read More

  © Blogger templates The Professional Template by Ourblogtemplates.com 2008

Header image adapted from atomicjeep