From d3c8d55b4f2598bf8232642796c2a0e8c1b8cfcd Mon Sep 17 00:00:00 2001 From: Don Armstrong Date: Wed, 16 Mar 2011 15:57:38 +0000 Subject: [PATCH] [svn-inject] Installing original source of libapache-gallery-perl (0.99-svn060811) git-svn-id: file:///srv/don_svn/deb_pkgs/libapache-gallery-perl/branches/upstream/current@533 8f7917da-ec0b-0410-a553-b9b0e350d17e --- Changes | 218 +++ INSTALL | 117 ++ LICENSE | 5 + MANIFEST | 79 ++ META.yml | 18 + Makefile.PL | 21 + README | 316 +++++ TODO | 24 + UPGRADE | 121 ++ htdocs/agfolder.png | Bin 0 -> 2946 bytes htdocs/application-doc.png | Bin 0 -> 3592 bytes htdocs/application-pdf.png | Bin 0 -> 3541 bytes htdocs/application-rtf.png | Bin 0 -> 3391 bytes htdocs/c.png | Bin 0 -> 1829 bytes htdocs/sound-mp3.png | Bin 0 -> 3902 bytes htdocs/sound-ogg.png | Bin 0 -> 4063 bytes htdocs/sound-wav.png | Bin 0 -> 3159 bytes htdocs/video-asf.png | Bin 0 -> 4309 bytes htdocs/video-avi.png | Bin 0 -> 4284 bytes htdocs/video-mov.png | Bin 0 -> 4330 bytes htdocs/video-mpeg.png | Bin 0 -> 3512 bytes htdocs/video-mpg.png | Bin 0 -> 4271 bytes htdocs/video-wmv.png | Bin 0 -> 4009 bytes lib/Apache/Gallery.pm | 1878 ++++++++++++++++++++++++++ t/001_use.t | 5 + t/002_graphlibs.t | 28 + t/002_injpg.jpg | Bin 0 -> 396 bytes t/002_inpng.png | Bin 0 -> 500 bytes t/003_comment.t | 8 + t/003_commenttest | 2 + t/004_cache_dir.t | 58 + t/005_imageinfo.t | 17 + t/005_jpg.jpg | Bin 0 -> 396 bytes t/006_thumbnails.t | 24 + t/007_pod.t | 19 + templates/bright/README | 9 + templates/bright/dircomment.tpl | 11 + templates/bright/directory.tpl | 1 + templates/bright/error.tpl | 22 + templates/bright/file.tpl | 1 + templates/bright/gallery.css | 128 ++ templates/bright/index.tpl | 23 + templates/bright/info.tpl | 1 + templates/bright/interval.tpl | 1 + templates/bright/intervalactive.tpl | 1 + templates/bright/layout.tpl | 18 + templates/bright/navpicture.tpl | 1 + templates/bright/nodircomment.tpl | 0 templates/bright/nopictureinfo.tpl | 0 templates/bright/orig.tpl | 1 + templates/bright/picture.tpl | 1 + templates/bright/pictureinfo.tpl | 5 + templates/bright/refresh.tpl | 1 + templates/bright/scale.tpl | 1 + templates/bright/scaleactive.tpl | 1 + templates/bright/showpicture.tpl | 38 + templates/bright/slideshowisoff.tpl | 1 + templates/bright/slideshowoff.tpl | 1 + templates/default/dircomment.tpl | 11 + templates/default/directory.tpl | 1 + templates/default/error.tpl | 9 + templates/default/file.tpl | 1 + templates/default/gallery.css | 66 + templates/default/index.tpl | 23 + templates/default/info.tpl | 1 + templates/default/interval.tpl | 1 + templates/default/intervalactive.tpl | 1 + templates/default/layout.tpl | 14 + templates/default/navpicture.tpl | 1 + templates/default/nodircomment.tpl | 0 templates/default/nopictureinfo.tpl | 11 + templates/default/orig.tpl | 1 + templates/default/picture.tpl | 1 + templates/default/pictureinfo.tpl | 12 + templates/default/refresh.tpl | 1 + templates/default/scale.tpl | 1 + templates/default/scaleactive.tpl | 1 + templates/default/showpicture.tpl | 33 + templates/default/slideshowisoff.tpl | 1 + templates/default/slideshowoff.tpl | 1 + templates/new/dircomment.tpl | 11 + templates/new/directory.tpl | 1 + templates/new/error.tpl | 22 + templates/new/file.tpl | 1 + templates/new/gallery.css | 78 ++ templates/new/index.tpl | 23 + templates/new/info.tpl | 1 + templates/new/interval.tpl | 1 + templates/new/intervalactive.tpl | 1 + templates/new/layout.tpl | 14 + templates/new/navpicture.tpl | 1 + templates/new/nodircomment.tpl | 0 templates/new/nopictureinfo.tpl | 11 + templates/new/orig.tpl | 1 + templates/new/picture.tpl | 1 + templates/new/pictureinfo.tpl | 8 + templates/new/refresh.tpl | 1 + templates/new/scale.tpl | 1 + templates/new/scaleactive.tpl | 1 + templates/new/showpicture.tpl | 30 + templates/new/slideshowisoff.tpl | 1 + templates/new/slideshowoff.tpl | 1 + 102 files changed, 3627 insertions(+) create mode 100644 Changes create mode 100644 INSTALL create mode 100644 LICENSE create mode 100644 MANIFEST create mode 100644 META.yml create mode 100644 Makefile.PL create mode 100644 README create mode 100644 TODO create mode 100644 UPGRADE create mode 100644 htdocs/agfolder.png create mode 100644 htdocs/application-doc.png create mode 100644 htdocs/application-pdf.png create mode 100644 htdocs/application-rtf.png create mode 100644 htdocs/c.png create mode 100644 htdocs/sound-mp3.png create mode 100644 htdocs/sound-ogg.png create mode 100644 htdocs/sound-wav.png create mode 100644 htdocs/video-asf.png create mode 100644 htdocs/video-avi.png create mode 100644 htdocs/video-mov.png create mode 100644 htdocs/video-mpeg.png create mode 100644 htdocs/video-mpg.png create mode 100644 htdocs/video-wmv.png create mode 100644 lib/Apache/Gallery.pm create mode 100644 t/001_use.t create mode 100644 t/002_graphlibs.t create mode 100644 t/002_injpg.jpg create mode 100644 t/002_inpng.png create mode 100644 t/003_comment.t create mode 100644 t/003_commenttest create mode 100644 t/004_cache_dir.t create mode 100644 t/005_imageinfo.t create mode 100644 t/005_jpg.jpg create mode 100644 t/006_thumbnails.t create mode 100644 t/007_pod.t create mode 100644 templates/bright/README create mode 100644 templates/bright/dircomment.tpl create mode 100644 templates/bright/directory.tpl create mode 100644 templates/bright/error.tpl create mode 100644 templates/bright/file.tpl create mode 100644 templates/bright/gallery.css create mode 100644 templates/bright/index.tpl create mode 100644 templates/bright/info.tpl create mode 100644 templates/bright/interval.tpl create mode 100644 templates/bright/intervalactive.tpl create mode 100644 templates/bright/layout.tpl create mode 100644 templates/bright/navpicture.tpl create mode 100644 templates/bright/nodircomment.tpl create mode 100644 templates/bright/nopictureinfo.tpl create mode 100644 templates/bright/orig.tpl create mode 100644 templates/bright/picture.tpl create mode 100644 templates/bright/pictureinfo.tpl create mode 100644 templates/bright/refresh.tpl create mode 100644 templates/bright/scale.tpl create mode 100644 templates/bright/scaleactive.tpl create mode 100644 templates/bright/showpicture.tpl create mode 100644 templates/bright/slideshowisoff.tpl create mode 100644 templates/bright/slideshowoff.tpl create mode 100644 templates/default/dircomment.tpl create mode 100644 templates/default/directory.tpl create mode 100644 templates/default/error.tpl create mode 100644 templates/default/file.tpl create mode 100644 templates/default/gallery.css create mode 100644 templates/default/index.tpl create mode 100644 templates/default/info.tpl create mode 100644 templates/default/interval.tpl create mode 100644 templates/default/intervalactive.tpl create mode 100644 templates/default/layout.tpl create mode 100644 templates/default/navpicture.tpl create mode 100644 templates/default/nodircomment.tpl create mode 100644 templates/default/nopictureinfo.tpl create mode 100644 templates/default/orig.tpl create mode 100644 templates/default/picture.tpl create mode 100644 templates/default/pictureinfo.tpl create mode 100644 templates/default/refresh.tpl create mode 100644 templates/default/scale.tpl create mode 100644 templates/default/scaleactive.tpl create mode 100644 templates/default/showpicture.tpl create mode 100644 templates/default/slideshowisoff.tpl create mode 100644 templates/default/slideshowoff.tpl create mode 100644 templates/new/dircomment.tpl create mode 100644 templates/new/directory.tpl create mode 100644 templates/new/error.tpl create mode 100644 templates/new/file.tpl create mode 100644 templates/new/gallery.css create mode 100644 templates/new/index.tpl create mode 100644 templates/new/info.tpl create mode 100644 templates/new/interval.tpl create mode 100644 templates/new/intervalactive.tpl create mode 100644 templates/new/layout.tpl create mode 100644 templates/new/navpicture.tpl create mode 100644 templates/new/nodircomment.tpl create mode 100644 templates/new/nopictureinfo.tpl create mode 100644 templates/new/orig.tpl create mode 100644 templates/new/picture.tpl create mode 100644 templates/new/pictureinfo.tpl create mode 100644 templates/new/refresh.tpl create mode 100644 templates/new/scale.tpl create mode 100644 templates/new/scaleactive.tpl create mode 100644 templates/new/showpicture.tpl create mode 100644 templates/new/slideshowisoff.tpl create mode 100644 templates/new/slideshowoff.tpl diff --git a/Changes b/Changes new file mode 100644 index 0000000..9e221e4 --- /dev/null +++ b/Changes @@ -0,0 +1,218 @@ +$Author: mil $ $Rev: 308 $ +$Date: 2005-09-16 11:52:59 +0300 (Fri, 16 Sep 2005) $ + +Revision history for Perl extension Apache::Gallery. + + - Handle files that match both GalleryDocFile and GalleryImgFile + correctly. (Claus Faerber) + +1.0RC3 Fri Sep 16 10:27:48 CEST 2005 + + - Add watermark even when picture doesn't need to be rescaled + (Andreas Plesner) + - Fix logging to work in Apache 1.3 (Andreas Plesner) + - Bugfix: If only one GallerySize was specified, the image's + max width was autmatically added to GallerySizes + (Andreas Plesner) + - Bugfix: Locate thm files if they are called .thm or .THM + (Michael Legart) + +1.0RC2 Wed Jun 1 09:11:50 CEST 2005 + + - Added access keys for navigation (Michael Knudsen) + +1.0RC1 Tue May 24 13:31:50 CEST 2005 + + - Added submit button to form in selection mode (Vlad Marchenko) + - Added new option GalleryRootPath for use when the gallery + is not running from the root of the virtual host (Lubomir Host) + - Report proper errors when there are problems with templates (Don Armstrong) + - Support newest mod_perl2 version (Philip Paeps) + +0.9.1 Sat Sep 11 23:52:16 CEST 2004 + + - Fix mod_perl 1 support that was broken with 0.9 (Michael Legart) + +0.9 Sat Sep 11 22:03:20 CEST 2004 + + - Handle .thm for all filetypes and not just tiff, gif and png + (Michael Legart) + - Make GallerySortBy work for directories (Michael Legart) + - Make GalleryDirSortBy override GallerySortBy for directories + (Andreas Plesner) + - Report 404 for HEAD requests to non-existing files or directories + (Michael Legart) + - Scale images when they are requested from the cache instead of + before the index is displayed. (Michael Legart) + - Sort pictures the same way when viewing images as when viewing + directories (Andreas Plesner) + - Make the "back" link on the error page work in IE (Michael Legart) + - Fixed the TITLE tag for folder comments (Ondra Kudlik) + - New option GalleryUnderscoresToSpaces to convert underscores to + spaces in the listing of directories. (Ondra Kudlik) + - Bugfix for when running outside a virtual host (Jeffrey Hartmann) + - Support Apache2 on FreeBSD (Jesper Dalberg) + - Avoid false 404 errors when running under mod_perl 2 (Tom Brown) + +0.8 Sun Mar 7 11:22:00 CET 2004 + + - Remember choosen width by setting a cookie (Rene Joergensen) + - Fixed a bug where $EXIFVALUES was left blank if a picture + had a comment. (Michael Legart) + - Fixed a bug where one line comments was showed as $COMMENT + (Jesper Skriver) + - Fixed a bug where comments did not get shown when using + the variables exif mode (Thomas L. Kjeldsen) + - Added two new configuration options GalleryDocFile and + GalleryImgFile that makes it possible to configured which + filetypes should be displayed. See the documentation for + details. (Guillaume Rousse) + - Added new option GalleryThumbnailSizeLS. If set to 1, + GalleryThumbnailSize is the long and the short side + of the thumbnail image instead of the width and height. + (Don Armstrong) + - Switched to use Text::Template instead of CGI::FastTemplate, + see the UPGRADE file for details. (Don Armstrong) + - Create copyright notices on pictures using truetype fonts + instead of png images. Font, color and size can be configured + (Thomas Petersen, Michael Legart) + +0.7 Mon Sep 8 22:30:35 CEST 2003 + + - Support mod_perl version 1 and 2 (1.99) (Michael Legart) + - Send status code 500 on errors, 404 on file not found and + make IE show our own errorpage. (Thomas L. Kjeldsen) + - Bugfix for directories named "0" (Andreas Plesner Jacobsen) + - Added "selection mode". Select images with checkboxes and + get a list of filenames. (Peter Andreasen) + - Fix to let the module work with perl 5.005 (Aaron) + - Do not allow scaling pictures to sizes above their + original size (Aaron) + - Added GalleryUseFileDate option to make A::G show + the files timestamps instead of using the EXIF value (Dennis Haney) + - Remember display size when turning Slideshow off (Hans Joergensen) + - Nice new layout (Thomas Kjaer) + - New option GalleryEXIFMode to control the way EXIF + info is displayed. See docs for details (Michael Legart) + - Support for the FNumber EXIF value (Thomas Corell) + - Added GalleryRootText option to allow changing the name of + the root element in the menu (Christopher Knight) + - Use Image::Imlib2 instead of Inline::C (Andreas Plesner Jacobsen) + - New option GalleryMaxThumbnailsPerPage to limit the number + of thumbnails displayed per page. Disabled by default + and requires templates update. (Michael Legart) + - Bugfix for the GalleryThumbnailSize option. Both height and + width max sizes are now obeyed. (David Gee) + +0.6 Tue Apr 22 10:24:40 CEST 2003 + + - Apache now internally handles image dispatch which enables + use of all Apache caching possibilities (Thomas Eibner) + - Documentation and better implementation of the .folder + feature. (Jesper Skriver) + - Support the EXIF Orientation key for automatic rotate, + if your camera supports that - like Canon G3. You can + disable this by setting GalleryAutoRotate to 0 (Me) + - Works with Inline > 0.42 (Andreas Plesner) + - Show nice icons and allow downloads for doc,mp3,ogg,rtf,wav + and wmv in addition to the current movie types (Me) + - Now displays nice values for Aperture,FocalLength,ShutterSpeed + exif values (Thomas Eibner) + - Directory comments added (Hans Joergensen) + - New GallerySortBy option to allow sort by time, size etc (Iain Wade) + - Set width/height on thumbnail images for better performance (Iain Wade) + +0.5.1 Sat Nov 9 11:49:29 CET 2002 + + - InlineDir is no longer configurable using PerlSetVar, which + fixes make test. (Me) + - Added test-suite (Me, Andreas Plesner Jacobsen) + - Write to the error log if unable to open files in the cache (Me) + - cache_dir changed to use File::Spec to make Apache::Gallery + more portable. It may even run under Windows now? (Andreas Plesner Jacobsen) + +0.5 Sun Sep 15 11:55:56 CEST 2002 + + - Added slideshow feature (Me) + - Code cleanup (Me) + - Moved the cache to one single directory outside the webscope (Rene Joergensen) + - Allow user to customize the "No info found" message (Me) + +0.4.1 Sun Aug 11 17:48:09 CEST 2002 + + - URI Escape image URL in the size selection URLs. (Me) + - Fixed bug where .cache directory was not created when requesting images directly (Me) + - Don't allow scaling images more than their original size (Jan Chrillesen) + - Handle already rotated images correct (Jan Chrillesen, Me) + - Fix bug when rotating pictures and a .thm file was present (Thomas Eibner) + - Apache::Gallery now allows for regular files to be served correctly (Thomas Eibner) + - Support for detailed flash information from Image::Info 1.11 (Me, Allan Joergensen) + - Moved Apache::Gallery into subversion revision control instead of CVS (Me) + +0.4 Sun Jun 2 13:11:09 CEST 2002 + + - Round height and width to integers when scaling to avoid + widths like 640x479.393939393939 (Me) + - Regenerate scaled pictures and thumbnails if the original + image has changed, the image.rotate file has been added or + changed or if the copyright image was added og changed. (Me) + - Don't show files starting with "." in the thumbnail index (Yann Kerhervé) + - Made thumbnailsizes configurable with the GalleryThumbnailSize + option. (Me) + - Print "Unknown" instead of $INFO in the imageinfo field if + unable to find any EXIF information. (Me) + - Added perldoc documentation of the module and a installationguide. (Me) + - Always list directories before images (Me) + - Allow textfiles (ie, robots.txt) (Me) + - Fixed a bug where $FILES was printed instead of "Empty directory" + if directory contained unsupported files (.txt, .htaccess etc) (Me) + - New templates where folders doesn't get displayed one on each line (Thomas Kjaer) + - Works without a VirtualHost now (Does not use DocumentRoot) (Peter Breton) + - New option GalleryWrapNavigation to enable a new feature in the + pictureview where "Next" at the end displays the first picture etc + (Peter Breton/Me) + - New option AllowOriginal for the user to be able to download the + original picture, not enabled by default (Thomas Eibner) + - TIFF and PPM support (Thomas Eibner) + - Initial movie support - download movie clips (Rene Joergensen) + +0.3.1 Thu Jan 10 15:47:39 CET 2002 + + - Fixed a huge memoryleak. + +0.3 Wed Jan 2 00:25:21 CET 2002 + + - Made Inline dir configurable. (Tim Coleman) + - Made it configurable which information about the image + should be viewed. (Thomas Eibner) + - Added GallerySizes option. You can now choose which + resolutions the user can scale between. The Gallery + will not allow scaling to 641x480 if you only configured + 640x480. (To prevent evil people filling up your disk) (Me) + - Handle spaces in files and directories correct. + - Now possible to rotate pictures on the fly. (Thomas Eibner) + - Copyright picture can be included on each picture (Thomas Eibner) + - Comments for each picture changed to be in + picture.jpg.comments (Thomas Eibner) + - Scale thumbnails correct when images are rotated 90-degrees. (Me) + +0.2 Sun Oct 14 19:57:06 2001 + - addcomments.pl renamed to gallery-editcomments.pl + - Added "viewing picture X of Y" when viewing images + - Switched to using Imlib2 instead of GD. Apache::Gallery + now supports all the image formats Imlib2 supports. + - Added gallery-buildcache.pl script to generated thumbnails + (Usefull if your browser times out the first time you + visit a new gallery) + +0.1.1 Sat Sep 30 01:10:03 2001 + - Added src/addcomments.pl script for editing picture + comments. + + - Templates have been updated by Erwin Lansing and + Thomas Kjaer and are now much nicer by default! + +0.1 Mon Aug 20 19:38:31 2001 + - original version; created by h2xs 1.21 with options + -XA -n Apache::Gallery + diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..71369d4 --- /dev/null +++ b/INSTALL @@ -0,0 +1,117 @@ +Apache/Gallery version 1.0 +=========================== + +INSTALLATION + +Before you start installing Apache::Gallery you need to check +that you have the following installed: + +- Perl 5 (http://www.cpan.org/src/README.html) +- Apache (http://httpd.apache.org/) - 1.3.x or 2.x +- mod_perl (http://perl.apache.org/) - 1.x or 2.x (2.0.0 or newer) +- X11 libraries (ie, XFree86) +- Imlib2 (http://prdownloads.sourceforge.net/enlightenment/imlib2-1.0.3.tar.gz) + +Perl Modules: (Use http://search.cpan.org/ to find them) + +- URI::Escape +- Image::Info version 1.11. (NB NB NB: Version 1.12 is known to give problems) +- Image::Size +- Text::Template +- CGI (3.08) +- Image::Imlib2 (1.02) + +When installing Imlib2 from rpm, deb or other packages formats, remember +that you need the imlib2-dev package too. On Debian this can be installed +by running: + +apt-get install libimlib2-dev + +Then, to install Apache::Gallery run the following commands: + + perl Makefile.PL + make + export MOD_PERL_API_VERSION=2 # Only if you run mod_perl 2.0 + make test (optional) + make install + +If you use Apache 1.3 and mod_perl 1, you need to configure +your virtualhostblock to look like: + + + ServerName gallery.yourdomain.org + DocumentRoot /data/pictures/ + ErrorLog logs/gallery-error_log + TransferLog logs/gallery-access_log + PerlSetVar GalleryTemplateDir '/usr/local/apache/gallery/templates/default/' + PerlSetVar GalleryInfo 'Picture Taken => DateTimeOriginal, Flash => Flash' + PerlSetVar GallerySizes '640 1024 1600 2272' + PerlSetVar GalleryThumbnailSize '100x75' + PerlSetVar GalleryCopyrightImage 'htdocs/c.png' + + SetHandler perl-script + PerlHandler Apache::Gallery + + + +In case you run apache 2 and modperl 2 (or 1.99), it needs to look +like: + + + ServerName gallery.yourdomain.org + DocumentRoot /data/pictures/ + ErrorLog logs/gallery-error_log + TransferLog logs/gallery-access_log + PerlSetVar GalleryTemplateDir '/usr/local/apache/gallery/templates/default/' + PerlSetVar GalleryInfo 'Picture Taken => DateTimeOriginal, Flash => Flash' + PerlSetVar GallerySizes '640 1024 1600 2272' + PerlSetVar GalleryThumbnailSize '100x75' + PerlSetVar GalleryCopyrightImage 'htdocs/c.png' + PerlOptions +GlobalRequest + + SetHandler modperl + PerlResponseHandler Apache::Gallery + + + +Warning: Apache::Gallery does not work properly if mod_autoindex +is loaded by Apache. Indeed, mod_autoindex overrides Apache::Gallery +and does not let it display directory content. + +To check if your apache loads mod_autoindex, just look for this line +in httpd.conf: + +LoadModule autoindex_module /usr/lib/apache/1.3/mod_autoindex.so + +If this line is not commented, Apache::Gallery will only work when an +image is loaded directly. Whenever a directory listing is requested, +Apache will respond with the classic (and ugly) directory listing performed +by mod_autoindex. + +Copy the files from templates/ to where you pointed GalleryTemplateDir to. + +Create a directory called gallery in your Apache icons directory and +copy the png files in htdocs to this directory. + +The gallery.css file from the template directory you choose must be +copied to the DocumentRoot of your gallery. + +It is possible to include a graphical copyright notice on each picture now. +By setting the GalleryCopyrightImage PerlSetVar you can define the path +to a picture that you want include in the bottom right of each picture. + +Feel free to contact me with questions if you have problems setting up +Apache::Gallery. You can write to michael@legart.dk + +Make sure you try the latest version of the gallery from + before reporting bugs. + +If you are brave you can also download the latest snapshot +from http://svn.apachegallery.dk/snapshots/ + +If you have problems installing Apache::Gallery, please make +sure to run "make test" to see, what may be the problem. + +When reporting bugs please use this page and include the output from make test +in your bugreport: + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..dc8e7d2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,5 @@ +$Author: mil $ $Rev: 255 $ +$Date: 2004-04-12 20:49:02 +0300 (Mon, 12 Apr 2004) $ + +Apache::Gallery is free software and is released under the Artistic License. +See for details. diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..3043ef1 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,79 @@ +MANIFEST +INSTALL +Makefile.PL +TODO +LICENSE +README +Changes +lib/Apache/Gallery.pm +UPGRADE +htdocs/sound-ogg.png +htdocs/video-wmv.png +htdocs/video-asf.png +htdocs/video-mov.png +htdocs/application-pdf.png +htdocs/application-doc.png +htdocs/sound-mp3.png +htdocs/sound-wav.png +htdocs/application-rtf.png +htdocs/video-mpeg.png +htdocs/video-mpg.png +htdocs/video-avi.png +htdocs/c.png +htdocs/agfolder.png +t/002_inpng.png +t/005_jpg.jpg +t/002_graphlibs.t +t/001_use.t +t/006_thumbnails.t +t/002_injpg.jpg +t/004_cache_dir.t +t/003_comment.t +t/003_commenttest +t/005_imageinfo.t +t/007_pod.t +templates/default/dircomment.tpl +templates/default/directory.tpl +templates/default/error.tpl +templates/default/file.tpl +templates/default/index.tpl +templates/default/info.tpl +templates/default/interval.tpl +templates/default/intervalactive.tpl +templates/default/layout.tpl +templates/default/navpicture.tpl +templates/default/nodircomment.tpl +templates/default/nopictureinfo.tpl +templates/default/orig.tpl +templates/default/picture.tpl +templates/default/pictureinfo.tpl +templates/default/refresh.tpl +templates/default/scale.tpl +templates/default/scaleactive.tpl +templates/default/showpicture.tpl +templates/default/slideshowisoff.tpl +templates/default/slideshowoff.tpl +templates/default/gallery.css +templates/new/intervalactive.tpl +templates/new/dircomment.tpl +templates/new/directory.tpl +templates/new/error.tpl +templates/new/file.tpl +templates/new/index.tpl +templates/new/info.tpl +templates/new/interval.tpl +templates/new/navpicture.tpl +templates/new/layout.tpl +templates/new/gallery.css +templates/new/nodircomment.tpl +templates/new/nopictureinfo.tpl +templates/new/orig.tpl +templates/new/picture.tpl +templates/new/pictureinfo.tpl +templates/new/refresh.tpl +templates/new/scale.tpl +templates/new/scaleactive.tpl +templates/new/showpicture.tpl +templates/new/slideshowisoff.tpl +templates/new/slideshowoff.tpl +META.yml Module meta-data (added by MakeMaker) diff --git a/META.yml b/META.yml new file mode 100644 index 0000000..53e532e --- /dev/null +++ b/META.yml @@ -0,0 +1,18 @@ +# http://module-build.sourceforge.net/META-spec.html +#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# +name: Apache-Gallery +version: 1.0RC3 +version_from: lib/Apache/Gallery.pm +installdirs: site +requires: + CGI: 3.08 + File::Spec: 0 + Image::Imlib2: 1.02 + Image::Info: 0 + Image::Size: 0 + Test::More: 0 + Text::Template: 0 + URI: 1.23 + +distribution_type: module +generated_by: ExtUtils::MakeMaker version 6.17 diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..213b3bc --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,21 @@ +use ExtUtils::MakeMaker; +# $Id: Makefile.PL,v 1.7 2002/02/09 06:32:03 thomas Exp $ +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'NAME' => 'Apache::Gallery', + 'VERSION_FROM' => 'lib/Apache/Gallery.pm', # finds $VERSION + 'PREREQ_PM' => { + Image::Info => 0, + Image::Size => 0, + Image::Imlib2 => 1.02, + Text::Template => 0, + URI => 1.23, + CGI => 3.08, + Test::More => 0, + File::Spec => 0 + }, # e.g., Module::Name => 1.1 + ($] >= 5.005 ? ## Add these new keywords supported since 5.005 + (ABSTRACT_FROM => 'lib/Apache/Gallery.pm', # retrieve abstract from module + AUTHOR => 'Michael Legart ') : ()), +); diff --git a/README b/README new file mode 100644 index 0000000..5572fe3 --- /dev/null +++ b/README @@ -0,0 +1,316 @@ +NAME + Apache::Gallery - mod_perl handler to create an image gallery + +SYNOPSIS + See the INSTALL file in the distribution for installation instructions. + +DESCRIPTION + Apache::Gallery creates an thumbnail index of each directory and allows + viewing pictures in different resolutions. Pictures are resized on the + fly and cached. The gallery can be configured and customized in many + ways and a custom copyright image can be added to all the images without + modifying the original. + +CONFIGURATION + In your httpd.conf you set the global options for the gallery. You can + also override each of the options in .htaccess files in your gallery + directories. + + The options are set in the httpd.conf/.htaccess file using the syntax: + PerlSetVar OptionName 'value' + + Example: PerlSetVar GalleryCacheDir '/var/tmp/Apache-Gallery/' + + GalleryAutoRotate + Some cameras, like the Canon G3, can detect the orientation of a the + pictures you take and will save this information in the + 'Orientation' EXIF field. Apache::Gallery will then automatically + rotate your images. + + This behavior is default but can be disabled by setting + GalleryAutoRotate to 0. + + GalleryCacheDir + Directory where Apache::Gallery should create its cache with scaled + pictures. The default is /var/tmp/Apache-Gallery/ . Here, a + directory for each virtualhost or location will be created + automaticly. Make sure your webserver has write access to the + CacheDir. + + GalleryTemplateDir + Full path to the directory where you placed the templates. This + option can be used both in your global configuration and in + .htaccess files, this way you can have different layouts in + different parts of your gallery. + + No default value, this option is required. + + GalleryInfo + With this option you can define which EXIF information you would + like to present from the image. The format is: ' + KeyInEXIF, MyOtherName => OtherKeyInEXIF' + + Examples of keys: ShutterSpeedValue, ApertureValue, SubjectDistance, + and Camera + + You can view all the keys from the EXIF header using this + perl-oneliner: + + perl "-e" 'use Data::Dumper; use Image::Info qw(image_info); print + Dumper(image_info(shift));' filename.jpg + + Default is: 'Picture Taken => DateTimeOriginal, Flash => Flash' + + GallerySizes + Defines which widths images can be scaled to. Images cannot be + scaled to other widths than the ones you define with this option. + + The default is '640 800 1024 1600' + + GalleryThumbnailSize + Defines the width and height of the thumbnail images. + + Defaults to '100x75' + + GalleryThumbnailSizeLS + If set to '1', GalleryThumbnailSize is the long and the short side + of the thumbnail image instead of the width and height. + + Defaults to '0'. + + GalleryCopyrightImage + Image you want to blend into your images in the lower right corner. + This could be a transparent png saying "copyright my name 2001". + + Optional. + + GalleryWrapNavigation + Make the navigation in the picture view wrap around (So Next at the + end displays the first picture, etc.) + + Set to 1 or 0, default is 0 + + GalleryAllowOriginal + Allow the user to download the Original picture without resizing or + putting the CopyrightImage on it. + + Set to 1 or 0, default is 0 + + GallerySlideshowIntervals + With this option you can configure which intervals can be selected + for a slideshow. The default is '3 5 10 15 30' + + GallerySortBy + Instead of the default filename ordering you can sort by any stat + attribute. For example size, atime, mtime, ctime. + + GalleryDirSortBy + Set this variable to sort directories differently than other items, + can be set to size, atime, mtime and ctime; setting any other value + will revert to sorting by name. + + GalleryMemoize + Cache EXIF data using Memoize - this will make Apache::Gallery + faster when many people access the same images, but it will also + cache EXIF data until the current Apache child dies. + + GalleryUseFileDate + Set this option to 1 to make A::G show the files timestamp instead + of the EXIF value for "Picture taken". + + GallerySelectionMode + Enable the selection mode. Select images with checkboxes and get a + list of filenames. + + GalleryEXIFMode + You can choose how Apache::Gallery should display EXIF info from + your images. + + The default setting is 'namevalue'. This setting will make + Apache::Gallery print out the names and values of the EXIF values + you configure with GalleryInfo. The information will be parsed into + $INFO in pictureinfo.tpl. + + You can also set it to 'values' which will make A::G parse the + configured values into the var $EXIFVALUES as 'value | value | + value' + + If you set this option to 'variables' the items you configure in + GalleryInfo will be available to your templates as $EXIF_ + (in all uppercase). That means that with the default setting + "Picture Taken => DateTimeOriginal, Flash => Flash" you will have + the variables $EXIF_DATETIMEORIGINAL and $EXIF_FLASH avilable to + your templates. You can place them anywhere you want. + + GalleryRootPath + Change the location of gallery root. The default is "" + + GalleryRootText + Change the name that appears as the root element in the menu. The + default is "root:" + + GalleryMaxThumbnailsPerPage + This options controls how many thumbnails should be displayed in a + page. It requires $BROWSELINKS to be in the index.tpl template file. + + GalleryImgFile + Pattern matching the files you want Apache::Gallery to view in the + index as thumbnails. + + The default is '\.(jpe?g|png|tiff?|ppm)$' + + GalleryDocFile + Pattern matching the files you want Apache::Gallery to view in the + index as normal files. All other filetypes will still be served by + Apache::Gallery but are not visible in the index. + + The default is + '\.(mpe?g|avi|mov|asf|wmv|doc|mp3|ogg|pdf|rtf|wav|dlt|html?|csv|eps) + $' + + GalleryTTFDir + To use the GalleryCopyrightText feature you must set this option to + the directory where your True Type fonts are stored. No default is + set. + + Example: + + PerlSetVar GalleryTTFDir '/usr/share/fonts/' + + GalleryTTFFile + To use the GalleryCopyrightText feature this option must be set to + the name of the True Type font you wish to use. Example: + + PerlSetVar GalleryTTFFile 'verdanab.ttf' + + GalleryTTFSize + Configure the size of the CopyrightText that will be inserted as + copyright notice in the corner of your pictures. + + Example: + + PerlSetVar GalleryTTFSize '10' + + GalleryCopyrightText + The text that will be inserted as copyright notice. + + Example: + + PerlSetVar GalleryCopyrightText '(c) Michael Legart' + + GalleryCopyrightColor + The text color of your copyright notice. + + Examples: + + White: PerlSetVar GalleryCopyrightColor '255,255,255,255' + + Black: PerlSetVar GalleryCopyrightColor '0,0,0,255' + + Red: PerlSetVar GalleryCopyrightColor '255,0,0,255' + + Green: PerlSetVar GalleryCopyrightColor '0,255,0,255' + + Blue: PerlSetVar GalleryCopyrightColor '0,0,255,255' + + Transparent orange: PerlSetVar GalleryCopyrightColor '255,127,0,127' + + GalleryCopyrightBackgroundColor + The background-color of a GalleryCopyrightText + + r,g,b,a - for examples, see GalleryCopyrightColor + + GalleryQuality + The quality (1-100) of scaled images + + This setting affects the quality of the scaled images. Set this to a + low number to reduce the size of the scaled images. Remember to + clear out your cache if you change this setting. Quality seems to + default to 75, at least in the jpeg and png loader code in Imlib2 + 1.1.0. + + Examples: + + Quality at 50: PerlSetVar GalleryQuality '50' + + GalleryUnderscoresToSpaces + Set this option to 1 to convert underscores to spaces in the listing + of directory names. + +FEATURES + Rotate images + Some cameras, like the Canon G3, detects the orientation of a + picture and adds this info to the EXIF header. Apache::Gallery + detects this and automaticly rotates images with this info. + + If your camera does not support this, you can rotate the images + manually, This can also be used to override the rotate information + from a camera that supports that. You can also disable this behavior + with the GalleryAutoRotate option. + + To use this functionality you have to create file with the name of + the picture you want rotated appened with ".rotate". The file should + include a number where these numbers are supported: + + "1", rotates clockwise by 90 degree + "2", rotates clockwise by 180 degrees + "3", rotates clockwise by 270 degrees + + So if we want to rotate "Picture1234.jpg" 90 degrees clockwise we + would create a file in the same directory called + "Picture1234.jpg.rotate" with the number 1 inside of it. + + Comments + To include comments for a directory you create a .comment + file where the first line can contain "TITLE: New title" which will + be the title of the page, and a comment on the following lines. To + include comments for each picture you create files called + picture.jpg.comment where the first line can contain "TITLE: New + title" which will be the title of the page, and a comment on the + following lines. + + Example: + + TITLE: This is the new title of the page + And this is the comment.
+ And this is line two of the comment. + + The visible name of the folder is by default identical to the name + of the folder, but can be changed by creating a file + .folder with the visible name of the folder. + +DEPENDENCIES + Perl 5 + Apache with mod_perl + URI::Escape + Image::Info + Image::Size + Text::Template + Image::Imlib2 + X11 libraries (ie, XFree86) + Imlib2 Remember the -dev package when using rpm, deb or other package + formats! + +AUTHOR + Michael Legart + +COPYRIGHT AND LICENSE + Copyright (C) 2001-2005 Michael Legart + + Templates designed by Thomas Kjaer + + Apache::Gallery is free software and is released under the Artistic + License. See http://www.perl.com/language/misc/Artistic.html for + details. + + The video icons are from the GNOME project. http://www.gnome.org/ + +THANKS + Thanks to Thomas Kjaer for templates and design of + http://apachegallery.dk Thanks to Thomas Eibner and other for patches. + (See the Changes file) + +SEE ALSO + perl, mod_perl, Image::Imlib2, CGI::FastTemplate, Image::Info, and + Image::Size. + diff --git a/TODO b/TODO new file mode 100644 index 0000000..8b4f1e1 --- /dev/null +++ b/TODO @@ -0,0 +1,24 @@ +$Author: mil $ $Rev: 255 $ +$Date: 2004-04-12 20:49:02 +0300 (Mon, 12 Apr 2004) $ + +- Write a gallery-cleancache.pl script for removing entries in + the cache where the original picture has been removed. + +- /admin page to edit comments and .rotate file. (Cleanup in + .cache when changing rotation) + +- Write perlscript to make static html galleries. + +- Sort by the DateTimeOriginal part of the EXIF header + if possible + +- Make the template and imagesystem pluggable + +- Make scaling quality configurable + +- Thumbnails are to be generated in tmp files first, + then moved to the correct location. + +- Use imlib_create_cropped_scaled_image in resizepicture + +- Try to avoid running too many resize processes diff --git a/UPGRADE b/UPGRADE new file mode 100644 index 0000000..6c82631 --- /dev/null +++ b/UPGRADE @@ -0,0 +1,121 @@ +# $Author: mil $ $Rev: 297 $ +# $Date: 2005-06-07 10:50:49 +0300 (Tue, 07 Jun 2005) $ + +For users upgrading to 1.0 + +If you are using mod_perl2 version mod_perl-2.0 is now required. + +Also, CGI 3.08 is required if using mod_perl2. + +To enable access keys for navigation update the navpicture.tpl and +showpicture.tpl templates. + +For users upgrading from 0.7 to 0.8 + +You need to create new directory called gallery in Apaches +icons directory. Copy the png files from the htdocs dictory +to this new directory. + +For those of you with pre-existing templates, a simple + + cd templates; perl -pi -e 's/(? DateTimeOriginal, Flash => Flash' +PerlSetVar GallerySizes '640 1024 1600 2272' + +to your virtualhost. + diff --git a/htdocs/agfolder.png b/htdocs/agfolder.png new file mode 100644 index 0000000000000000000000000000000000000000..fe1180f1c4aff93da88b92d9e5da5d752601d9a6 GIT binary patch literal 2946 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 literal 0 HcmV?d00001 diff --git a/htdocs/application-doc.png b/htdocs/application-doc.png new file mode 100644 index 0000000000000000000000000000000000000000..e404f9ae664d6f8597d7b341575e883c488b1f92 GIT binary patch literal 3592 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 VY6Vu77##or002ovPDHLkV1n_;DpyBcW zh;LKVp#TAdFG5&BmhRubKODq~jEp?@;>C+aK&Fv_fq`LSVxkO4{N1~Ezh};z`2;9; zZsEd(kvcj$g2~CrXD?j1uoX+BSVTod*?<_!mMuF1q^<(ZiqX>2;=Xq6+E<{SC1ga3 z1vDW%$B_`=cESMA?k7;S=g9~&VOLkzz>ba%-A$V|J!x!gTuRMI0SF*`5u!73;zTzG z2M3wx=;%Yh00#xIQGI>AM?*t{5wb!*KR+2`W8;VA<>fcepFi(BckWyu*Z2;Wz)@Se zbg3OQP+oy@1t?iO`3E$KR+Lo>#hK?DiA9mrDjmz{f6dB1!!*k0!^W6|Ns9F zId|^dE1;b#f&BMqkqWmH24>Bg^{czP`wB2H*@4^>NVyx7lYT+XeF#;KVdv}DuYVmm za^&Uh+qb_!#e|?ah6gG4y#?YoP;pQx!VWe63)DaFumw6m0O5)dHVFv{V_-^G2d091 zz`#2SG6(^gtX=x`wfeK75f<8VzVjzbABkkFY88c)+YJjOyA1Hr?jN-up z6zQNy25~?h2S(Ip5IZ+F*C{9{NQRG(kL}5mCtp^sT=_&*RTUHn3{p~3+`t6nFn|7h z6qr85tgsdqILHPo8`aDg}UU@&%P5LPA2UAoD?Hq^GA}0fyB&Y>@&G zK)5P($Y>dHjo3LDMlVvOs!qJ_CC-ukb@WP-o1MXFu;~WWBn>H)!hTBad&qY z$5M8~0nnl9KpY8jByvIk7JI>WOz`~WJlfC*$h)J?d+7idw#019AW zzyrOiA_&qC5(B1wu$`b>kIPPE!+<4$CP+W1Bmuf*9W()>08n@UbMh)fL&LpL^LU`e z8wLOfAQlpelAoZg2MZvi)GrJy2DETg;y3}Q_<-dUP{hD;2q;&6{`?shxeTDX1!ONU z=k0*m9Tyh|PF1|(gX#!qO1}*Zl#8I$3rf{z&z=nj6*-_*7^o6Q%7Vh`>goa@ z&q6COeBc}!{~<6HJ^_}=+^}*OR{nyDEl?`$?d`n*jKCA%wx^sNH%ud_H~`gKpjI2S zDUAVu@?yYZ$iK9-R0mWK0@*h~EiMon7L6JttP7v6)Zyz{kg@uJF0nPV- z7S&_}fB>A9F$#b%3`Ni2UYvW9LdPDpSJ1KG?ZaQ%Y+Hp_i_P&@R{@lxpe;4zK9UrHJ`)2#0O5-eAz-Qt0;Up==g*&iwY9Z94DA^H z!WV&{Rs^Wu0xSx)gIZl9V6+47Z)lGBx@y&`d(g`N1gVAr1Q5Om0Rcm3%J~e9(K~q5 z!a7H)SW@Y52FU(KE-`K*wLFOi00BfOLPi0d0YCtaj`j{R01!Z<5i-aCK!5=NHtIK& TXVAP)yEG89d%p_b#`|sotnZC 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 literal 0 HcmV?d00001 diff --git a/htdocs/video-avi.png b/htdocs/video-avi.png new file mode 100644 index 0000000000000000000000000000000000000000..065f0b282211ce82bcffcb804dc60ade574c8c59 GIT binary patch literal 4284 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 E0m2Pm1ONa4 literal 0 HcmV?d00001 diff --git a/htdocs/video-mpeg.png b/htdocs/video-mpeg.png new file mode 100644 index 0000000000000000000000000000000000000000..b304989d9df779e7f19636d0cce2034eca23e588 GIT binary patch literal 3512 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 mjB3lQ{lfZtA@}>cq5lFf(jlmnN)*Nb00006J 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 BBk}+M literal 0 HcmV?d00001 diff --git a/htdocs/video-wmv.png b/htdocs/video-wmv.png new file mode 100644 index 0000000000000000000000000000000000000000..0dfce337062f1bab8cd0189905114e4c3a3c13e4 GIT binary patch literal 4009 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 P00000NkvXXu0mjf6+Dy^ literal 0 HcmV?d00001 diff --git a/lib/Apache/Gallery.pm b/lib/Apache/Gallery.pm new file mode 100644 index 0000000..d543fca --- /dev/null +++ b/lib/Apache/Gallery.pm @@ -0,0 +1,1878 @@ +package Apache::Gallery; + +# $Author: mil $ $Rev: 316 $ +# $Date: 2006-08-04 16:28:06 +0300 (Fri, 04 Aug 2006) $ + +use strict; + +use vars qw($VERSION); + +$VERSION = "1.0RC3"; + +BEGIN { + + if (exists($ENV{MOD_PERL_API_VERSION}) + and ($ENV{MOD_PERL_API_VERSION}==2)) { + require mod_perl2; + if ($mod_perl::VERSION >= 1.99 && $mod_perl::VERSION < 2.0) { + die "mod_perl 2.0.0 or later is now required"; + } + require Apache2::ServerRec; + require Apache2::RequestRec; + require Apache2::Log; + require APR::Table; + require Apache2::RequestIO; + require Apache2::SubRequest; + require Apache2::Const; + + Apache2::Const->import(-compile => 'OK','DECLINED','FORBIDDEN','NOT_FOUND'); + + $::MP2 = 1; + } else { + require mod_perl; + + require Apache; + require Apache::Constants; + require Apache::Request; + + Apache::Constants->import('OK','DECLINED','FORBIDDEN','NOT_FOUND'); + $::MP2 = 0; + } +} + +use Image::Info qw(image_info); +use Image::Size qw(imgsize); +use Image::Imlib2; +use Text::Template; +use File::stat; +use File::Spec; +use POSIX qw(floor); +use URI::Escape; +use CGI; +use CGI::Cookie; + +use Data::Dumper; + +# Regexp for escaping URI's +my $escape_rule = "^A-Za-z0-9\-_.!~*'()\/"; +my $memoized; + +sub handler { + + my $r = shift or Apache2::RequestUtil->request(); + + if ((not $memoized) and ($r->dir_config('GalleryMemoize'))) { + require Memoize; + Memoize::memoize('get_imageinfo'); + $memoized=1; + } + + $r->headers_out->{"X-Powered-By"} = "apachegallery.dk $VERSION - Hest design!"; + $r->headers_out->{"X-Gallery-Version"} = '$Rev: 316 $ $Date: 2006-08-04 16:28:06 +0300 (Fri, 04 Aug 2006) $'; + + my $filename = $r->filename; + $filename =~ s/\/$//; + my $topdir = $filename; + + # Just return the http headers if the client requested that + if ($r->header_only) { + + if (!$::MP2) { + $r->send_http_header; + } + + if (-f $filename or -d $filename) { + return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); + } + else { + return $::MP2 ? Apache2::Const::NOT_FOUND() : Apache::Constants::NOT_FOUND(); + } + } + + my $cgi = new CGI; + + # Handle selected images + if ($cgi->param('selection')) { + my @selected = $cgi->param('selection'); + my $content = join "
\n",@selected; + $r->content_type('text/html'); + $r->headers_out->{'Content-Length'} = length($content); + + if (!$::MP2) { + $r->send_http_header; + } + + $r->print($content); + return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); + } + + # Selectmode providing checkboxes beside all thumbnails + my $select_mode = $cgi->param('select'); + + # Let Apache serve icons without us modifying the request + if ($r->uri =~ m/^\/icons/i) { + return $::MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED(); + } + # Lookup the file in the cache and scale the image if the cached + # image does not exist + if ($r->uri =~ m/\.cache\//i) { + + my $filename = $r->filename().$r->path_info(); + $filename =~ s/\.cache//; + + $filename =~ m/\/(\d+)x(\d+)\-/; + my $image_width = $1; + my $image_height = $2; + + $filename =~ s/\/(\d+)x(\d+)\-//; + + my ($width, $height, $type) = imgsize($filename); + + my $imageinfo = get_imageinfo($r, $filename, $type, $width, $height); + + my $cached = scale_picture($r, $filename, $image_width, $image_height, $imageinfo); + + my $file = cache_dir($r, 0); + $file =~ s/\.cache//; + + my $subr = $r->lookup_file($file); + $r->content_type($subr->content_type()); + + if ($::MP2) { + $r->sendfile($file); + return Apache2::Const::OK(); + } + else { + $r->path_info(''); + $r->filename($file); + return Apache::Constants::DECLINED(); + } + + } + + my $uri = $r->uri; + $uri =~ s/\/$//; + + unless (-f $filename or -d $filename) { + show_error($r, 404, "404!", "No such file or directory: ".uri_escape($r->uri, $escape_rule)); + return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); + } + + my $doc_pattern = $r->dir_config('GalleryDocFile'); + unless ($doc_pattern) { + $doc_pattern = '\.(mpe?g|avi|mov|asf|wmv|doc|mp3|ogg|pdf|rtf|wav|dlt|html?|csv|eps)$' + } + my $img_pattern = $r->dir_config('GalleryImgFile'); + unless ($img_pattern) { + $img_pattern = '\.(jpe?g|png|tiff?|ppm)$' + } + + # Let Apache serve files we don't know how to handle anyway + if (-f $filename && $filename !~ m/$img_pattern/i) { + return $::MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED(); + } + + if (-d $filename) { + + unless (-d cache_dir($r, 0)) { + unless (create_cache($r, cache_dir($r, 0))) { + return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); + } + } + + my $tpl_dir = $r->dir_config('GalleryTemplateDir'); + + # Instead of reading the templates every single time + # we need them, create a hash of template names and + # the associated Text::Template objects. + my %templates = create_templates({layout => "$tpl_dir/layout.tpl", + index => "$tpl_dir/index.tpl", + directory => "$tpl_dir/directory.tpl", + picture => "$tpl_dir/picture.tpl", + file => "$tpl_dir/file.tpl", + comment => "$tpl_dir/dircomment.tpl", + nocomment => "$tpl_dir/nodircomment.tpl", + }); + + + + + my %tpl_vars; + + $tpl_vars{TITLE} = "Index of: $uri"; + $tpl_vars{META} = " "; + + unless (opendir (DIR, $filename)) { + show_error ($r, 500, $!, "Unable to access directory $filename: $!"); + return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); + } + + $tpl_vars{MENU} = generate_menu($r); + + $tpl_vars{FORM_BEGIN} = $select_mode?'

':''; + $tpl_vars{FORM_END} = $select_mode?'
':''; + + # Read, sort, and filter files + my @files = grep { !/^\./ && -f "$filename/$_" } readdir (DIR); + + @files=gallerysort($r, @files); + + my @downloadable_files; + + if (@files) { + # Remove unwanted files from list + my @new_files = (); + foreach my $picture (@files) { + + my $file = $topdir."/".$picture; + + if ($file =~ /$img_pattern/i) { + push (@new_files, $picture); + } + + if ($file =~ /$doc_pattern/i) { + push (@downloadable_files, $picture); + } + + } + @files = @new_files; + } + + # Read and sort directories + rewinddir (DIR); + my @directories = grep { !/^\./ && -d "$filename/$_" } readdir (DIR); + my $dirsortby; + if (defined($r->dir_config('GalleryDirSortBy'))) { + $dirsortby=$r->dir_config('GalleryDirSortBy'); + } else { + $dirsortby=$r->dir_config('GallerySortBy'); + } + if ($dirsortby && $dirsortby =~ m/^(size|atime|mtime|ctime)$/) { + @directories = map(/^\d+ (.*)/, sort map(stat("$filename/$_")->$dirsortby()." $_", @directories)); + } else { + @directories = sort @directories; + } + + closedir(DIR); + + + # Combine directories and files to one listing + my @listing; + push (@listing, @directories); + push (@listing, @files); + push (@listing, @downloadable_files); + + if (@listing) { + + my $filelist; + + my $file_counter = 0; + my $start_at = 1; + my $max_files = $r->dir_config('GalleryMaxThumbnailsPerPage'); + + if (defined($cgi->param('start'))) { + $start_at = $cgi->param('start'); + if ($start_at < 1) { + $start_at = 1; + } + } + + my $browse_links = ""; + if (defined($max_files)) { + + for (my $i=1; $i<=scalar(@listing); $i++) { + + my $from = $i; + + my $to = $i+$max_files-1; + if ($to > scalar(@listing)) { + $to = scalar(@listing); + } + + if ($start_at < $from || $start_at > $to) { + $browse_links .= "
$from - ".$to." "; + } + else { + $browse_links .= "$from - $to "; + } + + $i+=$max_files-1; + + } + + } + + $tpl_vars{BROWSELINKS} = $browse_links; + + DIRLOOP: + foreach my $file (@listing) { + + $file_counter++; + + if ($file_counter < $start_at) { + next; + } + + if (defined($max_files) && $file_counter > $max_files+$start_at-1) { + last DIRLOOP; + } + + my $thumbfilename = $topdir."/".$file; + + my $fileurl = $uri."/".$file; + + if (-d $thumbfilename) { + my $dirtitle = ''; + if (-e $thumbfilename . ".folder") { + $dirtitle = get_filecontent($thumbfilename . ".folder"); + } + + $dirtitle = $dirtitle ? $dirtitle : $file; + $dirtitle =~ s/_/ /g if $r->dir_config('GalleryUnderscoresToSpaces'); + + $tpl_vars{FILES} .= + $templates{directory}->fill_in(HASH=> {FILEURL => uri_escape($fileurl, $escape_rule), + FILE => $dirtitle, + } + ); + } + elsif (-f $thumbfilename && $thumbfilename =~ /$doc_pattern/i && $thumbfilename !~ /$img_pattern/i) { + my $type = lc($1); + my $stat = stat($thumbfilename); + my $size = $stat->size; + my $filetype; + + if ($thumbfilename =~ m/\.(mpe?g|avi|mov|asf|wmv)$/i) { + $filetype = "video-$type"; + } elsif ($thumbfilename =~ m/\.(txt|html?)$/i) { + $filetype = "text-$type"; + } elsif ($thumbfilename =~ m/\.(mp3|ogg|wav)$/i) { + $filetype = "sound-$type"; + } elsif ($thumbfilename =~ m/\.(doc|pdf|rtf|csv|eps)$/i) { + $filetype = "application-$type"; + } else { + $filetype = "unknown"; + } + + $tpl_vars{FILES} .= + $templates{file}->fill_in(HASH => {%tpl_vars, + FILEURL => uri_escape($fileurl, $escape_rule), + ALT => "Size: $size Bytes", + FILE => $file, + TYPE => $type, + FILETYPE => $filetype, + } + ); + } + elsif (-f $thumbfilename) { + + my ($width, $height, $type) = imgsize($thumbfilename); + next if $type eq 'Data stream is not a known image file format'; + + my @filetypes = qw(JPG TIF PNG PPM GIF); + + next unless (grep $type eq $_, @filetypes); + my ($thumbnailwidth, $thumbnailheight) = get_thumbnailsize($r, $width, $height); + my $imageinfo = get_imageinfo($r, $thumbfilename, $type, $width, $height); + my $cached = get_scaled_picture_name($thumbfilename, $thumbnailwidth, $thumbnailheight); + + my $rotate = readfile_getnum($r, $imageinfo, $thumbfilename.".rotate"); + my %file_vars = (FILEURL => uri_escape($fileurl, $escape_rule), + FILE => $file, + DATE => $imageinfo->{DateTimeOriginal} ? $imageinfo->{DateTimeOriginal} : '', # should this really be a stat of the file instead of ''? + SRC => uri_escape($uri."/.cache/$cached", $escape_rule), + HEIGHT => (grep($rotate==$_, (1, 3)) ? $thumbnailwidth : $thumbnailheight), + WIDTH => (grep($rotate==$_, (1, 3)) ? $thumbnailheight : $thumbnailwidth), + SELECT => $select_mode?'  ':'',); + $tpl_vars{FILES} .= $templates{picture}->fill_in(HASH => {%tpl_vars, + %file_vars, + }, + ); + } + } + } + else { + $tpl_vars{FILES} = "No files found"; + $tpl_vars{BROWSELINKS} = ""; + } + + if (-f $topdir . '.comment') { + my $comment_ref = get_comment($topdir . '.comment'); + my %comment_vars; + $comment_vars{COMMENT} = $comment_ref->{COMMENT} . '
' if $comment_ref->{COMMENT}; + $comment_vars{TITLE} = $comment_ref->{TITLE} if $comment_ref->{TITLE}; + $tpl_vars{DIRCOMMENT} = $templates{comment}->fill_in(HASH => \%comment_vars); + $tpl_vars{TITLE} = $comment_ref->{TITLE} if $comment_ref->{TITLE}; + } else { + $tpl_vars{DIRCOMMENT} = $templates{nocomment}->fill_in(HASH=>\%tpl_vars); + } + + $tpl_vars{MAIN} = $templates{index}->fill_in(HASH => \%tpl_vars); + + $tpl_vars{MAIN} = $templates{layout}->fill_in(HASH => \%tpl_vars); + + $r->content_type('text/html'); + $r->headers_out->{'Content-Length'} = length($tpl_vars{MAIN}); + + if (!$::MP2) { + $r->send_http_header; + } + + $r->print($tpl_vars{MAIN}); + return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); + + } + else { + + # original size + if (defined($ENV{QUERY_STRING}) && $ENV{QUERY_STRING} eq 'orig') { + if ($r->dir_config('GalleryAllowOriginal') ? 1 : 0) { + $r->filename($filename); + return $::MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED(); + } else { + return $::MP2 ? Apache2::Const::FORBIDDEN() : Apache::Constants::FORBIDDEN(); + } + } + + # Create cache dir if not existing + my @tmp = split (/\//, $filename); + my $picfilename = pop @tmp; + my $path = (join "/", @tmp)."/"; + my $cache_path = cache_dir($r, 1); + + unless (-d $cache_path) { + unless (create_cache($r, $cache_path)) { + return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); + } + } + + my ($orig_width, $orig_height, $type) = imgsize($filename); + my $width = $orig_width; + + my $imageinfo = get_imageinfo($r, $filename, $type, $orig_width, $orig_height); + + my $original_size=$orig_height; + if ($orig_width>$orig_height) { + $original_size=$orig_width; + } + + # Check if the selected width is allowed + my @sizes = split (/ /, $r->dir_config('GallerySizes') ? $r->dir_config('GallerySizes') : '640 800 1024 1600'); + + my %cookies = fetch CGI::Cookie; + + if ($cgi->param('width')) { + unless ((grep $cgi->param('width') == $_, @sizes) or ($cgi->param('width') == $original_size)) { + show_error($r, 200, "Invalid width", "The specified width is invalid"); + return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); + } + + $width = $cgi->param('width'); + my $cookie = new CGI::Cookie(-name => 'GallerySize', -value => $width, -expires => '+6M'); + $r->headers_out->{'Set-Cookie'} = $cookie; + + } elsif ($cookies{'GallerySize'} && (grep $cookies{'GallerySize'}->value == $_, @sizes)) { + + $width = $cookies{'GallerySize'}->value; + + } else { + $width = $sizes[0]; + } + + my $scale; + my $image_width; + if ($orig_width<$orig_height) { + $scale = ($orig_height ? $width/$orig_height: 1); + $image_width=$width*$orig_width/$orig_height; + } + else { + $scale = ($orig_width ? $width/$orig_width : 1); + $image_width = $width; + } + + my $height = $orig_height * $scale; + + $image_width = floor($image_width); + $width = floor($width); + $height = floor($height); + + my $cached = get_scaled_picture_name($filename, $image_width, $height); + + my $tpl_dir = $r->dir_config('GalleryTemplateDir'); + + my %templates = create_templates({layout => "$tpl_dir/layout.tpl", + picture => "$tpl_dir/showpicture.tpl", + navpicture => "$tpl_dir/navpicture.tpl", + info => "$tpl_dir/info.tpl", + scale => "$tpl_dir/scale.tpl", + scaleactive => "$tpl_dir/scaleactive.tpl", + orig => "$tpl_dir/orig.tpl", + refresh => "$tpl_dir/refresh.tpl", + interval => "$tpl_dir/interval.tpl", + intervalactive => "$tpl_dir/intervalactive.tpl", + slideshowisoff => "$tpl_dir/slideshowisoff.tpl", + slideshowoff => "$tpl_dir/slideshowoff.tpl", + pictureinfo => "$tpl_dir/pictureinfo.tpl", + nopictureinfo => "$tpl_dir/nopictureinfo.tpl", + }); + + my %tpl_vars; + + my $resolution = (($image_width > $orig_width) && ($height > $orig_height)) ? + "$orig_width x $orig_height" : "$image_width x $height"; + + $tpl_vars{TITLE} = "Viewing ".$r->uri()." at $image_width x $height"; + $tpl_vars{META} = " "; + $tpl_vars{RESOLUTION} = $resolution; + $tpl_vars{MENU} = generate_menu($r); + $tpl_vars{SRC} = uri_escape(".cache/$cached", $escape_rule); + $tpl_vars{URI} = $r->uri(); + + my $exif_mode = $r->dir_config('GalleryEXIFMode'); + unless ($exif_mode) { + $exif_mode = 'namevalue'; + } + + unless (opendir(DATADIR, $path)) { + show_error($r, 500, "Unable to access directory", "Unable to access directory $path"); + return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); + } + my @pictures = grep { /$img_pattern/i } readdir (DATADIR); + closedir(DATADIR); + @pictures = gallerysort($r, @pictures); + + $tpl_vars{TOTAL} = scalar @pictures; + + my $prevpicture; + my $nextpicture; + + for (my $i=0; $i <= $#pictures; $i++) { + if ($pictures[$i] eq $picfilename) { + + $tpl_vars{NUMBER} = $i+1; + + $prevpicture = $pictures[$i-1]; + my $displayprev = ($i>0 ? 1 : 0); + + if ($r->dir_config("GalleryWrapNavigation")) { + $prevpicture = $pictures[$i>0 ? $i-1 : $#pictures]; + $displayprev = 1; + } + if ($prevpicture and $displayprev) { + my ($orig_width, $orig_height, $type) = imgsize($path.$prevpicture); + my ($thumbnailwidth, $thumbnailheight) = get_thumbnailsize($r, $orig_width, $orig_height); + my $imageinfo = get_imageinfo($r, $path.$prevpicture, $type, $orig_width, $orig_height); + my $cached = get_scaled_picture_name($path.$prevpicture, $thumbnailwidth, $thumbnailheight); + my %nav_vars; + $nav_vars{URL} = uri_escape($prevpicture, $escape_rule); + $nav_vars{FILENAME} = $prevpicture; + $nav_vars{WIDTH} = $width; + $nav_vars{PICTURE} = uri_escape(".cache/$cached", $escape_rule); + $nav_vars{DIRECTION} = "« prev"; + $nav_vars{ACCESSKEY} = "P"; + $tpl_vars{BACK} = $templates{navpicture}->fill_in(HASH => \%nav_vars); + } + else { + $tpl_vars{BACK} = " "; + } + + $nextpicture = $pictures[$i+1]; + if ($r->dir_config("GalleryWrapNavigation")) { + $nextpicture = $pictures[$i == $#pictures ? 0 : $i+1]; + } + + if ($nextpicture) { + my ($orig_width, $orig_height, $type) = imgsize($path.$nextpicture); + my ($thumbnailwidth, $thumbnailheight) = get_thumbnailsize($r, $orig_width, $orig_height); + my $imageinfo = get_imageinfo($r, $path.$nextpicture, $type, $thumbnailwidth, $thumbnailheight); + my $cached = get_scaled_picture_name($path.$nextpicture, $thumbnailwidth, $thumbnailheight); + my %nav_vars; + $nav_vars{URL} = uri_escape($nextpicture, $escape_rule); + $nav_vars{FILENAME} = $nextpicture; + $nav_vars{WIDTH} = $width; + $nav_vars{PICTURE} = uri_escape(".cache/$cached", $escape_rule); + $nav_vars{DIRECTION} = "next »"; + $nav_vars{ACCESSKEY} = "N"; + + $tpl_vars{NEXT} = $templates{navpicture}->fill_in(HASH => \%nav_vars); + $tpl_vars{NEXTURL} = uri_escape($nextpicture, $escape_rule); + } + else { + $tpl_vars{NEXT} = " "; + $tpl_vars{NEXTURL} = '#'; + } + } + } + + my $foundcomment = 0; + if (-f $path . '/' . $picfilename . '.comment') { + my $comment_ref = get_comment($path . '/' . $picfilename . '.comment'); + $foundcomment = 1; + $tpl_vars{COMMENT} = $comment_ref->{COMMENT} . '
' if $comment_ref->{COMMENT}; + $tpl_vars{TITLE} = $comment_ref->{TITLE} if $comment_ref->{TITLE}; + } else { + $tpl_vars{COMMENT} = ''; + } + + my @infos = split /, /, $r->dir_config('GalleryInfo') ? $r->dir_config('GalleryInfo') : 'Picture Taken => DateTimeOriginal, Flash => Flash'; + my $foundinfo = 0; + my $exifvalues; + foreach (@infos) { + + my ($human_key, $exif_key) = (split " => ")[0,1]; + my $value = $imageinfo->{$human_key}; + if (defined($value)) { + + $foundinfo = 1; + + if ($exif_mode eq 'namevalue') { + my %info_vars; + $info_vars{KEY} = $human_key; + $info_vars{VALUE} = $value; + $tpl_vars{INFO} .= $templates{info}->fill_in(HASH => \%info_vars); + } + + if ($exif_mode eq 'variables') { + $tpl_vars{"EXIF_".uc($exif_key)} = $value; + } + + if ($exif_mode eq 'values') { + $exifvalues .= "| ".$value." "; + } + + } + + } + + if ($exif_mode eq 'values') { + if (defined($exifvalues)) { + $tpl_vars{EXIFVALUES} = $exifvalues; + } + else { + $tpl_vars{EXIFVALUES} = ""; + } + } + + if ($foundcomment and !$foundinfo) { + $tpl_vars{INFO} = ""; + } + + if ($exif_mode ne 'namevalue') { + $tpl_vars{INFO} = ""; + } + + if ($exif_mode eq 'namevalue' && $foundinfo or $foundcomment) { + + $tpl_vars{PICTUREINFO} = $templates{pictureinfo}->fill_in(HASH => \%tpl_vars); + + unless (defined($exifvalues)) { + $tpl_vars{EXIFVALUES} = ""; + } + + } + else { + $tpl_vars{PICTUREINFO} = $templates{nopictureinfo}->fill_in(HASH => \%tpl_vars); + } + + # Fill in sizes and determine if any are smaller than the + # actual image. If they are, $scaleable=1 + my $scaleable = 0; + foreach my $size (@sizes) { + if ($size<=$original_size) { + my %sizes_vars; + $sizes_vars{IMAGEURI} = uri_escape($r->uri(), $escape_rule); + $sizes_vars{SIZE} = $size; + $sizes_vars{WIDTH} = $size; + if ($width == $size) { + $tpl_vars{SIZES} .= $templates{scaleactive}->fill_in(HASH => \%sizes_vars); + } + else { + $tpl_vars{SIZES} .= $templates{scale}->fill_in(HASH => \%sizes_vars); + } + $scaleable = 1; + } + } + + unless ($scaleable) { + my %sizes_vars; + $sizes_vars{IMAGEURI} = uri_escape($r->uri(), $escape_rule); + $sizes_vars{SIZE} = $original_size; + $sizes_vars{WIDTH} = $original_size; + $tpl_vars{SIZES} .= $templates{scaleactive}->fill_in(HASH => \%sizes_vars); + } + + $tpl_vars{IMAGEURI} = uri_escape($r->uri(), $escape_rule); + + if ($r->dir_config('GalleryAllowOriginal')) { + $tpl_vars{SIZES} .= $templates{orig}->fill_in(HASH => \%tpl_vars); + } + + my @slideshow_intervals = split (/ /, $r->dir_config('GallerySlideshowIntervals') ? $r->dir_config('GallerySlideshowIntervals') : '3 5 10 15 30'); + foreach my $interval (@slideshow_intervals) { + + my %slideshow_vars; + $slideshow_vars{IMAGEURI} = uri_escape($r->uri(), $escape_rule); + $slideshow_vars{SECONDS} = $interval; + $slideshow_vars{WIDTH} = ($width > $height ? $width : $height); + + if ($cgi->param('slideshow') && $cgi->param('slideshow') == $interval and $nextpicture) { + $tpl_vars{SLIDESHOW} .= $templates{intervalactive}->fill_in(HASH => \%slideshow_vars); + } + else { + + $tpl_vars{SLIDESHOW} .= $templates{interval}->fill_in(HASH => \%slideshow_vars); + + } + } + + if ($cgi->param('slideshow') and $nextpicture) { + + $tpl_vars{SLIDESHOW} .= $templates{slideshowoff}->fill_in(HASH => \%tpl_vars); + + unless ((grep $cgi->param('slideshow') == $_, @slideshow_intervals)) { + show_error($r, 200, "Invalid interval", "Invalid slideshow interval choosen"); + return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); + } + + $tpl_vars{URL} = uri_escape($nextpicture, $escape_rule); + $tpl_vars{WIDTH} = ($width > $height ? $width : $height); + $tpl_vars{INTERVAL} = $cgi->param('slideshow'); + $tpl_vars{META} .= $templates{refresh}->fill_in(HASH => \%tpl_vars); + + } + else { + $tpl_vars{SLIDESHOW} .= $templates{slideshowisoff}->fill_in(HASH => \%tpl_vars); + } + + $tpl_vars{MAIN} = $templates{picture}->fill_in(HASH => \%tpl_vars); + $tpl_vars{MAIN} = $templates{layout}->fill_in(HASH => \%tpl_vars); + + $r->content_type('text/html'); + $r->headers_out->{'Content-Length'} = length($tpl_vars{MAIN}); + + if (!$::MP2) { + $r->send_http_header; + } + + $r->print($tpl_vars{MAIN}); + return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); + + } + +} + +sub cache_dir { + + my ($r, $strip_filename) = @_; + + my $cache_root; + + unless ($r->dir_config('GalleryCacheDir')) { + + $cache_root = '/var/tmp/Apache-Gallery/'; + if ($r->server->is_virtual) { + $cache_root = File::Spec->catdir($cache_root, $r->server->server_hostname); + } else { + $cache_root = File::Spec->catdir($cache_root, $r->location); + } + + } else { + + $cache_root = $r->dir_config('GalleryCacheDir'); + + } + + # If the uri contains .cache we need to remove it + my $uri = $r->uri; + $uri =~ s/\.cache//; + + my (undef, $dirs, $filename) = File::Spec->splitpath($uri); + # We don't need a volume as this is a relative path + + if ($strip_filename) { + return(File::Spec->canonpath(File::Spec->catdir($cache_root, $dirs))); + } else { + return(File::Spec->canonpath(File::Spec->catfile($cache_root, $dirs, $filename))); + } +} + +sub create_cache { + + my ($r, $path) = @_; + + unless (mkdirhier ($path)) { + show_error($r, 500, $!, "Unable to create cache directory in $path: $!"); + return 0; + } + + return 1; +} + +sub mkdirhier { + + my $dir = shift; + + unless (-d $dir) { + + unless (mkdir($dir, 0755)) { + my $parent = $dir; + $parent =~ s/\/[^\/]*$//; + + mkdirhier($parent); + + mkdir($dir, 0755); + } + } +} + +sub get_scaled_picture_name { + + my ($fullpath, $width, $height) = @_; + + my (undef, undef, $type) = imgsize($fullpath); + + my @dirs = split(/\//, $fullpath); + my $filename = pop(@dirs); + my $newfilename; + + if (grep $type eq $_, qw(PPM TIF GIF)) { + $newfilename = $width."x".$height."-".$filename; + # needs to be configurable + $newfilename =~ s/\.(\w+)$/-$1\.jpg/; + } else { + $newfilename = $width."x".$height."-".$filename; + } + + return $newfilename; + +} + +sub scale_picture { + + my ($r, $fullpath, $width, $height, $imageinfo) = @_; + + my @dirs = split(/\//, $fullpath); + my $filename = pop(@dirs); + + my ($orig_width, $orig_height, $type) = imgsize($fullpath); + + my $cache = cache_dir($r, 1); + + my $newfilename = get_scaled_picture_name($fullpath, $width, $height); + + if (($width > $orig_width) && ($height > $orig_height)) { + # Run it through the resize code anyway to get watermarks + $width = $orig_width; + $height = $orig_height; + } + + my ($thumbnailwidth, $thumbnailheight) = get_thumbnailsize($r, $orig_width, $orig_height); + + # Do we want to generate a new file in the cache? + my $scale = 1; + + if (-f $cache."/".$newfilename) { + $scale = 0; + + # Check to see if the image has changed + my $filestat = stat($fullpath); + my $cachestat = stat($cache."/".$newfilename); + if ($filestat->mtime >= $cachestat->mtime) { + $scale = 1; + } + + # Check to see if the .rotate file has been added or changed + if (-f $fullpath . ".rotate") { + my $rotatestat = stat($fullpath . ".rotate"); + if ($rotatestat->mtime > $cachestat->mtime) { + $scale = 1; + } + } + # Check to see if the copyrightimage has been added or changed + if ($r->dir_config('GalleryCopyrightImage') && -f $r->dir_config('GalleryCopyrightImage')) { + unless ($width == $thumbnailwidth or $width == $thumbnailheight) { + my $copyrightstat = stat($r->dir_config('GalleryCopyrightImage')); + if ($copyrightstat->mtime > $cachestat->mtime) { + $scale = 1; + } + } + } + + } + + if ($scale) { + + my $newpath = $cache."/".$newfilename; + my $rotate = readfile_getnum($r, $imageinfo, $fullpath . ".rotate"); + my $quality = $r->dir_config('GalleryQuality'); + + if ($width == $thumbnailwidth or $width == $thumbnailheight) { + + resizepicture($r, $fullpath, $newpath, $width, $height, $rotate, '', '', '', '', '', ''); + + } else { + + resizepicture($r, $fullpath, $newpath, $width, $height, $rotate, + ($r->dir_config('GalleryCopyrightImage') ? $r->dir_config('GalleryCopyrightImage') : ''), + ($r->dir_config('GalleryTTFDir') ? $r->dir_config('GalleryTTFDir') : ''), + ($r->dir_config('GalleryCopyrightText') ? $r->dir_config('GalleryCopyrightText') : ''), + ($r->dir_config('GalleryCopyrightColor') ? $r->dir_config('GalleryCopyrightColor') : ''), + ($r->dir_config('GalleryTTFFile') ? $r->dir_config('GalleryTTFFile') : ''), + ($r->dir_config('GalleryTTFSize') ? $r->dir_config('GalleryTTFSize') : ''), + ($r->dir_config('GalleryCopyrightBackgroundColor') ? $r->dir_config('GalleryCopyrightBackgroundColor') : ''), + $quality); + + } + } + + return $newfilename; + +} + +sub get_thumbnailsize { + my ($r, $orig_width, $orig_height) = @_; + + my $gallerythumbnailsize=$r->dir_config('GalleryThumbnailSize'); + + if (defined($gallerythumbnailsize)) { + warn("Invalid setting for GalleryThumbnailSize") unless + $gallerythumbnailsize =~ /^\s*\d+\s*x\s*\d+\s*$/i; + } + + my ($thumbnailwidth, $thumbnailheight) = split(/x/i, ($gallerythumbnailsize) ? $gallerythumbnailsize : "100x75"); + + my $width = $thumbnailwidth; + my $height = $thumbnailheight; + + # If the image is rotated, flip everything around. + if (defined $r->dir_config('GalleryThumbnailSizeLS') + and $r->dir_config('GalleryThumbnailSizeLS') eq '1' + and $orig_width < $orig_height) { + + $width = $thumbnailheight; + $height = $thumbnailwidth; + } + + my $scale = ($orig_width ? $width/$orig_width : 1); + + if ($orig_height) { + if ($orig_height * $scale > $thumbnailheight) { + $scale = $height/$orig_height; + $width = $orig_width * $scale; + } + } + + $height = $orig_height * $scale; + + $height = floor($height); + $width = floor($width); + + return ($width, $height); +} + +sub get_imageinfo { + my ($r, $file, $type, $width, $height) = @_; + my $imageinfo = {}; + if ($type eq 'Data stream is not a known image file format') { + # should never be reached, this is supposed to be handled outside of here + log_error("Something was fishy with the type of the file $file\n"); + } else { + + # Some files, like TIFF, PNG, GIF do not have EXIF info + # embedded but use .thm files instead. + $imageinfo = get_imageinfo_from_thm_file($file, $width, $height); + + # If there is no .thm file and our file is a JPEG file we try to extract the EXIf + # info using Image::Info + unless (defined($imageinfo) && (grep $type eq $_, qw(JPG))) { + # Only for files that natively keep the EXIF info in the same file + $imageinfo = image_info($file); + } + } + + unless (defined($imageinfo->{width}) and defined($imageinfo->{height})) { + $imageinfo->{width} = $width; + $imageinfo->{height} = $height; + } + + my @infos = split /, /, $r->dir_config('GalleryInfo') ? $r->dir_config('GalleryInfo') : 'Picture Taken => DateTimeOriginal, Flash => Flash'; + foreach (@infos) { + + my ($human_key, $exif_key) = (split " => ")[0,1]; + if (defined($exif_key) && defined($imageinfo->{$exif_key})) { + my $value = ""; + if (ref($imageinfo->{$exif_key}) eq 'Image::TIFF::Rational') { + $value = $imageinfo->{$exif_key}->as_string; + } + elsif (ref($imageinfo->{$exif_key}) eq 'ARRAY') { + foreach my $element (@{$imageinfo->{$exif_key}}) { + if (ref($element) eq 'ARRAY') { + foreach (@{$element}) { + $value .= $_ . ' '; + } + } + elsif (ref($element) eq 'HASH') { + $value .= "
{ "; + foreach (sort keys %{$element}) { + $value .= "$_ = " . $element->{$_} . ' '; + } + $value .= "} "; + } + else { + $value .= $element; + } + $value .= ' '; + } + } + else { + my $exif_value = $imageinfo->{$exif_key}; + if ($human_key eq 'Flash' && $exif_value =~ m/\d/) { + my %flashmodes = ( + "0" => "No", + "1" => "Yes", + "9" => "Yes", + "16" => "No (Compulsory) Should be External Flash", + "17" => "Yes (External)", + "24" => "No", + "25" => "Yes (Auto)", + "73" => "Yes (Compulsory, Red Eye Reducing)", + "89" => "Yes (Auto, Red Eye Reducing)" + ); + $exif_value = defined $flashmodes{$exif_value} ? $flashmodes{$exif_value} : 'unknown flash mode'; + } + $value = $exif_value; + } + if ($exif_key eq 'MeteringMode') { + my $exif_value = $imageinfo->{$exif_key}; + if ($exif_value =~ /^\d+$/) { + my %meteringmodes = ( + '0' => 'unknown', + '1' => 'Average', + '2' => 'CenterWeightedAverage', + '3' => 'Spot', + '4' => 'MultiSpot', + '5' => 'Pattern', + '6' => 'Partial', + '255' => 'Other' + ); + $exif_value = defined $meteringmodes{$exif_value} ? $meteringmodes{$exif_value} : 'unknown metering mode'; + } + $value = $exif_value; + + } + if ($exif_key eq 'LightSource') { + my $exif_value = $imageinfo->{$exif_key}; + if ($exif_value =~ /^\d+$/) { + my %lightsources = ( + '0' => 'unknown', + '1' => 'Daylight', + '2' => 'Fluorescent', + '3' => 'Tungsten (incandescent light)', + '4' => 'Flash', + '9' => 'Fine weather', + '10' => 'Cloudy weather', + '11' => 'Shade', + '12' => 'Daylight fluorescent', + '13' => 'Day white fluorescent', + '14' => 'Cool white fluorescent', + '15' => 'White fluorescent', + '17' => 'Standard light A', + '18' => 'Standard light B', + '19' => 'Standard light C', + '20' => 'D55', + '21' => 'D65', + '22' => 'D75', + '23' => 'D50', + '24' => 'ISO studio tungsten', + '255' => 'other light source' + ); + $exif_value = defined $lightsources{$exif_value} ? $lightsources{$exif_value} : 'unknown light source'; + } + $value = $exif_value; + } + if ($exif_key eq 'FocalLength') { + if ($value =~ /^(\d+)\/(\d+)$/) { + $value = eval { $1 / $2 }; + if ($@) { + $value = $@; + } else { + $value = int($value + 0.5) . "mm"; + + } + } + } + if ($exif_key eq 'ShutterSpeedValue') { + if ($value =~ /^((?:\-)?\d+)\/(\d+)$/) { + $value = eval { $1 / $2 }; + if ($@) { + $value = $@; + } else { + eval { + $value = 1/(exp($value*log(2))); + if ($value < 1) { + $value = "1/" . (int((1/$value))); + } else { + $value = int($value*10)/10; + } + }; + if ($@) { + $value = $@; + } else { + $value = $value . " sec"; + } + } + } + } + if ($exif_key eq 'ApertureValue') { + if ($value =~ /^(\d+)\/(\d+)$/) { + $value = eval { $1 / $2 }; + if ($@) { + $value = $@; + } else { + # poor man's rounding + $value = int(exp($value*log(2)*0.5)*10)/10; + $value = "f" . $value; + } + } + } + if ($exif_key eq 'FNumber') { + if ($value =~ /^(\d+)\/(\d+)$/) { + $value = eval { $1 / $2 }; + if ($@) { + $value = $@; + } else { + $value = int($value*10+0.5)/10; + $value = "f" . $value; + } + } + } + $imageinfo->{$human_key} = $value; + } + } + + if ($r->dir_config('GalleryUseFileDate') && + ($r->dir_config('GalleryUseFileDate') eq '1' + || !$imageinfo->{"Picture Taken"} )) { + + my $st = stat($file); + $imageinfo->{"DateTimeOriginal"} = $imageinfo->{"Picture Taken"} = scalar localtime($st->mtime) if $st; + } + + return $imageinfo; +} + +sub get_imageinfo_from_thm_file { + + my ($file, $width, $height) = @_; + + my $imageinfo = undef; + # Windows based file extensions are often .THM, so check + # for both .thm and .THM + my $unix_file = $file; + my $windows_file = $file; + $unix_file =~ s/\.(\w+)$/.thm/; + $windows_file =~ s/\.(\w+)$/.THM/; + + if (-e $unix_file && -f $unix_file && -r $unix_file) { + $imageinfo = image_info($unix_file); + $imageinfo->{width} = $width; + $imageinfo->{height} = $height; + } + elsif (-e $windows_file && -f $windows_file && -r $windows_file) { + $imageinfo = image_info($windows_file); + $imageinfo->{width} = $width; + $imageinfo->{height} = $height; + } + + return $imageinfo; +} + + +sub readfile_getnum { + my ($r, $imageinfo, $filename) = @_; + + my $rotate = 0; + + # Check to see if the image contains the Orientation EXIF key, + # but allow user to override using rotate + if (!defined($r->dir_config("GalleryAutoRotate")) + || $r->dir_config("GalleryAutoRotate") eq "1") { + if (defined($imageinfo->{Orientation})) { + if ($imageinfo->{Orientation} eq 'right_top') { + $rotate=1; + } + elsif ($imageinfo->{Orientation} eq 'left_bot') { + $rotate=3; + } + } + } + + if (open(FH, "<$filename")) { + my $temp = ; + chomp($temp); + close(FH); + unless ($temp =~ /^\d$/) { + $rotate = 0; + } + unless ($temp == 1 || $temp == 2 || $temp == 3) { + $rotate = 0; + } + $rotate = $temp; + } + + return $rotate; +} + +sub get_filecontent { + my $file = shift; + open(FH, $file) or return undef; + my $content = ''; + { + local $/; + $content = ; + } + close(FH); + return $content; +} + +sub get_comment { + my $filename = shift; + my $comment_ref = {}; + $comment_ref->{TITLE} = undef; + $comment_ref->{COMMENT} = ''; + + open(FH, $filename) or return $comment_ref; + my $title = ; + if ($title =~ m/^TITLE: (.*)$/) { + chomp($comment_ref->{TITLE} = $1); + } + else { + $comment_ref->{COMMENT} = $title; + } + + while () { + chomp; + $comment_ref->{COMMENT} .= $_; + } + close(FH); + + return $comment_ref; +} + +sub show_error { + + my ($r, $statuscode, $errortitle, $error) = @_; + + my $tpl = $r->dir_config('GalleryTemplateDir'); + + my %templates = create_templates({layout => "$tpl/layout.tpl", + error => "$tpl/error.tpl", + }); + + my %tpl_vars; + $tpl_vars{TITLE} = "Error! $errortitle"; + $tpl_vars{META} = ""; + $tpl_vars{ERRORTITLE} = "Error! $errortitle"; + $tpl_vars{ERROR} = $error; + + $tpl_vars{MAIN} = $templates{error}->fill_in(HASH => \%tpl_vars); + + $tpl_vars{PAGE} = $templates{layout}->fill_in(HASH => \%tpl_vars); + + $r->status($statuscode); + $r->content_type('text/html'); + + $r->print($tpl_vars{PAGE}); + +} + +sub generate_menu { + + my $r = shift; + + my $root_text = (defined($r->dir_config('GalleryRootText')) ? $r->dir_config('GalleryRootText') : "root:" ); + my $root_path = (defined($r->dir_config('GalleryRootPath')) ? $r->dir_config('GalleryRootPath') : "" ); + + my $subr = $r->lookup_uri($r->uri); + my $filename = $subr->filename; + + my @links = split (/\//, $r->uri); + my $uri = $r->uri; + $uri =~ s/^$root_path//g; + + @links = split (/\//, $uri); + + # Get the full path of the base directory + my $dirname; + { + my @direlem = split (/\//, $filename); + for my $i ( 0 .. ( scalar(@direlem) - scalar(@links) ) ) { + $dirname .= shift(@direlem) . '/'; + } + chop $dirname; + } + + my $picturename; + if (-f $filename) { + $picturename = pop(@links); + } + + if ($r->uri eq $root_path) { + return qq{ $root_text }; + } + + my $menu; + my $menuurl = $root_path; + foreach my $link (@links) { + + $menuurl .= $link."/"; + my $linktext = $link; + unless (length($link)) { + $linktext = "$root_text "; + } + else { + + $dirname = File::Spec->catdir($dirname, $link); + + if (-e $dirname . ".folder") { + $linktext = get_filecontent($dirname . ".folder"); + } + } + + if ("$root_path$uri" eq $menuurl) { + $menu .= "$linktext / "; + } + else { + $menu .= "$linktext / "; + } + + } + + if (-f $filename) { + $menu .= $picturename; + } + else { + + if ($r->dir_config('GallerySelectionMode') && $r->dir_config('GallerySelectionMode') eq '1') { + $menu .= "[select] "; + } + } + + return $menu; +} + +sub resizepicture { + my ($r, $infile, $outfile, $x, $y, $rotate, $copyrightfile, $GalleryTTFDir, $GalleryCopyrightText, $text_color, $GalleryTTFFile, $GalleryTTFSize, $GalleryCopyrightBackgroundColor, $quality) = @_; + + # Load image + my $image = Image::Imlib2->load($infile) or warn("Unable to open file $infile, $!"); + + # Scale image + $image=$image->create_scaled_image($x, $y) or warn("Unable to scale image $infile. Are you running out of memory?"); + + # Rotate image + if ($rotate != 0) { + $image->image_orientate($rotate); + } + + # blend copyright image onto image + if ($copyrightfile ne '') { + if (-f $copyrightfile and (my $logo=Image::Imlib2->load($copyrightfile))) { + my $x = $image->get_width(); + my $y = $image->get_height(); + my $logox = $logo->get_width(); + my $logoy = $logo->get_height(); + $image->blend($logo, 0, 0, 0, $logox, $logoy, $x-$logox, $y-$logoy, $logox, $logoy); + } + else { + log_error("GalleryCopyrightImage $copyrightfile was not found"); + } + } + + if ($GalleryTTFDir && $GalleryCopyrightText && $GalleryTTFFile && $text_color) { + if (!-d $GalleryTTFDir) { + + log_error("GalleryTTFDir $GalleryTTFDir is not a dir\n"); + + } elsif ($GalleryCopyrightText eq '') { + + log_error("GalleryCopyrightText is empty. No text inserted to picture\n"); + + } elsif (!-e "$GalleryTTFDir/$GalleryTTFFile") { + + log_error("GalleryTTFFile $GalleryTTFFile was not found\n"); + + } else { + + $GalleryTTFFile =~ s/\.TTF$//i; + $image->add_font_path("$GalleryTTFDir"); + + $image->load_font("$GalleryTTFFile/$GalleryTTFSize"); + my($text_x, $text_y) = $image->get_text_size("$GalleryCopyrightText"); + my $x = $image->get_width(); + my $y = $image->get_height(); + + my $offset = 3; + + if (($text_x < $x - $offset) && ($text_y < $y - $offset)) { + if ($GalleryCopyrightBackgroundColor =~ /^\d+,\d+,\d+,\d+$/) { + my ($br_val, $bg_val, $bb_val, $ba_val) = split (/,/, $GalleryCopyrightBackgroundColor); + $image->set_colour($br_val, $bg_val, $bb_val, $ba_val); + $image->fill_rectangle ($x-$text_x-$offset, $y-$text_y-$offset, $text_x, $text_y); + } + my ($r_val, $g_val, $b_val, $a_val) = split (/,/, $text_color); + $image->set_colour($r_val, $g_val, $b_val, $a_val); + $image->draw_text($x-$text_x-$offset, $y-$text_y-$offset, "$GalleryCopyrightText"); + } else { + log_error("Text is to big for the picture.\n"); + } + } + } + + if ($quality && $quality =~ m/^\d+$/) { + $image->set_quality($quality); + } + + $image->save($outfile); + +} + +sub gallerysort { + my $r=shift; + my @files=@_; + my $sortby = $r->dir_config('GallerySortBy'); + my $filename=$r->lookup_uri($r->uri)->filename; + $filename=(File::Spec->splitpath($filename))[1] if (-f $filename); + if ($sortby && $sortby =~ m/^(size|atime|mtime|ctime)$/) { + @files = map(/^\d+ (.*)/, sort map(stat("$filename/$_")->$sortby()." $_", @files)); + } else { + @files = sort @files; + } + return @files; +} + +# Create Text::Template objects used by Apache::Gallery. Takes a +# hashref of template_name, template_filename pairs, and returns a +# list of template_name, texttemplate_object pairs. +sub create_templates { + my $templates = shift; + + # This routine is called whenever a template has an error. Prints + # the error to STDERR and sticks the error in the output + sub tt_broken { + my %args = @_; + # Pull out the name and filename from the arg option [see + # Text::Template for details] + @args{qw(name file)} = @{$args{arg}}; + print STDERR qq(Template $args{name} ("$args{file}") is broken: $args{error}); + # Don't include the file name in the output, as the user can see this. + return qq(); + } + + + + my %texttemplate_objects; + + for my $template_name (keys %$templates) { + my $tt_obj = Text::Template->new(TYPE => 'FILE', + SOURCE => $$templates{$template_name}, + BROKEN => \&tt_broken, + BROKEN_ARG => [$template_name, $$templates{$template_name}], + ) + or die "Unable to create new Text::Template object for $template_name: $Text::Template::ERROR"; + $texttemplate_objects{$template_name} = $tt_obj; + } + return %texttemplate_objects; +} + +sub log_error { + if ($::MP2) { + Apache2::RequestUtil->request->log_error(shift()); + } else { + Apache->request->log_error(shift()); + } +} + +1; + +=head1 NAME + +Apache::Gallery - mod_perl handler to create an image gallery + +=head1 SYNOPSIS + +See the INSTALL file in the distribution for installation instructions. + +=head1 DESCRIPTION + +Apache::Gallery creates an thumbnail index of each directory and allows +viewing pictures in different resolutions. Pictures are resized on the +fly and cached. The gallery can be configured and customized in many ways +and a custom copyright image can be added to all the images without +modifying the original. + +=head1 CONFIGURATION + +In your httpd.conf you set the global options for the gallery. You can +also override each of the options in .htaccess files in your gallery +directories. + +The options are set in the httpd.conf/.htaccess file using the syntax: +B + +Example: B + +=over 4 + +=item B + +Some cameras, like the Canon G3, can detect the orientation of a +the pictures you take and will save this information in the +'Orientation' EXIF field. Apache::Gallery will then automatically +rotate your images. + +This behavior is default but can be disabled by setting GalleryAutoRotate +to 0. + +=item B + +Directory where Apache::Gallery should create its cache with scaled +pictures. The default is /var/tmp/Apache-Gallery/ . Here, a directory +for each virtualhost or location will be created automaticly. Make +sure your webserver has write access to the CacheDir. + +=item B + +Full path to the directory where you placed the templates. This option +can be used both in your global configuration and in .htaccess files, +this way you can have different layouts in different parts of your +gallery. + +No default value, this option is required. + +=item B + +With this option you can define which EXIF information you would like +to present from the image. The format is: ' KeyInEXIF, +MyOtherName => OtherKeyInEXIF' + +Examples of keys: B, B, B, +and B + +You can view all the keys from the EXIF header using this perl-oneliner: + +perl C<-e> 'use Data::Dumper; use Image::Info qw(image_info); print Dumper(image_info(shift));' filename.jpg + +Default is: 'Picture Taken => DateTimeOriginal, Flash => Flash' + +=item B + +Defines which widths images can be scaled to. Images cannot be +scaled to other widths than the ones you define with this option. + +The default is '640 800 1024 1600' + +=item B + +Defines the width and height of the thumbnail images. + +Defaults to '100x75' + +=item B + +If set to '1', B is the long and the short side of +the thumbnail image instead of the width and height. + +Defaults to '0'. + +=item B + +Image you want to blend into your images in the lower right +corner. This could be a transparent png saying "copyright +my name 2001". + +Optional. + +=item B + +Make the navigation in the picture view wrap around (So Next +at the end displays the first picture, etc.) + +Set to 1 or 0, default is 0 + +=item B + +Allow the user to download the Original picture without +resizing or putting the CopyrightImage on it. + +Set to 1 or 0, default is 0 + +=item B + +With this option you can configure which intervals can be selected for +a slideshow. The default is '3 5 10 15 30' + +=item B + +Instead of the default filename ordering you can sort by any +stat attribute. For example size, atime, mtime, ctime. + +=item B + +Set this variable to sort directories differently than other items, +can be set to size, atime, mtime and ctime; setting any other value +will revert to sorting by name. + +=item B + +Cache EXIF data using Memoize - this will make Apache::Gallery faster +when many people access the same images, but it will also cache EXIF +data until the current Apache child dies. + +=item B + +Set this option to 1 to make A::G show the files timestamp +instead of the EXIF value for "Picture taken". + +=item B + +Enable the selection mode. Select images with checkboxes and +get a list of filenames. + +=item B + +You can choose how Apache::Gallery should display EXIF info +from your images. + +The default setting is 'namevalue'. This setting will make +Apache::Gallery print out the names and values of the EXIF values +you configure with GalleryInfo. The information will be parsed into +$INFO in pictureinfo.tpl. + +You can also set it to 'values' which will make A::G parse +the configured values into the var $EXIFVALUES as 'value | value | value' + +If you set this option to 'variables' the items you configure in GalleryInfo +will be available to your templates as $EXIF_ (in all uppercase). +That means that with the default setting "Picture Taken => DateTimeOriginal, +Flash => Flash" you will have the variables $EXIF_DATETIMEORIGINAL and +$EXIF_FLASH avilable to your templates. You can place them +anywhere you want. + +=item B + +Change the location of gallery root. The default is "" + +=item B + +Change the name that appears as the root element in the menu. The +default is "root:" + +=item B + +This options controls how many thumbnails should be displayed in a +page. It requires $BROWSELINKS to be in the index.tpl template file. + +=item B + +Pattern matching the files you want Apache::Gallery to view in the +index as thumbnails. + +The default is '\.(jpe?g|png|tiff?|ppm)$' + +=item B + +Pattern matching the files you want Apache::Gallery to view in the index +as normal files. All other filetypes will still be served by Apache::Gallery +but are not visible in the index. + +The default is '\.(mpe?g|avi|mov|asf|wmv|doc|mp3|ogg|pdf|rtf|wav|dlt|html?|csv|eps)$' + +=item B + +To use the GalleryCopyrightText feature you must set this option to the +directory where your True Type fonts are stored. No default is set. + +Example: + + PerlSetVar GalleryTTFDir '/usr/share/fonts/' + +=item B + +To use the GalleryCopyrightText feature this option must be set to the +name of the True Type font you wish to use. Example: + + PerlSetVar GalleryTTFFile 'verdanab.ttf' + +=item B + +Configure the size of the CopyrightText that will be inserted as +copyright notice in the corner of your pictures. + +Example: + + PerlSetVar GalleryTTFSize '10' + +=item B + +The text that will be inserted as copyright notice. + +Example: + + PerlSetVar GalleryCopyrightText '(c) Michael Legart' + +=item B + +The text color of your copyright notice. + +Examples: + +White: + PerlSetVar GalleryCopyrightColor '255,255,255,255' + +Black: + PerlSetVar GalleryCopyrightColor '0,0,0,255' + +Red: + PerlSetVar GalleryCopyrightColor '255,0,0,255' + +Green: + PerlSetVar GalleryCopyrightColor '0,255,0,255' + +Blue: + PerlSetVar GalleryCopyrightColor '0,0,255,255' + +Transparent orange: + PerlSetVar GalleryCopyrightColor '255,127,0,127' + +=item B + +The background-color of a GalleryCopyrightText + +r,g,b,a - for examples, see GalleryCopyrightColor + +=item B + +The quality (1-100) of scaled images + +This setting affects the quality of the scaled images. +Set this to a low number to reduce the size of the scaled images. +Remember to clear out your cache if you change this setting. +Quality seems to default to 75, at least in the jpeg and png loader code in +Imlib2 1.1.0. + +Examples: + +Quality at 50: + PerlSetVar GalleryQuality '50' + +=item B + +Set this option to 1 to convert underscores to spaces in the listing +of directory names. + +=back + +=head1 FEATURES + +=over 4 + +=item B + +Some cameras, like the Canon G3, detects the orientation of a picture +and adds this info to the EXIF header. Apache::Gallery detects this +and automaticly rotates images with this info. + +If your camera does not support this, you can rotate the images +manually, This can also be used to override the rotate information +from a camera that supports that. You can also disable this behavior +with the GalleryAutoRotate option. + +To use this functionality you have to create file with the name of the +picture you want rotated appened with ".rotate". The file should include +a number where these numbers are supported: + + "1", rotates clockwise by 90 degree + "2", rotates clockwise by 180 degrees + "3", rotates clockwise by 270 degrees + +So if we want to rotate "Picture1234.jpg" 90 degrees clockwise we would +create a file in the same directory called "Picture1234.jpg.rotate" with +the number 1 inside of it. + +=item B + +To include comments for a directory you create a .comment +file where the first line can contain "TITLE: New title" which +will be the title of the page, and a comment on the following +lines. +To include comments for each picture you create files called +picture.jpg.comment where the first line can contain "TITLE: New +title" which will be the title of the page, and a comment on the +following lines. + +Example: + + TITLE: This is the new title of the page + And this is the comment.
+ And this is line two of the comment. + +The visible name of the folder is by default identical to the name of +the folder, but can be changed by creating a file .folder +with the visible name of the folder. + +=back + +=head1 DEPENDENCIES + +=over 4 + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B +(ie, XFree86) + +=item B +Remember the -dev package when using rpm, deb or other package formats! + +=back + +=head1 AUTHOR + +Michael Legart + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2001-2005 Michael Legart + +Templates designed by Thomas Kjaer + +Apache::Gallery is free software and is released under the Artistic License. +See B for details. + +The video icons are from the GNOME project. B + +=head1 THANKS + +Thanks to Thomas Kjaer for templates and design of B +Thanks to Thomas Eibner and other for patches. (See the Changes file) + +=head1 SEE ALSO + +L, L, L, L, +L, and L. + +=cut diff --git a/t/001_use.t b/t/001_use.t new file mode 100644 index 0000000..6704b01 --- /dev/null +++ b/t/001_use.t @@ -0,0 +1,5 @@ +use Test::More tests => 1; + +BEGIN { use_ok('Apache::Gallery'); } + + diff --git a/t/002_graphlibs.t b/t/002_graphlibs.t new file mode 100644 index 0000000..0c2d258 --- /dev/null +++ b/t/002_graphlibs.t @@ -0,0 +1,28 @@ +use Test::More; +use Apache::Gallery; +use Image::Size qw(imgsize); + +eval { require Apache::FakeRequest; }; +if ($@) { + plan skip_all => 'skip Apache::FakeRequest not found'; +} +else { + + plan tests => 4; + + my $request = Apache::FakeRequest->new('get_remote_host' => 'localhost'); + + Apache::Gallery::resizepicture($request, 't/002_inpng.png', 't/inpng-resized.png', 10, 10, 0, ''); + Apache::Gallery::resizepicture($request, 't/002_injpg.jpg', 't/injpg-resized.jpg', 10, 10, 0, ''); + my ($pngwidth, $pngheight)=imgsize('t/inpng-resized.png'); + my ($jpgwidth, $jpgheight)=imgsize('t/injpg-resized.jpg'); + + is ($pngwidth, 10, 'PNG Width') or diag('You need to install libpng before libimlib'); + is ($pngheight, 10, 'PNG Height') or diag('You need to install libpng before libimlib'); + is ($jpgwidth, 10, 'JPG Width') or diag('You need to install libjpeg before libimlib'); + is ($jpgheight, 10, 'JPG Height') or diag('You need to install libjpeg before libimlib'); + + unlink('t/inpng-resized.png'); + unlink('t/injpg-resized.jpg'); + +} diff --git a/t/002_injpg.jpg b/t/002_injpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b3f30f854b2a2fe7bad8c2266eddb025d9fb97da GIT binary patch literal 396 zcmex=LJ%Z3brs z4mLJ+HdYRHc6Lrq4lW)MULJ049!Vi#ei2zIc{y1r85so?J#_^o9c39A4RcK$149!N z6M1z@TMHu_J!2CikRgnmoSZz|JQBRT5=M$Libf=Z{|6WZIT*MZ_?a1%7?=bZnFSgD zA7Ky!`+)%ou(7fO#gzmY7@1j^n3&-*Oh7&ZtDvHgp-Q0R#7#goq9E_107fRDu(%)t zGlsa}|62?^Kw&09WC t(Rg&G_EBM{B(?c2-9BrA&b^gCo2J~|^Hj;iexg@eu+rP5JL>=61OVv=Ru%vN literal 0 HcmV?d00001 diff --git a/t/002_inpng.png b/t/002_inpng.png new file mode 100644 index 0000000000000000000000000000000000000000..2759ff31bd5cecb335620da16410ab96e678e41f GIT binary patch literal 500 zcmVL8EA|kN9cEe-v1^En#8c>N}?Y3&d_Om`t$x?TRT|W z%U)@na;dditB=RyV_AjhDka?eVj4}{HDj9Q;N@7S`U31C+ zjFp^nOc9Z^3Y_JfyS@kLIirMB5FjZXr}1{18D)$T(hF{k)T%eSXOzSc_Z`=DMMTnS zBhBxgkirOQIVD8&>y~0jApqyfD9V}A8h7-54~XtyLkLh?yUjBtjdQjvODbi3o%)z%s3Ky+M)J%o?XzhB=!_j&GsL#=i7-g_Je zmrAV^zOJA54Yxfo=!~`6Xls-mPUt;Uq3GN1%kk)B&lzE)K8@HdE21yCV2oR7kK39f zrhTLCV1?9rIN5P>)6406zP!HLm$&iPg#&b*h<THR qITyykoW|k#?549Dr{Q_*l=%;}vFFY4moH%e0000 2; + +use Apache::Gallery; + +my $comment = Apache::Gallery::get_comment("t/003_commenttest"); + +is ( $comment->{TITLE}, "My test title", 'Title'); +is ( $comment->{COMMENT}, "My test comment", 'Comment'); diff --git a/t/003_commenttest b/t/003_commenttest new file mode 100644 index 0000000..190ae42 --- /dev/null +++ b/t/003_commenttest @@ -0,0 +1,2 @@ +TITLE: My test title +My test comment diff --git a/t/004_cache_dir.t b/t/004_cache_dir.t new file mode 100644 index 0000000..4998b3c --- /dev/null +++ b/t/004_cache_dir.t @@ -0,0 +1,58 @@ +use Apache::Gallery; +my $tests; +BEGIN { + $tests=8; + eval { require Test::MockObject }; + if ($@) { + print("1..$tests\n"); + for (1..$tests) { + print ("ok $_ # skip Test::MockObject not found\n"); + } + exit 0; + } +} +use Test::More tests => $tests; +use File::Spec; + +# Test these cases: +# +--------------------------------------------------+ +# | No. | GalleryCacheDir | Virtual | Strip Filename | +# | 1 | undef | y | y | +# | 2 | undef | y | n | +# | 3 | undef | n | y | +# | 4 | undef | n | n | +# | 5 | 't/cachetest' | y | y | +# | 6 | 't/cachetest' | y | n | +# | 7 | 't/cachetest' | n | y | +# | 8 | 't/cachetest' | n | n | +# +-----+-----------------+---------+----------------+ + +sub request { + my ($cachedir, $virtual) = @_; + my $r=Test::MockObject->new(); + $r->set_always('location', '/location'); + $r->set_always('uri', '/uripath1/uripath2/urifile'); + $r->set_always('dir_config', $cachedir); + my $server=Test::MockObject->new(); + $server->set_always('is_virtual', $virtual); + $server->set_always('server_hostname', 'hostname' ); + $r->set_always('server', $server); + + return $r; +} + +my $r=request(undef, 1); +is(Apache::Gallery::cache_dir($r, 1), '/var/tmp/Apache-Gallery/hostname/uripath1/uripath2'); +is(Apache::Gallery::cache_dir($r, 0), '/var/tmp/Apache-Gallery/hostname/uripath1/uripath2/urifile'); + +$r=request(undef, 0); +is(Apache::Gallery::cache_dir($r, 1), '/var/tmp/Apache-Gallery/location/uripath1/uripath2'); +is(Apache::Gallery::cache_dir($r, 0), '/var/tmp/Apache-Gallery/location/uripath1/uripath2/urifile'); + +$r=request('t/cachetest', 1); +is(Apache::Gallery::cache_dir($r, 1), 't/cachetest/uripath1/uripath2'); +is(Apache::Gallery::cache_dir($r, 0), 't/cachetest/uripath1/uripath2/urifile'); + +$r=request('t/cachetest', 0); +is(Apache::Gallery::cache_dir($r, 1), 't/cachetest/uripath1/uripath2'); +is(Apache::Gallery::cache_dir($r, 0), 't/cachetest/uripath1/uripath2/urifile'); diff --git a/t/005_imageinfo.t b/t/005_imageinfo.t new file mode 100644 index 0000000..2ebe355 --- /dev/null +++ b/t/005_imageinfo.t @@ -0,0 +1,17 @@ +use Apache::Gallery; +use Test::More; + +eval { require Apache::FakeRequest; }; +if ($@) { + plan skip_all => 'skip Apache::FakeRequest not found'; +} +else { + + plan tests => 1; + + my $request = Apache::FakeRequest->new('get_remote_host' => 'localhost'); + + my $info = Apache::Gallery::get_imageinfo($request, "t/005_jpg.jpg", "JPG", 15, 11); + + is ( $info->{Comment}, "Created with The GIMP", 'Comment'); +} diff --git a/t/005_jpg.jpg b/t/005_jpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b3f30f854b2a2fe7bad8c2266eddb025d9fb97da GIT binary patch literal 396 zcmex=LJ%Z3brs z4mLJ+HdYRHc6Lrq4lW)MULJ049!Vi#ei2zIc{y1r85so?J#_^o9c39A4RcK$149!N z6M1z@TMHu_J!2CikRgnmoSZz|JQBRT5=M$Libf=Z{|6WZIT*MZ_?a1%7?=bZnFSgD zA7Ky!`+)%ou(7fO#gzmY7@1j^n3&-*Oh7&ZtDvHgp-Q0R#7#goq9E_107fRDu(%)t zGlsa}|62?^Kw&09WC t(Rg&G_EBM{B(?c2-9BrA&b^gCo2J~|^Hj;iexg@eu+rP5JL>=61OVv=Ru%vN literal 0 HcmV?d00001 diff --git a/t/006_thumbnails.t b/t/006_thumbnails.t new file mode 100644 index 0000000..29cf3db --- /dev/null +++ b/t/006_thumbnails.t @@ -0,0 +1,24 @@ +use Apache::Gallery; +use Test::More; + +eval { require Test::MockObject; }; +if ($@) { + plan skip_all => 'skip because Test::MockObject not found'; +} +else { + + plan tests => 4; + + my $r = Test::MockObject->new(); + + $r->set_always('dir_config', '100x75'); + + my ($width, $height) = Apache::Gallery::get_thumbnailsize($r, 640, 480); + is ($width, 100, 'Width'); + is ($height, 75, 'Height'); + + ($width, $height) = Apache::Gallery::get_thumbnailsize($r, 480, 640); + is ($width, 56, 'Height rotated'); + is ($height, 75, 'Width rotated'); + +} diff --git a/t/007_pod.t b/t/007_pod.t new file mode 100644 index 0000000..77fe89e --- /dev/null +++ b/t/007_pod.t @@ -0,0 +1,19 @@ +use Test::More; +use File::Spec; +use File::Find; +use strict; + +eval "use Test::Pod 0.95"; + +if ($@) { + plan skip_all => 'Test::Pod v0.95 required for testing POD'; +} else { + Test::Pod->import; + my @files; + my $blib = File::Spec->catfile(qw(blib lib)); + find( sub {push @files, $File::Find::name if /\.p(l|m|od)$/}, $blib); + plan tests => scalar @files; + foreach my $file (@files) { + pod_file_ok($file); + } +} diff --git a/templates/bright/README b/templates/bright/README new file mode 100644 index 0000000..eeb95de --- /dev/null +++ b/templates/bright/README @@ -0,0 +1,9 @@ +For this template to work the first two of the following options are a necessity, option three and four only completes the +design. Option two should of course be hacked to fit the EXIF from your camera. + +Remember to copy the new gallery.css to your DocumentRoot as well. + +PerlSetVar GalleryEXIFMode 'variables' +PerlSetVar GalleryInfo 'Model => Model, Timestamp => DateTimeOriginal, Exposure Time => ExposureTime, ISO Speed Rating => ISOSpeedRatings, Focal Length => FocalLength, ApertureValue => ApertureValue, Flash => Flash' +PerlSetVar GalleryThumbnailSize '140x105' +PerlSetVar GalleryThumbnailSizeLS 1 diff --git a/templates/bright/dircomment.tpl b/templates/bright/dircomment.tpl new file mode 100644 index 0000000..2d12f64 --- /dev/null +++ b/templates/bright/dircomment.tpl @@ -0,0 +1,11 @@ + + + + + + +
+ { $COMMENT } +
+ + diff --git a/templates/bright/directory.tpl b/templates/bright/directory.tpl new file mode 100644 index 0000000..e828ec4 --- /dev/null +++ b/templates/bright/directory.tpl @@ -0,0 +1 @@ + diff --git a/templates/bright/error.tpl b/templates/bright/error.tpl new file mode 100644 index 0000000..bf0c033 --- /dev/null +++ b/templates/bright/error.tpl @@ -0,0 +1,22 @@ + + + + +
+

{ $ERRORTITLE }

+

{ $ERROR }

+

Back

+
+ + diff --git a/templates/bright/file.tpl b/templates/bright/file.tpl new file mode 100644 index 0000000..04ff664 --- /dev/null +++ b/templates/bright/file.tpl @@ -0,0 +1 @@ + diff --git a/templates/bright/gallery.css b/templates/bright/gallery.css new file mode 100644 index 0000000..5720dd0 --- /dev/null +++ b/templates/bright/gallery.css @@ -0,0 +1,128 @@ +body { + background-color: #eee; + font-family: tahoma, verdana, sans-serif; + color: #555; + text-align: center; + font-size: 11px; + margin: 10px; +} +td { + font-size: 11px; +} +a { + color: #506677; + text-decoration: none; +} +a:hover { + text-decoration: underline; +} +table { + margin: auto; +} +.gallery-info { + text-align: left; + margin-bottom: 30px; +} +/* +.img-white { + margin: 0px auto; + float: left; + background: url(/eeeBorder.gif) no-repeat top left; +} +.img-shadow { + float: left; + background: url(/eeeshadow.gif) no-repeat bottom right; +} +*/ +.img-border { + background-color: #fff; + border: 1px solid #555; + padding: 8px; + font-size: 11px; + margin: 6px; + text-align: right; +} +.img-shadow img { + border: 2px solid #ddd; + border-left: 2px solid #999; + border-top: 2px solid #999; +} +.img-border div { + margin-top: 4px; +} +.clr { + clear: both; +} +div.gallery-nav { + float: right; + text-align: right; +} +div.gallery-info { + float: left; + text-align: left; +} +div.gallery-info a { +} +div.gallery-info:hover { + color: #000; +} +div.gallery-info:hover a { + color: #5b8db2; +} +.img-info { + margin-bottom: 5px; +} +.img-info:hover { + color: #000; +} +.img-options { + margin-top: 5px; + margin-bottom: 100px; +} +.img-options:hover { + color: #000; +} +.img-options:hover a { + color: #5b8db2; +} +.aginfo:hover { + color: #000; +} +.aginfo:hover a { + color: #0066b2; +} +#directory { + background-color: #fff; + border: 4px solid #ddd; + padding: 20px; + text-align: left; + top: 0px; + width: 620px; +} +.thumb { + float: left; + text-align: center; + width: 150px; + height: 150px; + margin: 2px; +} +.thumb img { + border-color: #506677; + vertical-align: middle; +} +.folder { + float: left; + height: 100px; + padding: 2px; + text-align: center; + width: 120px; +} +.folder img { + border: 0px; +} +.folder a:hover img { + border: 0px; +} +.folder a:hover { + text-decoration: none; +} diff --git a/templates/bright/index.tpl b/templates/bright/index.tpl new file mode 100644 index 0000000..fcebc08 --- /dev/null +++ b/templates/bright/index.tpl @@ -0,0 +1,23 @@ + + +
+
+{ $FORM_BEGIN } +
+ + + + +
+
+{ $FILES } +
+
+ { $DIRCOMMENT } +
+
+ Indexed by Apache::Gallery - Copyright © 2001-2006 Michael Legart - Hest Design! +
+{ $FORM_END } diff --git a/templates/bright/info.tpl b/templates/bright/info.tpl new file mode 100644 index 0000000..b7f2e08 --- /dev/null +++ b/templates/bright/info.tpl @@ -0,0 +1 @@ +{ $KEY }: { $VALUE }
diff --git a/templates/bright/interval.tpl b/templates/bright/interval.tpl new file mode 100644 index 0000000..78e817f --- /dev/null +++ b/templates/bright/interval.tpl @@ -0,0 +1 @@ +{ $SECONDS } diff --git a/templates/bright/intervalactive.tpl b/templates/bright/intervalactive.tpl new file mode 100644 index 0000000..d0af3eb --- /dev/null +++ b/templates/bright/intervalactive.tpl @@ -0,0 +1 @@ +{ $SECONDS } diff --git a/templates/bright/layout.tpl b/templates/bright/layout.tpl new file mode 100644 index 0000000..7d82715 --- /dev/null +++ b/templates/bright/layout.tpl @@ -0,0 +1,18 @@ + + + + + +{ $TITLE } + + +{ $META } + + + +{ $MAIN } + + diff --git a/templates/bright/navpicture.tpl b/templates/bright/navpicture.tpl new file mode 100644 index 0000000..96c6112 --- /dev/null +++ b/templates/bright/navpicture.tpl @@ -0,0 +1 @@ +{ $DIRECTION } diff --git a/templates/bright/nodircomment.tpl b/templates/bright/nodircomment.tpl new file mode 100644 index 0000000..e69de29 diff --git a/templates/bright/nopictureinfo.tpl b/templates/bright/nopictureinfo.tpl new file mode 100644 index 0000000..e69de29 diff --git a/templates/bright/orig.tpl b/templates/bright/orig.tpl new file mode 100644 index 0000000..fd20746 --- /dev/null +++ b/templates/bright/orig.tpl @@ -0,0 +1 @@ +Original diff --git a/templates/bright/picture.tpl b/templates/bright/picture.tpl new file mode 100644 index 0000000..0036282 --- /dev/null +++ b/templates/bright/picture.tpl @@ -0,0 +1 @@ +
{ $FILE } - { $DATE }{ $SELECT }
diff --git a/templates/bright/pictureinfo.tpl b/templates/bright/pictureinfo.tpl new file mode 100644 index 0000000..c7b93c8 --- /dev/null +++ b/templates/bright/pictureinfo.tpl @@ -0,0 +1,5 @@ +
+
+ { $INFO } + { $COMMENT } +
diff --git a/templates/bright/refresh.tpl b/templates/bright/refresh.tpl new file mode 100644 index 0000000..8b9379f --- /dev/null +++ b/templates/bright/refresh.tpl @@ -0,0 +1 @@ + diff --git a/templates/bright/scale.tpl b/templates/bright/scale.tpl new file mode 100644 index 0000000..3e532b9 --- /dev/null +++ b/templates/bright/scale.tpl @@ -0,0 +1 @@ +{ $SIZE } diff --git a/templates/bright/scaleactive.tpl b/templates/bright/scaleactive.tpl new file mode 100644 index 0000000..22a4e75 --- /dev/null +++ b/templates/bright/scaleactive.tpl @@ -0,0 +1 @@ +{ $SIZE } diff --git a/templates/bright/showpicture.tpl b/templates/bright/showpicture.tpl new file mode 100644 index 0000000..07019da --- /dev/null +++ b/templates/bright/showpicture.tpl @@ -0,0 +1,38 @@ + + + +
+
+ IMG { $NUMBER } of { $TOTAL } + | { $EXIF_DATETIMEORIGINAL } + | { $EXIF_EXPOSURETIME }s + | { $EXIF_ISOSPEEDRATINGS }iso + | { $EXIF_FOCALLENGTH } + | { $EXIF_APERTUREVALUE } +
+ + + + +
+
+
+
+ * Image { $NUMBER } + { $PICTUREINFO } +
+
+
+
+
+
+[ Size: { $SIZES } | Slideshow: { $SLIDESHOW } ] +
+ +
+ Apache::Gallery © 2001-2006 Michael Legart, Hest Design! +
diff --git a/templates/bright/slideshowisoff.tpl b/templates/bright/slideshowisoff.tpl new file mode 100644 index 0000000..ce76936 --- /dev/null +++ b/templates/bright/slideshowisoff.tpl @@ -0,0 +1 @@ +Off diff --git a/templates/bright/slideshowoff.tpl b/templates/bright/slideshowoff.tpl new file mode 100644 index 0000000..3c03d57 --- /dev/null +++ b/templates/bright/slideshowoff.tpl @@ -0,0 +1 @@ +Off diff --git a/templates/default/dircomment.tpl b/templates/default/dircomment.tpl new file mode 100644 index 0000000..2d12f64 --- /dev/null +++ b/templates/default/dircomment.tpl @@ -0,0 +1,11 @@ + + + + + + +
+ { $COMMENT } +
+ + diff --git a/templates/default/directory.tpl b/templates/default/directory.tpl new file mode 100644 index 0000000..568bd3d --- /dev/null +++ b/templates/default/directory.tpl @@ -0,0 +1 @@ + diff --git a/templates/default/error.tpl b/templates/default/error.tpl new file mode 100644 index 0000000..3c18406 --- /dev/null +++ b/templates/default/error.tpl @@ -0,0 +1,9 @@ + + + + +
+

{ $ERRORTITLE }

+

{ $ERROR }

+

Back +

diff --git a/templates/default/file.tpl b/templates/default/file.tpl new file mode 100644 index 0000000..42a5194 --- /dev/null +++ b/templates/default/file.tpl @@ -0,0 +1 @@ + diff --git a/templates/default/gallery.css b/templates/default/gallery.css new file mode 100644 index 0000000..b9ac880 --- /dev/null +++ b/templates/default/gallery.css @@ -0,0 +1,66 @@ +body { + background-color: #cccccc; + font-family: Verdana, Lucida, Arial; + font-size: 10px; + margin-left: 10px; + margin-top: 10px; + text-align: center; +} +td { + font-size: 10px; +} +table { + margin-left: auto; + margin-right: auto; +} +#menu { + font-size: 11px; + text-align: left; + height: 30px; +} +#nav { + font-size: 11px; + text-align: left; + height: 30px; + text-align: right; +} +#directory { + background-color: #ffffff; + border: 1px solid #666666; + padding: 20px; + text-align: left; + top: 0px; +} +#folder { + float: left; + height: 100px; + padding: 2px; + text-align: center; + width: 120px; +} +#picture img { + border: 1px solid #000000; +} +a { + color: #5555aa; +} +a img { + border: 2px solid #5555aa; +} +a:hover { + color: #ff9400; +} +a:hover img { + border: 2px solid #ff9400; +} +#folder img { + border: 0px; +} +.info { + background-color: #eeeeee; + border: 1px dashed #888888; + color: #666666; + font-size: 10px; + margin: 10px; + padding: 5px; +} diff --git a/templates/default/index.tpl b/templates/default/index.tpl new file mode 100644 index 0000000..8208a5c --- /dev/null +++ b/templates/default/index.tpl @@ -0,0 +1,23 @@ +
+ + + + + + + { $DIRCOMMENT } + + + +
+
+{ $FILES } +
+
+ Indexed by Apache::Gallery - Copyright © 2001-2005 Michael Legart - Hest Design! +
+
diff --git a/templates/default/info.tpl b/templates/default/info.tpl new file mode 100644 index 0000000..06d0563 --- /dev/null +++ b/templates/default/info.tpl @@ -0,0 +1 @@ +{ $KEY }: { $VALUE }
diff --git a/templates/default/interval.tpl b/templates/default/interval.tpl new file mode 100644 index 0000000..b2d78fc --- /dev/null +++ b/templates/default/interval.tpl @@ -0,0 +1 @@ +{ $SECONDS } diff --git a/templates/default/intervalactive.tpl b/templates/default/intervalactive.tpl new file mode 100644 index 0000000..d0af3eb --- /dev/null +++ b/templates/default/intervalactive.tpl @@ -0,0 +1 @@ +{ $SECONDS } diff --git a/templates/default/layout.tpl b/templates/default/layout.tpl new file mode 100644 index 0000000..d9dea95 --- /dev/null +++ b/templates/default/layout.tpl @@ -0,0 +1,14 @@ + + + + + { $TITLE } + + { $META } + + + +{ $MAIN } + + diff --git a/templates/default/navpicture.tpl b/templates/default/navpicture.tpl new file mode 100644 index 0000000..10b30c0 --- /dev/null +++ b/templates/default/navpicture.tpl @@ -0,0 +1 @@ +
{ $DIRECTION } - { $FILENAME }
diff --git a/templates/default/nodircomment.tpl b/templates/default/nodircomment.tpl new file mode 100644 index 0000000..e69de29 diff --git a/templates/default/nopictureinfo.tpl b/templates/default/nopictureinfo.tpl new file mode 100644 index 0000000..a5ead9b --- /dev/null +++ b/templates/default/nopictureinfo.tpl @@ -0,0 +1,11 @@ + +
+ + + + +
+   +
+
+ diff --git a/templates/default/orig.tpl b/templates/default/orig.tpl new file mode 100644 index 0000000..fd20746 --- /dev/null +++ b/templates/default/orig.tpl @@ -0,0 +1 @@ +Original diff --git a/templates/default/picture.tpl b/templates/default/picture.tpl new file mode 100644 index 0000000..41e97a3 --- /dev/null +++ b/templates/default/picture.tpl @@ -0,0 +1 @@ + { $FILE } - { $DATE } diff --git a/templates/default/pictureinfo.tpl b/templates/default/pictureinfo.tpl new file mode 100644 index 0000000..4a525a4 --- /dev/null +++ b/templates/default/pictureinfo.tpl @@ -0,0 +1,12 @@ + +
+ + + + +
+ { $COMMENT } + { $INFO } +
+
+ diff --git a/templates/default/refresh.tpl b/templates/default/refresh.tpl new file mode 100644 index 0000000..8b9379f --- /dev/null +++ b/templates/default/refresh.tpl @@ -0,0 +1 @@ + diff --git a/templates/default/scale.tpl b/templates/default/scale.tpl new file mode 100644 index 0000000..3e532b9 --- /dev/null +++ b/templates/default/scale.tpl @@ -0,0 +1 @@ +{ $SIZE } diff --git a/templates/default/scaleactive.tpl b/templates/default/scaleactive.tpl new file mode 100644 index 0000000..22a4e75 --- /dev/null +++ b/templates/default/scaleactive.tpl @@ -0,0 +1 @@ +{ $SIZE } diff --git a/templates/default/showpicture.tpl b/templates/default/showpicture.tpl new file mode 100644 index 0000000..d13f14b --- /dev/null +++ b/templates/default/showpicture.tpl @@ -0,0 +1,33 @@ +
+ +
+ + + + + + + + { $PICTUREINFO } + + + + + + +
+ +
{ $BACK }{ $NEXT }
+ +
+
+
diff --git a/templates/default/slideshowisoff.tpl b/templates/default/slideshowisoff.tpl new file mode 100644 index 0000000..ce76936 --- /dev/null +++ b/templates/default/slideshowisoff.tpl @@ -0,0 +1 @@ +Off diff --git a/templates/default/slideshowoff.tpl b/templates/default/slideshowoff.tpl new file mode 100644 index 0000000..3c03d57 --- /dev/null +++ b/templates/default/slideshowoff.tpl @@ -0,0 +1 @@ +Off diff --git a/templates/new/dircomment.tpl b/templates/new/dircomment.tpl new file mode 100644 index 0000000..2d12f64 --- /dev/null +++ b/templates/new/dircomment.tpl @@ -0,0 +1,11 @@ + + + + + + +
+ { $COMMENT } +
+ + diff --git a/templates/new/directory.tpl b/templates/new/directory.tpl new file mode 100644 index 0000000..5778170 --- /dev/null +++ b/templates/new/directory.tpl @@ -0,0 +1 @@ + diff --git a/templates/new/error.tpl b/templates/new/error.tpl new file mode 100644 index 0000000..e5f9540 --- /dev/null +++ b/templates/new/error.tpl @@ -0,0 +1,22 @@ + + + + +
+

{ $ERRORTITLE }

+

{ $ERROR }

+

Back

+
+ + diff --git a/templates/new/file.tpl b/templates/new/file.tpl new file mode 100644 index 0000000..cae88f4 --- /dev/null +++ b/templates/new/file.tpl @@ -0,0 +1 @@ + diff --git a/templates/new/gallery.css b/templates/new/gallery.css new file mode 100644 index 0000000..2cfbf32 --- /dev/null +++ b/templates/new/gallery.css @@ -0,0 +1,78 @@ +body { + background-color: #cccccc; + color: #666666; + font-family: Verdana, Lucida, Arial, serif; + font-size: 10px; + margin-left: 10px; + margin-top: 10px; + text-align: center; +} +td { + font-size: 10px; +} +table { + margin-left: auto; + margin-right: auto; +} +#title { + font-size: 11px; + text-align: left; +} +#menu { + font-size: 13px; + text-align: right; + height: 30px; + margin-right: 20px; +} +#directory { + background-color: #ffffff; + border: 6px solid #aaaaaa; + padding: 20px; + text-align: left; + top: 0px; +} +.folder { + float: left; + height: 100px; + padding: 2px; + text-align: center; + width: 120px; +} +#picture { + text-align: center; +} +#picture img { + border: 6px solid #777777; +} +a { + color: #5555aa; + text-decoration: none; +} +a img { + border: 3px solid #5555aa; +} +a:hover { + color: #ff9400; +} +a:hover img { + border: 3px solid #ff9400; +} +.folder img { + border: 0px; +} +.folder a:hover img { + border: 0px; +} +#gallery { + margin-top: 50px; +} +#comment { + background-color: #333333; + border: 3px solid #555555; + color: #999999; + width: 400px; + margin-left: auto; + margin-right: auto; + margin-top: 20px; + padding: 5px; +} diff --git a/templates/new/index.tpl b/templates/new/index.tpl new file mode 100644 index 0000000..4ba4105 --- /dev/null +++ b/templates/new/index.tpl @@ -0,0 +1,23 @@ +
+
+{ $MENU } +
+ + { $FORM_BEGIN } + + + + + { $DIRCOMMENT } + + + +
+
+{ $FILES } +
+
+ Indexed by Apache::Gallery - Copyright © 2001-2005 Michael Legart - Hest Design! +
+ { $FORM_END } +
diff --git a/templates/new/info.tpl b/templates/new/info.tpl new file mode 100644 index 0000000..06d0563 --- /dev/null +++ b/templates/new/info.tpl @@ -0,0 +1 @@ +{ $KEY }: { $VALUE }
diff --git a/templates/new/interval.tpl b/templates/new/interval.tpl new file mode 100644 index 0000000..b2d78fc --- /dev/null +++ b/templates/new/interval.tpl @@ -0,0 +1 @@ +{ $SECONDS } diff --git a/templates/new/intervalactive.tpl b/templates/new/intervalactive.tpl new file mode 100644 index 0000000..d0af3eb --- /dev/null +++ b/templates/new/intervalactive.tpl @@ -0,0 +1 @@ +{ $SECONDS } diff --git a/templates/new/layout.tpl b/templates/new/layout.tpl new file mode 100644 index 0000000..d9dea95 --- /dev/null +++ b/templates/new/layout.tpl @@ -0,0 +1,14 @@ + + + + + { $TITLE } + + { $META } + + + +{ $MAIN } + + diff --git a/templates/new/navpicture.tpl b/templates/new/navpicture.tpl new file mode 100644 index 0000000..96c6112 --- /dev/null +++ b/templates/new/navpicture.tpl @@ -0,0 +1 @@ +{ $DIRECTION } diff --git a/templates/new/nodircomment.tpl b/templates/new/nodircomment.tpl new file mode 100644 index 0000000..e69de29 diff --git a/templates/new/nopictureinfo.tpl b/templates/new/nopictureinfo.tpl new file mode 100644 index 0000000..a5ead9b --- /dev/null +++ b/templates/new/nopictureinfo.tpl @@ -0,0 +1,11 @@ + +
+ + + + +
+   +
+
+ diff --git a/templates/new/orig.tpl b/templates/new/orig.tpl new file mode 100644 index 0000000..fd20746 --- /dev/null +++ b/templates/new/orig.tpl @@ -0,0 +1 @@ +Original diff --git a/templates/new/picture.tpl b/templates/new/picture.tpl new file mode 100644 index 0000000..a0bff91 --- /dev/null +++ b/templates/new/picture.tpl @@ -0,0 +1 @@ + { $FILE } - { $DATE }{ $SELECT } diff --git a/templates/new/pictureinfo.tpl b/templates/new/pictureinfo.tpl new file mode 100644 index 0000000..1c24017 --- /dev/null +++ b/templates/new/pictureinfo.tpl @@ -0,0 +1,8 @@ + + +
+ { $INFO } + { $COMMENT } +
+ + diff --git a/templates/new/refresh.tpl b/templates/new/refresh.tpl new file mode 100644 index 0000000..8b9379f --- /dev/null +++ b/templates/new/refresh.tpl @@ -0,0 +1 @@ + diff --git a/templates/new/scale.tpl b/templates/new/scale.tpl new file mode 100644 index 0000000..3e532b9 --- /dev/null +++ b/templates/new/scale.tpl @@ -0,0 +1 @@ +{ $SIZE } diff --git a/templates/new/scaleactive.tpl b/templates/new/scaleactive.tpl new file mode 100644 index 0000000..22a4e75 --- /dev/null +++ b/templates/new/scaleactive.tpl @@ -0,0 +1 @@ +{ $SIZE } diff --git a/templates/new/showpicture.tpl b/templates/new/showpicture.tpl new file mode 100644 index 0000000..b97f373 --- /dev/null +++ b/templates/new/showpicture.tpl @@ -0,0 +1,30 @@ +
+
+ { $MENU } +
+ + +
+ + + + + + + { $PICTUREINFO } + + + + +
+ IMG { $NUMBER } of { $TOTAL } { $EXIFVALUES }

+ * Image { $NUMBER }

+[ Size: { $SIZES } | Slideshow: { $SLIDESHOW } ]
+ +
+
+
diff --git a/templates/new/slideshowisoff.tpl b/templates/new/slideshowisoff.tpl new file mode 100644 index 0000000..ce76936 --- /dev/null +++ b/templates/new/slideshowisoff.tpl @@ -0,0 +1 @@ +Off diff --git a/templates/new/slideshowoff.tpl b/templates/new/slideshowoff.tpl new file mode 100644 index 0000000..3c03d57 --- /dev/null +++ b/templates/new/slideshowoff.tpl @@ -0,0 +1 @@ +Off -- 2.39.2