Newer
Older
Import / web / www.xiaofrog.com / gallery / modules / netpbm / classes / NetPbmToolkitHelper.class
<?php
/*
 * Gallery - a web based photo album viewer and editor
 * Copyright (C) 2000-2007 Bharat Mediratta
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
 */

/**
 * A helper class for the GalleryNetPbmToolkit class
 * @package NetPbm
 * @subpackage Classes
 * @author Bharat Mediratta <bharat@menalto.com>
 * @version $Revision: 15513 $
 * @static
 */
class NetPbmToolkitHelper {

    /**
     * Figure out what operations and properties are supported by the
     * NetPbmToolkit and return them.
     *
     * @param boolean $saveParameters (optional) true to save module parameters
     * @return object GalleryStatus a status code
     *         array('operations' => ..., 'properties' => ...)
     */
    function getOperationsAndProperties($saveParameters=false) {
	global $gallery;

	list ($ret, $netPbmPath) =
	    GalleryCoreApi::getPluginParameter('module', 'netpbm', 'path');
	if ($ret) {
	    return array($ret, null);
	}

	if (empty($netPbmPath)) {
	    return array(GalleryCoreApi::error(ERROR_MISSING_VALUE), null);
	}

	list ($ret, $tests, $mimeTypes) = NetPbmToolkitHelper::testBinaries($netPbmPath);
	if ($ret) {
	    return array($ret, null);
	}

	if ($saveParameters) {
	    $ret = NetPbmToolkitHelper::saveParameters($tests);
	    if ($ret) {
		return array($ret, null);
	    }
	}

	/* -------------------- Operations -------------------- */

	/* Convert TIFF and PPM to JPEG */
	$convertFrom[] = 'image/x-portable-pixmap';
	if (in_array('image/tiff', $mimeTypes)) {
	    $convertFrom[] = 'image/tiff';
	}

	$operations['convert-to-image/jpeg']['params'] = array();
	$operations['convert-to-image/jpeg']['description'] = $gallery->i18n('Convert to a JPEG');
	$operations['convert-to-image/jpeg']['mimeTypes'] = $convertFrom;
	$operations['convert-to-image/jpeg']['outputMimeType'] = 'image/jpeg';

	/* Scale */
	$operations['scale']['params'][] = array('type' => 'int', 'description' =>
		$gallery->i18n('target width (# pixels or #% of full size)', false));
	$operations['scale']['params'][] = array('type' => 'int', 'description' =>
		$gallery->i18n('(optional) target height, defaults to same as width'));
	$operations['scale']['description'] =
	    $gallery->i18n('Scale the image to the target size, maintain aspect ratio');
	$operations['scale']['mimeTypes'] = $mimeTypes;

	/* Thumbnail is an alias for scale */
	$operations['thumbnail'] = $operations['scale'];

	/* Resize */
	$operations['resize']['params'][] = array('type' => 'int', 'description' =>
		$gallery->i18n('target width (# pixels or #% of full size)', false));
	$operations['resize']['params'][] = array('type' => 'int', 'description' =>
		$gallery->i18n('target height (# pixels or #% of full size)', false));
	$operations['resize']['description'] =
	    $gallery->i18n('Resize the image to the target dimensions');
	$operations['resize']['mimeTypes'] = $mimeTypes;

	/* Rotate */
	$operations['rotate']['params'][] =
	    array('type' => 'int', 'description' => $gallery->i18n('rotation degrees'));
	$operations['rotate']['description'] = $gallery->i18n('Rotate the image');
	$operations['rotate']['mimeTypes'] = $mimeTypes;

	/* Crop */
	$operations['crop']['params'][] =
	    array('type' => 'float', 'description' => $gallery->i18n('left edge %'));
	$operations['crop']['params'][] =
	    array('type' => 'float', 'description' => $gallery->i18n('top edge %'));
	$operations['crop']['params'][] =
	    array('type' => 'float', 'description' => $gallery->i18n('width %'));
	$operations['crop']['params'][] =
	    array('type' => 'float', 'description' => $gallery->i18n('height %'));
	$operations['crop']['description'] = $gallery->i18n('Crop the image');
	$operations['crop']['mimeTypes'] = $mimeTypes;

	/* Watermark */
	$operations['composite']['params'][] =
	    array('type' => 'string', 'description' => $gallery->i18n('overlay path'));
	$operations['composite']['params'][] =
	    array('type' => 'string', 'description' => $gallery->i18n('overlay mime type'));
	$operations['composite']['params'][] =
	    array('type' => 'int', 'description' => $gallery->i18n('overlay width'));
	$operations['composite']['params'][] =
	    array('type' => 'int', 'description' => $gallery->i18n('overlay height'));
	$operations['composite']['params'][] =
	    array('type' => 'string', 'description' => $gallery->i18n('alignment type'));
	$operations['composite']['params'][] =
	    array('type' => 'int', 'description' => $gallery->i18n('alignment x %'));
	$operations['composite']['params'][] =
	    array('type' => 'int', 'description' => $gallery->i18n('alignment y %'));
	$operations['composite']['description'] =
	    $gallery->i18n('Overlay source image with a second one');
	$operations['composite']['mimeTypes'] = $mimeTypes;

	/* Compress */
	$qualityMimeTypes = array_intersect(array('image/jpeg', 'image/pjpeg'), $mimeTypes);
	if (!empty($qualityMimeTypes)) {
	    $operations['compress'] = array(
		'params' => array(
		    array('type' => 'int', 'description' => $gallery->i18n('target size in kb'))),
		'description' => $gallery->i18n('Reduce image quality to reach target file size'),
		'mimeTypes' => $qualityMimeTypes);
	}

	/*
	 * -------------------- Properties --------------------
	 */

	/* Dimensions */
	$properties['dimensions']['type'] = 'int,int';
	$properties['dimensions']['description'] =
	    $gallery->i18n('Get the width and height of the image');
	$properties['dimensions']['mimeTypes'] = array_merge($mimeTypes,
		array('image/x-portable-pixmap',
		      'application/x-shockwave-flash')); /* Supported by php getimagesize */

	return array(null, array('operations' => $operations, 'properties' => $properties));
    }

    /**
     * Test if the given path has a working jhead binary.
     *
     * This is done by calling jhead with the -V flag
     *
     * @param string $jheadPath path to the jhead binary
     * @return array object GalleryStatus general status of tests
     *	       array ('name' => string: the name of the binary,
     *		      'success' => boolean: test successful?
     *		      'message' => string: the error message
     *		     )
     *         array hash map of mime types
     */
    function testJhead($jheadPath) {
	global $gallery;
	$platform =& $gallery->getPlatform();
	/*
	 * If the path is restricted by open_basedir, then verify that it's legal.
	 * Else just hope that it's valid and use it.
	 */
	if (!$platform->isRestrictedByOpenBaseDir($jheadPath) && !@$platform->is_dir($jheadPath)) {
	    return array(GalleryCoreApi::error(ERROR_BAD_PATH), null, null);
	}
	$tests = array();
	$fullPath = $jheadPath . 'jhead';
	if (GalleryUtilities::isA($platform, 'WinNtPlatform')) {
	    $fullPath .= '.exe';
	}

	if (!$platform->isRestrictedByOpenBaseDir($fullPath) &&
		!$platform->file_exists($fullPath)) {
	    $success = false;
	    $results = array('File does not exist');
	} else {
	    list ($success, $results) = $platform->exec(array(array($fullPath, '-V')));
	}
	$tests[] = array('name' => 'jhead',
			 'success' => $success,
			 'message' => $results);

	return array(null, $tests, array());
    }

    /**
     * Test if the given path has a working set of NetPbm binaries.
     *
     * This is done by calling all the binaries with the --version flag and
     * making sure they run properly.
     *
     * @param string $netPbmPath path to the NetPbm we are testing
     * @return array object GalleryStatus general status of tests
     *	       array ('name' => string: the name of the binary,
     *		      'success' => boolean: test successful?
     *		      'message' => string: the error message
     *		     )
     *         array of string mime types
     */
    function testBinaries($netPbmPath) {
	global $gallery;
	$platform =& $gallery->getPlatform();
	$isRestrictedPath = $platform->isRestrictedByOpenBaseDir($netPbmPath);
	/*
	 * If the path is not restricted by open_basedir, then verify that it's legal.
	 * Else just hope that it's valid and use it.
	 */
	if (!$isRestrictedPath && !@$platform->is_dir($netPbmPath)) {
	    return array(GalleryCoreApi::error(ERROR_BAD_PATH), null, null);
	}

	$binaryData = array(
	    '' => array('pnmscale', 'pnmcut|pamcut', 'pnmfile|pamfile', 'pnmcomp|pamcomp',
			'exist' => 'pnmflip|pamflip'), /* No --version for this */
	    'image/jpeg|image/pjpeg' => array('jpegtopnm', 'pnmtojpeg|ppmtojpeg'),
	    'image/gif' => array('giftopnm', 'ppmtogif', 'exist' => 'ppmquant|pnmquant'),
	    'image/png' => array('pngtopnm', 'pnmtopng'),
	    'image/tiff' => array('tifftopnm', 'pnmtotiff|pamtotiff'),
	    'image/bmp' => array('bmptopnm|bmptoppm', 'ppmtobmp', 'exist' => 'ppmquant|pnmquant'),
	);

	$tests = $mimeTypes = array();
	foreach ($binaryData as $mimeList => $binaryList) {
	    $failCount = 0;
	    foreach ($binaryList as $i => $binaries) {
		$test = array();
		$checkExistenceOnly = is_string($i);
		foreach (explode('|', $binaries) as $binary) {
		    $fullPath = $netPbmPath . $binary;
		    if (GalleryUtilities::isA($platform, 'WinNtPlatform')) {
			if (!$isRestrictedPath && !$platform->file_exists($fullPath)) {
			    $fullPath .= '.exe';
			}
		    }
		    if (!$isRestrictedPath && !$platform->file_exists($fullPath)) {
			continue;
		    }
		    list ($success, $results) = $checkExistenceOnly ? array(true, array()) :
			$platform->exec(array(array($fullPath, '--version')));
		    if ($success) {
			$tests[] = array('name' => $binary,
					 'success' => true, 'message' => $results);
			continue 2;
		    } else if (empty($test)) {
			$test = array('name' => $binary, 'success' => false, 'message' => $results);
		    }
		}
		if (!empty($test)) {
		    $tests[] = $test;
		} else {
		    if (!isset($module)) {
			/* Only used for translation, so ignore version mismatch during upgrade */
			list ($ret, $module) = GalleryCoreApi::loadPlugin('module', 'netpbm', true);
			if ($ret) {
			    return array($ret, null, null);
			}
		    }
		    $tests[] = array(
			'name' => str_replace('|', $module->translate(' or '), $binaries),
			'success' => false,
			'message' => array($module->translate('File does not exist')));
		}
		$failCount++;
	    }
	    if ($failCount && empty($mimeList)) {
		/* These binaries are required; bail out */
		break;
	    } else if (!$failCount && !empty($mimeList)) {
		$mimeTypes = array_merge($mimeTypes, explode('|', $mimeList));
	    }
	}

	return array(null, $tests, $mimeTypes);
    }

    /**
     * Save module parameters based on test results.
     *
     * @param array $tests testBinaries test results
     * @return object GalleryStatus a status code
     */
    function saveParameters($tests) {
	$paramList = array('pnmtojpeg' => 'p.mtojpeg', 'bmptopnm' => 'bmptop.m',
			   'pnmcomp' => 'p.mcomp');
	foreach ($tests as $test) {
	    if (!$test['success']) {
		continue;
	    }
	    foreach ($paramList as $key => $match) {
		if (preg_match("|$match|", $test['name'])) {
		    $binary[$key] = $test['name'];
		}
	    }
	}
	foreach (array_keys($paramList) as $key) {
	    $ret = GalleryCoreApi::setPluginParameter('module', 'netpbm', $key,
						      isset($binary[$key]) ? $binary[$key] : $key);
	    if ($ret) {
		return $ret;
	    }
	}
	return null;
    }
}
?>