Make mediawiki.special.pageLanguage work again
[lhc/web/wiklou.git] / includes / media / XCF.php
1 <?php
2 /**
3 * Handler for the Gimp's native file format (XCF)
4 *
5 * Overview:
6 * https://en.wikipedia.org/wiki/XCF_(file_format)
7 * Specification in Gnome repository:
8 * http://svn.gnome.org/viewvc/gimp/trunk/devel-docs/xcf.txt?view=markup
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 * http://www.gnu.org/copyleft/gpl.html
24 *
25 * @file
26 * @ingroup Media
27 */
28
29 /**
30 * Handler for the Gimp's native file format; getimagesize() doesn't
31 * support these files
32 *
33 * @ingroup Media
34 */
35 class XCFHandler extends BitmapHandler {
36 /**
37 * @param File $file
38 * @return bool
39 */
40 function mustRender( $file ) {
41 return true;
42 }
43
44 /**
45 * Render files as PNG
46 *
47 * @param string $ext
48 * @param string $mime
49 * @param array $params
50 * @return array
51 */
52 function getThumbType( $ext, $mime, $params = null ) {
53 return array( 'png', 'image/png' );
54 }
55
56 /**
57 * Get width and height from the XCF header.
58 *
59 * @param File $image
60 * @param string $filename
61 * @return array
62 */
63 function getImageSize( $image, $filename ) {
64 $header = self::getXCFMetaData( $filename );
65 if ( !$header ) {
66 return false;
67 }
68
69 # Forge a return array containing metadata information just like getimagesize()
70 # See PHP documentation at: http://www.php.net/getimagesize
71 $metadata = array();
72 $metadata[0] = $header['width'];
73 $metadata[1] = $header['height'];
74 $metadata[2] = null; # IMAGETYPE constant, none exist for XCF.
75 $metadata[3] = sprintf(
76 'height="%s" width="%s"', $header['height'], $header['width']
77 );
78 $metadata['mime'] = 'image/x-xcf';
79 $metadata['channels'] = null;
80 $metadata['bits'] = 8; # Always 8-bits per color
81
82 assert( '7 == count($metadata); ' .
83 '# return array must contains 7 elements just like getimagesize() return' );
84
85 return $metadata;
86 }
87
88 /**
89 * Metadata for a given XCF file
90 *
91 * Will return false if file magic signature is not recognized
92 * @author Hexmode
93 * @author Hashar
94 *
95 * @param string $filename Full path to a XCF file
96 * @return bool|array Metadata Array just like PHP getimagesize()
97 */
98 static function getXCFMetaData( $filename ) {
99 # Decode master structure
100 $f = fopen( $filename, 'rb' );
101 if ( !$f ) {
102 return false;
103 }
104 # The image structure always starts at offset 0 in the XCF file.
105 # So we just read it :-)
106 $binaryHeader = fread( $f, 26 );
107 fclose( $f );
108
109 /**
110 * Master image structure:
111 *
112 * byte[9] "gimp xcf " File type magic
113 * byte[4] version XCF version
114 * "file" - version 0
115 * "v001" - version 1
116 * "v002" - version 2
117 * byte 0 Zero-terminator for version tag
118 * uint32 width With of canvas
119 * uint32 height Height of canvas
120 * uint32 base_type Color mode of the image; one of
121 * 0: RGB color
122 * 1: Grayscale
123 * 2: Indexed color
124 * (enum GimpImageBaseType in libgimpbase/gimpbaseenums.h)
125 */
126 try {
127 $header = wfUnpack(
128 "A9magic" . # A: space padded
129 "/a5version" . # a: zero padded
130 "/Nwidth" . # \
131 "/Nheight" . # N: unsigned long 32bit big endian
132 "/Nbase_type", # /
133 $binaryHeader
134 );
135 } catch ( Exception $mwe ) {
136 return false;
137 }
138
139 # Check values
140 if ( $header['magic'] !== 'gimp xcf' ) {
141 wfDebug( __METHOD__ . " '$filename' has invalid magic signature.\n" );
142
143 return false;
144 }
145 # TODO: we might want to check for sane values of width and height
146
147 wfDebug( __METHOD__ .
148 ": canvas size of '$filename' is {$header['width']} x {$header['height']} px\n" );
149
150 return $header;
151 }
152
153 /**
154 * Store the channel type
155 *
156 * Greyscale files need different command line options.
157 *
158 * @param File $file The image object, or false if there isn't one.
159 * Warning, FSFile::getPropsFromPath might pass an (object)array() instead (!)
160 * @param string $filename The filename
161 * @return string
162 */
163 public function getMetadata( $file, $filename ) {
164 $header = self::getXCFMetadata( $filename );
165 $metadata = array();
166 if ( $header ) {
167 // Try to be consistent with the names used by PNG files.
168 // Unclear from base media type if it has an alpha layer,
169 // so just assume that it does since it "potentially" could.
170 switch ( $header['base_type'] ) {
171 case 0:
172 $metadata['colorType'] = 'truecolour-alpha';
173 break;
174 case 1:
175 $metadata['colorType'] = 'greyscale-alpha';
176 break;
177 case 2:
178 $metadata['colorType'] = 'index-coloured';
179 break;
180 default:
181 $metadata['colorType'] = 'unknown';
182
183 }
184 } else {
185 // Marker to prevent repeated attempted extraction
186 $metadata['error'] = true;
187 }
188 return serialize( $metadata );
189 }
190
191 /**
192 * Should we refresh the metadata
193 *
194 * @param File $file The file object for the file in question
195 * @param string $metadata Serialized metadata
196 * @return bool One of the self::METADATA_(BAD|GOOD|COMPATIBLE) constants
197 */
198 public function isMetadataValid( $file, $metadata ) {
199 if ( !$metadata ) {
200 // Old metadata when we just put an empty string in there
201 return self::METADATA_BAD;
202 } else {
203 return self::METADATA_GOOD;
204 }
205 }
206
207 /**
208 * Must use "im" for XCF
209 *
210 * @param string $dstPath
211 * @param bool $checkDstPath
212 * @return string
213 */
214 protected function getScalerType( $dstPath, $checkDstPath = true ) {
215 return "im";
216 }
217
218 /**
219 * Can we render this file?
220 *
221 * Image magick doesn't support indexed xcf files as of current
222 * writing (as of 6.8.9-3)
223 * @param File $file
224 * @return bool
225 */
226 public function canRender( $file ) {
227 MediaWiki\suppressWarnings();
228 $xcfMeta = unserialize( $file->getMetadata() );
229 MediaWiki\restoreWarnings();
230 if ( isset( $xcfMeta['colorType'] ) && $xcfMeta['colorType'] === 'index-coloured' ) {
231 return false;
232 }
233 return parent::canRender( $file );
234 }
235 }