可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
With imagemagick, I'd like to crop an image, in a minimal fashion, so that it fits a given aspect ratio.
Example: given an image of, say, 3038 x 2014 px, I want to crop it to have a 3:2 aspect ratio. The resulting image would then be 3021 x 2014 px, cropped from the, say, center of the original image.
So looking for a command looking something like convert in.jpg -gravity center -crop_to_aspect_ratio 3:2 out.jpg
.
回答1:
1. Specific target resolution
If your goal at the end is to have a certain resolution (for example 1920x1080) then it's easy, using -geometry
, the circumflex/hat/roof/house symbol (^
) and -crop
:
convert in.jpg -geometry 1920x1080^ -gravity center -crop 1920x1080+0+0 out.jpg
To loop over multiple jpg files:
for i in *jpg
do convert "$i" -geometry 1920x1080^ -gravity center -crop 1920x1080+0+0 out-"$i"
done
2. Aspect ratio crop only
If you want to avoid scaling you have to calculate the new length of the cropped side outside of Imagemagick. This is more involved:
aw=16 #desired aspect ratio width...
ah=9 #and height
in="in.jpg"
out="out.jpg"
wid=`convert "$in" -format "%[w]" info:`
hei=`convert "$in" -format "%[h]" info:`
tarar=`echo $aw/$ah | bc -l`
imgar=`convert "$in" -format "%[fx:w/h]" info:`
if (( $(bc <<< "$tarar > $imgar") ))
then
nhei=`echo $wid/$tarar | bc`
convert "$in" -gravity center -crop ${wid}x${nhei}+0+0 "$out"
elif (( $(bc <<< "$tarar < $imgar") ))
then
nwid=`echo $hei*$tarar | bc`
convert "$in" -gravity center -crop ${nwid}x${hei}+0+0 "$out"
else
cp "$in" "$out"
fi
I'm using 16:9 in the examples, expecting it to be more useful than 3:2 to most readers. Change both occurences of 1920x1080
in solution 1 or the aw
/ah
variables in solution 2 to get your desired aspect ratio.
回答2:
Recent versions of Imagemagick (since 6.9.9-34) have an aspect crop. So you can do:
Input:
convert barn.jpg -gravity center -crop 3:2 +repage barn_crop_3to2.png
The output is 400x267+0+0. But note that the +repage is needed to remove the virtual canvas of 400x299+0+16, because PNG output supports virtual canvas. JPG output would not need the +repage, since it does not support a virtual canvas.
回答3:
With the advent of ImageMagick 7 you can use FX expressions to accomplish a crop to the largest image size possible given an aspect ratio in a single command.
The only trick is you're going to need to enter the desired aspect in four different places on the same command so I find it easiest to make a variable for that bit. The aspect can be a decimal number or a fraction as a string that the fx expression can resolve.
aspect="16/9"
magick input.png -gravity center \
-extent "%[fx:w/h>=$aspect?h*$aspect:w]x" \
-extent "x%[fx:w/h<=$aspect?w/$aspect:h]" \
output.png
Once the aspect is right, you can follow up the two -extent
operations with a -resize
to bring the finished image to your output size. The example above keeps it as large as it can be given the input image.
回答4:
You need to work out the reqired dimensions and then do a crop. Here's a function that, given the image's width
and height
plus the required aspect ratio as aspect_x
and aspect_y
, will output a crop string that can be used with Imagemagick.
def aspect(width, height, aspect_x, aspect_y)
old_ratio = width.to_f / height
new_ratio = aspect_x.to_f / aspect_y
return if old_ratio == new_ratio
if new_ratio > old_ratio
height = (width / new_ratio).to_i # same width, shorter height
else
width = (height * new_ratio).to_i # shorter width, same height
end
"#{width}x#{height}#" # the hash mark gives centre-gravity
end
I'm using something similar to this in an application that uses the Dragonfly Gem.
回答5:
I needed to split very long images vertically with A4 (1x1.414) paper aspect ratio. So I came up with below solution. Assume image filename is ch1.jpg:
convert -crop $(identify -format "%w" ch1.jpg)x$(printf "%.0f" $(echo $(identify -format "%w" ch1.jpg) \* 1.414|bc)) +repage ch1.jpg ch1.jpg