Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

creating pictures with imagemagick is too slow. how to improve?

I'm coding a little CMS, where you can upload several images. These images are converted into 3 versions (big, mid und thumbnail size) with imagemagick.

The problem is that imagemagick needs 5 minutes for creating these 3 versions of 4 pictures (which were uploaded).

here is the part with the imagemagick commands:

foreach($upIMGS as $key => $filename){
    list($width, $height) = getimagesize($path.$filename);
    if ($width > $height) $size = "x96";
    else $size = "96x";

    exec(P_IMAGEMAGICK." ".$path.$filename." -resize $size -gravity center -crop 96x96+0+0 +repage ".$path."th-".$filename);
    exec(P_IMAGEMAGICK." ".$path.$filename." -resize 320x320 ".$path."hl-".$filename);
    exec(P_IMAGEMAGICK." ".$path.$filename." -resize 514x ".$path."fl-".$filename);

    unlink($path.$filename);
}

[the $upIMGS is an array with all the filenames of the recently uploaded images]

I mean.. it does work, but toooo slow and after 5min the server gives me an error. some of the files are generated and some are not...

Would be very nice if you can give me a tip.

like image 664
John Doe Smith Avatar asked Dec 09 '22 00:12

John Doe Smith


2 Answers

I recently ran into the same issue, but I was only passing through the images once to resize them from their original 2592x1944 to 300xbestFit or bestFitx300

I am using the PHP class imagick instead of command lines but I cut my time in half by changing to -scale or scaleImage in my case. Here is a snippet of my test code.

while ($images = readdir($handle)) {
    // check to see if the first or second character is a '.' or '..', 
    // if so then remove from list
    if (substr($images,0,1) != '.') {
        //Check files to see if there extensions match any of the following image extensions. 
        // GLOB_BRACE looks for all glob criteria within the {braces}
        $images = glob($dir."{*.gif,*.jpg,*.png,*.jpeg}", GLOB_BRACE);
        // the glob function gives us an array of images
        $i = 0;
        foreach ($images as $image) {
            // parse the data given and remove the images/ $dir, 
            // imagemagick will not take paths, only image names.
            $i++;
            list ($dir, $image) = split('[/]', $image);
            echo $i, " ", $image, "<br />";

            $magick = new Imagick($dir."/".$image);
            $imageprops = $magick->getImageGeometry();

            if ($imageprops['width'] <= 300 && $imageprops['height'] <= 300) {
                // don't upscale
            } else {

                // 29 Images at 2592x1944 takes 11.555036068 seconds -> 
                // output size = 300 x 255
                $magick->scaleImage(300,300, true);

                // 29 Images at 2592x1944 takes 23.3927891254 seconds -> 
                // output size = 300 x 255
                //$magick->resizeImage(300,300, imagick::FILTER_LANCZOS, 0.9, true);
                $magick->writeImage("thumb_".$image);

            }
        }
    }
}

I am processing 29 images at 2592x1944 and went from 23.3927891254 seconds to 11.555036068 seconds. I hope this helps.

Edit:

In addition to what I said above I just ran into to the following, which might be helpful, on ImageMagick v6 Examples -- API & Scripting:

  • "Shell scripts are inherently slow. It is interpreted, require multiple steps and extra file handling to disk. This is of course better thanks to the new IM v6 option handling, allowing you to do a large number of image processing operations in a single command. Even so you can rarely can do everything in a single convert command, so you often have to use multiple commands to achieve what you want."

  • "When reading large or even a large number of images, it is better to use a Read Modifier to resize, or crop them, as IM does not them read in the full image, thus reducing its memory requirement."

  • "If you call ImageMagick as an Apache module it will also reduce startup time, as parts will be loaded once and kept available for multiple use, rather than needing re-loading over and over. This may become more practical in the future with a permanently running 'daemon' IM process."

like image 113
jnthnjns Avatar answered May 20 '23 15:05

jnthnjns


This example may help as it loads the main image into the memory and works on that to make the other images:

$cmd = " input.jpg \( -clone 0 -thumbnail x480 -write 480_wide.jpg +delete \)". 
" \( -clone 0 -thumbnail x250 -write 250_wide.jpg +delete \) ". 
" \( -clone 0 -thumbnail x100 -write 100_wide.jpg +delete \) -thumbnail 64x64! null: ";
exec("convert $cmd 64_square.jpg ");

This is creating 4 different size images.

like image 33
Bonzo Avatar answered May 20 '23 13:05

Bonzo