Gallery Plugin

http://www.dokuwiki.org/plugin:gallery


plugin


description: This Syntax Plugin allows you to embed an automatically created image gallery into a page. author : Andreas Gohr email : andi@splitbrain.org type : syntax lastupdate : 2010-04-30 compatible : 2009-12-25+ depends : conflicts : similar : tags : media, images, gallery, namespace, feed, embed, listing

downloadurl: http://github.com/splitbrain/dokuwiki-plugin-gallery/zipball/master sourcerepo : http://github.com/splitbrain/dokuwiki-plugin-gallery/ bugtracker : http://github.com/splitbrain/dokuwiki-plugin-gallery/issues donationurl: http://donate.dokuwiki.org/Gallery


Use the download link given above in the plugin manager or to download the plugin manually.

A basic gallery can be added by selecting a namespace like this:

{{gallery>namespace}}

All image files in the selected namespace will be added to the image gallery. Don't forget the “:” in front of the namespace.

Instead of using a whole namespace of images, you can also specify a single image – this makes most sense when combined with the lightbox mode (see below).

{{gallery>namespace:someimage.jpg}}

The created gallery can be aligned by using white space (defaults to centered):

{{gallery> namespace}} (right aligned)
{{gallery>namespace }} (left aligned)
{{gallery> namespace }} (centered)

Instead of a namespace, you can also give an HTTP(s) URL to any Media RSS or ATOM feed with enclosures (as produced by most photo sharing sites like Flickr). The images will then be pulled from that feed instead:

{{gallery>http://www.23hq.com/rss/schabloni}}

Note: since the question mark is used to separate the parameters (see next section) the URL can not contain any question mark. To use such a feed URL with the gallery plugin, just use one of the many short URL services like http://bit.ly.

E.g. instead of http://api.flickr.com/services/feeds/photos_public.gne?id=22019303@N00&lang=en-us&format=rss_200 use a shortened URL like http://bit.ly/HurZM.

Additionally, to have thumbnail creation correctly working you need to set fetchsize big enough to get the remote images downloaded.

A number of parameters can be set by appending them with ? character to the namespace or image. Each parameter needs to be separated with a & character. Defaults for all parameters can be set in the config manager. If a parameter is enabled by default it can be disabled in the syntax by prefixing it with the syllable no. E.g. the parameter cache is usually enabled and can be disabled using the keyword nocache. Below is a list of all recognized parameters

Parameter Default Description
<number>x<number> 120x120 Sets the size for thumbnails. Unless the crop option is set, this is a boundary box into which the thumbnail will be fitted, maintaining the correct aspect ratio.
<number>X<number> 800X600 Sets the size for the linked images in direct mode. This is a boundary box into which the image will be fitted, maintaining the correct aspect ratio. Note the uppercase X.
<number> 5 The number images per row in the gallery table. If you specify a 0 no table is used instead all thumbnails are added in a sequence.
=<number> =0 Limits the output to the given number of images. 0 means all.
+<number> +0 Skip the first number of images. Useful with the option above.
~<number> ~0 Add a pagination for the thumbnails displaying the number of given thumbnails per page. 0 disables pagination. Pagination is added through JavaScript - when no JavaScript is available all thumbnails are displayed
cache enabled Usually the output of the created gallery is cached. When the images in your selected namespace change, you have to manually force an update of the gallery page's cache. To disable the cache for the page showing the gallery, set nocache as option.
crop disabled Make thumbnails the exact given thumbnail size big, cropping when needed.
direct disabled Link thumbnails with the bigger sized images not with their detail page
lightbox disabled Show images in a fancy JavaScript modal browsing window, see below for details. Setting this option automatically implies the direct mode
reverse disabled Reverse the order of the displayed images
recursive enabled Find images in the given namespace and all sub namespaces
random disabled Sort images randomly. You might want to use nocache as well
modsort disabled Sort images by file modification date
datesort disabled Sort images by EXIF date
titlesort disabled Sort images by EXIF title
showname disabled Show filename below thumbnails
showtitle disabled Show EXIF title below thumbnails
anything containing a * jpg,gif,png images This can be used to filter the list of files found in the given namespace. * work as simple wildcard symbol.

Example:

{{gallery>images:vacation?image_*.jpg&80x80&crop&lightbox}}

This displays all images beginning with image_ and ending in .jpg from the namespace images:vacation. Thumbnails are cropped to 80×80 pixels and images will be opened in lightbox mode.

This mode will open the clicked picture inside the current browser window without leaving the current page1). You can close the picture view by clicking the little X in the upper right corner or anywhere in the picture. You can move to the next or previous image by using the arrow buttons in the lower corners.

The picture is downsized if necessary to fit into the current browser window. You can enlarge it with the arrow button in the top corner.

The following keys can be used to navigate:

Key Action
or n next image
or p previous image
x or c or ESC close the image view

Note: The feature does not use Version 2 of the Lightbox script because of its heavy and DokuWiki-incompatible dependencies.

Uploading images is beyond the scope of this plugin. Do not request any features regarding this.

  • Use the Mediamanager to upload images one by one
  • Use the archiveupload plugin to upload multiple images in a Zip file
  • Use the Flash Uploader to upload multiple files
  • Upload the files manually via FTP to the data/media directory. Keep in mind that image names need to be valid pagenames, all lowercase, no spaces or special chars!

The gallery output is cached by default. When you add pictures later, they may not show up in the gallery: add &purge=true to the end of the URL to clear the cache. See caching for details.

Optionally use the nocache parameter of the plugin (not recommended).

Problems with accessing EXIF or IPTC data in the images, should be reported as DokuWiki bugs and not for this plugin. All EXIF handling is in DokuWiki core. Currently EXIF Data is expected in UTF-8 encoding. There are some problems fetching the correct date from images, these are fixed in the current development version of DokuWiki.

When the lightbox mode doesn't work and instead images are simply opened in the same window, the JavaScript was not correctly loaded. This is most likely a Browser-Cache issue. Simply follow the steps described for fixing a similar problem with the toolbar.

It seems the image sizing parameters for direct mode don't apply to the lightbox. Ex. My images were being fit to 800×600 lightbox even with an <num>X<num> parameter. Setting the default direct image size in the configuration page did work though.

When no thumbnails are created, then your PHP install is missing the libGD extension. Either install the extension or configure DokuWiki to use imagemagick instead.

When no images from your feed are shown, be sure you don't have a question mark in your URL. Use an URL shortener as suggested above. Also be sure your feed URL (before shortening) starts with http:// or https:// and not with feed://. The latter is just a renamed HTTP link - simply rename it back.

As written above, you need to increase the fetchsize config option. Also make sure LibGD or ImageMagick are installed.

Be sure to read the Known Limitations and Caveats section first. Questions should be asked in the forum. Bugs and feature wishes should be reported in the issue tracker linked at the top. The section below will be removed in the future.

Use this syntax.php if you want comments for your images.

<gallery images:vacation?image_*.jpg&80x80&crop&lightbox>
image.jpg=Comment for image 
image2.jpg=second comment for another image 
</gallery>
<?php
/**
 * Embed an image gallery
 *
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Andreas Gohr <andi@splitbrain.org>
 * @author     Joe Lapp <joe.lapp@pobox.com>
 * @author     Dave Doyle <davedoyle.canadalawbook.ca>
 * @author     Gerry Weissbach <gerry.w@gammaproduction.de>
 */

if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');
require_once(DOKU_INC.'inc/search.php');
require_once(DOKU_INC.'inc/JpegMeta.php');

class syntax_plugin_gallery extends DokuWiki_Syntax_Plugin {
    /**
     * return some info
     */
    function getInfo(){
        return array(
            'author' => 'Andreas Gohr',
            'email'  => 'andi@splitbrain.org',
            'date'   => '2007-11-06',
            'name'   => 'Gallery Plugin',
            'desc'   => 'Creates a gallery of images from a namespace',
            'url'    => 'http://wiki.splitbrain.org/plugin:gallery',
        );
    }

    /**
     * What kind of syntax are we?
     */
    function getType(){
        return 'substition';
    }

    /**
     * What about paragraphs?
     */
    function getPType(){
        return 'block';
    }

    /**
     * Where to sort in?
     */
    function getSort(){
        return 301;
    }


    /**
     * Connect pattern to lexer
     */
    function connectTo($mode) {
        //$this->Lexer->addSpecialPattern('\{\{gallery>[^}]*\}\}',$mode,'plugin_gallery');
        $this->Lexer->addSpecialPattern('<gallery.*?>.+?</gallery>',$mode,'plugin_gallery');
    }


    /**
     * Parse option
     */
    function parseOpt($params, $name) {
        if(preg_match('/\b'.$name.'\b/i',$params,$match)) {
	    return true;
        }else if(preg_match('/\bno'.$name.'\b/i',$params,$match)) {
	    return false;
	}else{
            return $this->getConf($name);
        }
    }

    /**
     * Handle the match
     */
    function handle($all_match, $state, $pos, &$handler){
        //$match = substr($match,10,-2); //strip markup from start and end

        $data = array();

        //handle params
        //list($ns,$params) = explode('?',$match,2);
	preg_match("#<gallery(.*?)>#", $all_match, $para);
	list($ns,$params) = explode('?',$para[1],2);

        /*if ( substr($ns, 0, 1) == ' ' )
        	$data['float']="right";
        else if ( substr($ns, -1) == ' ' )
        	$data['float']="left";
        else
        	$data['float'] = null;
	*/
        //namespace
        $data['ns'] = $ns;

        //max thumb dimensions
        if(preg_match('/\b(\d+)x(\d+)\b/',$params,$match)){
            $data['w'] = $match[1];
            $data['h'] = $match[2];
        }else{
            $data['w'] = $this->getConf('thumbnail_width');
            $data['h'] = $this->getConf('thumbnail_height');
        }

        //max lightbox dimensions
        if(preg_match('/\b(\d+)X(\d+)\b/',$params,$match)){
            $data['w_lightbox'] = $match[1];
            $data['h_lightbox'] = $match[2];
        }else{
            $data['w_lightbox'] = $this->getConf('image_width');
            $data['h_lightbox'] = $this->getConf('image_height');
        }

        //number of images per row
        if(preg_match('/\b(\d+)\b/i',$params,$match)){
            $data['cols'] = $match[1];
        }else{
            $data['cols'] = $this->getConf('cols');
        }

        //show the filename
		$data['showname'] = $this->parseOpt($params, 'showname');

        //lightbox style?
		$data['lightbox'] = $this->parseOpt($params, 'lightbox');
	
        //direct linking?
		if($data['lightbox']) {
            $data['direct']   = true; //implicit direct linking
		}else{
	    	$data['direct'] = $this->parseOpt($params, 'direct');
		}

        //reverse sort?
		$data['reverse'] = $this->parseOpt($params, 'reverse');

        //resize thing?
        if(preg_match('/\bnoresize\b/i',$params,$match)) {
            $data['noresize'] = true;
        }else{
            $data['noresize'] = false;
        }

        //Layout thing?
        if(preg_match('/\bmagazine\b/i',$params,$match)) {
            $data['magazine'] = true;
        }else{
            $data['magazine'] = false;
        }

        //Layout thing?
        if(preg_match('/\bdiashow\b/i',$params,$match)) {
            $data['diashow'] = true;
        }else{
            $data['diashow'] = false;
        }

        //Layout thing?
        if(preg_match('/\bpageAmount=(\d+)\b/i',$params,$match)) {
            $data['pageAmount'] = $match[1];
        }else{
            $data['pageAmount'] = -1;
        }

	$match    = preg_replace('#<gallery.*?>|</gallery>#', '', $all_match);
	$match = preg_split ('#\n#',$match);
	foreach ($match as $line){
		list($name,$comment) = explode('=',$line,2);	
		$data['comments'][$name]=$comment;    
	}
                        
        return $data;
    }

    /**
     * Create output
     */
    function render($mode, &$renderer, $data) {
		if ( $data['pageAmount'] > 0 ) $renderer->info['cache'] = FALSE;

        if($mode == 'xhtml'){
            $renderer->doc .= $this->_gallery($data);
            return true;
        }
        return false;
    }

    /**
     * Does the gallery formatting
     */
    function _gallery($data){
        global $conf;
        global $lang;
        $ret = '';

        //use the search to get all files
        $ns = cleanID($data['ns']);
        $dir = utf8_encodeFN(str_replace(':','/',$ns));
        $files = array();
        search($files,$conf['mediadir'],'search_media',array(),$dir);

        //anything found?
        if(!count($files)){
            $ret .= '<div class="nothing"><pre>'.$lang['nothingfound'].print_r($data,$return=true).'</pre></div>';
            return $ret;
        }

        //reverse if wanted
        if($data['reverse']) rsort($files);
        
        //startPoint of Pages
        $startPoint = intval($_REQUEST['startPoint']);
       

		// build magazine
		if ($data['magazine'])
		{
			require_once(realpath(dirname(__FILE__)).'/inc/magazinelayout.class.php');

			$template = '<img src="/lib/plugins/gallery/inc/image.php?size=[size]&file=[image]" alt="" />';
			$mag = new magazinelayout($data['w'], $data['h']!=120?$data['h']:5, $template);
			$cols = $data['cols'];
			$cols = $cols > 8 ? 8 : $cols;
			
//			$content = '<div class="gallery">';

			$amount = 0;
			foreach($files as $img){
				if(!$img['isimg']) continue;
				$amount ++;
				if ( $amount < $startPoint ) continue;
				if ( $data['pageAmount'] > 0 && $amount-$startPoint >= $data['pageAmount'] ) break;
			
				$img['lightbox'] = $data['lightbox'];
				$img['h_lightbox'] = $data['h_lightbox'];
				$img['w_lightbox'] = $data['w_lightbox'];
				$img['direct'] =  $data['direct'];
				$img['float'] =  $data['float'];
			
				$mag->addImage($img);
			
				$cols --;
				if ($cols <= 0 )
				{
					$content .= $mag->getHtml();
					$mag = new magazinelayout($data['w'], $data['h']!=120?$data['h']:5, $template);
					$cols = $data['cols'];
				}
				
			}
		
			if ($mag->_numimages > 0) $content .= $mag->getHtml();
		
//			$content .= '<br style="clear:both" /></div></div></div>';

			$content .= $this->_pageSelect(count($files), $data['pageAmount'], $startPoint);
			return $content;
		}


        // build gallery
        if($data['cols'] > 0){ // format as table
            $ret .= '<table class="gallery"' . (!empty($data['float']) ? ' style="float: '.$data['float'].';"' : '') . '>';
            $i = 0;
            $amount = 0;
            foreach($files as $img){
                if(!$img['isimg']) continue;
				$amount ++;
				if ( $amount < $startPoint ) continue;
				if ( $data['pageAmount'] > 0 && $amount-$startPoint >= $data['pageAmount'] ) break;

                if($i == 0){
                    $ret .= '<tr>';
                }

                $ret .= '<td>';
                $ret .= $this->_image($img,$data);
                $ret .= $this->_showname($img,$data);
		$ret .= $this->_showcomment($img,$data);
                $ret .= '</td>';

                $i++;

                $close_tr = true;
                if($i == $data['cols']){
                    $ret .= '</tr>';
                    $close_tr = false;
                    $i = 0;
                }
            }

            if ($close_tr){
                // add remaining empty cells
                for(;$i < $data['cols']; $i++){
                    $ret .= '<td></td>';
                }
                $ret .= '</tr>';
            }

            $ret .= '</table>';
        }else{ // format as div sequence
            $ret .= '<div class="gallery"' . (!empty($data['float']) ? ' style="float: '.$data['float'].';"' : '') . '>';

			$amount = 0;
            foreach($files as $img){
                if(!$img['isimg']) continue;
				$amount ++;
				if ( $amount < $startPoint ) continue;
				if ( $data['pageAmount'] > 0 && $amount-$startPoint >= $data['pageAmount'] ) break;

                $ret .= '<div>';
                $ret .= $this->_image($img,$data);
                $ret .= $this->_showname($img,$data);
		$ret .= $this->_showcomment($img,$data);
                $ret .= '</div> ';
            }

            $ret .= '<br style="clear:both" /></div>';
        }

		$ret .= $this->_pageSelect(count($files), $data['pageAmount'], $startPoint);
        return $ret;
    }

    /**
     * Defines how a thumbnail should look like
     */
    function _image($img,$data){
        global $ID;

        $w = $img['meta']->getField('File.Width');
        $h = $img['meta']->getField('File.Height');
        $dim = array();
        
        if ( $data['noresize'])
        {
            $w = $data['w'];
            $h = $data['h'];
        }
        else if($w > $data['w'] || $h > $data['h']){
            $ratio = $img['meta']->getResizeRatio($data['w'],$data['h']);
            $w = floor($w * $ratio);
            $h = floor($h * $ratio);
            $dim = array('w'=>$w,'h'=>$h);
        }

        //prepare img attributes
        $i           = array();
        $i['width']  = $w;
        $i['height'] = $h;
        $i['border'] = 0;
        $i['alt']    = $img['meta']->getField('Simple.Title');
        $i['class']  = 'tn';
        $iatt = buildAttributes($i);
        $src  = ml($img['id'],$dim);

        // prepare lightbox dimensions
        $w_lightbox = $img['meta']->getField('File.Width');
        $h_lightbox = $img['meta']->getField('File.Height');
        $dim_lightbox = array();
        if($w_lightbox > $data['w_lightbox'] || $h_lightbox > $data['h_lightbox']){
            $ratio = $img['meta']->getResizeRatio($data['w_lightbox'],$data['h_lightbox']);
            $w_lightbox = floor($w_lightbox * $ratio);
            $h_lightbox = floor($h_lightbox * $ratio);
            $dim_lightbox = array('w'=>$w_lightbox,'h'=>$h_lightbox);
        }

        //prepare link attributes
        $a           = array();
        $a['title']  = $img['meta']->getField('Simple.Title');
        if($data['lightbox']){
            $href   = ml($img['id'],$dim_lightbox);
            $a['class'] = "lightbox JSnocheck";
            $a['rel']   = "lightbox";
        }else{
            $href   = ml($img['id'],array('id'=>$ID),$data['direct']);
        }
        $aatt = buildAttributes($a);

        // prepare output
        $ret  = '';
        $ret .= '<a href="'.$href.'" '.$aatt.'>';
        $ret .= '<img src="'.$src.'" '.$iatt.' />';
        $ret .= '</a>';
        return $ret;
    }


    /**
     * Defines how a filename + link should look
     */
    function _showname($img,$data){
        global $ID;

        if(!$data['showname']) { return ''; }

        //prepare link
        $lnk = ml($img['id'],array('id'=>$ID),false);

        // prepare output
        $ret  = '';
        $ret .= '<br /><a href="'.$lnk.'">';
        $ret .= $img['file']; // see fix posted on the wiki
        $ret .= '</a>';
        return $ret;
    }

    /**
     * Defines how a comment should look
     */
    function _showcomment($img,$data){
        global $ID;

        // prepare output
        $ret  = '';
        $ret .= '<br />';
        $ret .= $data['comments'][$img['file']]; 
      
        return $ret;
    }
    
    function _pageSelect($fileCount, $showCount, $startPoint)
    {
    	global $ID;
    	$content = '<div id="pageSelect">';
    	
    	$pages = ceil($fileCount / $showCount);
    	if ( $pages <= 1 ) return "";
    	
    	for ($i=0; $i<$pages; $i++)
    	{
	        $lnk = wl($ID, array('startPoint'=>$i*$showCount));
	        $content .= '<a href="' . $lnk . '">';
	        $content .= $i+1;
	        $content .= '</a>';
	        
	        if ( $i < $pages -1 )
	        	$content .= '&nbsp;-&nbsp;';
    	}
    	
    	$content .= '</div>';
    	return $content;
    }
}

//Setup VIM: ex: et ts=4 enc=utf-8 :
author     : Javier Espinosa Alfonso
email      : jespinosa@inetnova.com
description: Gallery image plugin modified to enable edit alternative text of a image.
type       : syntax
lastupdate : 2009-08-18
compatible : 2008-05-05


Edit text alternative for an image in the gallery with HTML tags: a and img. Like this:
<img alt=“Text alternative” src=“image1.png”>
<a title=“Title link” href=“go.html”>Go</a>

Examples:

{{gallery>:namespace:?image_*.png&lightbox|All images with the same text alternative}}
{{gallery>:namespace:image_123.png|Alternative text without params}}
{{gallery>:namespace:image_123.png?&lightbox|Alternative text with params}}
{{gallery>::namespace:image_123.png}} // Default value
<?php
/**
 * Embed an image gallery
 *
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Andreas Gohr <andi@splitbrain.org>
 * @author     Joe Lapp <joe.lapp@pobox.com>
 * @author     Dave Doyle <davedoyle.canadalawbook.ca>
 * @author     Javier Espinosa <jespinosa@inetnova.com | blog.virunner.com/javier-espinosa/>(changes with @JEA)
 */

if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');
require_once(DOKU_INC.'inc/search.php');
require_once(DOKU_INC.'inc/JpegMeta.php');

class syntax_plugin_gallery extends DokuWiki_Syntax_Plugin {

    /**
     * return some info
     */
    function getInfo(){
        return confToHash(dirname(__FILE__).'/info.txt');
    }

    /**
     * What kind of syntax are we?
     */
    function getType(){
        return 'substition';
    }

    /**
     * What about paragraphs?
     */
    function getPType(){
        return 'block';
    }

    /**
     * Where to sort in?
     */
    function getSort(){
        return 301;
    }


    /**
     * Connect pattern to lexer
     */
    function connectTo($mode) {
        $this->Lexer->addSpecialPattern('\{\{gallery>[^}]*\}\}',$mode,'plugin_gallery');
    }

    /**
     * Handle the match
     */
    function handle($match, $state, $pos, &$handler){
        global $ID;
        $match = substr($match,10,-2); //strip markup from start and end

        $data = array();

        $data['galid'] = substr(md5($match),0,4);

        // alignment
        $data['align'] = 0;
        if(substr($match,0,1) == ' ') $data['align'] += 1;
        if(substr($match,-1,1) == ' ') $data['align'] += 2;

// @JEA Begin
        // extract title
        list($match,$title) = explode('|',$match,2);
// @JEA End

        // extract params
        list($ns,$params) = explode('?',$match,2);
        $ns = trim($ns);

        // namespace (including resolving relatives)
        $data['ns'] = resolve_id(getNS($ID),$ns);

        // set the defaults
        $data['tw']       = $this->getConf('thumbnail_width');
        $data['th']       = $this->getConf('thumbnail_height');
        $data['iw']       = $this->getConf('image_width');
        $data['ih']       = $this->getConf('image_height');
        $data['cols']     = $this->getConf('cols');
        $data['filter']   = '';
        $data['lightbox'] = false;
        $data['direct']   = false;
        $data['showname'] = false;
        $data['showtitle'] = false;
        $data['reverse']  = false;
        $data['random']   = false;
        $data['cache']    = true;
        $data['crop']     = false;
        $data['sort']     = $this->getConf('sort');
        $data['limit']    = 0;
        $data['offset']   = 0;
        $data['paginate'] = 0;
// @JEA Begin
				// default value (can be changed)
        $data['title']    = 'No title';
        if (!empty($title)){
            $data['title'] = $title;
        }
// @JEA End

        // parse additional options
        $params = $this->getConf('options').','.$params;
        $params = preg_replace('/[,&\?]+/',' ',$params);
        $params = explode(' ',$params);
        foreach($params as $param){
            if($param === '') continue;
            if($param == 'titlesort'){
                $data['sort'] = 'title';
            }elseif($param == 'datesort'){
                $data['sort'] = 'date';
            }elseif($param == 'modsort'){
                $data['sort'] = 'mod';
            }elseif(preg_match('/^=(\d+)$/',$param,$match)){
                $data['limit'] = $match[1];
            }elseif(preg_match('/^\+(\d+)$/',$param,$match)){
                $data['offset'] = $match[1];
            }elseif(is_numeric($param)){
                $data['cols'] = (int) $param;
            }elseif(preg_match('/^~(\d+)$/',$param,$match)){
                $data['paginate'] = $match[1];
            }elseif(preg_match('/^(\d+)([xX])(\d+)$/',$param,$match)){
                if($match[2] == 'X'){
                    $data['iw'] = $match[1];
                    $data['ih'] = $match[3];
                }else{
                    $data['tw'] = $match[1];
                    $data['th'] = $match[3];
                }
            }elseif(strpos($param,'*') !== false){
                $param = preg_quote($param,'/');
                $param = '/^'.str_replace('\\*','.*?',$param).'$/';
                $data['filter'] = $param;
            }else{
                if(substr($param,0,2) == 'no'){
                    $data[substr($param,2)] = false;
                }else{
                    $data[$param] = true;
                }
            }
        }

        // implicit direct linking?
        if($data['lightbox']) $data['direct']   = true;


        return $data;
    }

    /**
     * Create output
     */
    function render($mode, &$R, $data) {
        if($mode != 'xhtml') return false;

        $R->info['cache'] = $data['cache'];
        $R->doc .= $this->_gallery($data);
        return true;
    }

    /**
     * Gather all photos matching the given criteria
     */
    function _findimages(&$data){
        global $conf;
        $files = array();

        $dir = utf8_encodeFN(str_replace(':','/',$data['ns']));

        // all possible images for the given namespace (or a single image)
        if(is_file($conf['mediadir'].'/'.$dir)){
            require_once(DOKU_INC.'inc/JpegMeta.php');
            $files[] = array(
                'id'    => $data['ns'],
                'isimg' => preg_match('/\.(jpe?g|gif|png)$/',$dir),
                'file'  => basename($dir),
                'mtime' => filemtime($conf['mediadir'].'/'.$dir),
                'meta'  => new JpegMeta($conf['mediadir'].'/'.$dir)
            );
            $data['_single'] = true;
        }else{
            search($files,$conf['mediadir'],'search_media',array(),$dir);
            $data['_single'] = false;
        }

        // done, yet?
        $len = count($files);
        if(!$len) return $files;
        if($data['single']) return $files;

        // filter images
        for($i=0; $i<$len; $i++){
            if(!$files[$i]['isimg']){
                unset($files[$i]); // this is faster, because RE was done before
            }elseif($data['filter']){
                if(!preg_match($data['filter'],noNS($files[$i]['id']))) unset($files[$i]);
            }
        }
        if($len<1) return $files;

        // random?
        if($data['random']){
            shuffle($files);
        }else{
            // sort?
            if($data['sort'] == 'date'){
                usort($files,array($this,'_datesort'));
            }elseif($data['sort'] == 'mod'){
                usort($files,array($this,'_modsort'));
            }elseif($data['sort'] == 'title'){
                usort($files,array($this,'_titlesort'));
            }

            // reverse?
            if($data['reverse']) $files = array_reverse($files);
        }

        // limits and offsets?
        if($data['offset']) $files = array_slice($files,$data['offset']);
        if($data['limit']) $files = array_slice($files,0,$data['limit']);

        return $files;
    }

    /**
     * usort callback to sort by file lastmodified time
     */
    function _modsort($a,$b){
        if($a['mtime'] < $b['mtime']) return -1;
        if($a['mtime'] > $b['mtime']) return 1;
        return strcmp($a['file'],$b['file']);
    }

    /**
     * usort callback to sort by EXIF date
     */
    function _datesort($a,$b){
        $da = $a['meta']->getDateField('EarliestTime');
        $db = $b['meta']->getDateField('EarliestTime');
        if($da < $db) return -1;
        if($da > $db) return 1;
        return strcmp($a['file'],$b['file']);
    }

    /**
     * usort callback to sort by EXIF title
     */
    function _titlesort($a,$b){
        $ta = $a['meta']->getField('Simple.Title');
        $tb = $b['meta']->getField('Simple.Title');
        return strcmp($ta,$tb);
    }


    /**
     * Does the gallery formatting
     */
    function _gallery($data){
        global $conf;
        global $lang;
        $ret = '';

        $files = $this->_findimages($data);

        //anything found?
        if(!count($files)){
            $ret .= '<div class="nothing">'.$lang['nothingfound'].'</div>';
            return $ret;
        }

        // prepare alignment
        $align = '';
        $xalign = '';
        if($data['align'] == 1){
            $align  = ' gallery_right';
            $xalign = ' align="right"';
        }
        if($data['align'] == 2){
            $align  = ' gallery_left';
            $xalign = ' align="left"';
        }
        if($data['align'] == 3){
            $align  = ' gallery_center';
            $xalign = ' align="center"';
        }
        if(!$data['_single']){
            if(!$align) $align = ' gallery_center'; // center galleries on default
            if(!$xalign) $xalign = ' align="center"';
        }

        $page = 0;

        // build gallery
        if($data['_single']){
            $ret .= $this->_image($files[0],$data);
            $ret .= $this->_showname($files[0],$data);
            $ret .= $this->_showtitle($files[0],$data);
        }elseif($data['cols'] > 0){ // format as table
            $close_pg = false;

            $i = 0;
            foreach($files as $img){

                // new page?
                if($data['paginate'] && ($i % $data['paginate'] == 0)){
                     $ret .= '<div class="gallery_page gallery__'.$data['galid'].'" id="gallery__'.$data['galid'].'_'.(++$page).'">';
                     $close_pg = true;
                }

                // new table?
                if($i == 0 || ($data['paginate'] && ($i % $data['paginate'] == 0))){
                    $ret .= '<table>';

                }

                // new row?
                if($i % $data['cols'] == 0){
                    $ret .= '<tr>';
                }

                // an image cell
                $ret .= '<td>';
                $ret .= $this->_image($img,$data);
                $ret .= $this->_showname($img,$data);
                $ret .= $this->_showtitle($img,$data);
                $ret .= '</td>';
                $i++;

                // done with this row? cloase it
                $close_tr = true;
                if($i % $data['cols'] == 0){
                    $ret .= '</tr>';
                    $close_tr = false;
                }

                // close current page and table
                if($data['paginate'] && ($i % $data['paginate'] == 0)){
                    if ($close_tr){
                        // add remaining empty cells
                        while($i % $data['cols']){
                            $ret .= '<td></td>';
                            $i++;
                        }
                        $ret .= '</tr>';
                    }
                    $ret .= '</table>';
                    $ret .= '</div>';
                    $close_pg = false;
                }

            }

            if ($close_tr){
                // add remaining empty cells
                while($i % $data['cols']){
                    $ret .= '<td></td>';
                    $i++;
                }
                $ret .= '</tr>';
            }

            if(!$data['paginate']){
                $ret .= '</table>';
            }elseif ($close_pg){
                $ret .= '</table>';
                $ret .= '</div>';
            }
        }else{ // format as div sequence
            $i = 0;
            $close_pg = false;
            foreach($files as $img){

                if($data['paginate'] && ($i % $data['paginate'] == 0)){
                     $ret .= '<div class="gallery_page gallery__'.$data['galid'].'" id="gallery__'.$data['galid'].'_'.(++$page).'">';
                     $close_pg = true;
                }

                $ret .= '<div>';
                $ret .= $this->_image($img,$data);
                $ret .= $this->_showname($img,$data);
                $ret .= $this->_showtitle($img,$data);
                $ret .= '</div> ';

                $i++;

                if($data['paginate'] && ($i % $data['paginate'] == 0)){
                    $ret .= '</div>';
                    $close_pg = false;
                }
            }

            if($close_pg) $ret .= '</div>';

            $ret .= '<br style="clear:both" />';
        }

        // pagination links
        $pgret = '';
        if($page){
            $pgret .= '<div class="gallery_pages">';
            for($j=1; $j<=$page; $j++){
                $pgret .= '<a href="#gallery__'.$data['galid'].'_'.$j.'" class="gallery_pgsel">'.$j.'</a> ';
            }
            $pgret .= '</div>';
        }

        return '<div class="gallery'.$align.'"'.$xalign.'>'.$pgret.$ret.'<div class="clearer"></div></div>';
    }

    /**
     * Defines how a thumbnail should look like
     */
    function _image($img,$data){
        global $ID;

        // calculate thumbnail size
        if($data['crop']){
            $w = $data['tw'];
            $h = $data['th'];
            $dim = array('w'=>$w,'h'=>$h);
        }else{
            $w = (int) $img['meta']->getField('File.Width');
            $h = (int) $img['meta']->getField('File.Height');
            $dim = array();
            if($w > $data['tw'] || $h > $data['th']){
                $ratio = $img['meta']->getResizeRatio($data['tw'],$data['th']);
                $w = floor($w * $ratio);
                $h = floor($h * $ratio);
                $dim = array('w'=>$w,'h'=>$h);
            }
        }

        //prepare img attributes
        $i             = array();
        $i['width']    = $w;
        $i['height']   = $h;
        $i['border']   = 0;
// @JEA Begin
//      $i['alt']      = $img['meta']->getField('Simple.Title');
        // alt attribute of <img>
        $i['alt']      = $data['title'];
// @JEA End
        $i['longdesc'] = trim(str_replace("\n",' ',$img['meta']->getField('Iptc.Caption')));
        if(!$i['longdesc']) unset($i['longdesc']);
        $i['class']    = 'tn';
        $iatt = buildAttributes($i);
        $src  = ml($img['id'],$dim);

        // prepare lightbox dimensions
        $w_lightbox = $img['meta']->getField('File.Width');
        $h_lightbox = $img['meta']->getField('File.Height');
        $dim_lightbox = array();
        if($w_lightbox > $data['iw'] || $h_lightbox > $data['ih']){
            $ratio = $img['meta']->getResizeRatio($data['iw'],$data['ih']);
            $w_lightbox = floor($w_lightbox * $ratio);
            $h_lightbox = floor($h_lightbox * $ratio);
            $dim_lightbox = array('w'=>$w_lightbox,'h'=>$h_lightbox);
        }

        //prepare link attributes
        $a           = array();
// @JEA Begin
//      $a['title']  = $img['meta']->getField('Simple.Title');
        // title attribute of <a>
        $a['title']  = $data['title'];
// @JEA End
        if($data['lightbox']){
            $href   = ml($img['id'],$dim_lightbox);
            $a['class'] = "lightbox JSnocheck";
            $a['rel']   = "lightbox";
        }else{
            $href   = ml($img['id'],array('id'=>$ID),$data['direct']);
        }
        $aatt = buildAttributes($a);

        // prepare output
        $ret  = '';
        $ret .= '<a href="'.$href.'" '.$aatt.'>';
        $ret .= '<img src="'.$src.'" '.$iatt.' />';
        $ret .= '</a>';
        return $ret;
    }


    /**
     * Defines how a filename + link should look
     */
    function _showname($img,$data){
        global $ID;

        if(!$data['showname'] ) { return ''; }

        //prepare link
        $lnk = ml($img['id'],array('id'=>$ID),false);

        // prepare output
        $ret  = '';
        $ret .= '<br /><a href="'.$lnk.'">';
        $ret .= hsc($img['file']);
        $ret .= '</a>';
        return $ret;
    }

    /**
     * Defines how title + link should look
     */
    function _showtitle($img,$data){
        global $ID;

        if(!$data['showtitle'] ) { return ''; }

        //prepare link
        $lnk = ml($img['id'],array('id'=>$ID),false);

        // prepare output
        $ret  = '';
        $ret .= '<br /><a href="'.$lnk.'">';
        $ret .= hsc($img['meta']->getField('Simple.Title'));
        $ret .= '</a>';
        return $ret;
    }
}

//Setup VIM: ex: et ts=4 enc=utf-8 :

Feature Suggestion:

Option to display a linklist, on which pages (of all pages namespaces or a special given namespace or a list of given namespaces ) the image is “used”, i.e. included in the page for embedded display or as link. So that the visitor can go by the linklist to the pages where the image is used. Maybe this list should be included just when I click on a picture so that it is displayed as single picture, and not on the real gallery display page ?! Rolf Hemmerling 2009-12-28 07:00

I am currently using the great gallery plugin together with the brand new dokutouch theme. Because of this, I have all my images named after my pages (so they display nicely in the left dokutouch column). It would be nice, if the gallery plugin could link to these pages. For images that do not have a page equivalent (e.g. the dokuwiki-128.png) there could be no link. (or the direct link as a fallback) Implemented as a new parameter (“page” instead of “direct” or so) this could be highly usable!!

I experimented a little bit: Adding

 }elseif($data['page']) {
            $new_id = cleanID($data['ns'].':'.substr($a['title'], 0, -strlen(strrchr($a['title'], '.'))));
            $newpath = wikiFN($new_id);
            if ( @file_exists($newpath) ) {
              $href = "/doku.php/".$data['ns']."/".substr($a['title'], 0, -strlen(strrchr($a['title'], '.')));
            }else{
              $href   = ml($img['id'],array('id'=>$ID),$data['direct']);
            } 

In line 534 of syntax.php and adding “page” in metadata.php and setting $data['page'] = false (Around line 84) gives the result I wanted. This is of course not yet foolproof. But very nice already.

The code below acts even more sophisticated: if multiple images with different numbers at the end exist, all images link to the page. E.g.: Page: Cake Images: cake, cake2, cake3. The Numbers get cut off, all images link to the “Cake” page.

        }elseif($data['page']) {
            $sitename = substr($a['title'], 0, -strlen(strrchr($a['title'], '.')));
            $new_id = cleanID($data['ns'].':'.$sitename);
            $newpath = wikiFN($new_id);
            if ( @file_exists($newpath) ) {
              $href = "/doku.php/".$data['ns']."/".$sitename;
            }else{
              while (is_numeric(substr($sitename, -1))) {  //Remove all trailing numbers.
                $sitename = substr($sitename, 0, -1);  
              }
              $new_id = cleanID($data['ns'].':'.$sitename);
              $newpath = wikiFN($new_id);
              if ( @file_exists($newpath) ) {
                $href = "/doku.php/".$data['ns']."/".$sitename; 
              }else {
                $href   = ml($img['id'],array('id'=>$ID),$data['direct']);
              }
            }

Setting the <img> as background has the advantage of easier styling. for instance, “border-radius” can work. Other things (like css3 transformations of reflections“ do also work (just a little bit) better on backgrounds.

#Line 562
        // prepare output
        $ret  = '';
        $ret .= '<center>';
        $ret .= '<a href="'.$href.'" '.$aatt.'>';
        $ret .= '<div style="width:'.$w.'px; height:'.$h.'px; background-image: url('.$src.');" '.$iatt.'></div>';
        $ret .= '</a>';
        $ret .= '</center>';
        return $ret;

The nice thing is, that the <center> tags do have NO EFFECT !! So the images are still displayed on the left of each <td> (thanks to the CSS float: left of the original plugin). But if this behaviour is not intended a “float:none” in the userstyles.css can fix it. :-)

It would be nice to be able to use wiki links in the exif title and/or caption. E.g. such that the user can be point to the related page (could be a “blog” page) to find more info.

Not sure whether using exif data is the sane place to allow wiki syntax… Perhaps the “keywords” exif field could use some more functionality.

Hi, any chances that the lightbox that pops up could either be made moveable while holding the left mouse button, or in the config you could tell it to open somewhere else ie. bottom, bottom-left etc…


1) This feature is based on the Lightbox and Lightbox Plus scripts with some additions
  • wiki/plugins/gallery.txt
  • Last modified: 2012/03/29 04:10
  • (external edit)