Image::Magick (perlmagick) изменение размера, соотношение сторон и проблемы с качеством (отличаются от утилиты командной строки convert)
Я пытаюсь выполнить некоторые операции масштабирования изображений с помощью ImageMagick и perlmagick (Image::Magick). Все изображения, которые у меня есть в качестве источников, являются большими изображениями, и я хочу изменить их размеры до различных интервалов, либо по высоте, либо по ширине. Я хочу всегда сохранять пропорции.
Учитывая пример изображения с размерами 3840 пикселей × 2160 пикселей (3840x2160), я хочу создать следующие изображения с измененным размером:
?x1000
?x500
?x100
1600x?
1200x?
800x?
400x?
Я могу сделать это очень просто, используя утилиту командной строки convert со следующими командами (по порядку):
convert input_filename.jpg -resize x1000 output_wx1000.jpg
convert input_filename.jpg -resize x500 output_wx500.jpg
convert input_filename.jpg -resize x100 output_wx100.jpg
convert input_filename.jpg -resize 1600 output_1600xh.jpg
convert input_filename.jpg -resize 1200 output_1200xh.jpg
convert input_filename.jpg -resize 800 output_800xh.jpg
convert input_filename.jpg -resize 400 output_400xh.jpg
Так как я пытаюсь выполнить эти операции массово в сочетании с другими операциями, я пытаюсь выполнить те же самые операции в perl, используя Image:: Magick. Я пробовал несколько разных методов со следующими результатами:
#METHOD 1
my $image = Image::Magick->new();
$image->Read($input_filename);
$image->Resize(
($width ? ('width' => $width) : ()),
($height ? ('height' => $height) : ()),
);
$image->Write(filename => $output_filename);
Это приводит к изображениям, которые не поддерживают соотношение сторон. Например, если указана высота 100, выходное изображение будет иметь оригинальную ширину на 100 (3840x100). Аналогичный эффект достигается при подаче ширины - высота сохраняется, а соотношение сторон - нет.
#METHOD 2
my $image = Image::Magick->new();
$image->Read($input_filename);
die "Only one dimension can be supplied" if $width && $height;
$image->Resize(geometry => $width) if $width;
$image->Resize(geometry => "x$height") if $height;
$image->Write(filename => $output_filename);
Это приводит к изображениям, которые поддерживают соотношение сторон, и, если геометрическая операция основана на высоте, результат будет именно тем, что и предполагался. Тем не менее, если указана ширина, результат будет очень размытым.
#METHOD 3
`convert "$input_filename" -resize $width "$output_filename"` if $width;
`convert "$input_filename" -resize x$height "$output_filename"` if $height;
Это приводит к изображениям, которые все правильные, но разветвляются за пределы процесса perl, что приводит к проблемам эффективности.
Есть ли лучший способ в perl, чтобы эта операция изменения размера производила те же результаты, что и утилита преобразования командной строки?
Моя утилита командной строки сообщает о версии 6.7.9-10, а Image:: Magick сообщает о версии 6.79.
2 ответа
Ваш метод № 2 находится на правильном пути. Чтобы сохранить соотношение сторон, укажите ширину и высоту через geometry
ключевое слово. Вашу процедуру можно сделать более общей, выполнив изменение размера за один вызов вместо двух:
$image->Resize(geometry => "${width}x${height}");
Это гарантирует, что Resize будет вызываться только один раз, даже если вы указали $ width и $ height. Просто убедитесь, что если какое-либо значение не указано, вы устанавливаете его в пустую строку. Если вы указали ширину и высоту для вашей процедуры в методе № 2, это могло быть причиной размытости, которую вы видели.
Другим возможным источником размытия является фильтр, используемый оператором изменения размера. Лучший фильтр для данной операции зависит как от цветовых характеристик изображения, так и от соотношения между исходными размерами и целевыми размерами. Я рекомендую ознакомиться с http://www.imagemagick.org/script/command-line-options.php для получения информации об этом. В PerlMagick вы можете указать фильтр для изменения размера для использования через filter
ключевое слово.
Тем не менее, я не нашел особых проблем с размытостью изображений, которые я пробовал, поэтому, если проблема не исчезнет, тестовое изображение будет наиболее полезным.
Возможно, я немного опоздал на эту вечеринку, но поскольку у меня была очень похожая цель - изменение размера изображения и поддержание баланса между качеством изображения и объемом дискового пространства, которое оно занимает, - я придумал следующий код. Я начал с кода OPs и следил за этой очень интересной статьей: https://www.smashingmagazine.com/2015/06/efficient-image-resizing-with-imagemagick/
Вот результат:
sub optimize_image_size
{
my $imagePath = shift();
my $height = shift(); #720
my $width = shift(); #1080
my $image = Image::Magick->new();
$image->Read($imagePath);
die "Only one dimension can be supplied" if $width && $height;
$image->Thumbnail(geometry => "$width",filter=>'Triangle') if $width;
$image->Thumbnail(geometry => "x$height",filter=>'Triangle') if $height;
$image->Colorspace(colorspace=>'sRGB');
$image->Posterize(levels=>136, dither=>'false');
$image->UnsharpMask(radius=>0.25, sigma=>0.25, threshold=>0.065, gain=>8);
$image->Write(filename => $imagePath
, quality=>'82'
, interlace=>'None'
);
}
По крайней мере, для меня это дает очень удовлетворительное уменьшение размера (мои образцы изображений с 6 МБ были уменьшены до примерно 90 КБ), сохраняя при этом качество, аналогичное настройкам Photoshops "для Интернета", и, конечно, сохраняя соотношение сторон независимо от того, указываете ли вы ширину или высоту.
Слишком поздно для OP, но, возможно, это поможет другим людям.