I am using ColdFusion's <cfimage>
to resize images and then save as #imagename#.jpg
on the server.
I can see options to specify quality
but I can't see anything to save the jpg as progressive or even optimised. I would like progressive because it gives a perceived impression of quicker loading on the page.
Is it possible to do this?
CFImage does not support writing progressive jpegs out of the box. From what I have read, it is supported in java to some extent. However, it is a big topic. So this is by no means a complete answer, just a starting point.
Java
My knowledge of the jpeg format is pretty rudimentary, but creating a basic progressive jpeg in java seemed pretty straight-forward:
One way to see it action, is by using Fiddler2 to simulate a slow connection. Under Rules > Performance, select "Simulate Modem speeds" and "Disable Caching".
Example:
// Create your CF image object
yourCFImage = imageNew("c:\path\input.jpg");
// ... resizing and other stuff
// Grab a JPEG writer. Validation omitted for brevity
// In real code, verify writer exists and progressives is supported first
// ie jpegWriters.hasNext() and imageParam.canWriteProgressive()
ImageIO = createObject("java", "javax.imageio.ImageIO");
jpegWriters = ImageIO.getImageWritersByFormatName("jpg");
writer = jpegWriters.next();
imageParam = writer.getDefaultWriteParam();
// Where to save new image on disk
destinationFile = createObject("java", "java.io.File").init( "c:\path\outut.jpg" );
destinationStream = ImageIO.createImageOutputStream( destinationFile );
// Parameters for desired image quality and interlacing
// NB: Compression type support varies (JPEG-LS, ...)
// Check availability with getCompressionType()
writer.setOutput( destinationStream );
imageParams = writer.getDefaultWriteParam();
imageParams.setCompressionMode( imageParams.MODE_EXPLICIT);
imageParams.setCompressionQuality( javacast("float", 0.80) ); // 80%
imageParams.setProgressiveMode( imageParams.MODE_DEFAULT );
// Write the new image to disk
buffImage = ImageGetBufferedImage( yourCFImage );
IIOImage = createObject("java", "javax.imageio.IIOImage");
imageToSave = IIOImage.init( buffImage, javacast("null", ""), javacast("null", ""));
writer.write( javacast("null", ""), imageToSave, imageParams );
// Cleanup object
destinationStream.flush();
destinationStream.close();
writer.dispose();
External Tools
Another option is use cfexecute
with an external tool like jpegtran or ImageMagic. Both support progressive jpegs and additional options for customization. For example, jpegtran supports customization though scan files, which offer a lot of control. (Unfortunately, I have not quite wrapped my head around those yet...). Try it out with the default settings first. Those may be good enough for your purposes.
<cfexecute name="C:\Program Files\ImageMagick-6.9.2-Q16\convert.exe"
arguments=" -interlace line -quality 85 c:\path\source.jpg c:\path\output.jpg"
...
>
As an aside, I came across an interesting tool while researching: JSK (JPEG Scan Killer). It is not used to create progressive jpegs, but it really helps explain how they are generated and where scanning fits into the process.