Saturday, November 28, 2009

OT: This is Unicode ?

While visiting the unicode.org site, I came across this unexpected title from 1992. (Yes, it really is about unicode. Who says unicode is a dry topic ;).


Kiss Your ASCII Goodbye (John Dvorak, PC Magazine/1992)

Friday, November 27, 2009

SOT: Heads or Tails? (Windows Resource Kit - Tail.exe Gotcha)

So I was comparing two windows implementations of tail, and came across something unexpected. While I was checking one of my tests, I noticed the results contained less lines than I requested. The base files definitely contained more than enough lines. So I knew that was not problem. After digging deeper, I discovered the lines returned were not even from the end of the file! They were from the middle.

<cfset specialChar  = chr(26)  />
<cfset newLine = chr(10) />
<cfsavecontent variable="data">
<cfoutput>
<cfloop from="1" to="50" index="x">Log file line #x# <cfif not x mod 10>#specialChar#</cfif>#newLine#</cfloop>
</cfoutput>
</cfsavecontent>

<cfset filePath = ExpandPath("./testLogFile.log") />
<cfset FileWrite( filePath, trim(data) ) />


Now use tail.exe to grab the last twenty (20) lines of the file. Due to the placement of the special characters, what you will end up with is the first 10 lines of the file, not the last twenty.




<cfset grabLines = 20 />
<cfexecute name='"c:\program files\Windows Resource Kits\tools\tail.exe"'
arguments='-#grabLines# #filePath#'
variable='output'
timeout='20' />

<!--- convert lines to array --->
<cfset linesFound = listToArray(output, chr(10), true) />
<cfset actualLines = listToArray( FileRead( filePath ), chr(10), true) />

<cfoutput>
<p><strong>Log File:</strong> #filePath# </p>
<p><strong>Requested Lines:</strong> #grabLines# </p>
<p><strong>Lines Found:</strong> #arrayLen(linesFound)#</p>
<p><strong>Actual Lines:</strong> #arrayLen(actualLines)#</p>
</cfoutput>


Fortunately, the GNUWin32 version does not suffer from this "problem" and returns the expected results. (Thank goodness someone knows basic subtraction)



As for the Windows Resource Kit version, well.. if we were flipping a coin, this time it was definitely "heads" - as in "head on over to sourceforge.net and get a yourself a working copy of tail.exe".

...Read More

Wednesday, November 25, 2009

OT: JAI Resources?

Does anyone know of any good resources (online, books, etcetera) on JAI? Frankly the sun docs leave a lot to be desired. If anyone can recommend a good book on the topic it would be greatly appreciated.

Tuesday, November 24, 2009

ColdFusion 8: Blowfish Encryption (Something smells fishy .. and it is not the algorithm)

A while back I saw a thread on the adobe forums about an issue with Blowfish encryption. The issue being the results from ColdFusion's encrypt function seemed to differ from other languages. Hardly uncommon given the "delicate" nature of encryption. What grabbed my attention was that the results from ColdFusion and Java were also different. Not what I would have expected.

<cfset myText        = "guess this!1 2 3" />
<cfset myKey         = generateSecretKey("Blowfish", 32) />
<cfset cfEncrypted   = Encrypt(myText, myKey, "Blowfish/ECB/NoPadding", "Hex") />

<!--- results (using 

tags because the blogger eats line breaks!) ---> <strong>ColdFusion:</strong><hr /> <cfoutput> <p><strong>MyText</strong> : #myText#</p> <p><strong>MyKey</strong> : #myKey#</p> <p><strong>CF Encrypted</strong> : #cfEncrypted#</p> </cfoutput>



Java
<!---  generate a secret key --->
<cfset SecretKeySpec     = createObject("java", "javax.crypto.spec.SecretKeySpec") />
<cfset myKeyBytes         = CharsetDecode(myKey, "utf8") />
<cfset keySpec             = SecretKeySpec.init(myKeyBytes, "Blowfish") />
<!--- get a cipher instance for encrypting --->
<cfset Cipher             = createObject("java", "javax.crypto.Cipher") />
<cfset encryptor         = Cipher.getInstance("Blowfish/ECB/NoPadding") />
<cfset encryptor.init(Cipher.ENCRYPT_MODE, keySpec) />
<!--- do the encryption --->
<cfset myTextBytes         = CharsetDecode(myText, "utf8") />
<cfset javaEncrypted     = encryptor.doFinal(myTextBytes) />

<!--- results --->
<cfoutput>
<p><strong>Java Encrypted</strong>  : #BinaryEncode(javaEncrypted, "hex")# </p>
</cfoutput>

Sample Results:


Since I am definitely not an expert on encryption, I just figured I was missing something. Eventually I did get the CF and java results to match by converting the secret key to binary and then back to base64.

<cfset myText        = "guess this!1 2 3" />
<cfset myKey         = generateSecretKey("Blowfish", 32) />
<cfset magicKey      = BinaryEncode(CharsetDecode(myKey, "utf8"), "base64") />
<cfset cfEncrypted   = Encrypt(myText, magicKey, "Blowfish/ECB/NoPadding", "Hex") />

The new results clearly showed my magicKey now matched the java keySpec value. So of course the encrypted strings also matched.


But I am not sure why that the extra step necessary. Supposedly the value returned from GenerateSecretKey() is already base64 encoded. Also, it seems to work correctly in reverse (ie when the secret key is generated from the javax.crypto.KeyGenerator).

So am I missing something here, or is this a "feature"?


Update: Yep! I was obviously staring at this for too long. I missed something obvious. I should have used BinaryDecode(myKey, "base64") to get the java key bytes and vice versa. Now it make sense! ;)

As mentioned in the comments, using CBC mode is a bit different. As it requires an IV (Initialization Vector). Here is a basic example using CBC mode. Though in practice, you probably would not use the same IV each time as I am doing here. I also included a lot of extra debugging output. So you can verify the values used by both ColdFusion and Java are the same.

<!---
    ENCRYPT WITH COLDFUSION
--->
<cfset algorithm      = "Blowfish/CBC/PKCS5Padding">
<cfset myText        = "can you guess this?" />
<cfset myKey         = generateSecretKey("Blowfish", 32) >
<cfset myIV             = CharsetDecode("12345678", "utf8")>
<cfset cfEncrypted   = Encrypt(myText, myKey, algorithm, "base64", myIV) />

<!--- results (using <p> tags because the blogger eats line breaks!) --->
<strong>ColdFusion (Encrypted):</strong><hr />
<cfoutput>
    <p><strong>MyText</strong> : #myText#</p> 
    <p><strong>MyKey</strong> : #myKey#</p>  
    <p><strong>MyIV</strong> : <cfdump var="#myIV#"></p>  
    <p><strong>CF Encrypted</strong> : #cfEncrypted#</p> 
</cfoutput>
</p>

<!---
    ENCRYPT WITH JAVA
--->
<cfset SecretKeySpec       = createObject("java", "javax.crypto.spec.SecretKeySpec") />
<cfset myKeyBytes          = BinaryDecode(myKey, "base64") />
<cfset keySpec             = SecretKeySpec.init(myKeyBytes, "Blowfish") />
<cfset ivSpec               = createObject("java", "javax.crypto.spec.IvParameterSpec").init( myIV )>
<cfset Cipher              = createObject("java", "javax.crypto.Cipher") />
<cfset encryptor           = Cipher.getInstance( algorithm ) />
<cfset encryptor.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec) />
<cfset myTextBytes         = CharsetDecode(myText, "utf8") />
<!--- convert encrypted byte array to base64 string --->
<cfset javaEncrypted       = BinaryEncode( encryptor.doFinal(myTextBytes), "base64") />

<!--- results (using <p> tags because the blogger eats line breaks!) --->
<strong>Java Encrypted:</strong><hr />
<cfoutput>
    <p><strong>myTextBytes (utf8)</strong> : #CharsetEncode(myTextBytes, "utf8")#</p>  
    <p><strong>keySpec</strong> : #BinaryEncode(keySpec.getEncoded(), "base64")#</p> 
    <p><strong>ivSpec (raw)</strong> : <cfdump var="#ivSpec.getIV()#"></p>  
    <p><strong>ivSpec (utf8)</strong> : #CharsetEncode(ivSpec.getIV(), "utf8")#</p>  
    <p><strong>Java Encrypted</strong>  : #javaEncrypted# </p>
</cfoutput>

Now just to prove the results are compatible, you can decrypt the ColdFusion results with Java (and vice versa).

<!---
    DECRYPT *COLDFUSION* RESULT WITH JAVA
--->
<cfset SecretKeySpec     = createObject("java", "javax.crypto.spec.SecretKeySpec") />
<cfset myKeyBytes        = BinaryDecode(myKey, "base64") />
<cfset keySpec           = SecretKeySpec.init(myKeyBytes, "Blowfish") />
<cfset ivSpec             = createObject("java", "javax.crypto.spec.IvParameterSpec").init( myIV )>
<cfset Cipher            = createObject("java", "javax.crypto.Cipher") />
<cfset decryptor         = Cipher.getInstance( algorithm ) />
<cfset decryptor.init(Cipher.DECRYPT_MODE, keySpec, ivSpec) />
<!--- convert our encrypted (base64 encoded) string to a byte array --->
<cfset encryptedBytes     = BinaryDecode( cfEncrypted , "base64") />
<!--- the decrypted bytes will be in UTF8 --->
<cfset javaDecrypted      = CharsetEncode( decryptor.doFinal( encryptedBytes ), "utf8") />

<cfoutput>
    <p><strong>Java Decrypted</strong>  : #javaDecrypted# </p>
</cfoutput>

<!---
    DECRYPT *JAVA* RESULT WITH COLDFUSION
--->
<!--- decrypt (base64 encoded) encrypted string --->
<cfset cfDecrypted   = Decrypt(javaEncrypted, myKey, algorithm, "base64", myIV) />

<cfoutput>
    <p><strong>ColdFusion Decrypted</strong>  : #cfDecrypted# </p>
</cfoutput>

...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 ...)

Wednesday, November 18, 2009

SOT: Who is the fairest browser of them all?

I have long been a fan of Firefox. But somewhere in between versions 2 and 3.5 it started behaving like a black-hole of resources, sucking up more and more memory, growing increasing sluggish. Not to mention taking forever to start up. So fickle user that I am, I have been trying out other browsers while I give Firefox one last chance before giving it the boot.


Update November 19, 2009: I am now experimenting with the Firefox 3.6b3 beta and also a plugin called AFOM 2.0 for memory management. (Note: I do not know if this plugin officially supports 3.6b3 yet). But the results from my limited testing seem very promising. (Windows only)


Update November 27, 2009: While the plugin helps, there are still issues. I think it is time to declare defeat. The memory problem is definitely Firefox!

...Read More

Monday, November 16, 2009

CFBarbecue.cfc (...Just because)

While experimenting with the Barbecue library last week, I put together a cfc for my testing. (You knew that was coming. It is the old developer story: read, test, build something, re-test). Anyway, I decided to post it for anyone else out there experimenting with Barbecue. The cfc can generate any of the 25+ barcodes Barbecue handles, with a full range of settings. (Rather than repeat the same code 25+ times, the cfc uses reflection)


November 19, 2009: Updated source to include missing lib\jdom.jar. Note: This jar is only needed if you are using the JavaLoader and want SVG functionality.

...Read More

Sunday, November 15, 2009

The Wrong Way to Retrieve the Last Record ID Inserted

Hardly a week goes by without seeing some forum post that either uses or recommends my pet peeve: the erroneous SELECT MAX(id) query. Mind you this is across the board, not just in CF. For some bizarre reason, this faulty technique never seems to die. And it REALLY should. There are so many correct alternatives, I cannot understand why anyone would still use it for new code. If you are even considering it, might I inject a note of sanity and recommend some excellent reading material on Adrian J. Moreno's blog:


(His comments on the topic are much more educational and polite than mine ;-)

Friday, November 13, 2009

Everything CFDBINFO Never Told You About Your Database (Connection Metadata)

I was doing some debugging and came across the nifty java.sql.DatbaseMetaData class. It is an interface implemented by the various database drivers and it provides you with a ton of information about both your database and driver capabilities. While you can glean some of the information from <cfdbinfo>, DatbaseMetaData tells you so much more.


  • What database or driver version you are using?
  • What is the maximum number of concurrent connections?
  • What is the maximum number of tables in an ORDER BY?
  • What happens when you concatenate a NULL value with a non-NULL value?


Apparently, the DatabaseMetaData class can tell you that. While I would not take all of these values "as gospel", they do provide some solid guidelines.
<cfscript>
myDSN = "MSSQL_2005";

// open a connection to the datasource
factory = createObject("java", "coldfusion.server.ServiceFactory");
datasource = factory.getDataSourceService().getDataSource( myDSN );
connection = datasource.getConnection();
// extract the database metadata
metadata = connection.getMetaData();

results = {};

// Display version information
results["getJDBCMajorVersion()"] = metadata.getJDBCMajorVersion();
results["getJDBCMinorVersion()"] = metadata.getJDBCMinorVersion();
results["getDriverMinorVersion()"] = metadata.getDriverMinorVersion();
results["getDriverName()"] = metadata.getDriverName();
results["getDriverVersion()"] = metadata.getDriverVersion();
results["getDatabaseMajorVersion()"] = metadata.getDatabaseMajorVersion();
results["getDatabaseMinorVersion()"] = metadata.getDatabaseMinorVersion();
results["getDatabaseProductName()"] = metadata.getDatabaseProductName();
results["getDatabaseProductVersion()"] = metadata.getDatabaseProductVersion();

// cleanup
connection.close();
</cfscript>

<cfdump var="#results#" label="[#myDSN#] java.sql.DatbaseMetaData" />
As there are so many functions, I used a bit of reflection to quickly dump all of the simple properties into a structure. (See the full code at the end of the entry). It was interesting to see how the metadata differed across drivers. Both in what information was exposed and the results of the core methods. Notice the sql keywords differ when using the JTDS driver and the built-in CF8 driver.

Note: Unfortunately, getSQLKeywords() only returns potential keywords that are not also ansi sql:2003 reserved words. But with a little effort you could easily create a function to list of all potential keywords.

CF8 Driver

JTDS Driver


The metadata contains all kinds of interesting information. So if you ever wondered about your database or driver capabilities, read up on java.sql.DatbaseMetaData. What it reveals could surprise you.

Full Code

<cfscript>
myDSN = "MSSQL_2005";

// open a connection to the datasource
factory = createObject("java", "coldfusion.server.ServiceFactory");
datasource = factory.getDataSourceService().getDataSource( myDSN );
connection = datasource.getConnection();
// extract the database metadata
connMetadata = connection.getMetaData();

// get all methods in the metadata class
allMethods = connMetadata.getClass().getDeclaredMethods();
Modifier = createObject("java", "java.lang.reflect.Modifier");

results = {};

// Execute all simple methods and store the results
for(x=1; x <= arrayLen(allMethods); x++)
{
method = allMethods[x];

// Get the parameters for the current method
parameters = method.getParameterTypes();

// If this is a simple method, requiring no extra information ..
if (Modifier.isPublic(method.getModifiers()))
{
if (not arrayLen(parameters) AND method.getName() neq "getConnection")
{
try
{
// run the current method
data = method.invoke( connMetadata, parameters );
// convert resultsets to a query object first
if ( isInstanceOf(data, "java.sql.ResultSet")) {
data = createObject("java", "coldfusion.sql.QueryTable").init(data);
}
results[method.getName()] = data;
}
catch(java.lang.Exception e)
{
results[method.getName()] = e.message;
}
}
}
}

connection.close() ;
</cfscript>

<cfdump var="#results#" label="connection.getMetaData() " />

...Read More

Thursday, November 12, 2009

MS SQL: Useless Function Trivia

While reviewing some MS SQL 2005 metadata, I stumbled across something I never noticed before.

 
<cfquery name="q" datasource="MSSQL_2005">
SELECT
{fn CurDate()} AS [CurrentDate],
{fn CurTime()} AS [CurrentTime],
{fn DayName( getDate() )} AS [DayName],
{fn DayOfMonth( getDate() )} AS [DayOfMonth],
{fn DayOfWeek (getDate() )} AS [DayOfWeek],
{fn DayOfYear(getDate() )} AS [DayOfYear],
{fn Extract(Day From getDate())} AS [ExtractDay],
{fn Hour(getDate() )} AS [Hour],
{fn Minute(getDate() )} AS [Minute],
{fn Month(getDate() )} AS [Month],
{fn MonthName(getDate() )} AS [MonthName],
{fn Now()} AS [Now],
{fn Quarter(getDate() )} AS [Quarter],
{fn Second(getDate() )} AS [Second],
{fn Week(getDate() )} AS [Week],
{fn Year(getDate() )} AS [Year],
{fn TimestampAdd(SQL_TSI_DAY, 14, getDate())} AS [TimestampAdd],
{fn TimestampDiff(SQL_TSI_DAY, '2009-10-31', getDate())} AS [TimestampDiff]
</cfquery>
<cfdump var="#q#" label="Old MS SQL Functions fn{}" />

...Read More

OT: Lame error messages

So I was having fun, trying to break things, and came across a lame excuse only a computer could get away with:

com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: memory exhausted.

I can see it now: "Sorry Boss-man. No can do. Geez, my memory is exhausted. I need time to relax, recharge, reboot. Check back with me tomorrow."

Sunday, November 8, 2009

ColdFusion: Introduction to the Java Barbecue Library (For Beginners)

Just to get this out of the way: if you are looking for a CF wrapper for the Barbecue library, this is not the entry for you. If you are interested in the basics of using Barbecue, feel free to read on.

Why write yet another entry on Barbecue? Well, I was recently reading about barcodes, for my own edification, and did not find many introductory resources (you know ... ones that ask and answer those silly novice questions?). So decided to write up my findings and first impressions, in the hopes of providing someone else with a starting point in their research. Even if they are not using CF.

Background on Barcodes
Obviously using the library requires you know at least a little bit about the different bar code types. For example, some encode numeric digits only, others have different limits as to how many characters they can encode, etcetera. Two of the more helpful references I came across were: Different Types of Barcodes and a high level Barcode Comparison Chart.

Installing the Barbecue Library
Using the Barbecue library is very simple. Just download the library from sourceforge.net and extract the main jar from the .zip file. The current jar version is: barbecue-1.5-beta1.jar. Then place the main jar somewhere in your CF classpath, such as: C:\ColdFusion8\wwwroot\WEB-INF\lib. Finally restart the ColdFusion server so it will detect the jar.

Another option is to use Mark Mandel's JavaLoader.cfc, which is the option I chose. Just load the Barbecue jar in your array of paths, and create a new instance of the JavaLoader. (Obviously, this is just for demonstration. Usually you store the javaLoader instance in the server scope to avoid memory leaks).

Note: The jdom.jar must also be added to the JavaLoader paths if you intend to use Barbecue's SVG functionality.

<cfset paths = [] />
<cfset arrayAppend(paths, expandPath('barbecue-1.5-beta1/barbecue-1.5-beta1.jar')) />
<cfset arrayAppend(paths, expandPath('barbecue-1.5-beta1/lib/jdom.jar')) />
<cfset loader = createObject("component", "javaloader.JavaLoader").init( paths ) />

Factory Workers: (So much for progress..)
I found the easiest way to work with bar codes was using the factory classes. The factories provide easy to use static methods that make it a breeze to create, format and save barcodes.


Creating a Barcode
To a create a barcode, you use the BarcodeFactory. This class contains about 25+ methods for creating several different types of barcodes, such as Interleaved 2 or 5, EAN128, etcetera. Currently, only one 2d bacode is supported: PDF417. The methods are intuitively named, and most require only the string to be encoded. For example, to create a Bookland barcode, just grab a reference to the Factory and call the createBookland() method with the value you wish to encode:

<cfset factory = loader.create("net.sourceforge.barbecue.BarcodeFactory") />
<cfset barcode = factory.createBookland( "0123456789" ) />

Creating a Barcode Image (Simple)

Now the object returned from the BarCodeFactory is not image. It is an instance of one of the Barbecue classes: net.sourceforge.barbecue.Barcode. But there are several easy ways for converting the barcode object into an image. I found at least five (5) methods. (There is a catch to a few of them, but more about that in a minute) .

The first three (3) options use the BarcodeImageHandler factory. It has a few handy methods for converting a barcode object to either an in memory image or to a physical file.

(1) Generating a BufferedImage
To convert a barcode object to a BufferedImage, simply grab a reference to the factory, then call the getImage() method. To display or manipulate the BufferedImage in CF, just wrap it in a CF image object.
<cfset ImageHandler = loader.create("net.sourceforge.barbecue.BarcodeImageHandler") />
<cfset buffImage = ImageHandler.getImage( barcode ) />
<cfset barcodeImage = ImageNew(buffImage) />
<cfimage action="writeToBrowser" source="#barcodeImage#" />
(2) Writing Images to an OutputStream
You can also write the image directly to an OutputStream. There are various uses of OuputStream's, such as streaming images to the browser. There is probably less need for that particular technique in later versions of CF. But as there are several different types of streams, it is good to be aware of this option.

The image handler has three (3) methods for writing images to a stream: writePNG(), writeGIF() and writeJPG(). As their names imply, they generate an image in the desired format and write the image bytes to the supplied stream. You can then use the stream however you wish:

<cfset ImageHandler = loader.create("net.sourceforge.barbecue.BarcodeImageHandler") />
<cfset outStream = loader.create("java.io.ByteArrayOutputStream").init() />
<cfset ImageHandler.writePNG( barcode, outStream ) />
<!--- 1) Display the image using cfimage ... --->
<cfset barcodeImage = ImageNew(outStream.toByteArray()) />
<cfimage action="writeToBrowser" source="#barcodeImage#" />

<!--- 2) OR .. using cfcontent ... --->
<cfcontent type="image/png" variable="#outStream.toByteArray()#" />

(3) Saving Images to a File
Lastly, the handler has three methods for saving barcode images to a physical file: saveGIF(), saveJPG() and savePNG(). It is much like the previous option, only you pass in a java.io.File object representing the output file.

<cfset ImageHandler = loader.create("net.sourceforge.barbecue.BarcodeImageHandler") />
<cfset IOFile = loader.create("java.io.File") />

<!--- save the barcode in three (3) different formats  --->
<cfset imageFile = IOFile.init( ExpandPath("myBarcode.gif") ) />
<cfset ImageHandler.saveGIF( barcode, imageFile ) />
<img src="myBarcode.gif" alt="GIF  Format" />

Now earlier I mentioned a catch. In my tests, the generated images all had a black border along the bottom of the barcode. I am guessing it has something to do with the canvas color of the image object. One way I was able to remove it, was by creating a blank image first. So I could control the canvas color. Then use some lower level methods to draw the barcode onto my image. That brings me to the other two (2) options for creating images.




Creating a Barcode Image (Advanced)

While not as easy as using the factory methods, you can also use two methods within the Barcode class itself to generate an image. But unlike using the image factory, it is strictly B.Y.O. (bring your own) .. image. You must already have a blank image in order to use these methods. They are probably what the BarcodeImageFactory uses behind the scenes. However, I thought I would point them out to explain how they work.

1) Using Barcode.draw(graphics, x, y)
The first, and simpler, method is: draw(). To use it, I just created a blank CF image. Since the default canvas color for "rgb" images is black, I changed it to white. Then extracted the graphics object from my image and passed it into the draw function. The result was a barcode without that bottom border.




<!--- Option 1: RBG image, white canvas --->
<cfset img = ImageNew("", barcode.getWidth(), barcode.getHeight(), "rgb", "ffffff") />
<cfset graphics = ImageGetBufferedImage(img).getGraphics() />
<cfset barcode.draw( graphics, 0, 0) />

<cfimage action="writeToBrowser" source="#img#">
<br /><br />

<!--- Option 2: Transparent image --->
<cfset img = ImageNew("", barcode.getWidth(), barcode.getHeight(), "argb") />
<cfset graphics = ImageGetBufferedImage(img).getGraphics() />
<cfset barcode.draw( graphics, 0, 0) />

<div style="background-color: blue;">
<cfimage action="writeToBrowser" source="#img#"> <br />
</div>

2) Using Barcode.output(output)
The second method is a little more complex. You probably will not need it. But still, it is good to know. The output() method works with an instance of what Barbecue calls an Output object. The are several types of Output classes, and they are all just used to convert Barcode objects from one format to another: like to image, svg or eps.

Since I wanted to create an image, I used the GraphicsOutput class. It is not as complicated as it looks, but it does involve more moving pieces than other options. Constructing a GraphicsOutput object requires several pieces of information: the image graphics, barcode font and fore/background colors. You simply pass these objects into the constructor to create a new Output object. Then call Barcode.output() to paint the barcode onto your image graphics using the supplied settings.

Example

Code

<!--- create a new image and extract the graphics --->
<cfset img = ImageNew("", barcode.getWidth(), barcode.getHeight(), "rgb", "ffffff") />
<cfset graphics = ImageGetBufferedImage(img).getGraphics() />

<!--- create the desired font and colors --->
<cfset Font = createObject("java", "java.awt.Font") />
<cfset Color = createObject("java", "java.awt.Color") />

<cfset barcodeFont = Font.init("Arial", Font.PLAIN, 12 ) />
<cfset backgroundColor = Color.BLUE />
<cfset foregroundColor = Color.decode("##008040") />

<!--- grab a Color object that will be used to set the barcode fore/background --->
<cfset GraphicsOutput = loader.create("net.sourceforge.barbecue.output.GraphicsOutput")>
<cfset gOut = GraphicsOutput.init( graphics, barcodeFont, foregroundColor, backgroundColor ) />
<cfset barcode.output( gOut ) />

<cfset ImageWrite( img, ExpandPath("ColdFusion_Barbecue_GraphicsOutput.png")) />
<!--- display the barcode image --->
<cfimage action="writeToBrowser" source="#img#"> <br />


Working with Barcode Properties

Working with the various ways of creating images eventually brought me back to the Barcode class itself, and using its methods to alter some of the default settings. One of the things that struck me about the Barcode class is that it extends JComponent. At first that seemed a bit strange, as JComponent is one of the base classes for swing gui components. But further reading revealed Barbecue can be used in servlets or swing applications. So extending JComponent made more sense.

Now I mentioned swing for a reason. After testing various Barcode properties, I quickly realized many of the properties only apply if you are using swing. For example, there are several methods for adjusting width and height. But they had no effect when using images. Considering these methods are inherited from JComponent, that makes sense. (Not that you can really force the barcode dimensions anyway). An entry on Adam Presley's blog confirmed my suspicion. You cannot set the dimensions explicitly. But instead should use the barWidth and barHeight properties to adjust the overall barcode size.

Here are some of the more useful Barcode properties.

Barcode.setBarWidth()/setBarHeight()
These methods can be used to set the width of the thinnest bar or the height of a single bar, within the overall barcode. You may need to experiment to get the correct settings. So you do not end up with an invalid barcode or one that does not render properly ;)

setBarWidth( 6 )


Code

<cfset BarcodeFactory = loader.create("net.sourceforge.barbecue.BarcodeFactory") />
<cfset barcode = BarcodeFactory.createStd2of5( "0123456789" ) />
<cfset barcode.setBarWidth( 6 ) />
...

Barcode.setDrawingQuietSection(boolean)
This setting controls whether extra whitespace (ie quiet zone) should be rendered.

Code

	<cfset barcode.setDrawingQuietSection( false ) />

setDrawingQuietSection(true)

setDrawingQuietSection(false)


Barcode.setDrawingText(boolean)
This setting controls whether the barcode data (ie un-encoded) is displayed beneath the barcode.

Code

	<cfset barcode.setDrawingText( false ) />
setDrawingText(false)


Barcode.setLabel(string)
This method should allow you to override the text displayed beneath the barcode. But I was not able to get this setting to work.

Barcode.setFont(java.awt.Font)
This method allows you to use a different font for any text displayed beneath the barcode.

Code:

<cfset Font = createObject("java", "java.awt.Font") />
<cfset barcodeFont = Font.init("Arial", Font.ITALIC, 12) />
<cfset barcode.setFont( barcodeFont ) />
setFont( [Arial, Italic, size 12] )



Barcode.setBackground(java.awt.Color)/setForeground(java.awt.Color)
These methods can be used to change the foreground or background colors of the barcode. They are inherited from JComponent, but are used by the Barcode class.

Code:

<!--- change foreground --->
<cfset Color = createObject("java", "java.awt.Color") />
<cfset barcode.setForeground( Color.RED ) />

<!--- change background (hex color) --->
<cfset Color = createObject("java", "java.awt.Color") />
<cfset barcode.setBackground( Color.decode("##0080c0") ) />

setForeground()


setBackground()


Barcode.setResolution(int)
Used to adjust the resolution. Default is 72dpi.

Code:
	<cfset barcode.setResolution( 300 ) />
SVG
You can also convert barcode objects to svg. Simply grab a reference to the SVGFormatter class, then call the formatAsSVG() method. The result is an svg string.

Code:
<cfset BarcodeFactory = loader.create("net.sourceforge.barbecue.BarcodeFactory") />
<cfset barcode = BarcodeFactory.createBookland( "0123456789" ) />
<cfset SVGFormatter = loader.create("net.sourceforge.barbecue.formatter.SVGFormatter") />
<cfset svgString = SVGFormatter.formatAsSVG( barcode )>
Related Entries:
CFBarbecue.cfc (...Just because)
Seeing Stripes: Experiment with ZXing


Saturday, November 7, 2009

OT: ColdFusion Trials (Let's Do The Time Warp Again)

I was checking my "trials" email folder the other day and these messages gave me a chuckle. That and the fact that I received a "Your ColdFusion 9 trial starts now" message, before my download had even finished! Can you spot what is wrong here?


Yes... I did download the ColdFusion 9 Trial previously. But it still made me laugh ;)

ColdFusion: Small Try/Catch Gotcha With CreateObject() and Exceptions

Exceptions can be deceptive and loathsome creatures at times. Case in point, I was happily using createObject() to load an object from a java jar in my classpath. I then added a try/catch. So I could detect when the jar probably was not added to the CF classpath properly, and display a more meaningful error message.


<cfscript>
try
{
handler = createObject("java", "net.sourceforge.barbecue.BarcodeImageHandler");
}
catch(java.lang.ClassNotFoundException e)
{
throwError(message="Verify the Barbecue jar is in your CF classpath", type="SupportingClassNotFound");
}
</cfscript>

Great in theory, the only problem was my try/catch did not work. I double checked the stack trace and it sure seemed like I was catching the correct exception type: java.lang.ClassNotFoundException. So I tried the broader type java.lang.Exception. Then cfdump'd the details, to see if I could spot the problem. Sure enough, the actual exception type was not what CF was reporting on the error screen. The actual exception type being:
coldfusion.runtime.java.JavaObjectClassNotFoundException.


(Boy, what a mouthful. As if the base exception name is not long enough already...?)


Apparently the stack trace in the error page was displaying the RootCause, not the actual exception thrown. While that makes some sense, unfortunately the thrown exception type is what is needed to catch the darned thing. Anyway, once I changed my try/catch to use the actual exception type being thrown, everything was just dandy.
<cfscript>
try
{
handler = createObject("java", "net.sourceforge.barbecue.BarcodeImageHandler");
}
catch(coldfusion.runtime.java.JavaObjectClassNotFoundException e)
{
throwError(message="Verify the Barbecue jar is in your CF classpath", type="SupportingClassNotFound");
}
</cfscript>
What is the world coming to when you cannot even trust error messages Oh, wait. Scratch that. Error messages lie all the time. I am sure they do not mean to lie, they just hold back critical information when you most need it. The secretive little trolls ;)

...Read More

No more use for StructFind() ?

For some reason I always forget about the one good use for StructFind(). (Thank goodness for old blog entries). Though it seems even that use is gone in ColdFusion 9. Can anyone think of another one?


<!--- Works in CF9, not CF8 --->
<cfoutput>
#getSomeStructure()["dog"]#
</cfoutput>

<cffunction name="getSomeStructure" returntype="struct">
<cfset var myStruct = {} />
<cfset myStruct.cat = "felix" />
<cfset myStruct.dog = "clifford" />
<cfreturn myStruct />
</cffunction>

Tuesday, November 3, 2009

A Better PdfPageEventHandler with JavaLoader/CFCDynamicProxy

Yesterday , I wrote about discovering a true gem in latest version of Mark Mandel's JavaLoader: the CFCDynamicProxy. This tiny, but powerful, class acts as a wrapper around a ColdFusion cfc. Essentially allowing it to mimic a native java object and communicate directly with other java objects in ways it never could before! We all know just about everything in ColdFusion boils down to a java object internally. But until now there were certain things you just could not do from a cfc without taking the r-e-a-l-l-y long way around. Well, the CFCDynamicProxy changes all that.



<cffunction name="onEndPage" access="public" returntype="void" output="true"
hint="Called when a page is finished, just before being written to the document.">
<cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
<cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
<cfset var Local = {} />

<cfscript>
if (len(variables.instance.footerText))
{
Local.cb = arguments.writer.getDirectContent();
Local.cb.saveState();

Local.cb.beginText();
Local.cb.setColorFill( variables.instance.textColor );
Local.cb.setFontAndSize( variables.instance.font, javacast("float", variables.instance.fontSize) );
Local.cb.setTextMatrix( arguments.document.left(), arguments.document.bottom() - 10);
Local.text = variables.instance.footerText &" page ["& arguments.writer.getPageNumber() &"]";
Local.cb.showText( Local.text );
Local.cb.endText();

Local.cb.restoreState();
}
</cfscript>

</cffunction>


Having completed my faux-java-class/cfc, the next step was using the CFCDynamicProxy to see if this stuff actually worked. Using the Dynamic proxy is like using any other jar with the JavaLoader. You just add the new cfcdynamicproxy.jar to the array of paths. Then create an instance of the JavaLoader, except this time you set the loadColdFusionClassPath parameter equal to true. This allows the JavaLoader to access ColdFusion's classes to create the proxy object.

...Read More

JavaLoader 1.0 / CFCDynamicProxy (I Think I am in Love)

So after many weeks, I finally got a chance to work with Mark Mandel's JavaLoader 1.0 Beta today, and boy did it put a smile on my face. When I started reading the documentation on the Dynamic Proxy, I nearly fell out of my chair.

In JavaLoader 1.0, I've written a Dynamic Proxy that you are able to wrap around a CFC, and thereby make Java Objects think they are interacting with a native Java object, but are in fact, talking to your CFC.

Holy cow! If you do any interaction with java from CF (or ever wanted to) I think you can appreciate this phenomenally cool feature. It means you can hook directly into a java library, from a CFC. No need to write and compile a custom java class. Now obviously it only applies to interfaces. But hey, most good libraries "program to the interface and not the implementation" anyway. So this opens up a lot of possibilities.

A good example is adding custom headers and footers with iText. (See this previous entry some background on page events). If you were using java, you would create a custom class that implements the PdfPageEvent interface. By implementing that interface, the custom class can capture certain pdf events like document opened, page added, etcetera. Then the code inside the custom class adds the desired headers, footers, watermarks, etcetera as those events are detected.

Now that is easy enough to do from java. But until now, it was not possible with ColdFusion alone, because iText requires an instance of a java class to handle the page events. Prior to now there were work-arounds, but none as elegant as using the Dynamic Proxy. With the new Proxy, you can simply write the event handler in CF. Then wrap it up in a proxy object and pass the proxy into iText. iText will think it is dealing with a real java class and simply route the events to your cfc as usual.

In a relatively short period of time, I was able to greatly simplify some old code for adding headers and footers to pdf documents using iText. I will post it shortly just so you can see how easy it was to interact with iText using the new Dynamic Proxy. I have to say it feels a lot more natural, and I am seeing endless possibilities here.

I said it before and I will say it again. That Mark Mandel is a freak...'in genius.

...Read More

What the heck is ConvolveOp? (ImageSharpen Alternative)

A recent question on the adobe forums mentioned the ImageSharpen() function was adding a black border to the generated image. As google did not turn up much on the topic, I concluded most people are using alternate methods to sharpen images. A quick peek at some of the more popular image components confirmed it. These components all use java's ConvolveOp class, internally, for sharpening.

So what is ConvolveOp? This article gives a great explanation on how it works, why the border effect occurs and how to avoid it: Java 2D's ConvolveOp Class. If you are already using one of the components above, you probably do not have to worry about it. But if you are curious about how things work, the article makes a good read.

Sunday, November 1, 2009

CFThread Must Die (Kill Bill) - Part 2

In Part 1 I mentioned the internal CF class coldfusion.thread.Task that seems to be used for running processes with cfthread. Tasks for a given thread can be retrieved from the FusionContext class using a method called getUserThreadTask(). So between the two, you should have enough information for makings of an experimental tracker.

<cfset threadName = "CFZombieThread_Test" >

<!--- Start the new thread ---->
<cfthread action="run" name="#threadName#" myName="#threadName#">
<cfset var zombieThreadName = getPageContext().getFusionContext().getCurrentUserThreadName() />

<cfloop from="1" to="20" index="counter">

<cfoutput>
Mindless groan from zombie thread #zombieThreadName# at #now()# ...<br/>
</cfoutput>
<!---
Force the thread to sleep to simulate a long running task
--->
<cfset sleep(1 * 1000) />

</cfloop>

</cfthread>

Next, I used the ever handy getPageContext() function to grab the FusionContext. I am not extremely familiar with this class. But from what I have learned, it provides executing requests with access to context-sensitive information like session variables, application settings, etcetera. After grabbing the context, I called the getUserThreadTask() method to retrieve the Task associated with my newly created thread.

Note: When using this method be sure to convert the thread name to upper case. I discovered through trial and error that the thread names are stored in some type of case sensitive structure, and all the keys are in upper case. So if you use mixed, or lower case, the method will not be able to locate your thread.


<cfset context = getPageContext().getFusionContext() />
<cfset task = context.getUserThreadTask(UCASE(threadName)) />
<cfdump var="#cfthread[threadName]#" label="#threadName# BEFORE cancel() request " />


Next, I forced the current page to take a brief nap, to give my thread a chance to produce some output and prove it was running. Finally, I used the Task's cancel() method to kill the thread. Then forced the parent page to sleep again before checking the thread's final status. Just to give the thread a chance to catch its breath.

<!--- Sleep for a few seconds to give the thread a chance to produce some output ...--->
<cfset createObject("java", "java.lang.Thread").currentThread().sleep(2000) />

<!--- Now, try and kill the thread --->
<cfset task.cancel() />

<!--- Finally, give the thread a chance to catch up before we check its final status ...--->
<cfset createObject("java", "java.lang.Thread").currentThread().sleep(500) />
<cfdump var="#cfthread[threadName]#" label="#threadName# AFTER cancel() request " />

As you can see, the thread was successfully terminated.



The next step was storing the thread information in a shared scope. So it could be accessed as needed. Now I know there are a few ways you could approach it and different scopes you could use. But for the sake of simplicity, I decided to have the threads add and remove themselves from a tracker object stored the application scope. It is obviously not as elegant as a built in monitor, and could definitely use improvement. But it was good enough for some simple tests.


<!--- Start the new thread ---->
<cfthread action="run" name="#newThreadName#" >

<cfset var myThreadUUID = "" />
<cfset var myThreadContext = getPageContext().getFusionContext() />
<cfset var myThreadName = myThreadContext.getCurrentUserThreadName() />

<!---
First, the thread will add itself to the tracker object
--->
<cfset myThreadUUID = application.threadTracker.addThread(
threadName = myThreadName,
threadTask = myThreadContext.getUserThreadTask(myThreadName)
) />

<!---
DO THREAD STUFF HERE .....
--->


<!---
Finally, the finished thread will remove itself from
the application tracker object
--->
<cfset application.threadTracker.removeThread(
threadUUID = myThreadUUID
) />
</cfthread>


Now for the Usual Disclaimers....
As there is a bit too much code to post, I threw together a small example to demonstrate the concepts. It is rough and highly experimental. So use it at your own risk ;) Now I have only had a chance to test it on the Developer version. I am assuming it will work on the Standard edition too.

...Read More

  © Blogger templates The Professional Template by Ourblogtemplates.com 2008

Header image adapted from atomicjeep