ImageMagick: как минимально обрезать изображение с определенным соотношением сторон?

С imagemagick я хотел бы обрезать изображение минимальным образом, чтобы он соответствовал данному соотношению сторон.

Пример: с учетом изображения, скажем, 3038 x 2014 px, я хочу обрезать его с соотношением сторон 3: 2. Тогда получившееся изображение будет 3021 x 2014 px, обрезанное из, скажем, центра исходного изображения.

Итак, ища команду, выглядящую как-то вроде convert in.jpg -gravity center -crop_to_aspect_ratio 3:2 out.jpg.

Ответы

Ответ 1

1. Конкретное разрешение цели

Если ваша цель в конце должна иметь определенное разрешение (например, 1920x1080), то легко, используя -geometry, символ circumflex/hat/roof/house (^) и -crop:

convert in.jpg -geometry 1920x1080^ -gravity center -crop 1920x1080+0+0 out.jpg

Чтобы перебрать несколько файлов jpg:

for i in *jpg
  do convert "$i" -geometry 1920x1080^ -gravity center -crop 1920x1080+0+0 out-"$i"
done

2. Только для формата изображения

Если вы хотите избежать масштабирования, вам нужно вычислить новую длину обрезанной стороны вне Imagemagick. Это более важно:

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

Я использую 16: 9 в примерах, ожидая, что он будет более полезен, чем 3: 2, для большинства читателей. Измените оба входа 1920x1080 в решении 1 или переменные aw/ah в решении 2, чтобы получить желаемое соотношение сторон.

Ответ 2

С появлением ImageMagick 7 вы можете использовать выражения FX для достижения урожая с максимальным размером изображения, которое возможно с учетом соотношения сторон в одной команде.

Единственный трюк - вам нужно будет ввести желаемый аспект в четырех разных местах по одной и той же команде, поэтому мне легче всего сделать переменную для этого бита. Аспект может быть десятичным числом или дробью в виде строки, которую может разрешить выражение fx.

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

Как только аспект прав, вы можете выполнить две операции -extent с помощью -resize, чтобы довести готовое изображение до вашего размера вывода. Приведенный выше пример сохраняет его как можно больше, поскольку ему может быть предоставлено входное изображение.

Ответ 3

Вам нужно выработать необходимые размеры, а затем сделать урожай. Здесь функция, которая при изображении width и height плюс требуемое соотношение сторон как aspect_x и aspect_y, выведет строку обрезки, которая может использоваться с 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

Я использую нечто похожее на это в приложении, использующем Dragonfly Gem.