]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/PhotoAlbum.php
Update from version 1.2 by Ted Vinke
[SourceForge/phpwiki.git] / lib / plugin / PhotoAlbum.php
1 <?php // -*-php-*-
2 rcs_id('$Id: PhotoAlbum.php,v 1.3 2004-02-27 08:03:35 rurban Exp $');
3 /*
4  Copyright 2003, 2004 $ThePhpWikiProgrammingTeam
5  
6  This file is part of PhpWiki.
7
8  PhpWiki is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  PhpWiki is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with PhpWiki; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 /**
24  * WikiPlugin which makes an 'album' of a set of photos with optional
25  * descriptions.
26  *
27  * @author: Ted Vinke <teddy@jouwfeestje.com>
28  *          local fs by Reini Urban
29  *
30  * Usage:
31  * <?plugin PhotoAlbum
32  *          src="http://server/textfile" or localfile or localdir or nothing
33  *          mode=[column|row]
34  *          desc=true
35  *          sort=false
36  *          height=50%
37  *          width=50%
38  * ?>
39
40  * (1) No src specified. Means [wikipagename].jpg from fixed albumlocation
41  *     will be displayed e.g. "Sandbox.jpg".
42  *
43  *     You can set the following constants:
44  */
45
46 define('allow_album_location', true);
47 define('album_location', 'http://kw.jouwfeestje.com/foto/redactie');
48 define('album_default_extension', '.jpg');
49
50 /**
51  * (2) Textfile. Local or remote e.g. http://myserver/images/MyPhotos.txt
52  *     E.g. possible content of a valid textfile:
53  *
54  *      photo-01.jpg; Me and my girlfriend
55  *      photo-02.jpg
56  *      christmas.gif; Merry Christmas!
57
58  *     Inside textfile, filenames and optional descriptions are seperated by
59  *     constant 'desc_separator' (default is semi-colon) on each line. Listed
60  *     files must be in same directory as textfile itself, so don't use
61  *     relative paths inside textfile.
62  */
63
64 define('desc_separator', ';');
65
66 /**
67  * (3) Directory. 
68  *     Need weblocation="" the webpath to the srcdir
69  *
70  * Other parameters that need explaining:
71  * "parameter"  "value"
72  *
73  * "mode"       "normal" - Normal table which shows photos full-size
74  *              "thumbs" - WinXP thumbnail style
75  *              "tiles"  - WinXP tiles style
76  *              "list"   - WinXP list style
77  *              "slide"  - Not yet implemented
78  *
79  * "numcols"    Amount of columns per row in table
80  *
81  * "showdesc"   "none"   - No descriptions next to photos
82  *              "name"   - Only filename shown
83  *              "desc"   - Only description (from textfile) shown
84  *              "both"   - If no description found, then filename will be used
85  *
86  * "link"       If true, each image will be hyperlink to page where only that
87  *              photo will be shown full-size. Only works when mode != 'normal'
88  *
89  * "attrib"     Array which can hold:
90  *              "sort"   - sort shown photos alphabetically
91  *              "nowrap" - descriptions won't be wrapped
92  *              "alt"    - descs instead of filenames are used in image ALT-tags
93  *
94  * "bgcolor"
95  * "hlcolor"    Cell background and highlight color
96  *
97  * "align"      Aligment of cell: "left", "center", "right"
98  *
99  * "height"
100  * "width"      Size of shown photos. Either absolute value (e.g. "50") or
101  *              HTML style percentage (e.g. "75%") or "auto" for no special
102  *              action.
103  *
104  * "cellwidth"  Width of cells in table. Either absolute value in pixels, HTML
105  *              style percentage, "auto" (no special action), "equal" (where
106  *              all columns are equally sized) or "image" (take height and
107  *              width of the photo in that cell).
108  *
109  * "tablewidth" Guess what.
110  */
111
112 define('default_mode', 'normal');       // normal|thumbs|tiles|list
113 define('default_numcols', 3);           // photos per row
114 define('default_showdesc', 'both');     // none|name|desc|both
115 define('default_link', true);           // show link to original sized photo
116 define('default_attrib', '');           // 'sort, nowrap, alt'
117 define('default_bgcolor', '#eae8e8');   // cell bgcolor (lightgrey)
118 define('default_hlcolor', '#c0c0ff');   // highlight color (lightblue)
119 define('default_align', 'center');      // alignment of all
120 define('default_height', 'auto');       // image height (auto|75|100%)
121 define('default_width', 'auto');        // image width (auto|75|100%)
122 define('default_cellwidth', 'image');   // cell (auto|equal|image|75|100%)
123 define('default_tablewidth', 1);        // table (75|100%)
124
125 /**
126  * TODO:
127  *
128  * - parse any local directory for pictures
129  * - implement WinXP style 'slide' mode
130  * - specify picture(s) as parameter(s)
131  * - limit amount of pictures on one page
132  * - use PHP to really resize or greyscale images (only where GD library
133  *   supports it)
134  *
135  * KNOWN ISSUES:
136  *
137  * - reading height and width, from images with spaces in their names, fails
138  *
139  * Fixed album location idea by Philip J. Hollenback. Thanks!
140  */
141
142 class WikiPlugin_PhotoAlbum
143 extends WikiPlugin
144 {
145     function getName () {
146         return _("PhotoAlbum");
147     }
148
149     function getDescription () {
150         return _("Displays a set of photos listed in a text file with optional descriptions");
151     }
152
153     function getVersion() {
154         return preg_replace("/[Revision: $]/", '',
155                             "\$Revision: 1.3 $");
156     }
157
158     function getDefaultArguments() {
159         return array('src'      => '',          // textfile
160                      'mode'     => default_mode,
161                      'numcols'  => default_numcols,
162                      'showdesc' => default_showdesc,
163                      'link'     => default_link,
164                      'attrib'   => default_attrib,
165                      'bgcolor'  => default_bgcolor,
166                      'hlcolor'  => default_hlcolor,
167                      'align'    => default_align,
168                      'height'   => default_height,
169                      'width'    => default_width,
170                      'cellwidth'=> default_cellwidth,
171                      'tablewidth'=> default_tablewidth,
172                      'p'        => false, // "displaythissinglephoto.jpg"
173                      'h'        => false, // "highlightcolorofthisphoto.jpg"
174                      'weblocation'  => false, // if src = localfs the web location
175                      );
176     }
177     // attrib arg allows multiple attributes attrib=sort,nowrap,alt
178     // 'sort' sorts alphabetically, 'nowrap' for cells, 'alt' to use
179     // descriptions (instead of filenames) for image alt-tags
180
181     function run($dbi, $argstr, $request) {
182         extract($this->getArgs($argstr, $request));
183
184         $attributes = $attrib ? explode(",", $attrib) : array();
185
186         $photos = array();
187         $html = HTML();
188
189         // check all parameters
190
191         // what type do we have?
192         if (!$src) {
193             $showdesc  = 'none';
194             $src   = $request->getArg('pagename');
195             $error = $this->fromLocation($src, $photos);
196         } else {
197             $error = $this->fromFile($src, $photos, $weblocation);
198         }
199         if ($error) {
200             return $this->error($error);
201         }
202
203         if ($numcols < 1) $numcols = 1;
204         if ($align != 'left' && $align != 'center' && $align != 'right') {
205             $align = default_align;
206         }
207
208         if (count($photos) == 0) return;
209
210         if (in_array("sort", $attributes))
211             sort($photos);
212
213         if ($p) {
214             $mode = "normal";
215         }
216
217         // set some fixed properties for each $mode
218         if ($mode == 'thumbs' || $mode == 'tiles') {
219             $attributes = array_merge($attributes, "alt");
220             $attributes = array_merge($attributes, "nowrap");
221             $cellwidth  = 'auto'; // else cell won't nowrap
222             $showdesc   = 'name';
223             $width      = 50;
224         } elseif ($mode == 'list') {
225             $numcols    = 1;
226             $cellwidth  = "auto";
227             if ($showdesc != "none") {
228                 $showdesc = "desc";
229             }
230         }
231
232         $row = HTML();
233         while (list($key, $value) = each($photos))  {
234             if ($p && basename($value["name"]) != "$p") {
235                 continue;
236             }
237             if ($h && basename($value["name"]) == "$h") {
238                 $color = $hlcolor ? $hlcolor : $bgcolor;
239             } else {
240                 $color = $bgcolor;
241             }
242             // $params will be used for each <img > tag
243             $params = array('src'    => $value["name"],
244                             'border' => "0",
245                             'alt'    => ($value["desc"] != "" &&
246                                          in_array("alt", $attributes)) ?
247                                          $value["desc"] :
248                                          basename($value["name"])
249                             );
250
251             // check description
252             switch ($showdesc) {
253                 case 'none':
254                     $value["desc"] = '';
255                     break;
256                 case 'name':
257                     $value["desc"] = basename($value["name"]);
258                     break;
259                 case 'desc':
260                     break;
261                 default: // 'both'
262                     $value["desc"] = ($value["desc"] != "") ?
263                                       $value["desc"] :
264                                       basename($value["name"]);
265                     break;
266             }
267
268             // FIXME: get getimagesize to work with names with spaces in it
269             $size = @getimagesize($value["name"]); // try " " => "\\ "
270
271             if (!$size) {
272                 trigger_error("Unable to getimagesize(".$value["name"].")",E_USER_NOTICE);
273             }
274
275             $newwidth = $this->newSize($size[0], $width);
276             $newheight = $this->newSize($size[1], $height);
277
278             if ($width != 'auto' && $newwidth > 0) {
279                 $params = array_merge($params, array("width" => $newwidth));
280             }
281             if ($height != 'auto' && $newheight > 0) {
282                 $params = array_merge($params, array("height" => $newheight));
283             }
284
285             // cell operations
286             $cell = array('align'   => "center",
287                           'valign'  => "top",
288                           'bgcolor' => "$color",
289                           );
290             if ($cellwidth != 'auto') {
291                 if ($cellwidth == 'equal') {
292                     $newcellwidth = round(100/$numcols)."%";
293                 } else if ($cellwidth == 'image') {
294                     $newcellwidth = $newwidth;
295                 } else {
296                     $newcellwidth = $cellwidth;
297                 }
298                 $cell = array_merge($cell, array("width" => $newcellwidth));
299             }
300             if (in_array("nowrap", $attributes)) {
301                 $cell = array_merge($cell, array("nowrap" => ""));
302             }
303             //create url to display single larger version of image on page
304             $url        = WikiURL($request->getPage(),
305                           array("p" => basename($value["name"])));
306             $b_url      = WikiURL($request->getPage(),
307                           array("h" => basename($value["name"]))).
308                                                 "#".
309                                                 basename($value["name"]);
310             $url_text   = $link ? HTML::a(array("href" => "$url"),
311                                                 basename($value["name"])) :
312                                                 basename($value["name"]);
313             if (! $p) {
314                 $url_image = $link ? HTML::a(array("href" => "$url"),
315                                                    HTML::img($params)) :
316                                                    HTML::img($params);
317             } else {
318                 $url_image = $link ? HTML::a(array("href" => "$b_url"),
319                                                    HTML::img($params)) :
320                                                    HTML::img($params);
321             }
322             $url_text = HTML::a(array("name" => basename($value["name"])),
323                                       $url_text);
324             // here we use different modes
325             if ($mode == 'tiles') {
326                 $row->pushContent(HTML::td($cell,
327                      HTML::table(array("cellpadding" => 1, "border" => 0),
328                      HTML::tr(
329                            HTML::td(array("valign" => "top", "rowspan" => 2),
330                                            $url_image),
331                            HTML::td(array("valign" => "top", "nowrap" => 0),
332                                           HTML::small(HTML::strong($url_text)),
333                                           HTML::br(),
334                                           HTML::small($size[0].
335                                                       " x ".
336                                                       $size[1].
337                                                       " pixels"))
338                               ))));
339             } else if ($mode == 'list') {
340                 $desc = ($showdesc != 'none') ? $value["desc"] : '';
341                 $row->pushContent(
342                     HTML::td(array("valign"  => "top",
343                                    "nowrap"  => 0,
344                                    "bgcolor" => $color),
345                                    HTML::small(HTML::strong($url_text))));
346                 $row->pushContent(
347                     HTML::td(array("valign"  => "top",
348                                    "nowrap"  => 0,
349                                    "bgcolor" => $color),
350                                    HTML::small($size[0].
351                                                " x ".
352                                                $size[1].
353                                                " pixels")));
354
355                 if ($desc != '') {
356                     $row->pushContent(HTML::td(array("valign"  => "top",
357                                                      "nowrap"  => 0,
358                                                      "bgcolor" => $color),
359                                                      HTML::small($desc)));
360                 }
361             } else if ($mode == 'thumbs') {
362                 $desc = ($showdesc != 'none') ?
363                         HTML::p(HTML::a(array("href" => "$url"),
364                                         $url_text)) :
365                                         '';
366                 $row->pushContent(
367                     (HTML::td($cell,
368                               $url_image,
369                               // FIXME: no HtmlElement for fontsizes?
370                               // rurban: use ->setAttr("style","font-size:small;")
371                               //         but better use a css class
372                               HTML::span(array('class'=>'gensmall'),$desc)
373                               )));
374             } else /* 'normal' mode */ {
375                 $desc = ($showdesc != 'none') ? HTML::p($value["desc"]) : '';
376                 $row->pushContent(
377                     (HTML::td($cell,
378                               $url_image,
379                               // FIXME: no HtmlElement for fontsizes?
380                               HTML::span(array('class'=>'gensmall'),$desc)
381                               )));
382             }
383
384             // no more images in one row as defined by $numcols
385             if ( ($key + 1) % $numcols == 0 ||
386                  ($key + 1) == count($photos) ||
387                   $p) {
388                 $html->pushcontent(HTML::tr($row));
389                 $row->setContent('');
390             }
391         }
392
393         //create main table
394         $html = HTML::table(array("border"      => 0,
395                                   "cellpadding" => 5,
396                                   "cellspacing" => 2,
397                                   "width"       => $tablewidth),
398                                   $html);
399         // align all
400         $html = HTML::div(array("align" => $align), $html);
401         return $html;
402     }
403
404     /**
405      * Calculate the new size in pixels when the original size
406      * with a value is given.
407      *
408      * @param integer $oldSize Absolute no. of pixels
409      * @param mixed $value Either absolute no. or HTML percentage e.g. '50%'
410      * @return integer New size in pixels
411      */
412     function newSize($oldSize, $value) {
413         if (substr($value, strlen($value) - 1) != "%") {
414             return $value;
415         }
416         substr_replace($value, "%", "");
417         return round(($oldSize*$value)/100);
418     }
419
420     /**
421     * fromLocation - read only one picture from fixed album_location
422     * and return it in array $photos
423     *
424     * @param string $src Name of page
425     * @param array $photos
426     * @return string Error if fixed location is not allowed
427     */
428     function fromLocation($src, &$photos) {
429         if (!allow_album_location) {
430             return $this->error(_("Fixed album location is not allowed.
431                                          Please specify parameter src."));
432         }
433         $photos[count($photos)] =
434           array ("name" => album_location."/$src".album_default_extension,
435                  "desc" => ""
436                  );
437     }
438
439     /**
440      * fromFile - read pictures & descriptions (separated by desc_sep)
441      * from file $src and return it in array $photos
442      *
443      * @param string $src Full path and filename of textfile
444      * @param array $photos
445      * @return string Error when bad url or file couldn't be opened
446      */
447     function fromFile($src, &$photos, $webpath = false) {
448         if (! IsSafeURL($src)) {
449             return $this->error(_("Bad url in src: remove all of <, >, \""));
450         }
451         if (!preg_match('/^(http|ftp|https):\/\//i',$src)) {
452             // check if src is a directory
453             if (file_exists($src) and filetype($src) == 'dir') {
454                 //all images
455                 $list = array();
456                 foreach (array('jpeg','jpg','png','gif') as $ext) {
457                     $fileset = new fileSet($src, "*.$ext");
458                     $list = array_merge($list,$fileset->getFiles());
459                 }
460                 // convert dirname($src) (local fs path) to web path
461                 natcasesort($list);
462                 foreach ($list as $file) {
463                     // convert local path to webpath
464                     $photos[] = array ("name" => $webpath . "/$file",
465                                        "desc" => "",
466                                        );
467                 }
468                 return;
469             }
470         } else {
471             if (! ini_get('allow_url_fopen'))
472                 return $this->error(fmt("Wrong server setting: allow_url_fopen set to Off"));
473         }
474         @$fp = fopen ($src,"r");
475         if (!$fp) {
476             return $this->error(fmt("Unable to read %s ", $src));
477         }
478         while ($data = fgetcsv ($fp, 1024, desc_separator)) {
479             if (count($data) == 0 || empty($data[0]))
480                 continue;
481             // otherwise when empty 'undefined index 1' PHP warning appears
482             if (empty($data[1]))
483                 $data[1] = '';
484             $photos[count($photos)] = array ("name" => dirname($src).
485                                                        "/".
486                                                        trim("$data[0]"),
487                                              "desc" => trim("$data[1]"),
488                                              );
489         }
490         fclose ($fp);
491     }
492 };
493
494 // $Log: not supported by cvs2svn $
495 // Revision 1.2  2004/02/17 12:11:36  rurban
496 // added missing 4th basepage arg at plugin->run() to almost all plugins. This caused no harm so far, because it was silently dropped on normal usage. However on plugin internal ->run invocations it failed. (InterWikiSearch, IncludeSiteMap, ...)
497 //
498 // Revision 1.1  2003/01/05 04:21:06  carstenklapp
499 // New plugin by Ted Vinke (sf tracker patch #661189)
500 //
501
502 // For emacs users
503 // Local Variables:
504 // mode: php
505 // tab-width: 8
506 // c-basic-offset: 4
507 // c-hanging-comment-ender-p: nil
508 // indent-tabs-mode: nil
509 // End:
510 ?>