2012-06-14 10:21:40 +02:00
# Copyright (C) 2004, 2012 Alex Schroeder <alex@gnu.org>
2012-06-14 08:39:25 +02:00
# 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"
2015-03-27 03:01:01 +02:00
use strict ;
2012-06-14 08:39:25 +02:00
require MIME::Base64 ;
use File::Path ;
2014-08-21 22:23:23 +02:00
AddModuleDescription ( 'thumbs.pl' , 'Image Thumbnails' ) ;
2012-06-14 08:39:25 +02:00
2015-04-10 13:31:28 +03:00
our ( $ q , $ OpenPageName , % IndexHash , @ UploadTypes , @ MyRules , $ FreeLinkPattern ) ;
2015-03-27 03:01:01 +02:00
2012-06-14 08:39:25 +02:00
# Tempoary directory to create thumbnails in
2015-03-27 03:01:01 +02:00
our $ ThumbnailTempDir = '/tmp' ;
2012-06-14 08:39:25 +02:00
# Path and name of external program to use to create thumbnails. Only
2012-06-14 10:04:54 +02:00
# 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';
2015-03-27 03:01:01 +02:00
our $ ThumbnailConvert = '/usr/bin/convert' ;
2012-06-14 08:39:25 +02:00
# Max size for a thumbnail. If larger size is specified just shows
# regular image
2015-03-27 03:01:01 +02:00
our $ ThumbnailMaxSize = 500 ;
2012-06-14 08:39:25 +02:00
# Default thumbnail size if non is specified
2015-03-27 03:01:01 +02:00
our $ ThumbnailDefaultSize = 100 ;
2012-06-14 08:39:25 +02:00
# MIME types to create thumbnail for, all allowed if empty list
2015-03-27 03:01:01 +02:00
our @ ThumbnailTypes = @ UploadTypes ;
2012-06-14 08:39:25 +02:00
# As well as using ALT, use TITLE. This enables comments to popup when
# hovering mouse over thumbnail
2015-03-27 03:01:01 +02:00
our $ ThumbnailImageUseTitle = 0 ;
2012-06-14 08:39:25 +02:00
2015-03-27 03:01:01 +02:00
our $ ThumbnailCacheDir = "oddmuse_thumbnail_cache" ;
our $ ThumbnailCacheUrl = "/oddmuse_thumbnail_cache" ;
2012-06-14 08:39:25 +02:00
# 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(\|.*?)?\]\])!g c )
{
$ 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
2015-04-17 01:43:19 +03:00
2012-06-14 08:39:25 +02:00
if ( $ IndexHash { $ id } )
{
if ( ! - e "$ThumbnailCacheDir/$id/$size" )
2015-04-17 01:39:47 +03:00
{
GenerateThumbNail ( $ id , $ size ) ;
2012-06-14 08:39:25 +02:00
}
2015-04-17 01:43:19 +03:00
2012-06-14 08:39:25 +02:00
my % img_attribs ;
2015-04-17 01:39:47 +03:00
my $ action = "$ThumbnailCacheUrl/" . UrlEncode ( $ id ) . "/$size" ;
2015-04-17 01:45:11 +03:00
2012-06-14 08:39:25 +02:00
$ img_attribs { '-src' } = $ action ;
2015-04-17 01:39:47 +03:00
if ( defined $ comment ) {
2012-06-14 08:39:25 +02:00
$ img_attribs { '-alt' } = "$comment" ;
$ img_attribs { '-title' } = "$comment" if $ ThumbnailImageUseTitle == 1 ;
2015-04-17 01:39:47 +03:00
}
2012-06-14 08:39:25 +02:00
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" ) ; }
2015-04-17 01:45:11 +03:00
2012-06-14 08:39:25 +02:00
if ( $ size > 0 ) {
2015-04-17 01:39:47 +03:00
$ result = $ q - > div ( { - style = > "width:" . ( $ size + 2 ) . "px" } , $ result ) ;
2012-06-14 08:39:25 +02:00
$ 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 ) . ']' ;
}
}
2015-04-17 01:39:47 +03:00
if ( defined $ result )
{
Dirty ( $ RawMatch ) ;
2012-06-14 08:39:25 +02:00
print $ result ;
2015-04-17 01:45:11 +03:00
2012-06-14 08:39:25 +02:00
$ result = '' ;
}
return $ result ;
2015-04-17 01:43:19 +03:00
2012-06-14 08:39:25 +02:00
}
# 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 {
2015-04-17 01:39:47 +03:00
my ( $ id , $ size ) = ( @ _ ) ;
2012-06-14 08:39:25 +02:00
ValidIdOrDie ( $ id ) ;
AllPagesList ( ) ;
2015-04-17 01:43:19 +03:00
2012-06-14 08:39:25 +02:00
if ( not $ IndexHash { $ id } ) { ReportError ( Ts ( 'Error creating thumbnail from non existant page %s.' , $ id ) , '500 INTERNAL SERVER ERROR' ) ; } # Page Doesn't exist,
my $ openpage = $ OpenPageName ; # remember the current page we are on
2015-04-17 01:43:19 +03:00
RequestLockOrError ( ) ;
2012-06-14 08:39:25 +02:00
OpenPage ( $ id ) ;
# Parse out some data
# Check MIME type supported
# Check is a file
my ( $ text , $ revision ) = GetTextRevision ( GetParam ( 'revision' , '' ) ) ; # maybe revision reset!
2012-06-14 10:04:54 +02:00
my ( $ type ) = TextIsFile ( $ text ) ; # MIME type if an uploaded file
my $ data = substr ( $ text , index ( $ text , "\n" ) + 1 ) ;
2012-06-14 08:39:25 +02:00
2012-06-14 10:04:54 +02:00
if ( $ type )
2012-06-14 08:39:25 +02:00
{
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
2015-05-02 03:19:25 +03:00
open ( my $ FD , '>' , $ 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 ) ;
2012-06-14 08:39:25 +02:00
eval { mkpath ( "$ThumbnailCacheDir/$id" ) } ;
if ( $@ ) {
ReportError ( Ts ( 'Can not create path for thumbnail - %s' , $@ ) , '500 INTERNAL SERVER ERROR' ) ;
}
# create the thumbnail
2012-06-14 10:04:54 +02:00
my $ command = "$ThumbnailConvert '$filename' -verbose -resize ${size}x '$ThumbnailCacheDir/$id/$size' 2>&1" ;
2015-05-02 03:49:07 +03:00
open ( my $ MESSAGE , '-|' , $ command )
2012-06-14 10:04:54 +02:00
or ReportError ( Tss ( "Failed to run %1 to create thumbnail: %2" , $ ThumbnailConvert , $! ) ,
'500 INTERNAL SERVER ERROR' ) ;
2012-06-14 08:39:25 +02:00
2015-05-02 03:49:07 +03:00
my $ convert = <$MESSAGE> ;
close ( $ MESSAGE ) ;
2012-06-14 10:04:54 +02:00
2012-06-14 08:39:25 +02:00
my $ scaled_size_x ;
my $ scaled_size_y ;
2012-06-14 10:04:54 +02:00
my $ thumbnail_data = '' ;
2012-06-14 08:39:25 +02:00
2012-06-14 10:04:54 +02:00
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+)/ ) {
2012-06-14 08:39:25 +02:00
$ scaled_size_x = $ 1 ;
$ scaled_size_y = $ 2 ;
2012-06-14 10:04:54 +02:00
} elsif ( ! $ convert ) {
ReportError ( Ts ( "%s produced no output" , $ ThumbnailConvert ) , '500 INTERNAL SERVER ERROR' ) ;
2012-06-14 08:39:25 +02:00
} else {
2012-06-14 10:04:54 +02:00
ReportError ( Ts ( "Failed to parse %s." , $ convert ) , '500 INTERNAL SERVER ERROR' ) ;
2012-06-14 08:39:25 +02:00
}
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();
2015-04-17 01:43:19 +03:00
2012-06-14 08:39:25 +02:00
ReleaseLock ( ) ;
OpenPage ( $ openpage ) ; # restore original open page
}