Leave That Thing Alone Blog

CFCPhotoBlog Adds Railo Support

CFCPhotoBlog has been updated to support Railo

There were actually very few changes required to make Railo happy. The main problem was that I had used several Adobe ColdFusion specific cfform tags that were not really needed.

View a demo and download from CFCPhotoBlog project page

 

CFCPhotoBlog 1.1 Update

CFCPhotoBlog has been updated to version 1.1. Here is what is new:

This is not a huge update mainly I wanted a new look on my photoblog, so I added two new skins 'moderndark' and 'modernlight'. For fun I added support for cooliris/piclens, this adds a special RSS feed that allows cooliris to view the photos.

As always suggestions and feature requests are welcomed. I am planning now for version 2.0.

CFCPhotoBlog project page

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

Using JAI and ColdFusion to create image histograms

Here's another look at creating image histograms in ColdFusion, this time using JAI (Java Advanced Imaging). With CFImageHistogram I decided not to use JAI because I didn't want the CFC to require any external Java libraries not currently available to CF6/CF7.

Since speed is definitely an issue with CFImageHistogram I thought I would post some example of code that uses JAI. JAI is much fast at producing image histograms than my method of inspecting pixels in a bufferedimage; however, this method requires that JAI be in the class path of your CF server.

Another advantage of using JAI is that you can get the histograms of more file types (jpg,bmp,tif)

Here is a basic example of using JAI to create a histogram:


<cfscript>
//image file name

filename = expandPath('01.JPG');
//create JAI object

JAI = createObject("Java","javax.media.jai.JAI");
//create JAI PlanarImage

image = JAI.create("fileload", filename);
//create ParameterBlock

pb = createObject("Java","java.awt.image.renderable.ParameterBlock").init();
//add image source

pb.addSource(image);
//RenderedOp

op = JAI.create("histogram", pb);
//get histogram (javax.media.jai.Histogram)

histogram = op.getProperty("histogram");
</cfscript>

To get the histogram array[3][256]:


histogram.getBins()

To get the mean:


histogram.getMean()

Finally here is some code to create an color image histogram png file:


<cfscript>
//image file name

filename = expandPath('01.JPG');
//create JAI object

JAI = createObject("Java","javax.media.jai.JAI");
//create JAI PlanarImage

image = JAI.create("fileload", filename);
//create ParameterBlock

pb = createObject("Java","java.awt.image.renderable.ParameterBlock").init();
//add image source

pb.addSource(image);
//RenderedOp

op = JAI.create("histogram", pb);
//get histogram (javax.media.jai.Histogram)

histogram = op.getProperty("histogram");
//histogram bins - array[3][256]

bins = histogram.getBins();
//set image height

histogramImageHeight = 100;

//get PNG buffered image to draw on

pngBuffered = getPNGBufferedImage(histogramImageHeight);
//get java.awt.Graphics2D

Graphics2D = pngBuffered.getGraphics();
//set background color to white

setImageBackgroundColor(255,255,255);
Graphics2D.setBackground(variables.imageBackgroundColor);
Graphics2D.clearRect(0,0,256,histogramImageHeight);

//set colors with alpha of 33% (85/255)

red = createObject("java", "java.awt.Color").init(javaCast("int",255),javaCast("int",0),javaCast("int",0),javaCast("int",85));
green = createObject("java", "java.awt.Color").init(javaCast("int",0),javaCast("int",255),javaCast("int",0),javaCast("int",85));
blue = createObject("java", "java.awt.Color").init(javaCast("int",0),javaCast("int",0),javaCast("int",255),javaCast("int",85));

//loop thru color bins r-g-b

for(i=1;i LTE 3; i=i+1) {
    //set color based on bin
    
    if (i eq 1) {//red
        
        currentColor = red;
    } else if (i eq 2) {//green
        
        currentColor = green;
    } else if (i eq 3) {//blue
        
        currentColor = blue;
    }
    //set drawing color
    Graphics2D.setPaint(currentColor);
    //loop thru all bins in color
    
    for(ii=1;ii LTE 256; ii=ii+1) {
        //set as 0 so we get a line not a rectangle
        
        rectWidth = javaCast("int",0);
        //set max height based on the max size found in array
        
        rectHeight = javaCast("int",(bins[i][ii]/arrayMax(bins[1])) * histogramImageHeight);
        //X left to right 0-255
        
        rectX = javaCast("int",ii-1);
        
        //switch Y (vertical) so that lines sit on bottom
        
        rectY = javaCast("int",histogramImageHeight-rectHeight);
        //create rectangle that is actually a line becasue we gave it no width
        
        rect = createObject("java", "java.awt.Rectangle").init(rectX,rectY,rectWidth,rectHeight);
        //draw line
        
        Graphics2D.draw(rect);
    }
}
writePNGImage(expandpath("hist.png"),pngBuffered);
</cfscript>

<cffunction name="getPNGBufferedImage" access="private" output="false" hint="I draw a histogram image">
    <cfargument name="height" required="yes" type="numeric" hint="height of png to create" />
    <cfscript>
        var width = 256;
        //create bufferedimage object
        
        var bufferedImage = createObject("java", "java.awt.image.BufferedImage");
        //create PNG based on width height
        
        bufferedImage.init(JavaCast("int", width), JavaCast("int", arguments.height), BufferedImage.TYPE_4BYTE_ABGR);
        //return the buffered image
        
        return bufferedImage;
    
</cfscript>
</cffunction>

<cffunction name="writePNGImage" access="private" output="false" hint="I write a PNG file to disk">
    <cfargument name="outputHistogramImage" required="yes" type="string" hint="filename" />
    <cfargument name="pngBuffered" required="yes" hint="buffered PNG" />
    <cfscript>
        //write PNG file
        
        var outputStream = createObject("java", "java.io.File").init(arguments.outputHistogramImage);
        var ImageIO = createObject("java", "javax.imageio.ImageIO");
        ImageIO.write(arguments.pngBuffered, "png", outputStream);
    
</cfscript>
</cffunction>

<cffunction name="setImageBackgroundColor" access="public" returntype="void" output="false" hint="I set the the buffered image, i can be used if you want to set a buffered image instead of specifying a image file name and path">
    <cfargument name="red" required="yes" default="255" type="numeric" hint="red color value 0-255" />
    <cfargument name="green" required="yes" default="255" type="numeric" hint="green color value 0-255" />
    <cfargument name="blue" required="yes" default="255" type="numeric" hint="blue color value 0-255" />
    <cfargument name="alpha" required="yes" default="255" type="numeric" hint="alpha color value 0-255" />
    <cfset variables.imageBackgroundColor = createObject("java", "java.awt.Color").init(javaCast("int",arguments.red),javaCast("int",arguments.green),javaCast("int",arguments.blue),javaCast("int",arguments.alpha)) />
</cffunction>


<img src="hist.png" style="border:black 1px solid;margin:4px;" />

The above code may get mangled in my small code view so here's a text version

Example Input JPG:

Example Output histogram PNG:

Small CFCPhotoBlog Update

I've added automatic image rotation/flip based on the Exif orientation to CFCPhotoBlog. Like all the other image manipulation features this is optional. You can still upload pre-sized and optimized images if you prefer to use a (better quality) desktop image manipulation program.

I'd like to thank Rick Root, author of imagecfc. ImageCFC is now used in CFCPhotoBlog to handle the photo rotate/flip.

I'm working on getting to version 1.0. The features are fairly nailed down, my big goal is to add several different skins to the application.

As always feedback is greatly appreciated.

CFCPhotoBlog Project Page

Image resize, thumbnail creation, and Exif retrieval added to CFCPhotoBlog

By uploading an original digital JPG CFCPhotoBlog can now: retrieve the Exif information, resize the image, and create a thumbnail automatically. All of these features are optional, if you would like to retrieve the Exif, but upload a pre-sized photo and/or thumbnail you can still do that.

Like I said all of these new image features are optional. You might want the ease of uploading a single image and have it resized and a thumbnail created. But you also might want to upload a pre-sized image that you have optimized using more sophisticated image manipulation program (like PhotoShop). I wanted to add some nice features, but didn't want to take away any options.

Thanks to Drew Noakes who created the metadata extraction in java, this allows CFCPhotoBlog to automatically retrieve EXIF details from JPEG files.

I would also like to thank Mark Mandel who created the JavaLoader.cfc. The JavaLoader.cfc allows the java based Exif extraction library to be used by ColdFusion in a shared hosting environment.

To make all the upload features possible the upload photo screen had to be changed quite a bit, it now has a lot more options. Hopefully I made everything clear, please give me feedback/suggestions if not.

Download CFCPhotoBlog

CFCPhotoBlog Updated

I've released version 0.9 of CFCPhotoBlog. Here is a list of the major features added:

  • Multiple CFCPhotoBlog instances supported
  • Width and height automatically added to all photos and thumbnails
  • Thumbnails view page added
  • Locations can be hidden on map but displayed in the photo details
  • Search page added (this link is commented out - see readme.html)

There are quite a few changes so if you are already running CFCPhotoBlog be sure to read the version-changes.txt.

Although CFCPhotoBlog is currently written for Model-Glue 1.0, it does work just fine with Model-Glue Unity.

Again as always feedback is appreciated.

View the CFCPhotoBlog project page.

A More Accessible Map

I'm very excited to have my "A More Accessible Map" article in A List Apart. The article describes how to create a map using CSS and DOM Scripting that is interactive and also accessible. You can read the full article here: http://www.alistapart.com/articles/cssmaps

I have made some code and worldmap image files available for the CSS map example. A ColdFusion CSS Map example is also available.

I want to thank the people at A List Apart, and I have to give a huge amount of thanks to Aaron Gustafson. Aaron was the production editor for the article; he made a bunch of great suggestions on improving the scripting and really made this a much better example and article.

Several scripting links I found very helpful:
http://www.wait-till-i.com/index.php?p=239
http://dean.edwards.name/weblog/2005/10/add-event/

I have also updated my CFCPhotoBlog to include the CSS mapping technique. The CSS map technique can be seen in action on the Photos By Location page.

CFCPhotoBlog Update

I have updated CFCPhotoBlog to support MySQL. The application supports MySQL5, but I tested on MySQL4 and it worked as well.

The project page for CFCPhotoBlog is here:
http://www.leavethatthingalone.com/projects/CFCPhotoBlog/

If you have previously downloaded CFCPhotoBlog, there are some database table name changes... I wanted to make sure all the database table names were unique to this application. A complete list of changes can be found in the "version-changes.txt" file in the install directory.

My next update will be to make application more skinnable, currently there is only one style. I want to change that so that there are several skins to choose from, and to make it easy to create your own. Oh and I have a new mapping technique that I might be adding.

Again any feedback on the application, features that you would like, code practices that could be improved, etc would be greatly appreciated.