Almost-minimal filesystem based blog.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
4.7 KiB

  1. package Display::Image;
  2. use strict;
  3. use warnings;
  4. use base qw(Exporter);
  5. our @EXPORT_OK = qw(image_size image_markup gallery);
  6. use Image::Size;
  7. use Imager;
  8. my $has_imgsize = 1;
  9. =item gallery
  10. Returns an HTML gallery of images for a given directory.
  11. Relies on Imager.
  12. =cut
  13. sub gallery {
  14. my ($dir, $baseurl) = @_;
  15. return unless -d $dir;
  16. opendir my ($dh), $dir;
  17. my (@images) = sort
  18. grep { /^[A-Za-z0-9]+[.](jpg|jpeg|png|gif)$/i }
  19. readdir $dh;
  20. closedir $dh;
  21. return unless (@images);
  22. my $thumb_dir = "$dir/Thumbs";
  23. mkdir $thumb_dir unless -e $thumb_dir;
  24. my $output;
  25. for my $image (@images) {
  26. my ($x, $y) = thumbnail($dir, $image);
  27. $output .= <<"HTML";
  28. <a href="$baseurl/$image">
  29. <img src="$baseurl/Thumbs/$image"
  30. width="$x"
  31. height="$y" />
  32. </a>
  33. HTML
  34. }
  35. return "<p>$output</p>";
  36. }
  37. sub thumbnail {
  38. my ($dir, $image) = @_;
  39. my $thumb_dir = "$dir/Thumbs";
  40. if (-e "$thumb_dir/$image") {
  41. # Return a size for the existing image:
  42. return image_size("$thumb_dir/$image");
  43. } else {
  44. # Make a new thumbnail and save a copy:
  45. my $img = Imager->new;
  46. $img->read(file => "$dir/$image")
  47. or die $img->errstr;
  48. my $scaled = $img->scale(xpixels => 128);
  49. $scaled->write(file => "$thumb_dir/$image");
  50. # Return the thumbnail size:
  51. return ($scaled->getwidth, $scaled->getheight);
  52. }
  53. }
  54. =cut
  55. =item image_size
  56. Returns (width, height) of a variety of image files. Called by icon_markup and
  57. line_parse. Uses Image::Size if available, otherwise uses a couple of built-in
  58. routines munged together from pngsize and jpegsize in wwwis, by Alex Knowles
  59. and Andrew Tong.
  60. =cut
  61. sub image_size {
  62. if ($has_imgsize) {
  63. return imgsize($_[0]);
  64. }
  65. else {
  66. return wwwis($_[0]);
  67. }
  68. }
  69. # If Image::Size isn't available, we use this instead:
  70. sub wwwis {
  71. my ($image_file) = shift;
  72. my ($head, $if);
  73. if ( ! open $if, '<', $image_file ) {
  74. print STDERR "can't open IMG $image_file";
  75. return (0, 0);
  76. } else {
  77. binmode $if;
  78. if ($image_file =~ m/\.png$/) { # it's a PNG
  79. my ($a, $b, $c, $d, $e, $f, $g, $h) = 0;
  80. if (defined($image_file)
  81. && read($if, $head, 8) == 8
  82. && ($head eq "\x8a\x4d\x4e\x47\x0d\x0a\x1a\x0a" ||
  83. $head eq "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a")
  84. && read($if, $head, 4) == 4
  85. && read($if, $head, 4) == 4
  86. && ($head eq "MHDR" || $head eq "IHDR")
  87. && read($if, $head, 8) == 8) {
  88. # ($x, $y) = unpack("I"x2, $head);
  89. # doesn't work on little-endian machines
  90. # return ($x,$y);
  91. ($a,$b,$c,$d,$e,$f,$g,$h) = unpack ("C"x8, $head);
  92. return ($a<<24|$b<<16|$c<<8|$d, $e<<24|$f<<16|$g<<8|$h);
  93. }
  94. } elsif ($image_file =~ m/\.jpe?g$/) { # it's a JPEG
  95. my($done) = 0;
  96. my($c1,$c2,$ch,$s,$length, $dummy) = (0,0,0,0,0,0);
  97. my($a,$b,$c,$d);
  98. if (defined($image_file)
  99. && read($if, $c1, 1)
  100. && read($if, $c2, 1)
  101. && ord($c1) == 0xFF
  102. && ord($c2) == 0xD8) {
  103. while (ord($ch) != 0xDA && !$done) {
  104. # Find next marker (JPEG markers begin with 0xFF)
  105. # This can hang the program!!
  106. while (ord($ch) != 0xFF) {
  107. return(0,0) unless read($if, $ch, 1);
  108. }
  109. # JPEG markers can be padded with unlimited 0xFF's
  110. while (ord($ch) == 0xFF) {
  111. return(0,0) unless read($if, $ch, 1);
  112. }
  113. # Now, $ch contains the value of the marker.
  114. if ((ord($ch) >= 0xC0) && (ord($ch) <= 0xC3)) {
  115. return(0,0) unless read ($if, $dummy, 3);
  116. return(0,0) unless read($if, $s, 4);
  117. ($a,$b,$c,$d)=unpack("C"x4,$s);
  118. return ($c<<8|$d, $a<<8|$b );
  119. } else {
  120. # We **MUST** skip variables, since FF's within
  121. # variable names are NOT valid JPEG markers
  122. return(0,0) unless read ($if, $s, 2);
  123. ($c1, $c2) = unpack("C"x2,$s);
  124. $length = $c1<<8|$c2;
  125. last if (!defined($length) || $length < 2);
  126. read($if, $dummy, $length-2);
  127. }
  128. }
  129. }
  130. }
  131. return (0,0);
  132. }
  133. }
  134. 1;