Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
38.46% |
20 / 52 |
|
14.29% |
1 / 7 |
CRAP | |
0.00% |
0 / 1 |
XCFHandler | |
38.46% |
20 / 52 |
|
14.29% |
1 / 7 |
93.51 | |
0.00% |
0 / 1 |
mustRender | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getThumbType | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getXCFMetaData | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
20 | |||
getSizeAndMetadata | |
80.95% |
17 / 21 |
|
0.00% |
0 / 1 |
6.25 | |||
isFileMetadataValid | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
hasGDSupport | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
canRender | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 |
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 | use MediaWiki\Libs\UnpackFailedException; |
30 | |
31 | /** |
32 | * Handler for the Gimp's native file format; getimagesize() doesn't |
33 | * support these files |
34 | * |
35 | * @ingroup Media |
36 | */ |
37 | class XCFHandler extends BitmapHandler { |
38 | /** |
39 | * @param File $file |
40 | * @return bool |
41 | */ |
42 | public function mustRender( $file ) { |
43 | return true; |
44 | } |
45 | |
46 | /** |
47 | * Render files as PNG |
48 | * |
49 | * @param string $ext |
50 | * @param string $mime |
51 | * @param array|null $params |
52 | * @return array |
53 | */ |
54 | public function getThumbType( $ext, $mime, $params = null ) { |
55 | return [ 'png', 'image/png' ]; |
56 | } |
57 | |
58 | /** |
59 | * Metadata for a given XCF file |
60 | * |
61 | * Will return false if file magic signature is not recognized |
62 | * @author Hexmode |
63 | * @author Hashar |
64 | * |
65 | * @param string $filename Full path to a XCF file |
66 | * @return array|null Metadata Array just like PHP getimagesize() |
67 | */ |
68 | private static function getXCFMetaData( $filename ) { |
69 | # Decode master structure |
70 | $f = fopen( $filename, 'rb' ); |
71 | if ( !$f ) { |
72 | return null; |
73 | } |
74 | # The image structure always starts at offset 0 in the XCF file. |
75 | # So we just read it :-) |
76 | $binaryHeader = fread( $f, 26 ); |
77 | fclose( $f ); |
78 | |
79 | /** |
80 | * Master image structure: |
81 | * |
82 | * byte[9] "gimp xcf " File type magic |
83 | * byte[4] version XCF version |
84 | * "file" - version 0 |
85 | * "v001" - version 1 |
86 | * "v002" - version 2 |
87 | * byte 0 Zero-terminator for version tag |
88 | * uint32 width With of canvas |
89 | * uint32 height Height of canvas |
90 | * uint32 base_type Color mode of the image; one of |
91 | * 0: RGB color |
92 | * 1: Grayscale |
93 | * 2: Indexed color |
94 | * (enum GimpImageBaseType in libgimpbase/gimpbaseenums.h) |
95 | */ |
96 | try { |
97 | $header = StringUtils::unpack( |
98 | "A9magic" . # A: space padded |
99 | "/a5version" . # a: zero padded |
100 | "/Nwidth" . # \ |
101 | "/Nheight" . # N: unsigned long 32bit big endian |
102 | "/Nbase_type", # / |
103 | $binaryHeader |
104 | ); |
105 | } catch ( UnpackFailedException $_ ) { |
106 | return null; |
107 | } |
108 | |
109 | # Check values |
110 | if ( $header['magic'] !== 'gimp xcf' ) { |
111 | wfDebug( __METHOD__ . " '$filename' has invalid magic signature." ); |
112 | |
113 | return null; |
114 | } |
115 | # TODO: we might want to check for correct values of width and height |
116 | |
117 | wfDebug( __METHOD__ . |
118 | ": canvas size of '$filename' is {$header['width']} x {$header['height']} px" ); |
119 | |
120 | return $header; |
121 | } |
122 | |
123 | public function getSizeAndMetadata( $state, $filename ) { |
124 | $header = self::getXCFMetaData( $filename ); |
125 | $metadata = []; |
126 | if ( $header ) { |
127 | // Try to be consistent with the names used by PNG files. |
128 | // Unclear from base media type if it has an alpha layer, |
129 | // so just assume that it does since it "potentially" could. |
130 | switch ( $header['base_type'] ) { |
131 | case 0: |
132 | $metadata['colorType'] = 'truecolour-alpha'; |
133 | break; |
134 | case 1: |
135 | $metadata['colorType'] = 'greyscale-alpha'; |
136 | break; |
137 | case 2: |
138 | $metadata['colorType'] = 'index-coloured'; |
139 | break; |
140 | default: |
141 | $metadata['colorType'] = 'unknown'; |
142 | } |
143 | } else { |
144 | // Marker to prevent repeated attempted extraction |
145 | $metadata['error'] = true; |
146 | } |
147 | return [ |
148 | 'width' => $header['width'] ?? 0, |
149 | 'height' => $header['height'] ?? 0, |
150 | 'bits' => 8, |
151 | 'metadata' => $metadata |
152 | ]; |
153 | } |
154 | |
155 | /** |
156 | * Should we refresh the metadata |
157 | * |
158 | * @param File $file The file object for the file in question |
159 | * @return bool|int One of the self::METADATA_(BAD|GOOD|COMPATIBLE) constants |
160 | */ |
161 | public function isFileMetadataValid( $file ) { |
162 | if ( !$file->getMetadataArray() ) { |
163 | // Old metadata when we just put an empty string in there |
164 | return self::METADATA_BAD; |
165 | } |
166 | |
167 | return self::METADATA_GOOD; |
168 | } |
169 | |
170 | protected function hasGDSupport() { |
171 | return false; |
172 | } |
173 | |
174 | /** |
175 | * Can we render this file? |
176 | * |
177 | * Image magick doesn't support indexed xcf files as of current |
178 | * writing (as of 6.8.9-3) |
179 | * @param File $file |
180 | * @return bool |
181 | */ |
182 | public function canRender( $file ) { |
183 | $xcfMeta = $file->getMetadataArray(); |
184 | if ( isset( $xcfMeta['colorType'] ) && $xcfMeta['colorType'] === 'index-coloured' ) { |
185 | return false; |
186 | } |
187 | return parent::canRender( $file ); |
188 | } |
189 | } |