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";
|
|
|
|
<a href="$baseurl/$image">
|
|
<img src="$baseurl/Thumbs/$image"
|
|
width="$x"
|
|
height="$y" />
|
|
</a>
|
|
|
|
HTML
|
|
}
|
|
|
|
return "<p>$output</p>";
|
|
}
|
|
|
|
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;
|