user3369022
user3369022

Reputation: 21

Image::Magick (perlmagick) resizing aspect ratio and quality issues (different than convert command line utility)

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

Answers (2)

Dantel35
Dantel35

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

retroj
retroj

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

Related Questions