* @author Gerry Weissbach */ // must be run within Dokuwiki if(!defined('DOKU_INC')) die(); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); require_once(DOKU_PLUGIN.'action.php'); class action_plugin_reflect extends DokuWiki_Action_Plugin { private $functions = null; function register(Doku_Event_Handler $controller) { if ( empty($_REQUEST['reflect']) ) { return; } $controller->register_hook('MEDIA_SENDFILE', 'BEFORE', $this, 'reflect__reflect'); } function reflect__reflect(&$event, $args) { if (extension_loaded('gd') == false && !@dl('gd.so')) { return; } /* Filename for reflect Image */ $data = $event->data; $ext = empty( $_REQUEST['return_type'] ) ? $this->getConf('return_type') : (in_array( hsc($_REQUEST['return_type']), array('png', 'jpg') ) ? hsc($_REQUEST['return_type']) : $this->getConf('return_type')); $data['height'] = $this->getConf('reflect_height'); if ( empty($_REQUEST['bgc']) ) $_REQUEST['bgc'] = $this->getConf('bgc'); if ( !empty($_REQUEST['reflect_height']) ) $data['height'] = $_REQUEST['reflect_height']; $cacheFile = getCacheName($data['file'],".media.reflect.{$_REQUEST['bgc']}.$ext"); $mtime = @filemtime($cacheFile); // 0 if not exists $cache = $data['cache']; if( ($mtime == 0) || // cache does not exist ($mtime < time()-$cache) // 'recache' and cache has expired ){ if ( $this->create_reflect_image( $data, $cacheFile, $_REQUEST['bgc'] ) ) { $data['orig'] = $data['file']; $data['file'] = $cacheFile; list($data['ext'],$data['mime'],$data['download']) = mimetype($cacheFile); $event->data = $data; } } } function create_reflect_image( $data, $cache_path, $imagebgcolor=null ) { global $conf; $input = $data['file']; $imagebgcolor = $this->calc_bgcolor($imagebgcolor); // How big is the image? if ( !($image_details = getimagesize($input)) ) { return false; } $width = $image_details[0]; $height = $image_details[1]; $type = $image_details[2]; $mime = $image_details['mime']; // height (how tall should the reflection be?) if (isset($data['height']) ) { $output_height = $data['height']; if ( $output_height == 0 ) $output_height = $this->getConf('reflect_height'); } else { // No height was given, so default to 50% of the source images height $output_height = $this->getConf('reflect_height'); } // Calculate the height of the output image if ($output_height < 1) { // The output height is a percentage $new_height = $height * $output_height; } else { // The output height is a fixed pixel value $new_height = $output_height; } if (isset($_REQUEST['fade_start'])) { if (strpos($_REQUEST['fade_start'], '%') !== false) { $alpha_start = str_replace('%', '', $_REQUEST['fade_start']); $alpha_start = (int) (127 * $alpha_start / 100); } else { $alpha_start = (int) $_REQUEST['fade_start']; if ($alpha_start < 1 || $alpha_start > 127) { $alpha_start = $this->getConf('fade_start'); } } } else { $alpha_start = $this->getConf('fade_start'); } if (isset($_REQUEST['fade_end'])) { if (strpos($_REQUEST['fade_end'], '%') !== false) { $alpha_end = str_replace('%', '', $_REQUEST['fade_end']); $alpha_end = (int) (127 * $alpha_end / 100); } else { $alpha_end = (int) $_REQUEST['fade_end']; if ($alpha_end < 1 || $alpha_end > 127) { $alpha_end = $this->getConf('fade_end'); } } } else { $alpha_end = $this->getConf('fade_end'); } $alpha_start = 127 - $alpha_start; $alpha_end = 127 - $alpha_end; // Detect the source image format - only GIF, JPEG and PNG are supported. If you need more, extend this yourself. switch ($type) { case 1:// GIF $source = imagecreatefromgif($input); break; case 2:// JPG $source = imagecreatefromjpeg($input); break; case 3:// PNG $source = imagecreatefrompng($input); break; default: return false; } /* ---------------------------------------------------------------- Build the reflection image ---------------------------------------------------------------- */ $output = $this->imagereflection($source, $width, $height, $new_height, $alpha_start, $alpha_end); /* ---------------------------------------------------------------- Output our final Image ---------------------------------------------------------------- */ if ( headers_sent() ) { return false; } // If you'd rather output a JPEG instead of a PNG then pass the parameter 'jpeg' (no value needed) on the querystring if ( substr($cache_path, -3) == 'png' ) { imagepng($output, $cache_path, intval($conf['jpg_quality'] / 11)); } else if ( substr($cache_path, -3) == 'jpg' ) { /* ----------------------------------------------------------------------- HACK - Build the reflection image by combining the png output image AND the color background in one new image! ------------------------------------------------------------------------ */ // Create transparent BG $finaloutput = imagecreatetruecolor($width, $height+$new_height); $white = imagecolorallocatealpha($finaloutput, $imagebgcolor['red'], $imagebgcolor['green'], $imagebgcolor['blue'], $imagebgcolor['alpha']); imagecolortransparent($finaloutput, $white); imagefill($finaloutput, 0, 0, $white); imagecopy($finaloutput, $output, 0, 0, 0, 0, $width, $height+$new_height); imagejpeg($finaloutput, $cache_path, intval($conf['jpg_quality'])); } imagedestroy($output); return true; } function calc_bgcolor( $bgcolor ) { if ( empty($bgcolor) ) { $bgcolor = $this->getConf('bgc'); } // Does it start with a hash? If so then strip it $bgcolor = str_replace('#', '', $bgcolor); switch (strlen($bgcolor)) { case 8: $red = hexdec(substr($bgcolor, 0, 2)); $green = hexdec(substr($bgcolor, 2, 2)); $blue = hexdec(substr($bgcolor, 4, 2)); $alpha = hexdec(substr($bgcolor, 6, 2)); break; case 6: $red = hexdec(substr($bgcolor, 0, 2)); $green = hexdec(substr($bgcolor, 2, 2)); $blue = hexdec(substr($bgcolor, 4, 2)); $alpha = hexdec('00'); break; case 4: $red = substr($bgcolor, 0, 1); $green = substr($bgcolor, 1, 1); $blue = substr($bgcolor, 2, 1); $alpha = substr($bgcolor, 3, 1); $red = hexdec($red . $red); $green = hexdec($green . $green); $blue = hexdec($blue . $blue); $alpha = hexdec($alpha . $alpha); break; case 3: $red = substr($bgcolor, 0, 1); $green = substr($bgcolor, 1, 1); $blue = substr($bgcolor, 2, 1); $red = hexdec($red . $red); $green = hexdec($green . $green); $blue = hexdec($blue . $blue); $alpha = hexdec('00'); break; default: // Wrong values passed, default to black $red = 0; $green = 0; $blue = 0; $alpha = 0; } $alpha = floor($alpha / 2); return array('red' => $red, 'green' => $green, 'blue' => $blue, 'alpha' => $alpha ); } function imagereflection($src_img, $src_width, $src_height, $reflection_height, $alpha_start, $alpha_end) { $dest_height = $src_height + $reflection_height; $dest_width = $src_width; // Create Reflected Object $reflected = imagecreatetruecolor($dest_width, $dest_height); imagealphablending($reflected, false); imagesavealpha($reflected, true); // Copy Source imagecopy($reflected, $src_img, 0, 0, 0, 0, $src_width, $src_height); if ( empty($reflection_height) ) $reflection_height = $src_height / 2; // Calc alpha width and step $alpha_length = abs($alpha_start - $alpha_end); // For each Pixel in the reflection area for ($y = 1; $y <= $reflection_height; $y++) { $pct = $y / $reflection_height; for ($x = 0; $x < $dest_width; $x++) { // copy pixel from x / $src_height - y to x / $src_height + y $rgba = imagecolorat($src_img, $x, $src_height - $y); $alpha = ($rgba & 0x7F000000) >> 24; // Get % of alpha if ($alpha_start > $alpha_end) { $alpha_calc = (int) ($alpha_start - ($pct * $alpha_length)); } else { $alpha_calc = (int) ($alpha_start + ($pct * $alpha_length)); } $alpha = max($alpha, $alpha_calc); $rgba = imagecolorsforindex($src_img, $rgba); $rgba = imagecolorallocatealpha($reflected, $rgba['red'], $rgba['green'], $rgba['blue'], $alpha); imagesetpixel($reflected, $x, $src_height + $y - 1, $rgba); } } return $reflected; } }