package Display::Image; use strict; use warnings; use base qw(Exporter); our @EXPORT_OK = qw(image_size image_markup gallery); use Image::Size; use Imager; my $has_imgsize = 1; =item gallery Returns an HTML gallery of images for a given directory. Relies on Imager. =cut sub gallery { my ($dir, $baseurl) = @_; return unless -d $dir; opendir my ($dh), $dir; my (@images) = sort grep { /^[A-Za-z0-9]+[.](jpg|jpeg|png|gif)$/i } readdir $dh; closedir $dh; return unless (@images); my $thumb_dir = "$dir/Thumbs"; mkdir $thumb_dir unless -e $thumb_dir; my $output; for my $image (@images) { my ($x, $y) = thumbnail($dir, $image); $output .= <<"HTML"; HTML } return "

$output

"; } sub thumbnail { my ($dir, $image) = @_; my $thumb_dir = "$dir/Thumbs"; if (-e "$thumb_dir/$image") { # Return a size for the existing image: return image_size("$thumb_dir/$image"); } else { # Make a new thumbnail and save a copy: my $img = Imager->new; $img->read(file => "$dir/$image") or die $img->errstr; my $scaled = $img->scale(xpixels => 128); $scaled->write(file => "$thumb_dir/$image"); # Return the thumbnail size: return ($scaled->getwidth, $scaled->getheight); } } =cut =item image_size Returns (width, height) of a variety of image files. Called by icon_markup and line_parse. Uses Image::Size if available, otherwise uses a couple of built-in routines munged together from pngsize and jpegsize in wwwis, by Alex Knowles and Andrew Tong. =cut sub image_size { if ($has_imgsize) { return imgsize($_[0]); } else { return wwwis($_[0]); } } # If Image::Size isn't available, we use this instead: sub wwwis { my ($image_file) = shift; my ($head, $if); if ( ! open $if, '<', $image_file ) { print STDERR "can't open IMG $image_file"; return (0, 0); } else { binmode $if; if ($image_file =~ m/\.png$/) { # it's a PNG my ($a, $b, $c, $d, $e, $f, $g, $h) = 0; if (defined($image_file) && read($if, $head, 8) == 8 && ($head eq "\x8a\x4d\x4e\x47\x0d\x0a\x1a\x0a" || $head eq "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a") && read($if, $head, 4) == 4 && read($if, $head, 4) == 4 && ($head eq "MHDR" || $head eq "IHDR") && read($if, $head, 8) == 8) { # ($x, $y) = unpack("I"x2, $head); # doesn't work on little-endian machines # return ($x,$y); ($a,$b,$c,$d,$e,$f,$g,$h) = unpack ("C"x8, $head); return ($a<<24|$b<<16|$c<<8|$d, $e<<24|$f<<16|$g<<8|$h); } } elsif ($image_file =~ m/\.jpe?g$/) { # it's a JPEG my($done) = 0; my($c1,$c2,$ch,$s,$length, $dummy) = (0,0,0,0,0,0); my($a,$b,$c,$d); if (defined($image_file) && read($if, $c1, 1) && read($if, $c2, 1) && ord($c1) == 0xFF && ord($c2) == 0xD8) { while (ord($ch) != 0xDA && !$done) { # Find next marker (JPEG markers begin with 0xFF) # This can hang the program!! while (ord($ch) != 0xFF) { return(0,0) unless read($if, $ch, 1); } # JPEG markers can be padded with unlimited 0xFF's while (ord($ch) == 0xFF) { return(0,0) unless read($if, $ch, 1); } # Now, $ch contains the value of the marker. if ((ord($ch) >= 0xC0) && (ord($ch) <= 0xC3)) { return(0,0) unless read ($if, $dummy, 3); return(0,0) unless read($if, $s, 4); ($a,$b,$c,$d)=unpack("C"x4,$s); return ($c<<8|$d, $a<<8|$b ); } else { # We **MUST** skip variables, since FF's within # variable names are NOT valid JPEG markers return(0,0) unless read ($if, $s, 2); ($c1, $c2) = unpack("C"x2,$s); $length = $c1<<8|$c2; last if (!defined($length) || $length < 2); read($if, $dummy, $length-2); } } } } return (0,0); } } 1;