img plugin: split resizing calculations and actual resizing
authorchrysn <chrysn@fsfe.org>
Mon, 14 Jul 2014 22:23:56 +0000 (00:23 +0200)
committerchrysn <chrysn@fsfe.org>
Tue, 15 Jul 2014 11:44:22 +0000 (13:44 +0200)
there is now a size calculating part (which chooses a final size) and a
scaling part (which triggers if the sizes calculated by the former
indicate a downscaling).

this solves the issue of unproportional upscalings
(bugs/image_rescaling_distorts_with_small_pictures).

also, "small" pdf files (or pdf files without explicit size settings),
which would not be converted under the old mechanism, now get rendered
to pngs.

this commit affects a unit test: while svgs were previously
unconditionally rendered to pngs, this now only happens on downscaling.
this is intentional -- while a small version of an svg graphic is
likely to be more compact when rendered (eg as a preview), a large
version would not have that benefit, and why convert something that
browsers basically can show and be inconsistend with how other images
are handled. the new unit test simply makes the original svg larger to
check for the same behaviros as before.

IkiWiki/Plugin/img.pm
t/img.t

index fe0ba2ef1388dd5f741a170b9521a7f4b57c2adf..1ab753352e2e28b65430dfd0cf574efc94dcf809 100644 (file)
@@ -80,73 +80,67 @@ sub preprocess (@) {
        
        my ($dwidth, $dheight);
 
-       if ($params{size} ne 'full') {
+       if ($params{size} eq 'full') {
+               $dwidth = $im->Get("width");
+               $dheight = $im->Get("height");
+       } else {
                my ($w, $h) = ($params{size} =~ /^(\d*)x(\d*)$/);
                error sprintf(gettext('wrong size format "%s" (should be WxH)'), $params{size})
                        unless (defined $w && defined $h &&
                                (length $w || length $h));
-               
-               if ((length $w && $w > $im->Get("width")) ||
-                   (length $h && $h > $im->Get("height"))) {
-                       # resizing larger
-                       $imglink = $file;
-
-                       # don't generate larger image, just set display size
-                       if (length $w && length $h) {
-                               ($dwidth, $dheight)=($w, $h);
-                       }
-                       # avoid division by zero on 0x0 image
-                       elsif ($im->Get("width") == 0 || $im->Get("height") == 0) {
-                               ($dwidth, $dheight)=(0, 0);
-                       }
-                       # calculate unspecified size from the other one, preserving
-                       # aspect ratio
-                       elsif (length $w) {
-                               $dwidth=$w;
-                               $dheight=$w / $im->Get("width") * $im->Get("height");
-                       }
-                       elsif (length $h) {
-                               $dheight=$h;
-                               $dwidth=$h / $im->Get("height") * $im->Get("width");
-                       }
+
+               if ($im->Get("width") == 0 || $im->Get("height") == 0) {
+                       ($dwidth, $dheight)=(0, 0);
+               } elsif (! length $w || (length $h && $im->Get("height")*$w > $h * $im->Get("width"))) {
+                       # using height because only height is given or ...
+                       # because original image is more portrait than $w/$h
+                       # ... slimness of $im > $h/w
+                       # ... $im->Get("height")/$im->Get("width") > $h/$w
+                       # ... $im->Get("height")*$w > $h * $im->Get("width")
+
+                       $dheight=$h;
+                       $dwidth=$h / $im->Get("height") * $im->Get("width");
+               } else { # (! length $h) or $w is what determines the resized size
+                       $dwidth=$w;
+                       $dheight=$w / $im->Get("width") * $im->Get("height");
+               }
+       }
+
+       if ($dwidth < $im->Get("width") || $ispdf) {
+               # resize down, or resize to pixels at all
+
+               my $outfile = "$config{destdir}/$dir/$params{size}-$base";
+               $imglink = "$dir/$params{size}-$base";
+
+               will_render($params{page}, $imglink);
+
+               if (-e $outfile && (-M $srcfile >= -M $outfile)) {
+                       $im = Image::Magick->new;
+                       $r = $im->Read($outfile);
+                       error sprintf(gettext("failed to read %s: %s"), $outfile, $r) if $r;
                }
                else {
-                       # resizing smaller
-                       my $outfile = "$config{destdir}/$dir/${w}x${h}-$base";
-                       $imglink = "$dir/${w}x${h}-$base";
-               
-                       will_render($params{page}, $imglink);
-
-                       if (-e $outfile && (-M $srcfile >= -M $outfile)) {
-                               $im = Image::Magick->new;
-                               $r = $im->Read($outfile);
-                               error sprintf(gettext("failed to read %s: %s"), $outfile, $r) if $r;
+                       $r = $im->Resize(geometry => "${dwidth}x${dheight}");
+                       error sprintf(gettext("failed to resize: %s"), $r) if $r;
+
+                       # don't actually write resized file in preview mode;
+                       # rely on width and height settings
+                       if (! $params{preview}) {
+                               $im->set(($issvg || $ispdf) ? (magick => 'png') : ());
+                               my @blob = $im->ImageToBlob();
+                               writefile($imglink, $config{destdir}, $blob[0], 1);
                        }
                        else {
-                               $r = $im->Resize(geometry => "${w}x${h}");
-                               error sprintf(gettext("failed to resize: %s"), $r) if $r;
-
-                               # don't actually write resized file in preview mode;
-                               # rely on width and height settings
-                               if (! $params{preview}) {
-                                       $im->set(($issvg || $ispdf) ? (magick => 'png') : ());
-                                       my @blob = $im->ImageToBlob();
-                                       writefile($imglink, $config{destdir}, $blob[0], 1);
-                               }
-                               else {
-                                       $imglink = $file;
-                               }
+                               $imglink = $file;
                        }
-
-                       # always get the true size of the resized image
-                       $dwidth  = $im->Get("width"); 
-                       $dheight = $im->Get("height");
                }
-       }
-       else {
-               $imglink = $file;
-               $dwidth = $im->Get("width");
+
+               # always get the true size of the resized image (it could be
+               # that imagemagick did its calculations differently)
+               $dwidth  = $im->Get("width");
                $dheight = $im->Get("height");
+       } else {
+               $imglink = $file;
        }
        
        if (! defined($dwidth) || ! defined($dheight)) {
diff --git a/t/img.t b/t/img.t
index c336c6744f21bfd44e0845bd2890bf35a929ee46..0183f8779d3034b36c8a436e558c428f8b88b636 100755 (executable)
--- a/t/img.t
+++ b/t/img.t
@@ -21,7 +21,7 @@ BEGIN { use_ok("Image::Magick"); }
 ok(! system("rm -rf t/tmp; mkdir -p t/tmp/in"));
 
 ok(! system("cp t/img/redsquare.png t/tmp/in/redsquare.png"));
-writefile("emptysquare.svg", "t/tmp/in", '<svg width="10" height="10"/>');
+writefile("emptysquare.svg", "t/tmp/in", '<svg width="30" height="30"/>');
 # using different image sizes for different pages, so the pagenumber selection can be tested easily
 ok(! system("cp t/img/twopages.pdf t/tmp/in/twopages.pdf"));