Files
oddmuse/modules/thumbs.pl
2016-06-22 15:37:04 +02:00

260 lines
8.2 KiB
Perl

# Copyright (C) 2004, 2012 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2005 Rob Neild
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
# Thumbnail (and improved image handling) module for OddMuse wiki
# Conflicts with the "Image extension module"
use strict;
use v5.10;
require MIME::Base64;
use File::Path;
AddModuleDescription('thumbs.pl', 'Image Thumbnails');
our ($q, $OpenPageName, %IndexHash, @UploadTypes, @MyRules, $FreeLinkPattern);
# Tempoary directory to create thumbnails in
our $ThumbnailTempDir = '/tmp';
# Path and name of external program to use to create thumbnails. Only
# ImageMagick 'convert' can be used. You may have to set the MAGICK_HOME
# environment variable in your config file if you set it to
# /usr/local/bin/convert and get the following error:
# convert: no decode delegate for this image format
# For your config file:
# $ENV{MAGICK_HOME} = '/usr/local';
our $ThumbnailConvert = '/usr/bin/convert';
# Max size for a thumbnail. If larger size is specified just shows
# regular image
our $ThumbnailMaxSize = 500;
# Default thumbnail size if non is specified
our $ThumbnailDefaultSize = 100;
# MIME types to create thumbnail for, all allowed if empty list
our @ThumbnailTypes = @UploadTypes;
# As well as using ALT, use TITLE. This enables comments to popup when
# hovering mouse over thumbnail
our $ThumbnailImageUseTitle = 0;
our $ThumbnailCacheDir = "oddmuse_thumbnail_cache";
our $ThumbnailCacheUrl = "/oddmuse_thumbnail_cache";
# Define new formatting rule "thumb" that inserts an auto generated thumbnail
# Syntax is [[thumb:page name | etc. ]]
push(@MyRules, \&ThumbNailSupportRule);
sub ThumbNailSupportRule {
my $result;
my $RawMatch;
if (m!\G(\[\[thumb:$FreeLinkPattern(\|.*?)?\]\])!cg)
{
$RawMatch = $1;
# Try and extract out all the options. They can be in any order, apart from comment at end
my $name = $2;
my $size="$ThumbnailDefaultSize"; # default size for thumbnail
my $frame;
my $comment; # default alignment for a non framed picture
my $alignment_framed = 'tright'; # default alignment for a framed picture
my $alignment;
my $params = $3 . '|';
if($params =~ s/\|([0-9]+)px\|/\|/) { $size = $1; }
if($params =~ s/\|thumb\|/\|/) { $frame = 'yes' ;}
if($params =~ s/\|frame\|/\|/) { $frame = 'yes'; }
if ($params =~ s/\|none\|/\|/) { $alignment_framed= 'tnone'; }
if ($params =~ s/\|right\|/\|/) { $alignment_framed= 'tright'; $alignment='floatright';}
if ($params =~ s/\|left\|/\|/) { $alignment_framed= 'tleft'; $alignment='floatleft'; }
if ($params =~ m/\|(.+)\|$/) { $comment = $1; }
my $id = FreeToNormal($name);
AllPagesList();
# if the page does exists
if ($IndexHash{$id})
{
if (!IsFile("$ThumbnailCacheDir/$id/$size"))
{
GenerateThumbNail ($id, $size);
}
my %img_attribs;
my $action = "$ThumbnailCacheUrl/" . UrlEncode($id) . "/$size";
$img_attribs{'-src'} = $action;
if (defined $comment) {
$img_attribs{'-alt'} ="$comment";
$img_attribs{'-title'} = "$comment" if $ThumbnailImageUseTitle==1;
}
else { $img_attribs{'-alt'} = "$name"; }
$img_attribs{'-class'} = 'upload';
$result = $q->img(\%img_attribs);
$result = ScriptLink(UrlEncode($id) , $result, 'image');
if (defined $frame) {
if (defined $comment) { $result = $result . $q->div({-class=>'thumbcaption'}, "$comment"); }
if ($size>0) {
$result = $q->div({-style=>"width:" . ($size+2) . "px"}, $result);
$result = $q->div({-class=>"thumb " . $alignment_framed}, $result);
}
}
else
{
if (defined $alignment) { $result = $q->div({-class=>"$alignment" }, $result); }
}
}
else
{
# if the image does not exist
$result = '[' . T('thumb') . ':' . $name . GetEditLink($id, '?', 1) . ']';
}
}
if (defined $result)
{
Dirty($RawMatch);
print $result;
$result = '';
}
return $result;
}
# define new action "thumbnail" that actually does the on fly generation of the image
# thumbnails are put into the file so they only need be generated once
# we also store the size of thumbnail so that can be used in the markup
# 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
# this enbles markup for non-thumbnail images better
sub GenerateThumbNail {
my ($id, $size) = (@_);
ValidIdOrDie($id);
AllPagesList();
if (not $IndexHash{$id}) { ReportError(Ts('Error creating thumbnail from nonexisting page %s.' , $id), '500 INTERNAL SERVER ERROR'); } # Page Doesn't exist,
my $openpage = $OpenPageName; # remember the current page we are on
RequestLockOrError();
OpenPage($id);
# Parse out some data
# Check MIME type supported
# Check is a file
my $text = GetTextRevision(GetParam('revision', ''))->{text}; # maybe revision reset!
my ($type) = TextIsFile($text); # MIME type if an uploaded file
my $data = substr($text, index($text, "\n") + 1);
if ($type)
{
my $regexp = quotemeta($type);
if (@ThumbnailTypes and not grep(/^$regexp$/, @ThumbnailTypes)) {
ReportError(Ts('Can not create thumbnail for file type %s.' , $type), '415 UNSUPPORTED MEDIA TYPE');
}
}
else
{
ReportError(T('Can not create thumbnail for a text document'), '500 INTERNAL SERVER ERROR');
}
my $filename = $ThumbnailTempDir . "/odd" . $id . "_" . $size;
# Decode the original image to a temp file
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');
binmode($FD);
print $FD MIME::Base64::decode($data);
close($FD);
eval { mkpath("$ThumbnailCacheDir/$id") };
if ($@) {
ReportError(Ts('Can not create path for thumbnail - %s', $@), '500 INTERNAL SERVER ERROR');
}
# create the thumbnail
my $command = "$ThumbnailConvert '$filename' -verbose -resize ${size}x '$ThumbnailCacheDir/$id/$size' 2>&1";
open (my $MESSAGE, '-|', $command)
or ReportError(Tss("Failed to run %1 to create thumbnail: %2", $ThumbnailConvert, $!),
'500 INTERNAL SERVER ERROR');
my $convert = <$MESSAGE>;
close($MESSAGE);
my $scaled_size_x;
my $scaled_size_y;
my $thumbnail_data= '';
if($?) {
ReportError(Ts("%s ran into an error", $ThumbnailConvert), '500 INTERNAL SERVER ERROR', undef,
$q->pre($command . "\n" . $convert));
} elsif($convert =~ m/=>(\d+)x(\d+)/) {
$scaled_size_x = $1;
$scaled_size_y = $2;
} elsif (!$convert) {
ReportError(Ts("%s produced no output", $ThumbnailConvert), '500 INTERNAL SERVER ERROR');
} else {
ReportError(Ts("Failed to parse %s.", $convert), '500 INTERNAL SERVER ERROR');
}
Unlink($filename);
# save tag to page
#$Page{'thumbnail_' . $size} = '#FILE ' . $type . ' created=' . $Now . ' revision=' . $Page{'revision'} . ' size=' . $scaled_size_x . 'x' . $scaled_size_y . "\n" . $thumbnail_data;
#SavePage();
ReleaseLock();
OpenPage($openpage); # restore original open page
}