ImageMagick multiple operations in single invocation - imagemagick

I'm trying to get ImageMagick to perform multiple operations (in this case, crops) in a single invocation, but it doesn't seem to be possible. For example, I can do a crop, rotate, and then another crop as two separate commands:
$ convert test.jpg -crop 223x187+588+757 -rotate 330 crop2.jpg
$ convert crop2.jpg -crop 200x100+43+87 crop3.jpg
But if I try to combine them into a single command, I get an error:
$ convert test.jpg -crop 223x187+588+757 -rotate 330 -crop
200x100+43+87 crop3.jpg
convert: geometry does not contain image `test.jpg' # warning/transform.c/CropImage/666.
Obviously I could just create a pipe, but if possible I want to avoid the extra overhead of multiple processes. Is there a way to do this?
Update:
Also, a pipe seems problematic: I don't want an extra compress/decompress stage so I try piping it as RGB, but I can't seem to get the parameters right:
convert test.jpg -crop 223x187+588+757 -rotate 330 rgb:- | convert -size 287x273 -depth 8 rgb:- -crop 200x100+43+87 crop3.jpg
convert: unexpected end-of-file `-': No such file or directory # error/rgb.c/ReadRGBImage/231.
Ok, so it turns out the above error is because my calculated size for the image differs from ImageMagick's calculations by two pixels. So obviously having to try to get the image size calculation exactly the same as IM is an extra problem introduced by the need to pipeline the two commands.

Here is a more generic approach to the question.
ImageMagick provides a few clever tricks which can help to optimize processing speed when...
...you want to process large images and
...when you want to create different output from the same original.
There are different methods which can even be combined:
Take advantage of ImageMagick's special mpr:{label} format and syntax.
This tells ImageMagick to temporarily save the input image into a named magick program register label.
(I've also seen it explained as magick persistent (memory) register or memory program register.)
The command pipeline can then later (while processing) read the image data much faster from there than it could read from harddisk.
And the command can read it as often as you want, multiple times.
Take advantage of ImageMagick's special mpc:{name} format and syntax.
This works similar to mpr:.
Its long name is magick pixel cache.
I've also seen it as magick persistent (disk) cache.
MPC is the native in-memory uncompressed file format of ImageMagick, but dumped to disk.
Once written to disk, it can be re-read faster into memory again than a JPEG, TIFF or PNG could, because no conversion is needed.
Construct a clever command sequence.
Make use of "sideway" processing, using the \( ... \) syntax in escaped parentheses where appropriate.
MPC
When the convert command reads input image (JPEG, TIFF, GIF, PNG... whatever format it may currently be), it first processes this format into an MPC.
This processed result is kept in RAM as an uncompressed raster format.
From there the further conversions and image manipulations happen.
When you want write an MPC to disk as MPC you can use +write mpc:myfilename.
This basically is simply a direct memory dump to disk.
ImageMagick then writes two, not one, (and larger than usual) binary files: myfilename.mpc and myfilename.cache.
The .mpc file holds the metadata of the image, .cache holds the actual pixel cache data.
A read from this disk file(s) is a fast memory map from disk to memory as needed (similar to memory page swapping).
But since the initial +write operation did store the native uncompressed internal, IM-native raster format, now no image decoding is needed.
So this can be faster (especially for large images) to use, IF you cannot avoid writing temporary files out which you need to read in again.
However, be careful with your disk space.
Remember to clean up, once you no longer need the MPC file on disk.
IM will not automatically track your +write commands for you.
(More technical details: MPC as a disk file format is not portable.
It also isn't suitable as a long-term archive format.
Its only suitability is as an intermediate format for high-performance image processing.
It requires two files to support one image.
It is not guaranteed to be 'stable' in between ImageMagick releases.
It may not work on a different machine from the one where you created it.)
If you still want to save this format to disk, remember this:
Image attributes are written to a file with the extension .mpc.
Image pixels are written to a file with the extension .cache.
MPC's main advantages lay in...
...processing very large images, or when
...applying several operations on one and the same image in "operation pipelines".
MPC was designed especially for workflow patterns which match the criteria "read many times, write once".
MPR
The MPR format (memory persistent register) does something similar as MPC.
It makes the image available via a named memory register.
You can use whatever name you want (even numbers).
Your process pipeline can also read the image again from that register -- multiple times even, should it need to do so.
The image mpr:label persists in the register until the current command pipeline exits. (This is the difference to a to-disk-written mpc:filename. This persists the completion of the current pipeline; it even survives system reboots.)
Clever command pipeline
(My use of the word 'pipeline' here is not to be confused with the pipelines in a shell, where multiple commands and processes are started and chained.
Here I talk only about a single invocation of convert which chains multiple image manipulations and operations into one process.)
So it is possible to accomplish all resize, crop, append, thumbnailing, color-manipulating, blurring, ... what-have-you operations in one single process writing out the different intermediate outputs you require.
Practical example...
...hmm, I'm not so sure if it is soooo practical. I haven't tested it, I just used my phantasy to construct an example which shows the principles about the usage of the different concepts.
Note: +write someimage is the same as -write someimage +delete.
convert \
very-very-large.jpg \
-write mpr:XY \
+delete \
-respect-parentheses \
\( mpr:XY -crop '3000x2001+0+491' -resize '170x116!>' +write pic1.png \) \
\( mpr:XY -crop '2981x2883+8+0' -resize '75x75!>' +write pic2.png \) \
\( mpr:XY -crop '1100x1983+0+0' -resize '160x160!>' +write pic3.png \) \
\( mpr:XY -crop '2000x2883+0+0' -resize '1024x960!>' +write pic4.png \) \
\( mpr:XY -crop '1000x2883+0+0' -resize '190x188!>' +write mpr:pic5 \) \
\( mpr:pic5 +write pic5.png \) \
\( mpr:XY -crop '3000x2000+0+0' -resize '2048x2047!>' +write pic6.png \) \
\( mpr:XY -crop '3000x2883+0+0' -resize '595x421!>' +write pic7.png \) \
\( mpr:XY -crop '3000x2883+0+0' -resize '3000x2883!>' +write mpr:AB \) \
\( mpr:AB +write pic8.tiff \) \
\( mpr:AB -blur 0x8 +write blur1.gif \) \
\( mpr:pic5 mpr:AB +append mpr:pic5 -append +write append.jpg \) \
\( mpr:pic5 -rotate -130 mpr:AB -gravity center \
-compose difference -composite +write final.png \) \
null:
After the first operation, -write mpr:XY, there are two images in the stack:
the input file, very-very-large.png, and
a copy of it which can be read from memory using its label XY.
We do not need the first of these two any more.
Hence we use +delete to remove it from the stack.
So this command used one single command pipeline which carried out multiple commands and manipulations creating 11 different output images in one go:
pic{1,2,3,4,5,6,7}.png, blur1.gif, pic8.tiff, append.jpg and final.png.

Quick'n'dirty answer: Insert a +repage into your first single command:
convert test.jpg \
-crop 223x187+588+757 \
-rotate 330 \
+repage \
-crop 200x100+43+87 \
crop3.jpg
Long and comprehensive answer: Will follow later. I have to complete another task first. The long answer will give you a more generic approach, how you can crop multiple sections in one single command, while keeping up performance.

Related

ImageMagick: Split image into two with 55% of original image each

I want to split some images by percentage using ImageMagick.
To be more precise, I want to split an image into two images. The output-image of the left side should be 55% of the left side of the original image, the output-image of the right side should be 55% of the right ride of the original image.
(In case I am not making myself clear: The point is that there is sometimes important information in the middle of the images and this information would be cut off if we split the images exactly in the middle.)
What I have so far is this: mogrify -crop 55%x100% +repage -path ./cropped *.jpg
So at the moment, I am splitting the image into two and saving it in the "cropped"-folder. BUT, only the left side is 55% of the left side of the original image, the right side is 45% of the right side of the original image.
As this is my first time working with ImageMagick, I would really appreciate your help!
Here is another approach to splitting an image to create two output images that are 55% from the left and 55% from the right of the original...
convert input.png -set filename:0 "%[t]" \
\( +clone -roll +55+0% \) -extent 55x100% "%[filename:0]_%d.png"
That starts by setting a file name variable to use for the output. Then it makes a clone of the input image, and rolls it 55% to the right. The result is moving the rightmost 55% of the image out of the frame to the right and back into the frame on the left. Then after the parentheses a simple -extent operation keeps the leftmost 55% of each image. The output files are named from the input file with a "_0" or "_1" added.
As fmw42 suggested, you can make a loop command to run on multiple inputs, and include the path names in the command for your output files.
I think you would have to run a script loop over each image and use convert rather than mogrify. Mogrify can only output one image for each input image. You do not say what platform/OS or what version of ImageMagick. The following assumes Unix-like system with IM 6 and is one way to do that.
infile="original_file.suffix"
convert "$infile" -set filename:fname "%t" -write mpr:img +delete \
\( mpr:img -gravity west -crop 55x100%+0+0 +repage +write "path_to/cropped/%[filename]_0.suffix" \) \
\( mpr:img -gravity east -crop 55x100%+0+0 +repage +write "path_to/cropped/%[filename]_1.suffix" \) \
null:
Or, you could just run mogrify twice. Once for the left side and once for the right side. Use -gravity to control which as in the convert command.

Combined Multiple Commands in Imagemagick

I'n very new to imagemagick and i need to learn how could i combined these two commands to make it work.
I need to add background image to a transparent image. I tried to combine these two commands but was not successful.
magick mogrify -path Output_Path -trim -filter Triangle -define filter:support=2 -thumbnail 450x450 -gravity center -extent 500x500 -unsharp 0.25x0.25+8+0.065 -dither None -posterize 136 -quality 82 -define jpeg:fancy-upsampling=off -define png:compression-filter=5 -define png:compression-level=9 -define png:compression-strategy=1 -define png:exclude-chunk=all -interlace none -colorspace sRGB -strip Transparent_Image_Path
magick Background_Image.png Transparent_Image.png -composite output.jpg
Result Should Be Like This :
Image Reference
Thanks in advance!
There are several possible syntaxes, depending on how your brain likes to work ;-)
What you need to bear in mind when trying to understand this is that all processing operations, e.g. -crop or -resize apply to all loaded images. So, you either need to load images that need processing and process them before loading images you don't want affected, or you need to restrict processing to certain images only... using parenthesised "aside" operations.
You can proceed like this:
load transparent foreground image first and process it before loading the background image, then
load background image, then
exchange the order and composite
That looks like this:
magick FOREGROUND.PNG -resize ... -crop ... \
BACKGROUND.PNG \
+swap -composite RESULT.JPG
Alternatively, you could:
load the background image, then
load the foreground image and process it "aside" within parentheses so that the background image is not affected
composite
That looks like this:
magick BACKGROUND.PNG \
\( FOREGROUND.PNG -resize ... -crop ... \) \
-composite RESULT.JPG
If you need to independently process both background and foreground images prior to compositing, use:
magick \
\( BACKGROUND.PNG -resize ... -crop ... \) \
\( FOREGROUND.PNG -resize ... -crop ... \) \
-composite RESULT.JPG
Note that if you use Windows:
the backslashes at line-ends become carets (^) and may not have trailing spaces after them,
the backslashes preceding opening and closing parentheses must be omitted,
most single quotes probably need replacing with double quotes - probably not applicable to this specific question.
Note that your command is probably unnecessarily complicated, I would recommend omitting quite a lot of it and seeing how you get on. For example, all the define png:XXX=YYY settings are irrelevant if you aren't creating a PNG as output.
You can carry forward the JPEG-related parameters (quality, interlace, upsampling) and put them in anywhere you like, probably at the start like this, but put the colorspace and strip at the end to ensure both input files are stripped:
magick -quality 82 -define jpeg:fancy-upsampling=off \
BACKGROUND.PNG ... \
FOREGROUND.PNG ... \
-composite -colorspace sRGB -strip RESULT.JPG

Compose multiple regions of an image into a target

I'm trying to use ImageMagick to compose different pieces of a rendered PDF into a target. E.g., I want to have ImageMagick render the PDF at 300dpi, then create a 300x400 pixel output image, then take from the PDF the area 10x20+30+40 and place it in the target (300x400 pixel image) at 12,34. Then take another (and a third and fourth) chunk at different coordinates with different sizes and place them at different places.
I cannot seem to figure out how to do this in one go, and doing it in multiple runs always re-renders the PDF and takes awfully long. Is this even possible?
Here's an idea of how you can approach this. It uses the MPR or "Memory Program Register" that Fred suggested in the comments. It is basically a named chunk of memory that I write into at the start and which I recall later when I need it.
Here is a rather wonderful start image from the Prokudin-Gorskii collection:
The code resizes the image and saves a copy in the MPR. Then, takes a copy of the MPR, crops out a head, resizes it and composites the resized result onto the resized original at a different location and then repeats the process for another head.
magick Prokudin.png -resize 300x400\! -write MPR:orig \
\( MPR:orig -crop 50x50+180+84 -resize 140x140 \) -geometry +10+240 -compose src-over -composite \
\( MPR:orig -crop 40x40+154+184 \) -geometry +40+100 -compose src-over -composite \
result.png
If you have trouble understanding it, try running it with the second or third line omitted so it just does one head ;-)
Hopefully it covers all the aspects of your question and you can adapt it to your PDF.

How to pass Imagemagick montage output and image properties to the convert command without using any temporary files?

I have a set of images, and I can use the Imagemagick montage command on them to produce a montage image file with transparent background (let's call this fgimg). Now I have another existing image (let's call this bgimg) that I'd like to use (after some special processing with the convert command) as the background for fgimg, which can be achieved within the same convert command. At this point it seems trivial to avoid writing the temporary fgimg to disk, simply by piping the standard output of montage to the standard input of convert.
My problem is that the special processing I'm applying to bgimg will require some knowledge of the image properties of fgimg (e.g., resizing bgimg to have the same size as fgimg), which I don't know in advance. How can this information be retrieved and used in the convert command?
Note: I'm using Imagemagick version 6.9.7-4 on Linux.
I'll include some commands below to further illustrate the problem in detail.
The following command produces the montage image fgimg from a set of input images. The output is in the 'special' miff format (which seems best for temporary output to be worked on later), and has transparent background so that the actual background can be applied later. Most of the other options here are not important, but the point is that the output size (dimensions) cannot be determined in advance.
montage input_*.jpg -tile 5x -border 2 -geometry '200x200>+20+20' \
-gravity center -set label '%f\n%G' -background none -fill white \
-title 'Sample Title' miff:fgimg
Next, I have another input image bgimg.jpg. I want to perform some processing on it before using it as background to fgimg. The processing can be quite complex in general, but in this example, I want to:
resize bgimg.jpg to fit inside the dimensions of fgimg without any cropping;
apply a fade-to-black effect around the edges;
make it the same size as fgimg, with a black background;
combine this with fgimg to produce the final output.
Notice that I need the size of fgimg in two places. I can first extract this into a shell variable:
size=$(identify -format '%G' miff:fgimg)
Then I can do all the steps above in one convert command (note that $size is used twice):
convert "bgimg.jpg[$size]" -gravity center \
\( +clone -fill white -colorize 100% -bordercolor black \
-shave 20 -border 20 -blur 0x20 \) -compose multiply -composite \
-background black -compose copy -extent $size \
miff:fgimg -compose over -composite final_out.jpg
Now here is the problem: I want to avoid writing the temporary file fgimg to disk.
I could replace miff:fgimg with miff:- in both the montage and convert commands and then just pipe one to the other: montage ... | convert .... But how do I deal with the $size?
I tried to use file descriptors (miff:fd:3) but this does not seem to work, which is confirmed by the comments to this question.
Is there a way to do this (in Imagemagick v6) without creating a temporary file?
This example command uses ImageMagick v6 on a bash shell. Instead of "montage" it starts by using "convert" to create a "logo:", one of IM's built-in sample images, then pipes it out as a MIFF and into the "convert" command that follows. You can pipe the output of "montage" just as easily. And it uses another IM built-in image "rose:" as your "bgimg.jpg"...
convert logo: miff:- | convert - rose: \
+distort SRT "%[fx:t?min(u.w/v.w,u.h/v.h):1] 0" \
-shave 1 +repage -gravity center -bordercolor black \
\( -clone 1 -fill white -colorize 100 -shave 6 -border 6 \
-blur 0x6 -clone 1 -compose multiply -composite \) -delete 1 \
\( -clone 0 -alpha off -fill black -colorize 100 \
-clone 1 -compose over -composite \) -delete 1 \
+swap -composite final_out.jpg
That reads the piped image "-" and the background image "rose:".
Then it uses "+distort" with an FX expression to scale "rose:" to the maximum dimensions that still fit within the original piped input image. That operation adds a pixel all around so we use "-shave 1" to get rid of that.
Next inside parentheses it clones that re-scaled background image, makes an edge blur mask, and composites them to make the fade-to-black edge on the background image. Right after the parentheses it deletes the non-edged background image.
In the next parentheses it clones the input image, makes it black, clones the modified background image, and composites it centered over the black one. Again the non-extended background image is discarded after the parentheses with "-delete 1".
Finally the modified background and the input image are put in the proper order with "+swap" and composited for the final output. Run this command without the last "-composite" to see the two images that result from the prior parts of the command.
Both the main input image and background image can be any size, any dimensions, and any aspect ratio. This works for me on v6.8.9 on a bash shell. It should work on any ImageMagick newer. It should work on Windows by removing all the backslashes that escape parentheses and changing the continued-line backslashes "\" to carets "^".
EDITED TO ADD:
You can use that FX expression to find the scaling amount, save it as a variable, then isolate the background image inside parentheses and use that variable to do the scaling and shaving there. That way it only affects the background image. There may be a rounding error with that, but the main image, which determines the exact final output dimensions, will be unaffected. Note the difference in the first few lines of this command...
convert logo: miff:- | convert - rose: \
-set option:v1 "%[fx:min(u.w/v.w,u.h/v.h)]" \
\( -clone 1 +distort SRT "%[v1] 0" -shave 1 \) -delete 1 \
+repage -gravity center -bordercolor black \
\( -clone 1 -fill white -colorize 100 -shave 6 -border 6 \
-blur 0x6 -clone 1 -compose multiply -composite \) -delete 1 \
\( -clone 0 -alpha off -fill black -colorize 100 \
-clone 1 -compose over -composite \) -delete 1 \
+swap final_out.jpg

How to get the result of an ImageMagick convert command as bitmap data

I am working on a project that will make a jigsaw puzzle from an image and present it to the user as separate pieces in a browser. I have done all the prototyping in Python. At the moment I can produce separate images for each puzzle piece.
As a last step I want to make a nice bevel on the pieces to make them look realistic. I found a ImageMagick convert command to do that just fine:
convert piece.png -alpha extract -blur 0x2 -shade 120x30 piece.png -compose Overlay -composite piece.png -alpha on -compose Dst_In -composite result.png
I execute the command by using os.system, but this is taking way too long to complete.
Can you give me an advice on a solution to execute the ImageMagick processing in the fastest way? I think that would involve executing the processing directly with the ImageMagick libraries, sending it the input bitmap data and receiving the result also as bitmap data. Then I can stream the result to user. The solution does not have to be Python.
Update
I have just been looking at your command again - I kind of assumed it was sensible as you implied you got it from Anthony Thyssen's excellent ImageMagick Usage pages - however I see you are reading the image piece.png three times which it must be possible to avoid by using -clone or -write MPR:save. Let me experiment some more. I haven't got your jigsaw piece to test with, so I am in the dark here, but you must be able to change your command to something like this:
convert piece.png -write mpr:piece \
\( +clone -alpha extract -blur 0x2 -shade 120x30 \) \
-compose Overlay -composite \
mpr:piece -alpha on -compose Dst_In -composite result.png
MPR is a Memory Program Register, or basically a named lump of RAM that ImageMagick can read and write to. There are details and examples here.
Original Answer
Three things spring to mind... which one, or which combination of things, will help depends on the specification of your CPU, memory and disks as well as the sizes of your pieces - none of which I know or can test,
Firstly, if you used the libraries, you would avoid the overhead of creating a new process to run the convert - so that should help, but if your pieces are large and the bottleneck is actually the processing, using the libraries will make little difference.
Secondly, if your images are large, the time to read them in off disk and write them back to disk may be what is killing your performance. To test this, I would create a small RAMdisk and store the images on there and see if that helps. It is a quick and relatively easy test.
Thirdly, I assume you are generating many pieces and you currently do them one after the other in a sequential fashion. If this is the case, I would definitely recommend going multi-threaded. Either do this in your code with your language's threading environment, or try out GNU Parallel which has always been brilliant for me. So, if you were going to do
convert piece1.png -alpha extract ... -composite result1.png
convert piece2.png -alpha extract ... -composite result2.png
convert piece3.png -alpha extract ... -composite result3.png
...
convert piece1000.png -alpha extract ... -composite result1000.png
just either send all those commands to GNU Parallel on its stdin and it will execute them all in parallel on as many cores as your CPU has like this
(
echo convert piece1.png ... -composite result1.png
echo convert piece2.png ... -composite result2.png
echo convert piece3.png ... -composite result3.png
) | parallel
or build the command like this
parallel convert {} -alpha ..... result-{} ::: piece*.png

Resources