Skip to content

Instantly share code, notes, and snippets.

@Daniel-KM
Last active May 18, 2018 11:19
Show Gist options
  • Save Daniel-KM/7559570 to your computer and use it in GitHub Desktop.
Save Daniel-KM/7559570 to your computer and use it in GitHub Desktop.
Allow to use Omeka when server forbids to use ImageMagick via command line (See http://omeka.org/forums/topic/imagemagick-as-php-module). Simply replace application/libraries/Omeka/File/Derivative/Image/Creator.php with this file. Some work needs to be done in order to be able to select it via the admin UI.
<?php
/**
* Omeka
*
* @copyright Copyright 2007-2012 Roy Rosenzweig Center for History and New Media
* @copyright Copyright 2013 Daniel Berthereau for Mines ParisTech
* @license http://www.gnu.org/licenses/gpl-3.0.txt GNU GPLv3
*/
/**
* Create derivative images for a file in Omeka via the php Imagick extension.
*
* @package Omeka\File\Derivative
*/
class Omeka_File_Derivative_Image_Creator
{
/**
* Determine whether or not the Php Imagick extension is installed.
*
* @todo To be renamed.
*
* @return boolean
*/
public static function isValidImageMagickPath($dirToIm)
{
return class_exists('Imagick');
}
/**
* Create all the derivatives requested with addDerivative().
*
* @param string $fromFilePath
* @param string $derivFilename
* @param string $mimeType
* @return boolean
*/
public function create($fromFilePath, $derivFilename, $mimeType)
{
if (empty($derivFilename) || !is_string($derivFilename)) {
throw new InvalidArgumentException("Invalid derivative filename.");
}
if (!is_readable($fromFilePath)) {
throw new RuntimeException("File at '$fromFilePath' is not readable.");
}
if (!$this->_isDerivable($fromFilePath)) {
return false;
}
// If we have no derivative images to generate, signal nothing was done.
if (empty($this->_derivatives)) {
return false;
}
$workingDir = dirname($fromFilePath);
if (empty($workingDir) || !is_string($workingDir)) {
throw new InvalidArgumentException("Invalid derivative working path.");
}
if (!(is_dir($workingDir) && is_writable($workingDir))) {
throw new RuntimeException("Derivative working directory '$workingDir' is not writable.");
}
foreach ($this->_derivatives as $storageType => $cmdArgs) {
$newFilePath = rtrim($workingDir, DIRECTORY_SEPARATOR )
. DIRECTORY_SEPARATOR . $storageType . '_' . $derivFilename;
$this->_createImage($fromFilePath, $newFilePath, $cmdArgs);
}
return true;
}
/**
* Add a derivative image to be created.
*
* @param string $storageType
* @param integer|string $size If an integer, it is the size constraint for
* the image, meaning it will have that maximum width or height, depending
* on whether the image is landscape or portrait. Otherwise, it is a string
* of comma separated process to be passed to ImageMagick. Each process
* should be a method name followed by its arguments, for example:
* flattenImages, cropImage 300 300 0 0
* @param boolean $square Whether the derivative to add should be made square.
*/
public function addDerivative($storageType, $sizeOrProcess, $square = false)
{
if (!preg_match('/^\w+$/', $storageType)) {
throw new InvalidArgumentException("Invalid derivative type given: '$storageType' "
. "must be alphanumeric string.");
}
if (empty($sizeOrProcess)) {
throw new InvalidArgumentException("Invalid derivative storage size given.");
}
if (is_numeric($sizeOrProcess)) {
$this->_derivatives[$storageType] = $this->_getResizeCmdArgs($sizeOrProcess, $square);
} elseif (is_string($sizeOrProcess)) {
$this->_derivatives[$storageType] = $this->_getProcessArgs($sizeOrProcess);
} else {
throw new InvalidArgumentException("Invalid derivative storage size given.");
}
}
/**
* Generate a derivative image from an existing file stored in Omeka.
*
* This image will be generated based on a constraint given in pixels. For
* example, if the constraint is 500, the resulting image file will be scaled
* so that the largest side is 500px. If the image is less than 500px on both
* sides, the image will not be resized.
*
* Derivative images will only be generated for files with mime types
* that can be identified with ImageMagick's 'identify' command
*
* @throws Omeka_File_Derivative_Exception
* @param string $origPath Path to original file.
* @param string $newPath Path to newly generated derivative file.
* @param array $convertArgs List of methods and arguments to pass to
* ImageMagick.
*/
private function _createImage($origPath, $newPath, $convertArgs)
{
try {
$image = new Imagick();
$image->readImage($origPath);
// Automatic use of first image of multi-pages images, because we
// convert to thumbnail.
foreach ($convertArgs as $method => $args) {
if (is_null($args)) {
$image->$method();
}
elseif (!is_array($args)) {
$image->$method($args);
}
else {
// ImageMagick don't have more than eight arguments.
switch (count($args)) {
case 0:
$image->$method();
break;
case 1:
$image->$method($args[0]);
break;
case 2:
$image->$method($args[0], $args[1]);
break;
case 3:
$image->$method($args[0], $args[1], $args[2]);
break;
case 4:
$image->$method($args[0], $args[1], $args[2], $args[3]);
break;
case 5:
$image->$method($args[0], $args[1], $args[2], $args[3], $args[4]);
break;
case 6:
$image->$method($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]);
break;
case 7:
$image->$method($args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6]);
break;
case 8:
default:
$image->$method($args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6], $args[7]);
}
}
}
$image->writeImage($newPath);
$image->destroy();
} catch (ImagickException $e) {
throw new Omeka_File_Derivative_Exception("ImageMagick failed.");
}
}
/**
* Get the ImageMagick process for resizing to the given constraints.
*
* @param integer $constraint Maximum side length in pixels.
* @param boolean $square Whether the derivative should be squared off.
* @return array
*/
private function _getResizeCmdArgs($constraint, $square)
{
$process = array();
if (!$square) {
$process['setImageBackgroundColor'] = new ImagickPixel('#ffffff');
$process['flattenImages'] = null;
// Tthumbnailing isn't used in order to get better quality images.
// Generally, the time used to import images in Omeka is not a
// problem.
$process['resizeImage'] = array($constraint, $constraint, Imagick::FILTER_LANCZOS, 1, true);
// Remove the canvas.
$process['setImagePage'] = array(0, 0, 0, 0);
}
else {
$process['setImageBackgroundColor'] = new ImagickPixel('#ffffff');
$process['flattenImages'] = null;
$process['cropThumbnailImage'] = array($constraint, $constraint);
// Remove the canvas.
$process['setImagePage'] = array(0, 0, 0, 0);
}
return $process;
}
/**
* Get the ImageMagick process selected by the user.
*
* @param string $process A comma-separated string to convert to a process.
* Example:
* flattenImages, cropImage 300 300 0 0
* @return array
*/
private function _getProcessArgs($process)
{
$list = array();
foreach (explode(',', $process) as $value) {
$value = trim($value);
if (strpos($value, ' ') === false) {
$list[$value] = array();
}
else {
$values = explode(' ', $value);
$key = trim($values[0]);
unset($values[0]);
$list[$key] = $values;
}
}
return $list;
}
/**
* Returns true only if ImageMagick is able to make derivative images of that file based
* upon whether or not it can be identified by ImageMagick's 'identify' binary. Otherwise returns false.
*
* @param string $filePath
* @return boolean
*/
private function _isDerivable($filePath)
{
// Next we'll check that it is identifiable by ImageMagick, and isn't on a blacklist
return (file_exists($filePath)
&& is_readable($filePath)
&& $this->_isIdentifiable($filePath));
}
/**
* Returns true only if the file can be identified by ImageMagick.
*
* @param string $filePath
* @return boolean
*/
private function _isIdentifiable($filePath)
{
try {
$image = new Imagick();
$image->readImage($filePath);
$isImage = $image->identifyImage();
$isImage = (boolean) $isImage;
$image->destroy();
} catch (ImagickException $e) {
$isImage = false;
}
return $isImage;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment