X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/4d8b2d84d5635e0e718e9f66fcdf6e20587fbc2c..bd8198fb77ed5cf77ddeb860ca1ac983bfaacbbd:/IkiWiki/Plugin/img.pm diff --git a/IkiWiki/Plugin/img.pm b/IkiWiki/Plugin/img.pm index 0606f5001..17a58ca7a 100644 --- a/IkiWiki/Plugin/img.pm +++ b/IkiWiki/Plugin/img.pm @@ -5,96 +5,212 @@ package IkiWiki::Plugin::img; use warnings; use strict; -use IkiWiki; +use IkiWiki 3.00; my %imgdefaults; -sub import { #{{{ - hook(type => "preprocess", id => "img", call => \&preprocess); -} #}}} - -sub preprocess (@) { #{{{ +sub import { + hook(type => "getsetup", id => "img", call => \&getsetup); + hook(type => "preprocess", id => "img", call => \&preprocess, scan => 1); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "widget", + }, +} + +sub preprocess (@) { my ($image) = $_[0] =~ /$config{wiki_file_regexp}/; # untaint my %params=@_; - if (! exists $imgdefaults{$params{page}}) { - $imgdefaults{$params{page}} = {}; + if (! defined $image) { + error("bad image filename"); + } + + if (exists $imgdefaults{$params{page}}) { + foreach my $key (keys %{$imgdefaults{$params{page}}}) { + if (! exists $params{$key}) { + $params{$key}=$imgdefaults{$params{page}}->{$key}; + } + } + } + + if (! exists $params{size} || ! length $params{size}) { + $params{size}='full'; } - my $size = $params{size} || $imgdefaults{$params{page}}->{size} || 'full'; - my $alt = $params{alt} || $imgdefaults{$params{page}}->{alt} || ''; if ($image eq 'defaults') { - $imgdefaults{$params{page}} = { - size => $size, - alt => $alt, - }; + $imgdefaults{$params{page}} = \%params; return ''; } + add_link($params{page}, $image); add_depends($params{page}, $image); - my $file = bestlink($params{page}, $image) - || return "[[img ".sprintf(gettext("%s not found"), $image)."]]"; - my $dir = IkiWiki::dirname($file); + # optimisation: detect scan mode, and avoid generating the image + if (! defined wantarray) { + return; + } + + my $file = bestlink($params{page}, $image); + my $srcfile = srcfile($file, 1); + if (! length $file || ! defined $srcfile) { + return htmllink($params{page}, $params{destpage}, $image); + } + + my $dir = $params{page}; my $base = IkiWiki::basename($file); + my $issvg = $base=~s/\.svg$/.png/i; + my $ispdf = $base=~s/\.pdf$/.png/i; + my $pagenumber = exists($params{pagenumber}) ? int($params{pagenumber}) : 0; + if ($pagenumber != 0) { + $base = "p$pagenumber-$base"; + } eval q{use Image::Magick}; - error($@) if $@; - my $im = Image::Magick->new; + error gettext("Image::Magick is not installed") if $@; + my $im = Image::Magick->new(); my $imglink; - my $r; + my $imgdatalink; + my $r = $im->Read("$srcfile\[$pagenumber]"); + error sprintf(gettext("failed to read %s: %s"), $file, $r) if $r; + + if (! defined $im->Get("width") || ! defined $im->Get("height")) { + error sprintf(gettext("failed to get dimensions of %s"), $file); + } + + my ($dwidth, $dheight); + + 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 ($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 - if ($size ne 'full') { - my ($w, $h) = ($size =~ /^(\d+)x(\d+)$/); - return "[[img ".sprintf(gettext('bad size "%s"'), $size)."]]" - unless (defined $w && defined $h); + my $outfile = "$config{destdir}/$dir/$params{size}-$base"; + $imglink = "$dir/$params{size}-$base"; - 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($file) >= -M $outfile)) { + if (-e $outfile && (-M $srcfile >= -M $outfile)) { + $im = Image::Magick->new; $r = $im->Read($outfile); - return "[[img ".sprintf(gettext("failed to read %s: %s"), $outfile, $r)."]]" if $r; + error sprintf(gettext("failed to read %s: %s"), $outfile, $r) if $r; } else { - $r = $im->Read(srcfile($file)); - return "[[img ".sprintf(gettext("failed to read %s: %s"), $file, $r)."]]" if $r; + $r = $im->Resize(geometry => "${dwidth}x${dheight}"); + error sprintf(gettext("failed to resize: %s"), $r) if $r; - $r = $im->Resize(geometry => "${w}x${h}"); - return "[[img ".sprinftf(gettext("failed to resize: %s"), $r)."]]" if $r; - - # don't actually write file in preview mode + $im->set(($issvg || $ispdf) ? (magick => 'png') : ()); + my @blob = $im->ImageToBlob(); + # don't actually write resized file in preview mode; + # rely on width and height settings if (! $params{preview}) { - will_render($params{page}, $imglink); - my @blob = $im->ImageToBlob(); writefile($imglink, $config{destdir}, $blob[0], 1); } else { - $imglink = $file; + eval q{use MIME::Base64}; + error($@) if $@; + $imgdatalink = "data:image/".$im->Get("magick").";base64,".encode_base64($blob[0]); } } - } - else { - $r = $im->Read(srcfile($file)); - return "[[img ".sprintf(gettext("failed to read %s: %s"), $file, $r)."]]" if $r; + + # 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; } - - add_depends($imglink, $params{page}); + + if (! defined($dwidth) || ! defined($dheight)) { + error sprintf(gettext("failed to determine size of image %s"), $file) + } my ($fileurl, $imgurl); - if (! $params{preview}) { - $fileurl=IkiWiki::abs2rel($file, IkiWiki::dirname($params{destpage})); - $imgurl=IkiWiki::abs2rel($imglink, IkiWiki::dirname($params{destpage})); + my $urltobase = $params{preview} ? undef : $params{destpage}; + $fileurl=urlto($file, $urltobase); + $imgurl=$imgdatalink ? $imgdatalink : urlto($imglink, $urltobase); + + if (! exists $params{class}) { + $params{class}="img"; + } + + my $attrs=''; + foreach my $attr (qw{alt title class id hspace vspace}) { + if (exists $params{$attr}) { + $attrs.=" $attr=\"$params{$attr}\""; + } + } + + my $imgtag=''; + + my $link; + if (! defined $params{link}) { + $link=$fileurl; + } + elsif ($params{link} =~ /^\w+:\/\//) { + $link=$params{link}; + } + + if (defined $link) { + $imgtag=''.$imgtag.''; } else { - $fileurl="$config{url}/$file"; - $imgurl="$config{url}/$imglink"; + my $b = bestlink($params{page}, $params{link}); + + if (length $b) { + add_depends($params{page}, $b, deptype("presence")); + $imgtag=htmllink($params{page}, $params{destpage}, + $params{link}, linktext => $imgtag, + noimageinline => 1, + ); + } } - return ''.$alt.''; -} #}}} + if (exists $params{caption}) { + return ''. + ''. + ''. + '
'.$params{caption}.'
'.$imgtag.'
'; + } + else { + return $imgtag; + } +} 1