in reply to Re^2: Using ImageMagick effectively
in thread Using ImageMagick effectively

It looks like the only way to use resize is to use the command line. I don't know how to make that happen with perl driving the logic other than through a system command followed by some script you've written. That's what I attempt to do here, but I seem to be hung up on a printf statement. Why is the %s not working in this printf call? I can see on my terminal that the loop is loading all the images in the directory, and that the logic for entering into the inner control seems to work, that is filesizes less than the target value are ignored, which gets rid of . and .. too. What follows is the routine followed by the helper script it creates.

sub resize_images { use 5.010; use Path::Class; use Image::Magick; my ($rvars) = shift; my %vars = %$rvars; $vars{"target"}= 100; $vars{"bias"}= 2; $vars{"helpscript"}= "helper1.sh"; my $file2 = $vars{"helpscript"}; my $path = $vars{"to_images"}; open( my $fh, ">", $file2 ) or die("Can't open $file2 for writing: $!"); my $cd = "cd $path \n"; print $fh $cd; my $ls = "ls -lt >>text1.txt\n"; print $fh $ls; opendir my $hh, $path or warn "warn $!\n"; while (defined ($_ = readdir($hh))){ my $image = Image::Magick->new; my $file = file($path,$_); $image->ReadImage($file); $x = $image->Get('filesize'); my $k = $x/1024; say "$file has filesize of $x bytes or $k k"; if ($k>$vars{"target"}){ say "file is $file"; my $ratio = $k/($vars{"target"}-$vars{"bias"}); say "ratio is $ratio"; my $percent = 100/$ratio; say "percent is $percent"; my $mogrify_spec = "mogrify -resize %2.2f\% %s\n"; printf $fh $mogrify_spec, $percent, $file; #printf $fh "file is $file\n"; } close $fh; } }
$ cat helper1.sh cd /home/fred/Desktop/root3/pages/raiders/template_stuff/aimages ls -lt >>text1.txt mogrify -resize 40.04%s $

Replies are listed 'Best First'.
Re^4: Using ImageMagick effectively
by Anonymous Monk on Sep 27, 2014 at 11:35 UTC

    The "\%" in your $mogrify_spec isn't doing what you think - it results in the format string containing a "%". Even if you put a backslash in the string via "\\", that's not what you want:

    $ perl -wMstrict -e 'print "foo %2.2f\% %s\n"' foo %2.2f% %s $ perl -wMstrict -e 'printf "foo %2.2f\% %s\n", 40.04, "bar"' foo 40.04%s $ perl -wMstrict -e 'print "foo %2.2f\\% %s\n"' foo %2.2f\% %s $ perl -wMstrict -e 'printf "foo %2.2f\\% %s\n", 40.04, "bar"' foo 40.04\%s

    See sprintf: The way to escape a percent sign in a format string is "%%":

    $ perl -wMstrict -e 'print "foo %2.2f%% %s\n"' foo %2.2f%% %s $ perl -wMstrict -e 'printf "foo %2.2f%% %s\n", 40.04, "bar"' foo 40.04% bar

    (I'm a little surprised Perl doesn't warn about this, because there are several other warnings about bad format strings and such...)

      Ok, good, I made sprintf its own statement and dropped the printf altogether. I think the common advice is to use printf only when you have to. I get partial results from this now. It does resize the jpgs but I think it has problems with spaces in the names of files, which doesn't sound unusual on a command line. First, the subroutine:

      sub resize_images { use 5.010; use Path::Class; use Image::Magick; my ($rvars) = shift; my %vars = %$rvars; $vars{"target"}= 100; $vars{"bias"}= 2; $vars{"helpscript"}= "helper1.sh"; my $file2 = $vars{"helpscript"}; my $path = $vars{"to_images"}; open( my $fh, ">", $file2 ) or die("Can't open $file2 for writing: $!"); my $cd = "cd $path \n"; print $fh $cd; my $ls1 = "ls -lht >>text1.txt\n"; print $fh $ls1; opendir my $hh, $path or warn "warn $!\n"; while (defined ($_ = readdir($hh))){ my $image = Image::Magick->new; my $file = file($path,$_); $image->ReadImage($file); $x = $image->Get('filesize'); my $k = $x/1024; say "$file has filesize of $x bytes or $k k"; if ($k>$vars{"target"}){ say "file is $file"; my $ratio = $k/($vars{"target"}-$vars{"bias"}); say "ratio is $ratio"; my $percent = 100/$ratio; say "percent is $percent"; my $trim= sprintf("%3.2f", $percent); say "default is $_"; my $mogrify = "mogrify -resize $trim% $file\n"; print $fh $mogrify; } } my $ls2 = "ls -lht >>text2.txt\n"; print $fh $ls2; close $fh; ## system call my $system = 'bash helper1.sh'; my $return = system( $system ); return $return; }

      The output was hard for me to believe, but I don't think my computer is lying to me. html output The thing that jumps out is how a jpg of size 853 becomes 17k after a resize that should have landed it at 98k. But it's definitely a washed-out image. This is what the ls commands and the helper script look like:

      $ pwd /home/fred/Desktop/root3/pages/baylor/template_stuff/aimages $ cat text1.txt total 1.6M -rw-rw-r-- 1 fred fred 0 Sep 27 17:17 text1.txt -rw-rw-r-- 1 fred fred 232K Sep 27 17:14 yjj.jpg -rw-rw-r-- 1 fred fred 853K Sep 27 17:14 zbears.jpg -rw-rw-r-- 1 fred fred 80K Sep 27 17:14 Screenshot from 2014-08-21 13 +:22:42.png -rw-rw-r-- 1 fred fred 163K Sep 27 17:14 Screenshot from 2014-09-25 17 +:14:08.png -rw-rw-r-- 1 fred fred 245K Sep 27 17:14 Screenshot from 2014-08-21 13 +:10:18.png $ cat text2.txt total 568K -rw-rw-r-- 1 fred fred 0 Sep 27 17:17 text2.txt -rw-rw-r-- 1 fred fred 50K Sep 27 17:17 yjj.jpg -rw-rw-r-- 1 fred fred 17K Sep 27 17:17 zbears.jpg -rw-rw-r-- 1 fred fred 406 Sep 27 17:17 text1.txt -rw-rw-r-- 1 fred fred 80K Sep 27 17:14 Screenshot from 2014-08-21 13 +:22:42.png -rw-rw-r-- 1 fred fred 163K Sep 27 17:14 Screenshot from 2014-09-25 17 +:14:08.png -rw-rw-r-- 1 fred fred 245K Sep 27 17:14 Screenshot from 2014-08-21 13 +:10:18.png $ cd .. $ cd .. $ cat helper1.sh cd /home/fred/Desktop/root3/pages/baylor/template_stuff/aimages ls -lht >>text1.txt mogrify -resize 40.04% /home/fred/Desktop/root3/pages/baylor/template_ +stuff/aimages/Screenshot from 2014-08-21 13:10:18.png mogrify -resize 60.40% /home/fred/Desktop/root3/pages/baylor/template_ +stuff/aimages/Screenshot from 2014-09-25 17:14:08.png mogrify -resize 11.50% /home/fred/Desktop/root3/pages/baylor/template_ +stuff/aimages/zbears.jpg mogrify -resize 42.31% /home/fred/Desktop/root3/pages/baylor/template_ +stuff/aimages/yjj.jpg ls -lht >>text2.txt $

      How do I write this script so that perl knows it exited successfully? stdout has the details, and I liked the calculations that were going to land these images at the desired sizes. Clearly, I need to poke around with other numbers for resize.

      So I'm at the point where I'm wondering about the tool chain. As I said in the original post, working up an ImageMagick capability feels like being hazed, but it's all about honing the tools. I don't think I want to use mogrify, because that's gonna stomp all over my image in round one. Furthermore, I want to compare results when I use differing scaling schemas. The only thing significant about the image names is their extension and their lexicographic order relative to each other, as this determines their order. Is there a module for coming up with arbitrary filenames which are guaranteed to be well-behaved?

        A couple of tips:

        Just like you would in the shell, put quotes around filenames that have spaces, e.g. my $mogrify = "mogrify -resize $trim% '$file'\n"; (that'll help against spaces and a few other metachars, but not everything - you may need String::ShellQuote for that)

        Adding the line set -e at the top of your bash script will cause it to terminate when any of the called commands exits with a nonzero exit value.

        How to check if a called command exited with an error is documented in system, its simplest form is my $success = system(...)==0;

        Coming up with your own filenames probably doesn't require a module, and it really depends on what you want your filenames to look like. In its simplest form you could do something like sprintf("%010d.jpg",$sequence_number);

        By the way, since you're importing Path::Class, you could use its ->open method to replace your opendir (see Path::Class::Dir).

Re^4: Using ImageMagick effectively
by Anonymous Monk on Sep 28, 2014 at 20:58 UTC
    It looks like the only way to use resize is to use the command line.

    The following works for me. The API is documented here: http://www.imagemagick.org/script/perl-magick.php

    use Image::Magick; my $img = Image::Magick->new; my $rv = $img->Read('/tmp/foo.jpg'); die "$rv" if "$rv"; $rv = $img->Resize(geometry=>'50%'); die "$rv" if "$rv"; $rv = $img->Write('/tmp/bar.jpg'); die "$rv" if "$rv";