Search code examples
coldfusionjpegcoldfusion-11

How to use cfimage to save image as progressive jpg?


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?


Solution

  • 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:

    1. Grab an instance of a JPEG writer
    2. Initialize the image parameters and output settings
    3. Extract the underlying BufferedImage from the CF image object
    4. Write the new jpeg to disk

    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.