Leave That Thing Alone Blog

Introduction to CFCs at Sacramento ColdFusion User Group July 8th

Join SacCFUG Tuesday July 8th for a great presentation by Nolan Erck on ColdFusion Components. If you are new to CFCs or just want to brush up on your CFC skills this will be a great presentation for you.

Visit the SacCFUG website for more details and meeting location info.

Sacramento ColdFusion User Group Meets June 10th

The Sacramento ColdFusion User Group is meeting Tuesday June 10th at 6:30pm, this month's topic will be code generation from UML. Please visit the SacCFUG website for more details.

SacCFUG is also happy to announce we have a new sponsor Clear Capital. Our monthly meetings will now be help at Clear Capital's office. Please see the meeting location page for the address and map.

One last note, SacCFUG has moved to a new email list you can subscribe here.

Using Exif Orientation to Rotate Digital Photos with ColdFusion

Here's a ColdFusion 8 function to rotate digital photographs via Exif 'orientation'. This function will accept a cfimage or a filename and return a rotated/flipped (if needed) image in cfimage format.

With ColdFusion 8's 'ImageGetEXIFMetadata' tag you can get the 'orientation' of a digital photograph. The 'orientation' value indicates if the camera was held/rotated landscape, upside down, portrait with right on the top, etc.

What makes this a bit more difficult is that there are 8 different orientation possibilities and the 'orientation' value can be a number or comma separated text. For example value 1== 'top, left side'. Full exif 'orientation' details here.


Example usages of imageExifOrientationRotate:


<!--- specify image via filename --->
<cfset myImage = imageExifOrientationRotate('IMG_3087.jpg') />
<!--- resize --->
<cfset imageResize(myImage,"200","") />
<!--- display --->
<cfimage action="writeToBrowser" source="#myImage#" />

or


<!--- read image --->
<cfimage action="read" source="IMG_3087.jpg" name="myImage" />
<!--- specify image via cfimage --->
<cfset myImage = imageExifOrientationRotate(myImage) />
<!--- resize --->
<cfset imageResize(myImage,"200","") />
<!--- display --->
<cfimage action="writeToBrowser" source="#myImage#" />

View imageExifOrientationRotate function:

Opening/Viewing multipage TIFFs with ColdFusion 8

Here's a quick example of how to open and/or view a multipage TIFF with ColdFusion 8. This example requires no external Java libraries.

The first step is to open the multi-page tiff and using the JAI ImageCodec we're able to determine the number of pages in that tif and create an array of the pages.


<cfscript>
    //set TIFF file name

    tifFileName = expandpath('samples\patent.tif');
    //create FileSeekableStream

    ss = createObject("Java","com.sun.media.jai.codec.FileSeekableStream").init(tifFileName);
    //create JAI ImageDecoder

    decoder = createObject("Java","com.sun.media.jai.codec.ImageCodec").createImageDecoder("tiff", ss, JavaCast("null",""));
    //create array

    tifPageArray = arrayNew(1);
    //loop through pages of tiff add to array

    for (i=0;i
<decoder.getNumPages();i++) {
        //add each to array (com.sun.media.jai.codecimpl.TIFFImage)

        tifPageArray[i+1] = decoder.decodeAsRenderedImage(i);
    }
</cfscript>

At this point we have array of tiff images (of type com.sun.media.jai.codecimpl.TIFFImage). Based on your needs your code will probably need to change after this. To be able to easliy 'use' these TIFF pages in ColdFusion we need to convert them to the cfimage format. One of the great features about the ColdFusion 'imageNew' tag is that it accepts BufferedImage as an input

So to move from TIFF to cfimage we do this:
TIFF -> PlanarImage -> BufferedImage -> cfimage

Here's some code to loop though all the pages and write a JPG for each page in the mulitpage tiff:


<cfscript>
    //loop through all tiff pages

    for (i=0;i
<decoder.getNumPages();i++) {
        //create PlanarImage

        pImg = createObject("Java","javax.media.jai.PlanarImage").wrapRenderedImage(tifPageArray[i+1]);
        //get buffered image

        bufferedImage = pImg.getAsBufferedImage();
        //use CF image tage to create CF image from bufferedImage

        myImage = imageNew(bufferedImage);
        //write image

        imageWrite(myImage,"page#i+1#.jpg");
    }
</cfscript>


You may want to alter the code above as writing TIFF pages to JPGs might not be what you need. After 'imageNew(bufferedImage)' we have a cfimage so you are able to do any ColdFusion 8 image function on the TIFF page.

Update:
Multi-Page Tiff support has now been added to ImageUtils

ColdFusion and Miro port 8500 conflict

Hopefully this post will save someone some grief. I have been having problems on my local development ColdFusion server where ColdFusion would just randomly stop responding to requests to http://localhost:8500 . I couldn't figure out a pattern.

finally I realized that this would happen when I was running Miro. Turns out Miro by default uses ports 8500-8600 for torrents and my dev CF server was using port 8500...

To fix this problem change the ports that Miro uses, go to 'File' - 'Options' - 'Downloads' tab and change the port(s) settings under the BitTorrent section.

NorCal Flex User Group hosts Ryan Stewart

If you're in the Sacramento area come to the NorCal Flex User group January 23rd to see Ryan Stewart talk about Flex 3 and AIR.

meeting details

CFCPhotoBlog Version 1.0

Version 1.0 of CFCPhotoBlog has finally been released...

Here are the main new features:

  • Photo's location linked to photo location thumbnail page display
  • Photo's category(s) now linked to category thumbnail page display
  • Added photo thumbnails to RSS feed
  • 2 new basic styles/skins added
  • New skins are text based support any width/height photo and better i18n support
  • An 'About' page added
  • Ability to display photo details by default on main photo display page
  • Added end images to bottom tabs to allow for easier tab add/remove (in default skin)

It has been really hard to find time to work on this starting the new job, but occasionally when I take the train to SF I get a bit of time to knock out a couple things. I will be working on the next version which I hope to add color indexing/searching and take advantage of some of the new CF8 image features. Hopefully it wont take another year and a half to get to version 2.0...

I'd like to thank those people who have sent in feature requests, sorry if I didn't include yours. I haven't had time to get to all of them, but please keep sending them.

This project is now on riaforge so if you have feature requests please visit the forums.

CFCPhotoBlog project page

ColdFusion8 at the August Sacramento ColdFusion User Group

The August 14th Sacramento ColdFusion User Group meeting is all about ColdFusion 8. Please join us as we demonstrate all the new features of CF8.

We will be giving away a free copy of ColdFusion 8 Standard Server!

Check out www.saccfug.org for more details.

ColdFusion 8 Exif and IPTC

New in ColdFusion 8 is the cfimage tag and several functions specific to metadata contained in digital images. Here are some basic examples on how to the new ColdFusion 8 Exif and IPTC tags for digital photos, also several things to be careful about when using these tags.

ColdFusion 8 now has tags for getting Exif and IPTC metadata directly from your digital photos. The new tags are:

  • ImageGetEXIFTag() - Returns the specified Exif tag in an image.
  • ImageGetExifMetadata() - Returns a structure of all available Exif tags
  • ImageGetIPTCTag - Returns the specified IPTC tag for an image.
  • ImageGetIPTCMetadata() - Returns a structure of all available IPTC tags

So what are EXIF and IPTC? Exif metadata is the information in a digital image that describes the settings of the camera that took the photo. For example 'Shutter speed', 'aperature', and 'ISO'. Exif data is added to the digital image by a camera when the photo is taken.
IPTC metadata contains user added information like 'author' or 'copyright' of the digital image. This information is generally added after an image has been taken. Unfortunately ColdFusion 8 does not allow you to edit or add IPTC metadata.

How are these tags used?

Example of getting all Exif Metadata from a digital image:


<cfimage action="read" source="IMG_7654.JPG" name="myImage" />

<cfset exif = ImageGetEXIFMetadata(myImage) />

<cfdump var="#exif#" label="Exif Metadata">

Output:
coldfusion 8 exif metadata

Example of how to display an individual Exif tag:

<cfimage action="read" source="IMG_7654.JPG" name="myImage" />

<cfset model = ImageGetEXIFTag(myImage,"model") />

<cfoutput>#model#</cfoutput>

Output:
Canon 30D

Example of getting all IPTC Metadata from a digital image:

<cfimage action="read" name="myImage" source="img_7654.jpg">

<cfset IPTC = imageGetIPTCMetadata(myImage) />

<cfdump var="#IPTC#">

In this case the IPTC data was added using Adobe Bridge, I labeled the fields as they are labeled in Bridge. This will show that that the IPTC tag names don't always match the tags in the tool the author used to add them. Adobe Bridge (CS2) has 30 IPTC fields, ColdFusion only retrieves 19 of them:

Output:
ColdFusion IPTC metadata

Some things to be careful/aware about:

  • Not all digital cameras write the same Exif metadata tags, so don't count on a particular tag existing. For example "Shutter Speed" may exist in a image taken with one digital camera but not in a different camera
  • ImageGetEXIFTag() and ImageGetIPTCTag() return a null if a requested tag does not exist. This means if you set a variable to this result value you may get an error if you try to evaluate it.
  • Date formats in Exif are generally stored in a format not formattable with the CF DateFormat() function.
  • Just like most other image manipulation programs if you save a new version of an image the Exif and IPTC metadata will not exist in the new image.
  • All four Exif and IPTC tags require the cfimage tag to read in an entire image before metadata is available, this can be time consuming and resource intensive.
  • Not all IPTC metadata tags may be available or be named as expected.

Retrieving individual Exif tags

Keep in mind that not all images have Exif/IPTC metadata, and if they do have metadata the tags may be different from camera to camera. A digital photo that has been manipulated/re-saved/re-sized/etc may very likely have lost its metadata. Also different digital cameras use different names for tags.

Using ImageGetEXIFTag() can cause problems if you are looking for a tag that doesn't exist in the image:

Erroring code:

<cfimage action="read" source="IMG_7654.JPG" name="myImage" />

<cfset badTagName = ImageGetExifTag(myimage,"Bad Tag Name") />

<cfoutput>#badTagName#</cfoutput>

Will cause error: " Variable BADTAGNAME is undefined."

One solution to this:

<cfif isdefined('badTagName')>

<cfoutput>#badTagName#</cfoutput>

</cfif>

Another solution to get around not knowing if certain Exif tags exist is to use ImageGetExifMetadata():

<cfimage action="read" source="IMG_7654.JPG" name="myImage" />

<cfset exifMetadata = ImageGetExifMetadata(myimage) />

<cfif structKeyExists(exifMetadata,"Date/Time")>

<cfoutput>#ImageGetExifTag(myimage,"Date/Time")#</cfoutput>

</cfif>

Exif Date Issues

Most Exif Date/Time stamps are stored in a format that is not a valid ColdFusion date (that can be converted from a string). So to evaluate or dateFormat() an Exif date you may have to do a replace() or regex to format the date for CF.

Sample code to retrieve the date and time a digital photo was taken:

<cfimage action="read" source="IMG_7654.JPG" name="myImage" />

<cfset datetime = ImageGetExifTag(myimage,"Date/Time") />

<cfdump var="#datetime#">

Output:
2005:12:28 12:20:32

CFImageHistogram ColdFusion 8 Version

I've added a ColdFusion 8 version of CFImageHistogram. This version takes advantage of the new cfimage capabilities, and JAI (Java Advanced Imaging) because that is now available in CF8.

The ColdFusion 8 version will return a struct containing the histogram statistics, it will also return an image of the histogram in cfimage format.

I've also done some speed comparisons between CF7 and CF8. Keep in mind these aren't scientific tests but they give you an idea of the speed increases using CF8 and JAI:

getColorHistogram() for a 300x450 pixel image
  CF7 CF7 with JAI CF8
time ms: 2518 56 165


getColorHistogram() for a 2048x3072 digital photo
  CF7 CF7 with JAI CF8
time ms: timeout 1484 943


getColorHistogramImage() for a 300x450 pixel image
  CF7 CF7 with JAI CF8
time ms: 2903 734 334


getColorHistogramImage() for a 2048x3072 digital photo
  CF7 CF7 with JAI CF8
time ms: timeout 2422 1040

Please note these tests were done with an older computer (Pentium4 2.4 Ghz, 1 GB RAM)

While 1040ms may seem like a long time to get the histogram of a 8megapixel digital photo, it is pretty impressive to think that 6,291,456 pixel's colors have been inspected in that time.

See the CFImageHistogram project page for more info, and since I get of lot of question about what image histograms can be used for see this.

More Entries