127bbde00SAndreas Gohr<?php 227bbde00SAndreas Gohr/** 327bbde00SAndreas Gohr * Embed an image gallery 427bbde00SAndreas Gohr * 527bbde00SAndreas Gohr * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 627bbde00SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 727bbde00SAndreas Gohr */ 827bbde00SAndreas Gohr 927bbde00SAndreas Gohrif(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../../').'/'); 1027bbde00SAndreas Gohrif(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC.'lib/plugins/'); 1127bbde00SAndreas Gohrrequire_once(DOKU_PLUGIN.'syntax.php'); 1227bbde00SAndreas Gohrrequire_once(DOKU_INC.'inc/search.php'); 1327bbde00SAndreas Gohrrequire_once(DOKU_INC.'inc/JpegMeta.php'); 1427bbde00SAndreas Gohr 1527bbde00SAndreas Gohrclass syntax_plugin_panoview extends DokuWiki_Syntax_Plugin { 1627bbde00SAndreas Gohr 1727bbde00SAndreas Gohr /** 1827bbde00SAndreas Gohr * What kind of syntax are we? 1927bbde00SAndreas Gohr */ 2027bbde00SAndreas Gohr function getType() { 2127bbde00SAndreas Gohr return 'substition'; 2227bbde00SAndreas Gohr } 2327bbde00SAndreas Gohr 2427bbde00SAndreas Gohr /** 2527bbde00SAndreas Gohr * What about paragraphs? 2627bbde00SAndreas Gohr */ 2727bbde00SAndreas Gohr function getPType() { 2827bbde00SAndreas Gohr return 'block'; 2927bbde00SAndreas Gohr } 3027bbde00SAndreas Gohr 3127bbde00SAndreas Gohr /** 3227bbde00SAndreas Gohr * Where to sort in? 3327bbde00SAndreas Gohr */ 3427bbde00SAndreas Gohr function getSort() { 3527bbde00SAndreas Gohr return 301; 3627bbde00SAndreas Gohr } 3727bbde00SAndreas Gohr 3827bbde00SAndreas Gohr /** 3927bbde00SAndreas Gohr * Connect pattern to lexer 4027bbde00SAndreas Gohr */ 4127bbde00SAndreas Gohr function connectTo($mode) { 4227bbde00SAndreas Gohr $this->Lexer->addSpecialPattern('\{\{panoview>[^}]*\}\}', $mode, 'plugin_panoview'); 4327bbde00SAndreas Gohr } 4427bbde00SAndreas Gohr 4527bbde00SAndreas Gohr /** 4627bbde00SAndreas Gohr * Handle the match 4727bbde00SAndreas Gohr */ 48*0f7356f2SAndreas Gohr function handle($match, $state, $pos, Doku_Handler $handler) { 4927bbde00SAndreas Gohr global $ID; 5027bbde00SAndreas Gohr 511a675665SAndreas Gohr $data = array( 5227bbde00SAndreas Gohr 'width' => 500, 5327bbde00SAndreas Gohr 'height' => 250, 541a675665SAndreas Gohr 'align' => 0, 554212171fSAndreas Gohr 'initialZoom' => 1, 5627bbde00SAndreas Gohr 'tileBaseUri' => DOKU_BASE.'lib/plugins/panoview/tiles.php', 5727bbde00SAndreas Gohr 'tileSize' => 256, 5827bbde00SAndreas Gohr 'maxZoom' => 10, 5927bbde00SAndreas Gohr 'blankTile' => DOKU_BASE.'lib/plugins/panoview/gfx/blank.gif', 6027bbde00SAndreas Gohr 'loadingTile' => DOKU_BASE.'lib/plugins/panoview/gfx/progress.gif', 6127bbde00SAndreas Gohr ); 6227bbde00SAndreas Gohr 631a675665SAndreas Gohr $match = substr($match, 11, -2); //strip markup from start and end 6427bbde00SAndreas Gohr 651a675665SAndreas Gohr // alignment 661a675665SAndreas Gohr $data['align'] = 0; 671a675665SAndreas Gohr if(substr($match, 0, 1) == ' ') $data['align'] += 1; 681a675665SAndreas Gohr if(substr($match, -1, 1) == ' ') $data['align'] += 2; 691a675665SAndreas Gohr 701a675665SAndreas Gohr // extract params 711a675665SAndreas Gohr list($img, $params) = explode('?', $match, 2); 721a675665SAndreas Gohr $img = trim($img); 731a675665SAndreas Gohr 741a675665SAndreas Gohr // resolving relatives 751a675665SAndreas Gohr $data['image'] = resolve_id(getNS($ID), $img); 761a675665SAndreas Gohr 771a675665SAndreas Gohr $file = mediaFN($data['image']); 781a675665SAndreas Gohr list($data['imageWidth'], $data['imageHeight']) = @getimagesize($file); 791a675665SAndreas Gohr 804212171fSAndreas Gohr // calculate maximum zoom 81359cb25cSAndreas Gohr $data['maxZoom'] = ceil(sqrt(max($data['imageWidth'], $data['imageHeight']) / $data['tileSize'])); 824212171fSAndreas Gohr 831a675665SAndreas Gohr // size 844212171fSAndreas Gohr if(preg_match('/\b(\d+)[xX](\d+)\b/', $params, $match)) { 851a675665SAndreas Gohr $data['width'] = $match[1]; 861a675665SAndreas Gohr $data['height'] = $match[2]; 871a675665SAndreas Gohr } 881a675665SAndreas Gohr 894212171fSAndreas Gohr // initial zoom 904212171fSAndreas Gohr if(preg_match('/\b[zZ](\d+)\b/', $params, $match)) { 914212171fSAndreas Gohr $data['initialZoom'] = $match[1]; 924212171fSAndreas Gohr } 934212171fSAndreas Gohr if($data['initialZoom'] < 0) $data['initialZoom'] = 0; 9424e066d7SAndreas Gohr if($data['initialZoom'] > $data['maxZoom']) $data['initialZoom'] = $data['maxZoom']; 954212171fSAndreas Gohr 961a675665SAndreas Gohr return $data; 9727bbde00SAndreas Gohr } 9827bbde00SAndreas Gohr 9927bbde00SAndreas Gohr /** 10027bbde00SAndreas Gohr * Create output 10127bbde00SAndreas Gohr */ 102*0f7356f2SAndreas Gohr function render($mode, Doku_Renderer $R, $data) { 10327bbde00SAndreas Gohr if($mode != 'xhtml') return false; 104da5b8f02SAndreas Gohr global $ID; 10527bbde00SAndreas Gohr require_once(DOKU_INC.'inc/JSON.php'); 10627bbde00SAndreas Gohr $json = new JSON(); 10727bbde00SAndreas Gohr 108da5b8f02SAndreas Gohr $img = '<a href="'.ml($data['image'], array('id'=> $ID), false).'"><img src="'. 1091a675665SAndreas Gohr ml($data['image'], array('w'=> $data['width'], 'h'=> $data['height'])).'" width="'. 1101a675665SAndreas Gohr $data['width'].'" height="'.$data['height'].'" alt="" /></a>'; 11127bbde00SAndreas Gohr 1121613315fSAndreas Gohr if($data['align'] == 1) { 1131613315fSAndreas Gohr $align = 'medialeft'; 1141613315fSAndreas Gohr } elseif($data['align'] == 2) { 1151613315fSAndreas Gohr $align = 'mediaright'; 1161613315fSAndreas Gohr } else { 1171613315fSAndreas Gohr $align = 'mediacenter'; 1181613315fSAndreas Gohr } 1191613315fSAndreas Gohr 12027bbde00SAndreas Gohr $R->doc .= ' 1211613315fSAndreas Gohr <div class="panoview_plugin '.$align.'" style="width: '.$data['width'].'px; height: '.$data['height'].'px;"> 1229d7db126SAndreas Gohr <div class="well"><!-- --></div> 1239d7db126SAndreas Gohr <div class="surface">'.$img.'</div> 12427bbde00SAndreas Gohr <p class="controls" style="display: none"> 12527bbde00SAndreas Gohr <span class="zoomIn" title="Zoom In">+</span> 12627bbde00SAndreas Gohr <span class="zoomOut" title="Zoom Out">-</span> 127493e6d40SAndreas Gohr <span class="maximize"><img src="'.DOKU_BASE.'lib/plugins/panoview/gfx/window.gif" style="position: absolute; bottom: 4px; right: 5px;" title="Maximize"></span> 12827bbde00SAndreas Gohr </p> 12927bbde00SAndreas Gohr <div class="options" style="display:none">'.hsc($json->encode($data)).'</div> 13027bbde00SAndreas Gohr </div> 13127bbde00SAndreas Gohr '; 13227bbde00SAndreas Gohr 13327bbde00SAndreas Gohr return true; 13427bbde00SAndreas Gohr } 13527bbde00SAndreas Gohr 1361faa1ff0SAndreas Gohr // ----------- Tile Generator below --------------- 1371faa1ff0SAndreas Gohr 1381faa1ff0SAndreas Gohr /** 1391faa1ff0SAndreas Gohr * Create a tile using libGD 1401faa1ff0SAndreas Gohr */ 1411faa1ff0SAndreas Gohr function tile_gd($d) { 1421faa1ff0SAndreas Gohr global $conf; 1431faa1ff0SAndreas Gohr 1441faa1ff0SAndreas Gohr $img = null; 1451faa1ff0SAndreas Gohr if(preg_match('/\.jpe?g$/', $d['file'])) { 1461faa1ff0SAndreas Gohr $img = @imagecreatefromjpeg($d['file']); 1471faa1ff0SAndreas Gohr } elseif(preg_match('/\.png$/', $d['file'])) { 1481faa1ff0SAndreas Gohr $img = @imagecreatefrompng($d['file']); 1491faa1ff0SAndreas Gohr } elseif(preg_match('/\.gif$/', $d['file'])) { 1501faa1ff0SAndreas Gohr $img = @imagecreatefromgif($d['file']); 1511faa1ff0SAndreas Gohr } 1521faa1ff0SAndreas Gohr if(!$img) $this->gfx_error('generic'); 1531faa1ff0SAndreas Gohr 1541faa1ff0SAndreas Gohr $crop = $this->image_crop($img, $d['width'], $d['height'], $d['tlx'], $d['tly'], $d['brx'], $d['bry']); 1551faa1ff0SAndreas Gohr imagedestroy($img); 1561faa1ff0SAndreas Gohr 1571faa1ff0SAndreas Gohr $scale = $this->image_scale($crop, abs($d['brx'] - $d['tlx']), abs($d['bry'] - $d['tly']), $d['ts'], $d['ts']); 1581faa1ff0SAndreas Gohr imagedestroy($crop); 1591faa1ff0SAndreas Gohr 1601faa1ff0SAndreas Gohr imagejpeg($scale, $d['cache'], $conf['jpg_quality']); 1611faa1ff0SAndreas Gohr imagedestroy($scale); 1621faa1ff0SAndreas Gohr 1631faa1ff0SAndreas Gohr if($conf['fperm']) chmod($d['cache'], $conf['fperm']); 1641faa1ff0SAndreas Gohr } 1651faa1ff0SAndreas Gohr 1661faa1ff0SAndreas Gohr /** 1671faa1ff0SAndreas Gohr * Create a tile using Image Magick 1681faa1ff0SAndreas Gohr */ 1691faa1ff0SAndreas Gohr function tile_im($d) { 1701faa1ff0SAndreas Gohr global $conf; 1711faa1ff0SAndreas Gohr 1721faa1ff0SAndreas Gohr $cmd = $this->getConf('nice'); 1731faa1ff0SAndreas Gohr $cmd .= ' '.$conf['im_convert']; 1741faa1ff0SAndreas Gohr $cmd .= ' '.escapeshellarg($d['file']); 1751faa1ff0SAndreas Gohr $cmd .= ' -crop \''.abs($d['brx'] - $d['tlx']).'x'.abs($d['bry'] - $d['tly']).'!+'.$d['tlx'].'+'.$d['tly'].'\''; 1761faa1ff0SAndreas Gohr $cmd .= ' -background black'; 1771faa1ff0SAndreas Gohr $cmd .= ' -extent \''.abs($d['brx'] - $d['tlx']).'x'.abs($d['bry'] - $d['tly']).'!\''; 1781faa1ff0SAndreas Gohr $cmd .= ' -resize \''.$d['ts'].'x'.$d['ts'].'!\''; 1791faa1ff0SAndreas Gohr 1801faa1ff0SAndreas Gohr $cmd .= ' -quality '.$conf['jpg_quality']; 1811faa1ff0SAndreas Gohr $cmd .= ' '.escapeshellarg($d['cache']); 1821faa1ff0SAndreas Gohr 1831faa1ff0SAndreas Gohr # dbg($cmd); exit; 1841faa1ff0SAndreas Gohr 1851faa1ff0SAndreas Gohr @exec($cmd, $out, $retval); 1861faa1ff0SAndreas Gohr if($retval == 0) return true; 1871faa1ff0SAndreas Gohr $this->gfx_error('generic'); 1881faa1ff0SAndreas Gohr } 1891faa1ff0SAndreas Gohr 1901faa1ff0SAndreas Gohr /** 1911faa1ff0SAndreas Gohr * Scale an image with libGD 1921faa1ff0SAndreas Gohr */ 1931faa1ff0SAndreas Gohr function image_scale($image, $x, $y, $w, $h) { 1941faa1ff0SAndreas Gohr $scale = imagecreatetruecolor($w, $h); 1951faa1ff0SAndreas Gohr imagecopyresampled($scale, $image, 0, 0, 0, 0, $w, $h, $x, $y); 1961faa1ff0SAndreas Gohr return $scale; 1971faa1ff0SAndreas Gohr } 1981faa1ff0SAndreas Gohr 1991faa1ff0SAndreas Gohr /** 2001faa1ff0SAndreas Gohr * Crop an image with libGD 2011faa1ff0SAndreas Gohr */ 2021faa1ff0SAndreas Gohr function image_crop($image, $x, $y, $left, $upper, $right, $lower) { 2031faa1ff0SAndreas Gohr $w = abs($right - $left); 2041faa1ff0SAndreas Gohr $h = abs($lower - $upper); 2051faa1ff0SAndreas Gohr $crop = imagecreatetruecolor($w, $h); 2061faa1ff0SAndreas Gohr imagecopy($crop, $image, 0, 0, $left, $upper, $w, $h); 2071faa1ff0SAndreas Gohr return $crop; 2081faa1ff0SAndreas Gohr } 2091faa1ff0SAndreas Gohr 2101faa1ff0SAndreas Gohr /** 2111faa1ff0SAndreas Gohr * Send a graphical error message and stop script 2121faa1ff0SAndreas Gohr */ 2131faa1ff0SAndreas Gohr function gfx_error($type) { 2141faa1ff0SAndreas Gohr $file = dirname(__FILE__).'/gfx/'.$type.'.gif'; 2151faa1ff0SAndreas Gohr $time = filemtime($file); 2161faa1ff0SAndreas Gohr header('Content-type: image/gif'); 2171faa1ff0SAndreas Gohr 2181faa1ff0SAndreas Gohr http_conditionalRequest($time); 2191faa1ff0SAndreas Gohr http_sendfile($file); 2201faa1ff0SAndreas Gohr readfile($file); 2211faa1ff0SAndreas Gohr exit; 2221faa1ff0SAndreas Gohr } 2231faa1ff0SAndreas Gohr 2241faa1ff0SAndreas Gohr /** 2251faa1ff0SAndreas Gohr * Acquire a lock for the tile generator 2261faa1ff0SAndreas Gohr */ 2271faa1ff0SAndreas Gohr function tile_lock($d) { 2281faa1ff0SAndreas Gohr global $conf; 2291faa1ff0SAndreas Gohr 2301faa1ff0SAndreas Gohr $lockDir = $conf['lockdir'].'/'.md5($d['id']).'.panoview'; 2311faa1ff0SAndreas Gohr @ignore_user_abort(1); 2321faa1ff0SAndreas Gohr 2331faa1ff0SAndreas Gohr $timeStart = time(); 2341faa1ff0SAndreas Gohr do { 2351faa1ff0SAndreas Gohr //waited longer than 25 seconds? -> stale lock? 2361faa1ff0SAndreas Gohr if((time() - $timeStart) > 25) { 237d6577f0fSAndreas Gohr if(time() - @filemtime($lockDir) > 30) $this->tile_unlock($d); 238d6577f0fSAndreas Gohr send_redirect(DOKU_URL.'lib/plugins/panoview/tiles.php?tile='.$d['zoom'].'-'.$d['col'].'-'.$d['row'].'&image='.rawurlencode($d['id'])); 2391faa1ff0SAndreas Gohr exit; 2401faa1ff0SAndreas Gohr } 2411faa1ff0SAndreas Gohr $locked = @mkdir($lockDir, $conf['dmode']); 2421faa1ff0SAndreas Gohr if($locked) { 2431faa1ff0SAndreas Gohr if(!empty($conf['dperm'])) chmod($lockDir, $conf['dperm']); 2441faa1ff0SAndreas Gohr break; 2451faa1ff0SAndreas Gohr } 2461faa1ff0SAndreas Gohr usleep(rand(500, 3000)); 2471faa1ff0SAndreas Gohr } while($locked === false); 2481faa1ff0SAndreas Gohr } 2491faa1ff0SAndreas Gohr 2501faa1ff0SAndreas Gohr /** 2511faa1ff0SAndreas Gohr * Unlock the tile generator 2521faa1ff0SAndreas Gohr */ 2531faa1ff0SAndreas Gohr function tile_unlock($d) { 2541faa1ff0SAndreas Gohr global $conf; 2551faa1ff0SAndreas Gohr 2561faa1ff0SAndreas Gohr $lockDir = $conf['lockdir'].'/'.md5($d['id']).'.panoview'; 2571faa1ff0SAndreas Gohr @rmdir($lockDir); 2581faa1ff0SAndreas Gohr @ignore_user_abort(0); 2591faa1ff0SAndreas Gohr } 2601faa1ff0SAndreas Gohr 26127bbde00SAndreas Gohr} 26227bbde00SAndreas Gohr 26327bbde00SAndreas Gohr//Setup VIM: ex: et ts=4 enc=utf-8 : 264