ColdFusion - Reading in lots of images

287 Views Asked by At

What is the most efficient way of reading in lots of images in CF / Railo and checking their width and height?

In my app, I need to typically read in about 20 images + and at the moment this takes up to 14 seconds to complete. A bit too long really.

theImageRead = ImageNew(theImageSrc);
if ( imageGetWidth(theImageRead) > 100 ) {
    writeOutput('<img src="' & theImageSrc & '" />');
}

Images are read from a list of absolute URL's. I need to get images specified over a certain dimension.

If there's a quicker solution to this then I'd love to get your insight. Perhaps underlying java methods?

I am also using jSoup if there's anything in that which could help.

Thanks, Michael.

2

There are 2 best solutions below

4
On

I have written this utility function quite a while ago (it runs on older ColdFusion versions, too). Maybe it helps.

Note that this requires the Java Advanced Imaging Image I/O Tools (Jai-imageio). Download the .jar and put it in your class path (restarting CF is necessary).

/**
 * Reads basic properties of many types of images. Values are
 * returned as a struct consisting of the following elements:
 *
 * Property names, their types and default values:
 *   ImgInfo.width       = 0        (pixels)
 *   ImgInfo.height      = 0        (pixels)
 *   ImgInfo.size        = 0        (bytes)
 *   ImgInfo.isGrayscale = false    (boolean)
 *   ImgInfo.isFile      = false    (boolean)
 *   ImgInfo.success     = false    (boolean)
 *   ImgInfo.error       = ""       (string)
 *
 * @param FilePath    Physical path to image file.
 * @return            A struct, as described.
 */
function GetImageProperties(FilePath) {
    var ImgInfo         = StructNew();
    var jImageIO        = CreateObject("java", "javax.imageio.ImageIO");
    var jFile           = CreateObject("java", "java.io.File").init(FilePath);
    var jBufferedImage  = 0;
    var jColorSpace     = 0;

    ImgInfo.width       = "";
    ImgInfo.height      = "";
    ImgInfo.fileSize    = 0;
    ImgInfo.isGrayscale = false;
    ImgInfo.isFile      = jFile.isFile();
    ImgInfo.success     = false;
    ImgInfo.error       = "";

    try {
        jBufferedImage      = jImageIO.read(jFile);
        ImgInfo.fileSize    = jFile.length();
        ImgInfo.width       = jBufferedImage.getWidth();
        ImgInfo.height      = jBufferedImage.getHeight();
        jColorSpace         = jBufferedImage.getColorModel().getColorSpace();
        ImgInfo.isGrayscale = (jColorSpace.getType() eq jColorSpace.TYPE_GRAY);
        ImgInfo.success     = true;
    }
    catch (any ex) {
        ImgInfo.error   = ToString(ex);
    }
    jImageIO = JavaCast("null", "");
    jFile = JavaCast("null", "");
    jBufferedImage = JavaCast("null", "");
    jColorSpace = JavaCast("null", "");

    return ImgInfo;
}

Use like:

imageInfo = GetImageProperties(theImageSrc);
if (imageInfo.success and imageInfo.width > 100)
    writeOutput('<img src="#HTMLEditFormat(theImageSrc)#" />');
}
0
On

I don't believe there's any way to determine the pixel dimensions of an image without reading the bytes and creating an image object. The main bottleneck here will be the http request overhead.

that said there are a few ways to speed up what you're trying to do.

  1. use threads to concurrently request images, then when all threads have finished processing output the images.

  2. If you display the same image or set of images more than once cache it. If you don't want to cache the actually image you can cache the metadata to avoid having to perform a http request for every image.

  3. decide if you need to output all the images to the page immediately, or could some or all of these be deferred and loaded via and ajax request