Reputation: 21
I am attempting to do some bulk resizing operations of images using ImageMagick and perlmagick (Image::Magick). All of the images I have as sources are large images and I want to resize them down to various intervals or either height or width. I want to always preserve the aspect ratio.
Given an example image with dimensions of 3840 pixels × 2160 pixels (3840x2160) I want to create the following resized images:
?x1000
?x500
?x100
1600x?
1200x?
800x?
400x?
I can do this very simply using the convert command line utility with the following commands (in order):
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
Since I am attempting to perform these operations in bulk in conjunction with other operations I am attempting to perform these same operations in perl using Image::Magick. I have tried several different methods with the following results:
#METHOD 1
my $image = Image::Magick->new();
$image->Read($input_filename);
$image->Resize(
($width ? ('width' => $width) : ()),
($height ? ('height' => $height) : ()),
);
$image->Write(filename => $output_filename);
This results in images that do not maintain aspect ratio. For example, if a height of 100 is supplied, the output image will be the original width by 100 (3840x100). A comparable effect is had when supplying a width -- the height is maintained, but the aspect ratio is not.
#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);
This results in images that maintain aspect ratio, and if the geometry operation is based on height, the output is exactly what is intended. However, if a width is supplied the output is terribly blurry.
#METHOD 3
`convert "$input_filename" -resize $width "$output_filename"` if $width;
`convert "$input_filename" -resize x$height "$output_filename"` if $height;
This results in images that are all correct, but forks outside of the perl process leading to efficiency issues.
Is there a better way in perl to make this resize operation produce the same results as the command-line convert utility?
My command line utility reports version 6.7.9-10, and Image::Magick reports version 6.79.
Upvotes: 2
Views: 5343
Reputation: 135
I might be a little late to this party, but as I had a very similar goal - resizing an image and maintaining a balance between image quality and the amount of disc space it takes up - I came up with the following code. I started out with OPs code and followed this very interesting article: https://www.smashingmagazine.com/2015/06/efficient-image-resizing-with-imagemagick/
This is the result:
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'
);
}
At least for me it produces very satisfactory size reduction (my 6MB sample images were reduced to about 90Kb), while keeping a quality similar to Photoshops "for web" settings and of course maintaining aspect ratio no matter if you provide width or height.
Too late for OP but maybe it helps other people.
Upvotes: 1
Reputation: 747
Your method #2 is on the right track. To preserve aspect ratio, supply the width and height via the geometry
keyword. Your procedure can be made more general by performing the resize in one call instead of two:
$image->Resize(geometry => "${width}x${height}");
This ensures that Resize will only be called once, even if you supply both $width and $height. Just make sure that if either value is not supplied, you set it to the empty string. If you supplied both a width and height to your procedure in method #2, that could have been the cause of the blurriness you saw.
Another possible source of blurriness is the filter used by the resize operator. The best filter to use for a given operation depends on both the color characteristics of the image and the relationship between the original dimensions and the target dimensions. I recommend reading through http://www.imagemagick.org/script/command-line-options.php#filter for information about that. In PerlMagick, you can specify the filter for Resize to use via the filter
keyword.
That said, I did not find particular problems with blurriness with images that I tried, so if the problem persists, a test image would be most helpful.
Upvotes: 2