Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to chain image conversions with ImageMagick's convert command?

I've got an original image (say, 1600x1200) for which I want to create a series of thumbnails with a variety of resolutions:

  • 900x0 (i.e. means that the image is scaled proportionally to 900 px wide)
  • 700x0
  • 0x550 (i.e. means that the image is scaled proportionally to 550 px tall)
  • 0x400
  • 0x150
  • 200x200 (i.e. cropped and centred)

Individually, I can process each of these conversions with a convert command. The problem is that it's a huge waste of resources to continually reinitialize convert; it would be better to chain things so that convert could reuse its work.

Using ImageMagick 6.7.0-10 I've tried the following (using the +write option, see http://www.imagemagick.org/script/command-line-options.php#write), but it doesn't work as the +write command appears to be ineffective in restoring the image to its original state:

convert '/tmp/original.jpg'[0] -quality 95 -density 72x72 -resample 72x72 +profile '!xmp,*'\
-resize '900>' +write '/tmp/900.jpg'\
-resize '700>' +write '/tmp/700.jpg'\
-resize '200x' -crop '200x200+0+35' +repage +write '/tmp/200.jpg' \
-resize 'x550>' +write '/tmp/550.jpg'\
-resize 'x400>' +write '/tmp/400.jpg'\
-resize 'x150>' '/tmp/150.jpg'\

* end-of-line backslashes for readability purposes

Alternatively, I tried the following (using +clone and -delete). It seems to work, but could probably be made more efficient (perhaps with mpr:, http://www.imagemagick.org/Usage/files/#mpr):

convert 'original.jpg'[0] -quality 95 -density 72x72 -resample 72x72 +profile '!xmp,*' \
    \(+clone -resize 'x150>' -write '150.jpg' \) \ 
-delete 1 \(+clone -resize 'x400>' -write '400.jpg' \) \ 
-delete 1 \(+clone -resize 'x550>' -write '550.jpg' \) \ 
-delete 1 \(+clone -resize '200x' -crop '200x200+0+35' +repage -write '200.jpg' \) \ 
-delete 1 \(+clone -resize '700>' -write '700.jpg' \) -delete 1 -resize '900>' '900.jpg' \

Can anyone explain what I'm doing wrong in the first example (with the +write command)? Also, can anyone suggest any improvements to make things more CPU/memory efficient?

POST-ANSWER

I'm still curious why +write doesn't work.

like image 796
David Carney Avatar asked Jul 05 '11 15:07

David Carney


2 Answers

Turns out that using mpr: is the way to go (from what I've seen on forums and whatnot):

convert 'original.jpg'[0] -quality 95 -density 72x72 -resample 72x72 +profile '!xmp,*' \
-write mpr:orig +delete \
mpr:orig -resize 'x150>' -write '150.jpg' +delete \
mpr:orig -resize 'x400>' -write '400.jpg' +delete \
mpr:orig -resize 'x550>' -write '550.jpg' +delete \
mpr:orig -resize '200x' -crop '200x200+0+35' +repage -write '200.jpg' +delete \ 
mpr:orig -resize '700>' -write '700.jpg' +delete \ 
mpr:orig -resize '900>' '900.jpg' +delete 

NOTE: just in case you missed it, you don't need a -write command for the last image in the chain.

ALSO NOTE: it's important that you use an extension on the files being output. If you omit it, convert doesn't know which format it should use when writing them (presumably because storing the image in mpr: destroys that information).

like image 167
David Carney Avatar answered Sep 18 '22 17:09

David Carney


You misunderstood the meaning of the +write argument. It will not undo any of your image processing performed previous to the write operation, it will only undo any processing caused by the write operation itself.

E.g. assume you have a JPG image and you do the following:

convert original.jpg -scale 50% -write output1.gif output2.jpg

What is going to happen? convert reads original.jpg to memory and shrinks it to half the resolution. Now it should write it to output1.gif, but as the GIF format only supports images that are palette based, it will convert the image to 256 colors and write the GIF file. Now it will take the current image, which was reduced to 256 colors, convert it back to true color (24 Bit RGB) and write it to output2.jpg, because JPG files don't support palette based images. Still, the JPG will look pretty much like if you had convert the GIF file to JPG (it will be limited to about 256 distinct colors).

Now let's try the same thing again, but this time we do the following:

convert original.jpg -scale 50% +write output1.gif output2.jpg

What is going to happen? convert reads original.jpg to memory and shrinks it to half the resolution. Now it should write it to output1.gif, however, without modifying it, that's what the +write is saying, so it first clones the image in memory. It converts the clone to 256 colors and writes the result to output1.gif. Then it discards the clone again and continues processing with the image it had prior to cloning. This image is now written to output2.jpg, which means this time, output2.jpg will be a downscaled version of original.jpg and not looking like a 256 color palette based image.

Under no circumstances the scale operation is undone, because it is completely unrelated to the write operation. If you want to undo the scale operation, you need to either save the image, scale it, write it and then restore it, or clone it, scale it, write it and then discard the clone. Either way should be equally fast because the number of copies performed in memory is identical in both cases, it's just the command line syntax that is different.

like image 25
Mecki Avatar answered Sep 17 '22 17:09

Mecki