767 lines
26 KiB
Plaintext
767 lines
26 KiB
Plaintext
<?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 GalleryImageMagickToolkit class
|
|
* @package ImageMagick
|
|
* @subpackage Classes
|
|
* @author Bharat Mediratta <bharat@menalto.com>
|
|
* @version $Revision: 15513 $
|
|
* @static
|
|
*/
|
|
class ImageMagickToolkitHelper {
|
|
|
|
/**
|
|
* Figure out what operations and properties are supported by the
|
|
* ImageMagickToolkit and return them.
|
|
*
|
|
* @return object GalleryStatus a status code
|
|
* array('operations' => ..., 'properties' => ...)
|
|
*/
|
|
function getOperationsAndProperties() {
|
|
global $gallery;
|
|
|
|
list ($ret, $mimeTypes) = ImageMagickToolkitHelper::discoverMimeTypes();
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
|
|
/* -------------------- Operations -------------------- */
|
|
|
|
/*
|
|
* Provide some mime type conversions. G2 will use convert-to-image/jpeg for
|
|
* types that aren't viewable inline (TIFF, SVG, PDF, etc)..
|
|
*/
|
|
foreach (array('image/jpeg', 'image/png', 'image/gif',
|
|
'image/tiff', 'image/jp2') as $convertToMimeType) {
|
|
if (is_int($i = array_search($convertToMimeType, $mimeTypes))) {
|
|
$convertFromMimeTypes = array_merge($mimeTypes, array('image/x-portable-pixmap'));
|
|
array_splice($convertFromMimeTypes, $i, 1);
|
|
$operations['convert-to-' . $convertToMimeType] = array(
|
|
'params' => array(),
|
|
'description' => $gallery->i18n('Convert to') . " $convertToMimeType",
|
|
'mimeTypes' => $convertFromMimeTypes,
|
|
'outputMimeType' => $convertToMimeType);
|
|
}
|
|
}
|
|
|
|
/* Scale */
|
|
$operations['scale'] = array(
|
|
'params' => array(array('type' => 'int', 'description' =>
|
|
$gallery->i18n('target width (# pixels or #% of full size)', false)),
|
|
array('type' => 'int', 'description' =>
|
|
$gallery->i18n('(optional) target height, defaults to same as width'))),
|
|
'description' =>
|
|
$gallery->i18n('Scale the image to the target size, maintain aspect ratio'),
|
|
'mimeTypes' => $mimeTypes);
|
|
|
|
/* Thumbnail is an alias for scale */
|
|
$operations['thumbnail'] = $operations['scale'];
|
|
|
|
/* Resize */
|
|
$operations['resize'] = array(
|
|
'params' => array(array('type' => 'int', 'description' =>
|
|
$gallery->i18n('target width (# pixels or #% of full size)', false)),
|
|
array('type' => 'int', 'description' =>
|
|
$gallery->i18n('target height (# pixels or #% of full size)', false))),
|
|
'description' => $gallery->i18n('Resize the image to the target dimensions'),
|
|
'mimeTypes' => $mimeTypes);
|
|
|
|
/* Rotate */
|
|
$operations['rotate'] = array(
|
|
'params' => array(array('type' => 'int',
|
|
'description' => $gallery->i18n('rotation degrees'))),
|
|
'description' => $gallery->i18n('Rotate the image'),
|
|
'mimeTypes' => $mimeTypes);
|
|
|
|
/* Crop */
|
|
$operations['crop'] = array(
|
|
'params' => array(array('type' => 'float',
|
|
'description' => $gallery->i18n('left edge %')),
|
|
array('type' => 'float',
|
|
'description' => $gallery->i18n('top edge %')),
|
|
array('type' => 'float',
|
|
'description' => $gallery->i18n('width %')),
|
|
array('type' => 'float',
|
|
'description' => $gallery->i18n('height %'))),
|
|
'description' => $gallery->i18n('Crop the image'),
|
|
'mimeTypes' => $mimeTypes);
|
|
|
|
/* Composite */
|
|
$operations['composite'] = array(
|
|
'params' => array(array('type' => 'string',
|
|
'description' => $gallery->i18n('overlay path')),
|
|
array('type' => 'string',
|
|
'description' => $gallery->i18n('overlay mime type')),
|
|
array('type' => 'int',
|
|
'description' => $gallery->i18n('overlay width')),
|
|
array('type' => 'int',
|
|
'description' => $gallery->i18n('overlay height')),
|
|
array('type' => 'string',
|
|
'description' => $gallery->i18n('alignment type')),
|
|
array('type' => 'int',
|
|
'description' => $gallery->i18n('alignment x %')),
|
|
array('type' => 'int',
|
|
'description' => $gallery->i18n('alignment y %'))),
|
|
'description' => $gallery->i18n('Overlay source image with a second one'),
|
|
'mimeTypes' => $mimeTypes);
|
|
|
|
/* Select Page */
|
|
$multiPageMimeTypes = array_intersect(
|
|
array('image/tiff', 'application/pdf',
|
|
'application/postscript', 'application/photoshop'),
|
|
$mimeTypes);
|
|
if (!empty($multiPageMimeTypes)) {
|
|
$operations['select-page'] = array(
|
|
'params' => array(array('type' => 'int',
|
|
'description' => $gallery->i18n('page number'))),
|
|
'description' => $gallery->i18n('Select a single page from a multi-page file'),
|
|
'mimeTypes' => $multiPageMimeTypes);
|
|
}
|
|
|
|
/* Compress */
|
|
$qualityMimeTypes = array_intersect(array('image/jpeg', 'image/png'), $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'] = array(
|
|
'type' => 'int,int',
|
|
'description' => $gallery->i18n('Get the width and height of the image'),
|
|
'mimeTypes' => array_merge($mimeTypes, array('image/x-portable-pixmap',
|
|
'application/x-shockwave-flash'))); /* Supported by php getimagesize */
|
|
|
|
if (!empty($multiPageMimeTypes)) {
|
|
$properties['page-count'] = array(
|
|
'type' => 'int',
|
|
'description' => $gallery->i18n('Get the number of pages'),
|
|
'mimeTypes' => $multiPageMimeTypes);
|
|
}
|
|
|
|
$cmykTypes = $rgbTypes = array();
|
|
foreach ($mimeTypes as $mimeType) {
|
|
if (substr($mimeType, -5) == '-cmyk') {
|
|
$cmykTypes[] = $mimeType;
|
|
$rgbTypes[] = substr($mimeType, 0, -5);
|
|
}
|
|
}
|
|
if (!empty($cmykTypes)) {
|
|
$properties['colorspace'] = array(
|
|
'type' => 'string',
|
|
'description' => $gallery->i18n('Get the colorspace of the image'),
|
|
'mimeTypes' => $rgbTypes);
|
|
}
|
|
|
|
return array(null, array('operations' => $operations, 'properties' => $properties));
|
|
}
|
|
|
|
/**
|
|
* Return an array of cmds needed to execute ImageMagick/GraphicsMagick commands
|
|
*
|
|
* @param string $cmd an ImageMagick command (eg. "convert")
|
|
* @param string $imageMagickPath (optional) ImageMagick path (default=module configuration)
|
|
* @return array object GalleryStatus
|
|
* array commands
|
|
*/
|
|
function getCommand($cmd, $imageMagickPath=null) {
|
|
global $gallery;
|
|
$platform =& $gallery->getPlatform();
|
|
|
|
if ($imageMagickPath == null) {
|
|
list ($ret, $imageMagickPath) =
|
|
GalleryCoreApi::getPluginParameter('module', 'imagemagick', 'path');
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
list ($ret, $binary) =
|
|
GalleryCoreApi::getPluginParameter('module', 'imagemagick', 'binary');
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
} else {
|
|
list ($ret, $binary) = ImageMagickToolkitHelper::discoverBinary($imageMagickPath);
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
}
|
|
|
|
if (empty($binary)) {
|
|
return array(null, array($imageMagickPath . $cmd .
|
|
(GalleryUtilities::isA($platform, 'WinNtPlatform') ? '.exe' : '')));
|
|
} else {
|
|
return array(null, array($imageMagickPath . $binary, $cmd));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find out which mime types our ImageMagick installation supports.
|
|
* This is done by trying to run 'identify' on a couple of sample images.
|
|
*
|
|
* @param string $imageMagickPath (optional) path to the ImageMagick we are testing;
|
|
* if not given, use the 'imagemagick.path' module parameter
|
|
* @return array object GalleryStatus
|
|
* array supported mime-types
|
|
*/
|
|
function discoverMimeTypes($imageMagickPath=null) {
|
|
global $gallery;
|
|
$platform =& $gallery->getPlatform();
|
|
$slash = $platform->getDirectorySeparator();
|
|
$dataPath = dirname(dirname(__FILE__)) . "${slash}data${slash}";
|
|
|
|
if (empty($imageMagickPath)) {
|
|
list ($ret, $imageMagickPath) =
|
|
GalleryCoreApi::getPluginParameter('module', 'imagemagick', 'path');
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
|
|
if (empty($imageMagickPath)) {
|
|
return array(GalleryCoreApi::error(ERROR_MISSING_VALUE), null);
|
|
}
|
|
}
|
|
|
|
$tests = array();
|
|
$tests[] = array('mime' => array('image/gif'), 'file' => 'test.gif',
|
|
'expected' => '(GIF.*PseudoClass|PseudoClass.*GIF|DirectClass.*GIF)');
|
|
$tests[] = array('mime' => array('image/jpeg', 'image/pjpeg'), 'file' => 'test.jpg',
|
|
'expected' => '(JPEG.*(Direct|Pseudo)Class|DirectClass.*JPEG)');
|
|
$tests[] = array('mime' => array('image/jp2', 'image/jpg2', 'image/jpx'),
|
|
'file' => 'test.jp2',
|
|
'expected' => '(JP2.*(Pseudo|Direct)Class|(Pseudo|Direct)Class.*JP2)');
|
|
$tests[] = array('mime' => array('image/png'), 'file' => 'test.png',
|
|
'expected' => '(PNG.*DirectClass|DirectClass.*PNG)');
|
|
$tests[] = array('mime' => array('image/tiff'), 'file' => 'test.tif',
|
|
'expected' => '(TIFF.*(Pseudo|Direct)Class|(Pseudo|Direct)Class.*TIFF)');
|
|
$tests[] = array('mime' => array('image/svg+xml'), 'file' => 'test.svg',
|
|
'expected' => '(SVG.*DirectClass|DirectClass.*SVG)');
|
|
$tests[] = array('mime' => array('image/bmp'), 'file' => 'test.bmp',
|
|
'expected' => '(BMP.*PseudoClass|PseudoClass.*BMP)');
|
|
$tests[] = array('mime' => array('application/pdf'), 'file' => 'test.pdf',
|
|
'expected' => '(PDF.*(Pseudo|Direct)Class|PseudoClass.*PDF)');
|
|
$tests[] = array('mime' => array('application/postscript'), 'file' => 'test.eps',
|
|
'expected' => '(PS.*(Pseudo|Direct)Class|PseudoClass.*PS)');
|
|
$tests[] = array('mime' => array('application/photoshop'), 'file' => 'test.psd',
|
|
'expected' => '(PSD.*(Pseudo|Direct)Class|PseudoClass.*PSD)');
|
|
$tests[] = array('mime' => array('image/x-photo-cd'), 'file' => 'truncated.pcd',
|
|
'expected' => '(PCD.*(Pseudo|Direct)Class|PseudoClass.*PCD)');
|
|
$tests[] = array('mime' => array('image/wmf'), 'file' => 'test.wmf',
|
|
'expected' => '(WMF.*(Pseudo|Direct)Class|(Pseudo|Direct)Class.*WMF)');
|
|
$tests[] = array('mime' => array('image/tga'), 'file' => 'test.tga',
|
|
'expected' => '(TGA.*(Pseudo|Direct)Class|(Pseudo|Direct)Class.*TGA)');
|
|
|
|
$oldPwd = $platform->getcwd();
|
|
$platform->chdir($gallery->getConfig('data.gallery.tmp'));
|
|
|
|
$successCount = 0;
|
|
$mimeTypes = array();
|
|
foreach ($tests as $test) {
|
|
list ($ret, $command) =
|
|
ImageMagickToolkitHelper::getCommand('identify', $imageMagickPath);
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
$command = array_merge($command, array($dataPath . $test['file']));
|
|
list ($success, $results) = $platform->exec(array($command));
|
|
|
|
$successCount += $success;
|
|
if ($success || $test['file'] == 'truncated.pcd') {
|
|
/* Ignore error status for truncated.pcd.. it should still identify the file ok */
|
|
foreach ($results as $resultLine) {
|
|
if (ereg($test['expected'], $resultLine)) {
|
|
foreach ($test['mime'] as $type) {
|
|
$mimeTypes[$type] = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$platform->chdir($oldPwd);
|
|
if ($successCount == 0) {
|
|
return array(GalleryCoreApi::error(ERROR_TOOLKIT_FAILURE), null);
|
|
}
|
|
|
|
list ($ret, $cmykSupport) =
|
|
ImageMagickToolkitHelper::discoverColorspaceSupport($imageMagickPath);
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
if ($cmykSupport) {
|
|
foreach (array('image/jpeg', 'image/tiff', 'application/photoshop') as $mimeType) {
|
|
if (isset($mimeTypes[$mimeType])) {
|
|
$mimeTypes[$mimeType . '-cmyk'] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return array(null, array_keys($mimeTypes));
|
|
}
|
|
|
|
/**
|
|
* Test if the given path has a working set of ImageMagick binaries.
|
|
* This is done by trying to run 'identify' on a sample image.
|
|
*
|
|
* @param string $imageMagickPath path to the ImageMagick 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, in case of
|
|
* IMAGEMAGIC_TEST_ERROR)
|
|
*/
|
|
function testBinaries($imageMagickPath) {
|
|
global $gallery;
|
|
$platform =& $gallery->getPlatform();
|
|
$slash = $platform->getDirectorySeparator();
|
|
$dataPath = dirname(dirname(__FILE__)) . "${slash}data${slash}";
|
|
|
|
/*
|
|
* 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 (!$platform->isRestrictedByOpenBaseDir($imageMagickPath) &&
|
|
!@$platform->is_dir($imageMagickPath)) {
|
|
return array(GalleryCoreApi::error(ERROR_BAD_PATH), null);
|
|
}
|
|
|
|
/* We need to translate some strings */
|
|
list ($ret, $module) = GalleryCoreApi::loadPlugin('module', 'imagemagick');
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
|
|
/* What do we want to test */
|
|
$binaries = array('identify', 'convert', 'composite');
|
|
|
|
/*
|
|
* Change to tmp, because IM5 sometimes wants to write stuff
|
|
* to current working directory (e.g. on pdf/eps)
|
|
*/
|
|
$oldCwd = $platform->getcwd();
|
|
$platform->chdir($gallery->getConfig('data.gallery.tmp'));
|
|
|
|
/* Test each binary */
|
|
$testArray = array();
|
|
foreach ($binaries as $binary) {
|
|
switch ($binary) {
|
|
case 'identify':
|
|
list ($ret, $command) =
|
|
ImageMagickToolkitHelper::getCommand('identify', $imageMagickPath);
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
|
|
if (!$platform->isRestrictedByOpenBaseDir($command[0])
|
|
&& !$platform->file_exists($command[0])) {
|
|
$success = false;
|
|
$results = array($module->translate('File does not exist'));
|
|
} else {
|
|
$command = array_merge($command, array($dataPath . 'test.gif'));
|
|
list ($success, $results) = $platform->exec(array($command));
|
|
}
|
|
|
|
if (!$success) {
|
|
$testArray[] =
|
|
array('name' => 'identify',
|
|
'success' => false,
|
|
'message' => array_merge(
|
|
array($module->translate('Problem executing binary:')),
|
|
$results));
|
|
$testArray[] = array('name' => 'identify',
|
|
'success' => false,
|
|
'message' => array_merge(
|
|
array($module->translate('Problem executing binary:')),
|
|
$results));
|
|
} else if (!ereg('(GIF.*PseudoClass|PseudoClass.*GIF|DirectClass.*GIF)',
|
|
implode(',', $results))) {
|
|
$testArray[] = array('name' => 'identify',
|
|
'success' => false,
|
|
'message' => array_merge(
|
|
array($module->translate('Binary output:')),
|
|
$results));
|
|
} else {
|
|
$testArray[] = array('name' => 'identify',
|
|
'success' => true);
|
|
}
|
|
break;
|
|
case 'convert':
|
|
/* We will try to scale a gif using the 'convert' binary */
|
|
list ($ret, $command) =
|
|
ImageMagickToolkitHelper::getCommand('convert', $imageMagickPath);
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
$tmpDir = $gallery->getConfig('data.gallery.tmp');
|
|
$tmpFilename = $platform->tempnam($tmpDir, 'imgk_');
|
|
if (empty($tmpFilename)) {
|
|
/* This can happen if the $tmpDir path is bad */
|
|
return array(GalleryCoreApi::error(ERROR_BAD_PATH, __FILE__, __LINE__,
|
|
"Could not create tmp file in '$tmpDir'"),
|
|
null);
|
|
}
|
|
|
|
if (!$platform->isRestrictedByOpenBaseDir($command[0])
|
|
&& !$platform->file_exists($command[0])) {
|
|
$success = false;
|
|
$results = array($module->translate('File does not exist'));
|
|
} else {
|
|
$command = array_merge($command,
|
|
array('-size', '200x200',
|
|
'-geometry', '200x200',
|
|
$dataPath . 'test.gif',
|
|
$tmpFilename)
|
|
);
|
|
list ($success, $results) = $platform->exec(array($command));
|
|
}
|
|
|
|
if (!$success) {
|
|
$testArray[] =
|
|
array('name' => 'convert',
|
|
'success' => false,
|
|
'message' => array_merge(
|
|
array($module->translate('Problem executing binary:')),
|
|
$results));
|
|
} else if (implode('', $results) != '') {
|
|
/* 'convert' normally doesn't say anything; if it does it was an error */
|
|
$testArray[] = array('name' => 'convert',
|
|
'success' => false,
|
|
'message' => array_merge(
|
|
array($module->translate('Binary output:')),
|
|
$results));
|
|
} else {
|
|
$testArray[] = array('name' => 'convert',
|
|
'success' => true);
|
|
}
|
|
@$platform->unlink($tmpFilename);
|
|
break;
|
|
case 'composite':
|
|
list ($ret, $compositeCmd) =
|
|
ImageMagickToolkitHelper::discoverCompositeCmd($imageMagickPath);
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
list ($ret, $command) =
|
|
ImageMagickToolkitHelper::getCommand($compositeCmd, $imageMagickPath);
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
$tmpDir = $gallery->getConfig('data.gallery.tmp');
|
|
$tmpFilename = $platform->tempnam($tmpDir, 'imgk_');
|
|
if (empty($tmpFilename)) {
|
|
/* This can happen if the $tmpDir path is bad */
|
|
return array(GalleryCoreApi::error(ERROR_BAD_PATH, __FILE__, __LINE__,
|
|
"Could not create tmp file in '$tmpDir'"),
|
|
null);
|
|
}
|
|
$command = array_merge($command,
|
|
array('-geometry', '+0+0',
|
|
$dataPath . 'test.jpg',
|
|
$dataPath . 'test.gif',
|
|
$tmpFilename)
|
|
);
|
|
list ($success, $results) = $platform->exec(array($command));
|
|
if (!$success) {
|
|
$testArray[] = array('name' => $compositeCmd,
|
|
'success' => false,
|
|
'message' => array_merge(
|
|
array($module->translate('Problem executing binary:')),
|
|
$results));
|
|
} else if (!empty($results)) {
|
|
/* 'composite' normally doesn't say anything; if it does it was an error */
|
|
$testArray[] = array('name' => $compositeCmd,
|
|
'success' => false,
|
|
'message' => array_merge(
|
|
array($module->translate('Binary output:')),
|
|
$results));
|
|
} else {
|
|
$testArray[] = array('name' => $compositeCmd,
|
|
'success' => true);
|
|
}
|
|
@$platform->unlink($tmpFilename);
|
|
break;
|
|
default:
|
|
return array(GalleryCoreApi::error(ERROR_BAD_PARAMETER), null);
|
|
break;
|
|
}
|
|
}
|
|
$platform->chdir($oldCwd);
|
|
|
|
return array(null, $testArray);
|
|
}
|
|
|
|
/**
|
|
* Check if we need to prefix every command with another binary name
|
|
*
|
|
* ImageMagick 4.x: <none>
|
|
* ImageMagick 5.x, 6.x: <none>
|
|
* GraphicsMagick: "gm"
|
|
*
|
|
* @return array object GalleryStatus
|
|
* string name of the binary
|
|
*/
|
|
function discoverBinary($imageMagickPath=null) {
|
|
global $gallery;
|
|
$platform =& $gallery->getPlatform();
|
|
|
|
if (empty($imageMagickPath)) {
|
|
list ($ret, $imageMagickPath) =
|
|
GalleryCoreApi::getPluginParameter('module', 'imagemagick', 'path');
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
if (empty($imageMagickPath)) {
|
|
return array(GalleryCoreApi::error(ERROR_MISSING_VALUE), null);
|
|
}
|
|
}
|
|
|
|
$suffix = GalleryUtilities::isA($platform, 'WinNtPlatform') ? '.exe' : '';
|
|
$gmBinary = $imageMagickPath . 'gm' . $suffix;
|
|
if ($platform->file_exists($gmBinary) && $platform->is_executable($gmBinary)) {
|
|
return array(null, 'gm' . $suffix);
|
|
}
|
|
return array(null, '');
|
|
}
|
|
|
|
/**
|
|
* Discovers the version of the installed ImageMagick/GraphicsMagick
|
|
*
|
|
* @return array object GalleryStatus
|
|
* array string "ImageMagick" | "GraphicsMagick"
|
|
* string version
|
|
* boolean true if version is vulnerable to
|
|
* http://nvd.nist.gov/nvd.cfm?cvename=CVE-2005-1739
|
|
*/
|
|
function discoverVersion($imageMagickPath=null) {
|
|
global $gallery;
|
|
$platform =& $gallery->getPlatform();
|
|
|
|
list ($ret, $command) = ImageMagickToolkitHelper::getCommand('identify', $imageMagickPath);
|
|
if ($ret) {
|
|
return array($ret, null, null);
|
|
}
|
|
|
|
list ($success, $results) = $platform->exec(array($command));
|
|
foreach ($results as $resultLine) {
|
|
if (preg_match('/(ImageMagick|GraphicsMagick)\s+([\d\.r-]+)/', $resultLine, $matches)) {
|
|
$version = array($matches[1], $matches[2]);
|
|
$vulnerable = ($version[0] == 'ImageMagick' &&
|
|
version_compare($version[1], '6.2.9-1', '<')) ||
|
|
($version[0] == 'GraphicsMagick' &&
|
|
version_compare($version[1], '1.1.6-r1', '<'));
|
|
return array(null, $version, $vulnerable);
|
|
}
|
|
}
|
|
return array(GalleryCoreApi::error(ERROR_TOOLKIT_FAILURE), null, null);
|
|
}
|
|
|
|
/**
|
|
* Checks which composite binary is available in this ImageMagick.
|
|
*
|
|
* ImageMagick 4.x: combine
|
|
* ImageMagick 5.x, 6.x: composite
|
|
* GraphicsMagick: composite
|
|
*
|
|
* @return array object GalleryStatus
|
|
* string name of the binary (defaults to composite)
|
|
*/
|
|
function discoverCompositeCmd($imageMagickPath=null) {
|
|
global $gallery;
|
|
$platform =& $gallery->getPlatform();
|
|
|
|
list ($ret, $binary) = ImageMagickToolkitHelper::discoverBinary($imageMagickPath);
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
if ($binary != '') {
|
|
/* GraphicsMagick is always 'composite' */
|
|
return array(null, 'composite');
|
|
}
|
|
|
|
if (empty($imageMagickPath)) {
|
|
list ($ret, $imageMagickPath) =
|
|
GalleryCoreApi::getPluginParameter('module', 'imagemagick', 'path');
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
if (empty($imageMagickPath)) {
|
|
return array(GalleryCoreApi::error(ERROR_MISSING_VALUE), null);
|
|
}
|
|
}
|
|
|
|
$binaries = array('combine', 'composite');
|
|
foreach ($binaries as $binary) {
|
|
$binaryPath = $imageMagickPath . $binary .
|
|
(GalleryUtilities::isA($platform, 'WinNtPlatform') ? '.exe' : '');
|
|
if ($platform->file_exists($binaryPath) && $platform->is_executable($binaryPath)) {
|
|
return array(null, $binary);
|
|
}
|
|
}
|
|
return array(null, 'composite');
|
|
}
|
|
|
|
/**
|
|
* Checks which switch to use to remove meta-data from jpegs
|
|
*
|
|
* ImageMagick 4.x: <none>
|
|
* ImageMagick 5.x, 6.x, GraphicsMagick: +profile '*'
|
|
* ImageMagick 6.x: -strip
|
|
*
|
|
* @return array object GalleryStatus
|
|
* array the needed parameters
|
|
*/
|
|
function discoverRemoveMetaDataSwitch($imageMagickPath=null) {
|
|
global $gallery;
|
|
$platform =& $gallery->getPlatform();
|
|
$slash = $platform->getDirectorySeparator();
|
|
$dataPath = dirname(dirname(__FILE__)) . "${slash}data${slash}";
|
|
|
|
list ($ret, $convertCmd) =
|
|
ImageMagickToolkitHelper::getCommand('convert', $imageMagickPath);
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
|
|
$tmpDir = $gallery->getConfig('data.gallery.tmp');
|
|
$tmpFilename = $platform->tempnam($tmpDir, 'imgk_');
|
|
if (empty($tmpFilename)) {
|
|
/* This can happen if the $tmpDir path is bad */
|
|
return array(GalleryCoreApi::error(ERROR_BAD_PATH, __FILE__, __LINE__,
|
|
"Could not create tmp file in '$tmpDir'"), null);
|
|
}
|
|
|
|
foreach (array(array('-strip'), array('+profile', '*')) as $param) {
|
|
$command = array_merge($convertCmd, $param,
|
|
array($dataPath . 'testProfile.jpg', $tmpFilename));
|
|
$originalSize = $platform->filesize($dataPath . 'testProfile.jpg');
|
|
list ($success, $results) = $platform->exec(array($command));
|
|
$size = $platform->filesize($tmpFilename);
|
|
@$platform->unlink($tmpFilename);
|
|
if ($success) {
|
|
if ($size > 0 && $size < $originalSize) {
|
|
return array(null, $param);
|
|
}
|
|
}
|
|
}
|
|
return array(null, array());
|
|
}
|
|
|
|
/**
|
|
* Checks if we can detect and convert jpegs with CMYK colorspace
|
|
*
|
|
* @return array object GalleryStatus
|
|
* boolean true if CMYK is supported
|
|
*/
|
|
function discoverColorspaceSupport($imageMagickPath=null) {
|
|
global $gallery;
|
|
$platform =& $gallery->getPlatform();
|
|
$slash = $platform->getDirectorySeparator();
|
|
$dataPath = dirname(dirname(__FILE__)) . "${slash}data${slash}";
|
|
|
|
list ($ret, $convertCmd) =
|
|
ImageMagickToolkitHelper::getCommand('convert', $imageMagickPath);
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
list ($ret, $identifyCmd) =
|
|
ImageMagickToolkitHelper::getCommand('identify', $imageMagickPath);
|
|
if ($ret) {
|
|
return array($ret, null);
|
|
}
|
|
|
|
$tmpDir = $gallery->getConfig('data.gallery.tmp');
|
|
$tmpFilename = $platform->tempnam($tmpDir, 'imgk_');
|
|
if (empty($tmpFilename)) {
|
|
/* This can happen if the $tmpDir path is bad */
|
|
return array(GalleryCoreApi::error(ERROR_BAD_PATH, __FILE__, __LINE__,
|
|
"Could not create tmp file in '$tmpDir'"), null);
|
|
}
|
|
|
|
$cmykSupport = false;
|
|
list ($success, $results) = $platform->exec(array(
|
|
array_merge($identifyCmd, array('-format', '%r', $dataPath . 'cmyk.jpg'))));
|
|
if ($success && count($results) && strpos($results[0], 'CMYK') !== false) {
|
|
list ($success) = $platform->exec(array(
|
|
array_merge($convertCmd,
|
|
array('-colorspace', 'RGB', $dataPath . 'cmyk.jpg', $tmpFilename))));
|
|
if ($success) {
|
|
list ($success, $results) = $platform->exec(array(
|
|
array_merge($identifyCmd, array('-format', '%r', $tmpFilename))));
|
|
if ($success && count($results) && strpos($results[0], 'RGB') !== false) {
|
|
/* We successfully identified a CMYK jpeg and converted it to RGB */
|
|
$cmykSupport = true;
|
|
}
|
|
}
|
|
}
|
|
@$platform->unlink($tmpFilename);
|
|
return array(null, $cmykSupport);
|
|
}
|
|
|
|
/**
|
|
* Given a imageMagickPath, discover and store some platform-specific
|
|
* settings in the plugins parameter map
|
|
*
|
|
* @return object GalleryStatus
|
|
*/
|
|
function savePlatformParameters($imageMagickPath=null) {
|
|
/* Find out if we are GraphicsMagick, using "gm" as a binary */
|
|
list ($ret, $binary) = ImageMagickToolkitHelper::discoverBinary($imageMagickPath);
|
|
if ($ret) {
|
|
return $ret;
|
|
}
|
|
$ret = GalleryCoreApi::setPluginParameter('module', 'imagemagick', 'binary', $binary);
|
|
if ($ret) {
|
|
return $ret;
|
|
}
|
|
|
|
/* Find out what composite cmd to use */
|
|
list ($ret, $compositeCmd) =
|
|
ImageMagickToolkitHelper::discoverCompositeCmd($imageMagickPath);
|
|
if ($ret) {
|
|
return $ret;
|
|
}
|
|
$ret = GalleryCoreApi::setPluginParameter('module', 'imagemagick',
|
|
'compositeCmd', $compositeCmd);
|
|
if ($ret) {
|
|
return $ret;
|
|
}
|
|
|
|
/* Find out how to remove meta data from jpegs */
|
|
list ($ret, $removeMetaDataSwitch) =
|
|
ImageMagickToolkitHelper::discoverRemoveMetaDataSwitch($imageMagickPath);
|
|
if ($ret) {
|
|
return $ret;
|
|
}
|
|
$ret = GalleryCoreApi::setPluginParameter('module', 'imagemagick', 'removeMetaDataSwitch',
|
|
implode('|', $removeMetaDataSwitch));
|
|
if ($ret) {
|
|
return $ret;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
?>
|