#!/usr/bin/perl
# Ikiwiki enhanced image handling plugin
# cm@tahina.priv.at 20061002
package IkiWiki::Plugin::img;

use warnings;
use strict;
use IkiWiki;
use Image::Magick;
use Data::Dumper;
#use File::Basename;

my $convert = 'convert';

my %imgdefaults;

sub import { #{{{
    IkiWiki::hook(type => "preprocess", id => "img",
		  call => \&preprocess);
      IkiWiki::hook(type => "filter", id => "img",
		    call => \&filter);
  }

sub preprocess (@) { #{{{
    my $image = $_[0];
    my %params=@_;

    my $page = $params{page};
    my $destpage = $params{destpage};
    my $inline = $params{inline} || $imgdefaults{$page}->{inline} ||
	return "'inline' missing";
    my $more = $params{more} || $imgdefaults{$page}->{more} || '';
    my $alt = $params{alt} || $imgdefaults{alt} || '';

    if($image eq 'defaults') {
	$imgdefaults{$params{page}} =
	{ inline => $inline,
	  more => $more,
	  alt => $alt };
	return '';
    }

    $inline =~ /^(\d+)x(\d+)$/i || return "bad 'inline' param";
    my(@more);
    foreach my $dim (split(/\s+/, $more)) {
	if($dim ne 'full' && $dim !~ /^(\d+)x(\d+)$/i) {
	    return "bad 'more' component '$dim'";
	}
	push(@more, $dim);
    }
    
    my $link = $image;
    $link =~ /^[\w\d\._\-]+$/ || return "bad img filename";
    $link = IkiWiki::possibly_foolish_untaint($link);

    $link = IkiWiki::bestlink($page, $link) ||
	return "file not found: '$image'";
    IkiWiki::add_depends($page, $link);
    my $file = IkiWiki::srcfile($link);

    my %sizes;

    for my $dim ($inline, @more) {

	my $result = {};
	my $r = scale_image($file, $link, $dim, $result);
	return $r if $r;

	my $defused_imglink = $result->{imglink};
	$defused_imglink =~ s/\.([^\.]*)$/-$1/;
	$result->{mdwnfile} = $defused_imglink . '.mdwn';
	$result->{htmlabs} = $defused_imglink . '.html',
	$result->{htmllink} = IkiWiki::basename($defused_imglink);
	$result->{dimensions} = $dim;
	$sizes{$dim} = $result;
	IkiWiki::add_depends($defused_imglink,$page);
    }

    my %moresizes;
    for my $dim (@more) {
	$moresizes{$dim} = $sizes{$dim};
    }

    for my $dim (@more) {
	my $d = $sizes{$dim};
	my $tt = IkiWiki::template("imgpage.tmpl");
	return "error opening template 'imgpage.tmpl'" unless $tt;
	$tt->param(alt => $alt,
		   width => $d->{width},
		   height => $d->{height},
		   imglink =>
		   IkiWiki::abs2rel($d->{imglink},
				    IkiWiki::dirname($d->{mdwnfile})),
		   sizes => [values %moresizes]);
	IkiWiki::writefile($d->{mdwnfile}, $IkiWiki::config{srcdir},
			   $tt->output) ||
			       return "error processing template";
    }

    return sprintf('<a href="%s"><img src="%s" alt="%s" width="%s" ' .
		   'height="%s" /></a>',
		   IkiWiki::abs2rel($sizes{$more[0]}->{htmlabs},
				  IkiWiki::dirname($destpage)),
		   IkiWiki::abs2rel($sizes{$inline}->{imglink},
				  IkiWiki::dirname($destpage)),
		   $alt,
		   $sizes{$inline}->{width},
		   $sizes{$inline}->{height});
}

sub filter (@) { #{{{
    my %params=@_;

    $imgdefaults{$params{page}} = {};

    return $params{content};
} # }}}


sub scale_image {
    my $infile = shift;
    my $link = shift;
    my $dim = shift;
    my $res = shift;

    my $dir = IkiWiki::dirname($link);
    my $base = IkiWiki::basename($link);

    my $image = Image::Magick->new;
    my $r;

    if($dim ne 'full') {
	my($w,$h) = ($dim =~ /^(\d+)x(\d+)$/);
	return "bad image dimensions '$dim'" unless (defined $w && defined $h);

	my $outfile = "$IkiWiki::config{destdir}/$dir/${w}x${h}-$base";
	$res->{imglink} = "$dir/${w}x${h}-$base";

	if(-e $outfile && (-M $infile >= -M $outfile)) {
	    $r = $image->Read($outfile);
	    return "read outfile: $r" if $r;
	    ($res->{width}, $res->{height}) = $image->Get('width', 'height');
#	    warn "scale_image notmodified\n";
#	    warn Dumper(\$res);
	    return undef;
	} else {
	    $r = $image->Read($infile);
	    return "read infile: $r" if $r;
	}

	$r = $image->Resize(geometry => "${w}x${h}");
	return "resize: $r" if $r;

	my @blob = $image->ImageToBlob();
	IkiWiki::writefile($res->{imglink}, $IkiWiki::config{destdir},
			   $blob[0], 1); # binmode 1!
			   
#	$r = $image->Write($outfile);
#	return "write outfile: $r" if $r;
    } else {
	$r = $image->Read($infile);
	return "read infile(full): $r" if $r;

	$res->{outfile} = $infile;
	$res->{imglink} = $link;
    }

    ($res->{width}, $res->{height}) = $image->Get('width', 'height');
#    warn "scale_image returns\n";
#    warn Dumper(\$res);
    return undef;
}

1;
