thumbs.pl 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. # Copyright (C) 2004, 2012 Alex Schroeder <alex@gnu.org>
  2. # Copyright (C) 2005 Rob Neild
  3. #
  4. # This program is free software: you can redistribute it and/or modify it under
  5. # the terms of the GNU General Public License as published by the Free Software
  6. # Foundation, either version 3 of the License, or (at your option) any later
  7. # version.
  8. #
  9. # This program is distributed in the hope that it will be useful, but WITHOUT
  10. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License along with
  14. # this program. If not, see <http://www.gnu.org/licenses/>.
  15. # Thumbnail (and improved image handling) module for OddMuse wiki
  16. # Conflicts with the "Image extension module"
  17. use strict;
  18. use v5.10;
  19. require MIME::Base64;
  20. use File::Path;
  21. AddModuleDescription('thumbs.pl', 'Image Thumbnails');
  22. our ($q, $OpenPageName, %IndexHash, @UploadTypes, @MyRules, $FreeLinkPattern);
  23. # Tempoary directory to create thumbnails in
  24. our $ThumbnailTempDir = '/tmp';
  25. # Path and name of external program to use to create thumbnails. Only
  26. # ImageMagick 'convert' can be used. You may have to set the MAGICK_HOME
  27. # environment variable in your config file if you set it to
  28. # /usr/local/bin/convert and get the following error:
  29. # convert: no decode delegate for this image format
  30. # For your config file:
  31. # $ENV{MAGICK_HOME} = '/usr/local';
  32. our $ThumbnailConvert = '/usr/bin/convert';
  33. # Max size for a thumbnail. If larger size is specified just shows
  34. # regular image
  35. our $ThumbnailMaxSize = 500;
  36. # Default thumbnail size if non is specified
  37. our $ThumbnailDefaultSize = 100;
  38. # MIME types to create thumbnail for, all allowed if empty list
  39. our @ThumbnailTypes = @UploadTypes;
  40. # As well as using ALT, use TITLE. This enables comments to popup when
  41. # hovering mouse over thumbnail
  42. our $ThumbnailImageUseTitle = 0;
  43. our $ThumbnailCacheDir = "oddmuse_thumbnail_cache";
  44. our $ThumbnailCacheUrl = "/oddmuse_thumbnail_cache";
  45. # Define new formatting rule "thumb" that inserts an auto generated thumbnail
  46. # Syntax is [[thumb:page name | etc. ]]
  47. push(@MyRules, \&ThumbNailSupportRule);
  48. sub ThumbNailSupportRule {
  49. my $result;
  50. my $RawMatch;
  51. if (m!\G(\[\[thumb:$FreeLinkPattern(\|.*?)?\]\])!cg)
  52. {
  53. $RawMatch = $1;
  54. # Try and extract out all the options. They can be in any order, apart from comment at end
  55. my $name = $2;
  56. my $size="$ThumbnailDefaultSize"; # default size for thumbnail
  57. my $frame;
  58. my $comment; # default alignment for a non framed picture
  59. my $alignment_framed = 'tright'; # default alignment for a framed picture
  60. my $alignment;
  61. my $params = $3 . '|';
  62. if($params =~ s/\|([0-9]+)px\|/\|/) { $size = $1; }
  63. if($params =~ s/\|thumb\|/\|/) { $frame = 'yes' ;}
  64. if($params =~ s/\|frame\|/\|/) { $frame = 'yes'; }
  65. if ($params =~ s/\|none\|/\|/) { $alignment_framed= 'tnone'; }
  66. if ($params =~ s/\|right\|/\|/) { $alignment_framed= 'tright'; $alignment='floatright';}
  67. if ($params =~ s/\|left\|/\|/) { $alignment_framed= 'tleft'; $alignment='floatleft'; }
  68. if ($params =~ m/\|(.+)\|$/) { $comment = $1; }
  69. my $id = FreeToNormal($name);
  70. AllPagesList();
  71. # if the page does exists
  72. if ($IndexHash{$id})
  73. {
  74. if (!IsFile("$ThumbnailCacheDir/$id/$size"))
  75. {
  76. GenerateThumbNail ($id, $size);
  77. }
  78. my %img_attribs;
  79. my $action = "$ThumbnailCacheUrl/" . UrlEncode($id) . "/$size";
  80. $img_attribs{'-src'} = $action;
  81. if (defined $comment) {
  82. $img_attribs{'-alt'} ="$comment";
  83. $img_attribs{'-title'} = "$comment" if $ThumbnailImageUseTitle==1;
  84. }
  85. else { $img_attribs{'-alt'} = "$name"; }
  86. $img_attribs{'-class'} = 'upload';
  87. $result = $q->img(\%img_attribs);
  88. $result = ScriptLink(UrlEncode($id) , $result, 'image');
  89. if (defined $frame) {
  90. if (defined $comment) { $result = $result . $q->div({-class=>'thumbcaption'}, "$comment"); }
  91. if ($size>0) {
  92. $result = $q->div({-style=>"width:" . ($size+2) . "px"}, $result);
  93. $result = $q->div({-class=>"thumb " . $alignment_framed}, $result);
  94. }
  95. }
  96. else
  97. {
  98. if (defined $alignment) { $result = $q->div({-class=>"$alignment" }, $result); }
  99. }
  100. }
  101. else
  102. {
  103. # if the image does not exist
  104. $result = '[' . T('thumb') . ':' . $name . GetEditLink($id, '?', 1) . ']';
  105. }
  106. }
  107. if (defined $result)
  108. {
  109. Dirty($RawMatch);
  110. print $result;
  111. $result = '';
  112. }
  113. return $result;
  114. }
  115. # define new action "thumbnail" that actually does the on fly generation of the image
  116. # thumbnails are put into the file so they only need be generated once
  117. # we also store the size of thumbnail so that can be used in the markup
  118. # if we get passed a size of zero then all we need to do is check whether we have the image size stored in thumbnail_0
  119. # this enbles markup for non-thumbnail images better
  120. sub GenerateThumbNail {
  121. my ($id, $size) = (@_);
  122. ValidIdOrDie($id);
  123. AllPagesList();
  124. if (not $IndexHash{$id}) { ReportError(Ts('Error creating thumbnail from nonexisting page %s.' , $id), '500 INTERNAL SERVER ERROR'); } # Page Doesn't exist,
  125. my $openpage = $OpenPageName; # remember the current page we are on
  126. RequestLockOrError();
  127. OpenPage($id);
  128. # Parse out some data
  129. # Check MIME type supported
  130. # Check is a file
  131. my $text = GetTextRevision(GetParam('revision', ''))->{text}; # maybe revision reset!
  132. my ($type) = TextIsFile($text); # MIME type if an uploaded file
  133. my $data = substr($text, index($text, "\n") + 1);
  134. if ($type)
  135. {
  136. my $regexp = quotemeta($type);
  137. if (@ThumbnailTypes and not grep(/^$regexp$/, @ThumbnailTypes)) {
  138. ReportError(Ts('Can not create thumbnail for file type %s.' , $type), '415 UNSUPPORTED MEDIA TYPE');
  139. }
  140. }
  141. else
  142. {
  143. ReportError(T('Can not create thumbnail for a text document'), '500 INTERNAL SERVER ERROR');
  144. }
  145. my $filename = $ThumbnailTempDir . "/odd" . $id . "_" . $size;
  146. # Decode the original image to a temp file
  147. open(my $FD, '>', encode_utf8($filename)) or ReportError(Ts("Could not open %s for writing whilst trying to save image before creating thumbnail. Check write permissions.",$filename), '500 INTERNAL SERVER ERROR');
  148. binmode($FD);
  149. print $FD MIME::Base64::decode($data);
  150. close($FD);
  151. eval { mkpath("$ThumbnailCacheDir/$id") };
  152. if ($@) {
  153. ReportError(Ts('Can not create path for thumbnail - %s', $@), '500 INTERNAL SERVER ERROR');
  154. }
  155. # create the thumbnail
  156. my $command = "$ThumbnailConvert '$filename' -verbose -resize ${size}x '$ThumbnailCacheDir/$id/$size' 2>&1";
  157. open (my $MESSAGE, '-|', $command)
  158. or ReportError(Tss("Failed to run %1 to create thumbnail: %2", $ThumbnailConvert, $!),
  159. '500 INTERNAL SERVER ERROR');
  160. my $convert = <$MESSAGE>;
  161. close($MESSAGE);
  162. my $scaled_size_x;
  163. my $scaled_size_y;
  164. my $thumbnail_data= '';
  165. if($?) {
  166. ReportError(Ts("%s ran into an error", $ThumbnailConvert), '500 INTERNAL SERVER ERROR', undef,
  167. $q->pre($command . "\n" . $convert));
  168. } elsif($convert =~ m/=>(\d+)x(\d+)/) {
  169. $scaled_size_x = $1;
  170. $scaled_size_y = $2;
  171. } elsif (!$convert) {
  172. ReportError(Ts("%s produced no output", $ThumbnailConvert), '500 INTERNAL SERVER ERROR');
  173. } else {
  174. ReportError(Ts("Failed to parse %s.", $convert), '500 INTERNAL SERVER ERROR');
  175. }
  176. Unlink($filename);
  177. # save tag to page
  178. #$Page{'thumbnail_' . $size} = '#FILE ' . $type . ' created=' . $Now . ' revision=' . $Page{'revision'} . ' size=' . $scaled_size_x . 'x' . $scaled_size_y . "\n" . $thumbnail_data;
  179. #SavePage();
  180. ReleaseLock();
  181. OpenPage($openpage); # restore original open page
  182. }