From 1b82b6dc2384fe49903c480ea0a1f9427ce94e10 Mon Sep 17 00:00:00 2001 From: Antoine Musso Date: Thu, 5 Jan 2012 14:48:55 +0000 Subject: [PATCH] rewrite getXCFMetaData() to get ride of im identify By reading the file header and unpacking the data, we can avoid shelling out to imagemagick 'identify'. Save up some CPU cycles :D An XCF is made of a canvas of a given width / height, the various layers are applied to it which must fit in the canvas. So we just use the canvas size :-) I do not think we have any usage for channels count, so I have just skip that part. I am not sure it makes any sense when the picture can be made of several layers each using different channels count. Bits per color is always 8 per definition. Grayscale is 0 - 255 and indexed palette is 256 colors at most. XCF spec: http://svn.gnome.org/viewvc/gimp/trunk/devel-docs/xcf.txt?view=markup pack() / unpack() is familiar to perl monkeys Fully reimplements r107351 --- includes/media/XCF.php | 96 +++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 38 deletions(-) diff --git a/includes/media/XCF.php b/includes/media/XCF.php index 837c8554dd..c72927b9b8 100644 --- a/includes/media/XCF.php +++ b/includes/media/XCF.php @@ -42,55 +42,75 @@ class XCFHandler extends BitmapHandler { return self::getXCFMetaData( $filename ); } + /** + * Metadata for a given XCF file + * + * Will return false if file magic signature is not recognized + * @author Hexmode + * @author Hashar + * + * @param $filename String Full path to a XCF file + * @return false|metadata array just like PHP getimagesize() + */ static function getXCFMetaData( $filename ) { - global $wgImageMagickIdentifyCommand; - - $cmd = wfEscapeShellArg( $wgImageMagickIdentifyCommand ) . ' -verbose ' . wfEscapeShellArg( $filename ); - wfDebug( __METHOD__ . ": Running $cmd \n" ); - - $retval = null; - $return = wfShellExec( $cmd, $retval ); - if( $retval !== 0 ) { - wfDebug( __METHOD__ . ": error encountered while running $cmd\n" ); + # Decode master structure + $f = fopen( $filename, 'rb' ); + if( !$f ) { return false; } + # The image structure always starts at offset 0 in the XCF file. + # So we just read it :-) + $binaryHeader = fread( $f, 26 ); + fclose($f); - $colorspace = preg_match_all( '/ *Colorspace: RGB/', $return, $match ); - $frameCount = preg_match_all( '/ *Geometry: ([0-9]+x[0-9]+)\+[+0-9]*/', $return, $match ); - wfDebug( __METHOD__ . ": Got $frameCount matches\n" ); - - /* if( $frameCount == 1 ) { */ - /* preg_match( '/([0-9]+)x([0-9]+)/sm', $match[1][0], $m ); */ - /* $sizeX = $m[1]; */ - /* $sizeY = $m[2]; */ - /* } else { */ - $sizeX = 0; - $sizeY = 0; + # Master image structure: + # + # byte[9] "gimp xcf " File type magic + # byte[4] version XCF version + # "file" - version 0 + # "v001" - version 1 + # "v002" - version 2 + # byte 0 Zero-terminator for version tag + # uint32 width With of canvas + # uint32 height Height of canvas + # uint32 base_type Color mode of the image; one of + # 0: RGB color + # 1: Grayscale + # 2: Indexed color + # (enum GimpImageBaseType in libgimpbase/gimpbaseenums.h) + $header = unpack( + "A9magic" # A: space padded + . "/a5version" # a: zero padded + . "/Nwidth" # \ + . "/Nheight" # N: unsigned long 32bit big endian + . "/Nbase_type" # / + , $binaryHeader + ); - # Find out the largest width and height used in any frame - foreach( $match[1] as $res ) { - preg_match( '/([0-9]+)x([0-9]+)/sm', $res, $m ); - if( $m[1] > $sizeX ) { - $sizeX = $m[1]; - } - if( $m[2] > $sizeY ) { - $sizeY = $m[2]; - } - } - /* } */ + # Check values + if( $header['magic'] !== 'gimp xcf' ) { + var_dump( $header ); + wfDebug( __METHOD__ . " '$filename' has invalid magic signature.\n" ); + return false; + } + # TODO: we might want to check for sane values of width and height - wfDebug( __METHOD__ . ": Found $sizeX x $sizeY x $frameCount \n" ); + wfDebug( __METHOD__ . ": canvas size of '$filename' is {$header['width']} x {$header['height']} px\n" ); # Forge a return array containing metadata information just like getimagesize() # See PHP documentation at: http://www.php.net/getimagesize $metadata = array(); - $metadata['frameCount'] = $frameCount; - $metadata[0] = $sizeX; - $metadata[1] = $sizeY; - $metadata[2] = null; - $metadata[3] = "height=\"$sizeY\" width=\"$sizeX\""; + $metadata[0] = $header['width']; + $metadata[1] = $header['height']; + $metadata[2] = null; # IMAGETYPE constant, none exist for XCF. + $metadata[3] = sprintf( + 'height="%s" width="%s"', $header['height'], $header['width'] + ); $metadata['mime'] = 'image/x-xcf'; - $metadata['channels'] = $colorspace == 1 ? 3 : 4; + $metadata['channels'] = null; + $metadata['bits'] = 8; # Always 8-bits per color + + assert( '7 == count($metadata); # return array must contains 7 elements just like getimagesize() return' ); return $metadata; } -- 2.20.1