How to resize overlay image by ratio and with relative position it from the right? - imagemagick

Let's start with a background and an overlay image:
magick convert -size 500x500! xc:red background.jpg # make a big red background
magick convert -size 100x100! xc:blue overlay.jpg # make a smaller blue overlay
To composite from right side I can use
$geom=magick convert overlay.jpg -print "+%[fx:w+50]+0" null:
magick convert background.jpg overlay.jpg -gravity northeast -geometry $geom -composite output.jpg
However, in my real project, I need to run this with various background images, whose sizes are also various. I would like the overlay to use relative size to the background instead of absolute size.
To overlaying a watermark/logo with relative dimentions, I can use:
magick background.jpg overlay.jpg -resize %[fx:t?u.w*0.9:u.w]x%[fx:t?u.h*0.9:u.h] -gravity northease -composite output.jpg
To resize overlay image by ratio and with relative position it from the right, I try:
magick background.jpg overlay.jpg -resize %[fx:t?u.w*0.1:u.w]x%[fx:t?u.h*0.1:u.h] -gravity northeast -geometry +[fx:t?u.w*0.1:u.w]+[fx:t?u.h*0.1:u.h] -composite output.jpg
But it says:
magick.exe: invalid argument for option '-geometry' '+[fx:t?u.w*0.1:u.w]+[fx:t?u.h*0.1:u.h]' at CLI arg 7 # error/operation.c/CLISimpleOperatorImage/2522.
The documentation for geometry doesn't seem to talk about this. Do you know why?
I'm using v7 on Windows

I miss the %. Correct code:
magick .\base.jpg .\logo.png -resize %[fx:t?u.w*0.1:u.w]x%[fx:t?u.h*0.1:u.h] -gravity northeast -geometry +%[fx:t?u.w*0.03:u.w]+%[fx:t?u.w*0.03:u.w] -composite output.png
See Format and Print Image Properties
The reasoning behind the %[fx:t?u.w*0.9:u.w]
From The FX Special Effects Image Operator:
u: first image in list
v: second image in list
t: index of current image (s) in list
w: width of this image
So in plain language, it means that if the image in question is the second image, whose index is one, of which the ternary conditional operator also read as true, then resize it to 90% width of the first image, else do no resize. Or else -resize option will apply to each images in an image sequence (i.e. all input images before it, but not after it).

Related

Can I refer to the image width and height in an argument?

I want to convert multiple images into square format, filling any empty space with black. Assuming the images have a width of 1000 and a height of less than 1000 (or vice versa), I can do it like this (using PowerShell):
magick.exe convert -background black -gravity center `
-resize 1000x1000 -extent 1000x1000 `
-set filename:original '%t' '.\*.jpg' './%[filename:original]-resized.jpg'
However, I want this to work for arbitrarily sized images. I need to do something like this, which is not an actually supported syntax:
#...
-resize 'max(%w,%h)xmax(%w,%h)' -extent 'max(%w,%h)xmax(%w,%h)' `
# ...
Is there an Imagemagick syntax for what I'm trying to do?
In Imagemagick 7, use magick, not magick convert and move the input parameter to the first parameter position, i.e. magick '.\*.jpg'.
Then, to do what you want change
-resize 'max(%w,%h)xmax(%w,%h)' -extent 'max(%w,%h)xmax(%w,%h)'
to
-resize "%[fx:max(w,h)]x%[fx:max(w,h)]" -extent "%[fx:max(w,h)]x%[fx:max(w,h)]"

imagemagick trim but keep canvas size and *position*

Friends,
I need to -trim some images but keep the original canvas size. Works like this:
convert in.png -fuzz 10% -trim -background white -set page "%[fx:w]x%[fx:h]" +repage out.png
But how can I position the trimmed image part at it's original position? -gravitiy center is not an option as the to-be-trimmed part usually not at the canvas center.
Any ideas?
You should be able to -trim an image, then use -flatten to lay it back onto its original canvas. Try this command...
convert logo: -background none -trim -flatten trimmed.png
#GeeMack's answer is certainly simpler and more succinct, but if you need more flexibility for dinking around, another way is to get the image height and width and the trimbox in one invocation and use them in the next - maybe with adaptation.
So, starting with this image:
# Get image width and height and the trim-box
read geom trim < <(magick start.png -format "%G %#" info:)
# Make a new white canvas same size as original and trim new image onto it
magick -size $geom xc:white \( start.png -crop $trim \) -flatten result.png
I put an artificial yellow border around it so you can see the extent of it on SO's white background.

How to split an image with a grid and preserve transparency bounding box

I have some png images that I want to split it into parts, like by grid or size.
But each part should have the same bounding box (transparency) as original image.
Example:
Splitting image into 2 parts.
Original: 200 × 89
Output:
part_1.png, 200 × 89
part_2.png, 200 × 89
Can ImageMagick do this? Or any other app or method.
My actual goal is to split into 100+ slices images.
EDIT:
Another goal to have an indents for each slice. Say indent = 10px.
Example:
Input: 200 x 100
Output:
part_1.png, 200 x 100
part_2.png, 200 x 100
And just as example, to visually compare input and output: combined output images in Photoshop as layer added one onto another
200 x 100 :
Also this is showing input image added onto combined(so it's better to see what was cropped and how):
In ImageMagick, you can split an image into many parts with the -crop command. For your example above with two parts, you can do that with the following commands. ImageMagick will append -0, -1 ... to the output file names.
ImageMagick 6:
dim=`convert image.png -format "%wx%h" info:`
convert \( -size $dim xc:none \) null: \( image.png -crop 50x100% \) -layers composite result.png
ImageMagick 7:
magick \( image.png -set option:dim "%wx%h" -crop 50x100% \) null: \( -size "%[dim]" xc:none \) -reverse -layers composite result.png
The results are:
See
http://www.imagemagick.org/Usage/crop/#crop
http://www.imagemagick.org/Usage/crop/#crop_percent
http://www.imagemagick.org/Usage/crop/#crop_tile
http://www.imagemagick.org/Usage/crop/#crop_quad
http://www.imagemagick.org/Usage/crop/#crop_equal
http://www.imagemagick.org/script/command-line-options.php#layers
Note that -crop keeps the virtual canvas information if you do not add +repage afterwards. So to put the individual images back into their original placement, you have to composite them onto a transparent background the size of the input. That is done in one command using -layers composite using the null: separator.
Here is another way to add transparent areas between parts of a crop in ImageMagick. Crop the image into pieces, chop off the parts you want to remove, then pipe to montage to add the spacing back.
Input:
Here I make this into a 4x4 grid of images with 10 pixel spacing:
convert lena.png -crop 25%x25% +repage -gravity east -chop 10x0 -gravity south -chop 0x10 +repage miff:- | montage - -background none -tile 4x4 -geometry +5+5 result.png
To answer your new question, you can do that with a script loop. On a Unix-like platform, assuming your images do not have spaces, you can do the following:
cd path/to/current_folder
list=`ls *.png`
for img in $list; do
name=`convert $img -format "%t" info:`
dim=`convert $img -format "%wx%h" info:`
convert \( -size $dim xc:none \) null: \( $img -crop 50x100% \) -layers composite -scene 1 path/to/new_folder/${name}_%d.png
done
If you want leading 0s in the output, say 3, use path/to/new_folder/${name}_%03d.png.
Note that to start with 1 rather than 0, I have added -scene 1.
Sorry, I do not know how to script for Windows.
Please always provide your ImageMagick version and platform.
In ImageMagick, the best way to put transparent areas into your image is with a binary mask that is put into the alpha channel of your image.
convert input.png \( -size 200x89 xc:white -size 10x89 xc:black -gravity center -composite \) -alpha off -compose copy_opacity -composite result.png
You can add as many blank areas as you want by adding more white areas to the mask or by tiling out one region of black and one region of white to create the mask with regular spacing of black and white.
Edited to add this ImageMagick 6 example which splits the input image into 4 pieces, 25% of the original width and 100% of its height, then creates a transparent canvas for each piece the same dimensions of the input image, and locates the pieces at their original offsets on those canvases.
convert input.png -set option:distort:viewport %[w]x%[h] -crop 25x100% \
-virtual-pixel none -distort affine "0,0 %[fx:s.page.x],%[fx:s.page.y]" out%03d.png
The output file names will be numbered starting from zero like "out000.png", etc.
Original message...
Here's a simple command using ImageMagick 7 that can crop an image into any number of pieces, and output all the pieces at their original offsets on transparent backgrounds of the original input dimensions...
magick input.png -crop 100x1# -background none \
-extent "%[fx:s.page.width]x%[fx:s.page.height]-%[fx:s.page.x]-%[fx:s.page.y]" out%03d.png
That "-crop 100x1#" tells it to split the image into a grid 100 pieces wide by 1 piece high. You could just as well specify the crop sizes as percents or numbers of pixels.
Edited again to add:
This following command will split the input image into the individual pieces specified with the "-crop" operator, then shave 5 pixels from every side of each piece, then apply a 5 pixel transparent border to every side of each piece. It will still remember the original locations of the pieces within the input canvas, so the "-distort affine ..." can extend the canvases and place the pieces where they were in the input image.
convert input.png -set option:distort:viewport %[w]x%[h] \
-bordercolor none -background none -virtual-pixel none \
-crop 25x100% -shave 5x5 -border 5x5 \
-distort affine "0,0 %[fx:s.page.x],%[fx:s.page.y]" out%03d.png
To use this command with IM7 you need to change "convert" to "magick".
Given the changes of requirements provided by Kamikaze, here is one way to achieve the split with indent in ImageMagick, assuming I understand correctly.
dim=`convert image.png -format "%wx%h" info:`
convert \( -size $dim xc:none \) null: \( image.png -crop 50x100% -shave 5x5 \) -geometry +5+5 -layers composite result.png
To check, I flatten over a blue background:
convert result-0.png result-1.png -background blue -flatten result.png

Imagemagick crop transparent image to mask

So here is my original image (note the transparent border) src.png:
Here's the mask I want to use to crop. White means keep, black means crop mask.png: (Note that it isn't necessarily going to be a square. It could be a heart or a star or anything)
I also have transparent.png, which is a fully transparent image. All three images have the same dimensions.
So, running this command generates the following image:
convert transparent.png src.png mask.png -composite out.png
Which is masking perfectly, but now I want it cropped to the size of the white mask area. Using -trim is sort of close, but it gets rid of the transparent areas that are inside the mask.
How can I resize the masked image to the size of the white area in the mask?
I am not sure I understand what you want for the result. Why do you need the fully transparent image? Do either of these do what you want?
Full sized transparent image with masked area showing:
convert src.png mask.png -alpha off -compose copy_opacity -composite result1.png
Trimmed to just the part you want:
convert src.png mask.png -alpha off -compose copy_opacity -composite -trim +repage result2.png
Not sure I understand what you are trying to do, not least why you need a full size transparent canvas. Your command does not give the same results on my ImageMagick version 7.
This command may be what you are looking for:
convert src.png mask.png -compose darken -composite -trim out.png
It gives this - I have artificially added a red border so you can see the full extent on StackOverflow's white background:
Or maybe you want the trim box from your mask and to use that to crop your source:
convert mask.png -format %# info:
113x113+570+33
convert src.png -crop 113x113+570+33 result.png
If you want to crop a square from picture, you no needs using mask, just crop it:
magick Uq328.png -crop -crop 111x111+570+331 +repage cropped.png
according to https://legacy.imagemagick.org/Usage/crop/

ImageMagick: Layering Images with convert -composite with gravity center

background
overlay
composite -gravity center overlay.png background.jpg result1.jpg
result1.jpg
convert -composite background.jpg overlay.png -gravity center result2.jpg
result2.jpg
convert -composite background.jpg -gravity center tool_marker.png result3.jpg
result3.jpg
How can I achieve the results from result1 while using convert as the executable rather than composite?
Thanks!
You can start by using the operators in the right order. That is set the 'settings' first.
"Composite" command is 'read all settings then apply ONE operation, type of command (traditional UNIX)
"Convert" is a 'do options as you see them', with MULTIPLE operations possible. (script-like command)
convert background.jpg tool_marker.png -geometry +50+50 -composite result4.jpg
Note the +50+50 is the location of the top-left corner of the 'tool_marker.png" image. You will need to subtract the 'pin-point' location in that image to get it to pin point in the right location.
Gravity Center (if given BEFORE the -composite operation that uses it), aligns the center of BOTH images.
convert background.jpg tool_marker.png -gravity center -composite result4.jpg

Resources