Search code examples
imagemagickimagemagick-convert

ImageMagick : Compose with results of multiple convert


I want to create an image from to others, which are results of convert operations their self, without saving intermediate results to file system.

Long explanation:

I have two images, the two needs specific transformations :

  • avatar.jpg needs to be transformed to a rounded image -> rounded-avatar.jpg
  • background.jpg needs to have a color layer applied -> colored-background.jpg

Then I want to dissolve rounded-avatar.png in colored-background.jpg, so that I get something looking like this:

  +-----------+
  |     O     |
  +-----------+

What I have so far:

I know how to make those operations sequentially (maybe not the best way but that is not the subject of this question), I even made a working bash script :

#!/bin/bash

convert $1 -alpha set -background none -vignette 0x0 rounded-avatar.png

convert $2 -auto-orient -thumbnail 600x313^ -gravity center -extent 600x313 -region 100%x100% -fill "#256997" -colorize 72% colored-background.jpg

composite -dissolve 100 -gravity Center rounded-avatar.png colored-background.jpg -alpha Set $3

That I can call it with

$ ./myScript.sh avatar.jpg background.jpg output.jpg

What I want:

I want to avoid the saving of the two temporary images (rounded-avatar.jpg and colored-background.jpg) on the file system.

Why ?

  • This procedure has to be ran automatically on a web platform, I don't want to have to handle concurrency on those temp files with naming tricks.
  • The current script makes IM load the images two times in memory, it would probably be more efficient to reuse the computed images instead of writing them to disk and then load them in a new process.
  • Disk I/O are scarcity these days, let's save some.

I hope I am just missing the right keywords to find the answer in the documentation.

I am aware that this might seems over optimisation and I am not struggling with C10k issues here, but I just want to do this right (and understand IM syntax).


Solution

  • Kind of hard to help without seeing your images! I guess it will look something like this though:

    convert -gravity center                                    \
            \( $1 -alpha set -background none -vignette 0x0 \) \
            \( $2 -auto-orient -thumbnail 600x313^ -gravity center -extent 600x313 -region 100%x100% -fill "#256997" -colorize 72% \) \
            -compose dissolve -composite result.jpg
            
    

    The salient parts are

    a) that you can use parentheses to do 'aside-processing' to one particular image

    b) that you can load 2, or more, images onto a kind of stack of images to process

    c) that you can use the convert command's -composite operator after setting the -compose type in place of the actual compose command itself.

    Option 2

    Another option may be to use the MIFF format for multiple images and a pipe like this:

    convert \( $1 .... \) \( $2 ... \) miff:- | composite -dissolve 100 -gravity center -   ... 
    

    Option 3

    Yet another option is to use a separate convert for each input file and then send the concatenated results to a third convert or composite like this:

    (convert -size 100x100 xc:red miff:- ; convert -size 100x100 xc:blue miff:- ) | convert - +append result.jpg
    

    which gives this:

    enter image description here

    Option 4

    If the images need a significant amount of processing before being combined, you can develop Option 3 so that the 2 input images are processed in parallel, like this

    mkfifo fifo1 fifo2 2>/dev/null
    convert -size 2000x2000 xc:gray +noise gaussian -median 7 jpeg:fifo1 &
    convert -size 2000x2000 xc:gray +noise gaussian -median 7 jpeg:fifo2 &
    convert fifo1 fifo2 +append result.jpg       # or equally "convert fifo[12] ..."
    

    which takes 33 seconds, whereas the sequential version below, takes 64 seconds and uses 2MB of disk space on top

    convert -size 2000x2000 xc:gray +noise gaussian -median 7 1.jpg
    convert -size 2000x2000 xc:gray +noise gaussian -median 7 2.jpg
    convert 1.jpg 2.jpg +append result.jpg       # or equally "convert [12].jpg..."