Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
1.04% |
1 / 96 |
|
6.25% |
1 / 16 |
CRAP | |
0.00% |
0 / 1 |
ImageHandler | |
1.04% |
1 / 96 |
|
6.25% |
1 / 16 |
1920.13 | |
0.00% |
0 / 1 |
canRender | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
getParamMap | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
validateParam | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
makeParamString | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
parseParamString | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
getScriptParams | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
normaliseParams | |
0.00% |
0 / 28 |
|
0.00% |
0 / 1 |
182 | |||
validateThumbParams | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
20 | |||
getScriptedTransform | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
20 | |||
getImageSize | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
getSizeAndMetadata | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
getImageArea | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getShortDesc | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
getLongDesc | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
getDimensionsString | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
sanitizeParamsForBucketing | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * Media-handling base classes and generic functionality. |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License along |
16 | * with this program; if not, write to the Free Software Foundation, Inc., |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | * http://www.gnu.org/copyleft/gpl.html |
19 | * |
20 | * @file |
21 | * @ingroup Media |
22 | */ |
23 | |
24 | use Wikimedia\AtEase\AtEase; |
25 | |
26 | /** |
27 | * Media handler abstract base class for images |
28 | * |
29 | * @stable to extend |
30 | * |
31 | * @ingroup Media |
32 | */ |
33 | abstract class ImageHandler extends MediaHandler { |
34 | /** |
35 | * @inheritDoc |
36 | * @stable to override |
37 | * @param File $file |
38 | * @return bool |
39 | */ |
40 | public function canRender( $file ) { |
41 | return ( $file->getWidth() && $file->getHeight() ); |
42 | } |
43 | |
44 | /** |
45 | * @inheritDoc |
46 | * @stable to override |
47 | * @return string[] |
48 | */ |
49 | public function getParamMap() { |
50 | return [ 'img_width' => 'width' ]; |
51 | } |
52 | |
53 | /** |
54 | * @inheritDoc |
55 | * @stable to override |
56 | */ |
57 | public function validateParam( $name, $value ) { |
58 | return in_array( $name, [ 'width', 'height' ] ) && $value > 0; |
59 | } |
60 | |
61 | /** |
62 | * @inheritDoc |
63 | * @stable to override |
64 | * @throws MediaTransformInvalidParametersException |
65 | */ |
66 | public function makeParamString( $params ) { |
67 | if ( isset( $params['physicalWidth'] ) ) { |
68 | $width = $params['physicalWidth']; |
69 | } elseif ( isset( $params['width'] ) ) { |
70 | $width = $params['width']; |
71 | } else { |
72 | throw new MediaTransformInvalidParametersException( 'No width specified to ' . __METHOD__ ); |
73 | } |
74 | |
75 | # Removed for ProofreadPage |
76 | # $width = intval( $width ); |
77 | return "{$width}px"; |
78 | } |
79 | |
80 | /** |
81 | * @inheritDoc |
82 | * @stable to override |
83 | */ |
84 | public function parseParamString( $str ) { |
85 | $m = false; |
86 | if ( preg_match( '/^(\d+)px$/', $str, $m ) ) { |
87 | return [ 'width' => $m[1] ]; |
88 | } |
89 | return false; |
90 | } |
91 | |
92 | /** |
93 | * @stable to override |
94 | * @param array $params |
95 | * @return array |
96 | */ |
97 | protected function getScriptParams( $params ) { |
98 | return [ 'width' => $params['width'] ]; |
99 | } |
100 | |
101 | /** |
102 | * @inheritDoc |
103 | * @stable to override |
104 | * @param File $image |
105 | * @param array &$params @phan-ignore-reference |
106 | * @return bool |
107 | * @phan-assert array{width:int,physicalWidth:int,height:int,physicalHeight:int,page:int} $params |
108 | */ |
109 | public function normaliseParams( $image, &$params ) { |
110 | if ( !isset( $params['width'] ) ) { |
111 | return false; |
112 | } |
113 | |
114 | if ( !isset( $params['page'] ) ) { |
115 | $params['page'] = 1; |
116 | } else { |
117 | $params['page'] = (int)$params['page']; |
118 | if ( $params['page'] > $image->pageCount() ) { |
119 | $params['page'] = $image->pageCount(); |
120 | } |
121 | |
122 | if ( $params['page'] < 1 ) { |
123 | $params['page'] = 1; |
124 | } |
125 | } |
126 | |
127 | $srcWidth = $image->getWidth( $params['page'] ); |
128 | $srcHeight = $image->getHeight( $params['page'] ); |
129 | |
130 | if ( isset( $params['height'] ) && $params['height'] !== -1 ) { |
131 | # Height & width were both set |
132 | if ( $params['width'] * $srcHeight > $params['height'] * $srcWidth ) { |
133 | # Height is the relative smaller dimension, so scale width accordingly |
134 | $params['width'] = self::fitBoxWidth( $srcWidth, $srcHeight, $params['height'] ); |
135 | |
136 | if ( $params['width'] == 0 ) { |
137 | # Very small image, so we need to rely on client side scaling :( |
138 | $params['width'] = 1; |
139 | } |
140 | |
141 | $params['physicalWidth'] = $params['width']; |
142 | } else { |
143 | # Height was crap, unset it so that it will be calculated later |
144 | unset( $params['height'] ); |
145 | } |
146 | } |
147 | |
148 | if ( !isset( $params['physicalWidth'] ) ) { |
149 | # Passed all validations, so set the physicalWidth |
150 | // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset False positive, checked above |
151 | $params['physicalWidth'] = $params['width']; |
152 | } |
153 | |
154 | # Because thumbs are only referred to by width, the height always needs |
155 | # to be scaled by the width to keep the thumbnail sizes consistent, |
156 | # even if it was set inside the if block above |
157 | $params['physicalHeight'] = File::scaleHeight( $srcWidth, $srcHeight, |
158 | $params['physicalWidth'] ); |
159 | |
160 | # Set the height if it was not validated in the if block higher up |
161 | if ( !isset( $params['height'] ) || $params['height'] === -1 ) { |
162 | $params['height'] = $params['physicalHeight']; |
163 | } |
164 | |
165 | if ( !$this->validateThumbParams( $params['physicalWidth'], |
166 | $params['physicalHeight'], $srcWidth, $srcHeight ) |
167 | ) { |
168 | return false; |
169 | } |
170 | |
171 | return true; |
172 | } |
173 | |
174 | /** |
175 | * Validate thumbnail parameters and fill in the correct height |
176 | * |
177 | * @param int &$width Specified width (input/output) |
178 | * @param int &$height Height (output only) |
179 | * @param int $srcWidth Width of the source image |
180 | * @param int $srcHeight Height of the source image |
181 | * @return bool False to indicate that an error should be returned to the user. |
182 | */ |
183 | private function validateThumbParams( &$width, &$height, $srcWidth, $srcHeight ) { |
184 | $width = (int)$width; |
185 | |
186 | if ( $width <= 0 ) { |
187 | wfDebug( __METHOD__ . ": Invalid destination width: $width" ); |
188 | |
189 | return false; |
190 | } |
191 | if ( $srcWidth <= 0 ) { |
192 | wfDebug( __METHOD__ . ": Invalid source width: $srcWidth" ); |
193 | |
194 | return false; |
195 | } |
196 | |
197 | $height = File::scaleHeight( $srcWidth, $srcHeight, $width ); |
198 | if ( $height == 0 ) { |
199 | # Force height to be at least 1 pixel |
200 | $height = 1; |
201 | } |
202 | |
203 | return true; |
204 | } |
205 | |
206 | /** |
207 | * @inheritDoc |
208 | * @stable to override |
209 | * @param File $image |
210 | * @param string $script |
211 | * @param array $params |
212 | * @return MediaTransformOutput|false |
213 | */ |
214 | public function getScriptedTransform( $image, $script, $params ) { |
215 | if ( !$this->normaliseParams( $image, $params ) ) { |
216 | return false; |
217 | } |
218 | $url = wfAppendQuery( $script, $this->getScriptParams( $params ) ); |
219 | |
220 | if ( $image->mustRender() || $params['width'] < $image->getWidth() ) { |
221 | return new ThumbnailImage( $image, $url, false, $params ); |
222 | } |
223 | } |
224 | |
225 | public function getImageSize( $image, $path ) { |
226 | AtEase::suppressWarnings(); |
227 | $gis = getimagesize( $path ); |
228 | AtEase::restoreWarnings(); |
229 | |
230 | return $gis; |
231 | } |
232 | |
233 | public function getSizeAndMetadata( $state, $path ) { |
234 | // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged |
235 | $gis = @getimagesize( $path ); |
236 | if ( $gis ) { |
237 | $info = [ |
238 | 'width' => $gis[0], |
239 | 'height' => $gis[1], |
240 | ]; |
241 | if ( isset( $gis['bits'] ) ) { |
242 | $info['bits'] = $gis['bits']; |
243 | } |
244 | } else { |
245 | $info = []; |
246 | } |
247 | return $info; |
248 | } |
249 | |
250 | /** |
251 | * Function that returns the number of pixels to be thumbnailed. |
252 | * Intended for animated GIFs to multiply by the number of frames. |
253 | * |
254 | * If the file doesn't support a notion of "area" return 0. |
255 | * @stable to override |
256 | * |
257 | * @param File $image |
258 | * @return int |
259 | */ |
260 | public function getImageArea( $image ) { |
261 | return $image->getWidth() * $image->getHeight(); |
262 | } |
263 | |
264 | /** |
265 | * @inheritDoc |
266 | * @stable to override |
267 | * @param File $file |
268 | * @return string |
269 | */ |
270 | public function getShortDesc( $file ) { |
271 | global $wgLang; |
272 | $nbytes = htmlspecialchars( $wgLang->formatSize( $file->getSize() ) ); |
273 | $widthheight = wfMessage( 'widthheight' ) |
274 | ->numParams( $file->getWidth(), $file->getHeight() )->escaped(); |
275 | |
276 | return "$widthheight ($nbytes)"; |
277 | } |
278 | |
279 | /** |
280 | * @inheritDoc |
281 | * @stable to override |
282 | * @param File $file |
283 | * @return string |
284 | */ |
285 | public function getLongDesc( $file ) { |
286 | $pages = $file->pageCount(); |
287 | if ( $pages === false || $pages <= 1 ) { |
288 | $msg = wfMessage( 'file-info-size' )->numParams( $file->getWidth(), |
289 | $file->getHeight() )->sizeParams( $file->getSize() )->params( |
290 | '<span class="mime-type">' . $file->getMimeType() . '</span>' )->parse(); |
291 | } else { |
292 | $msg = wfMessage( 'file-info-size-pages' )->numParams( $file->getWidth(), |
293 | $file->getHeight() )->sizeParams( $file->getSize() )->params( |
294 | '<span class="mime-type">' . $file->getMimeType() . '</span>' )->numParams( $pages )->parse(); |
295 | } |
296 | |
297 | return $msg; |
298 | } |
299 | |
300 | /** |
301 | * @inheritDoc |
302 | * @stable to override |
303 | * @param File $file |
304 | * @return string |
305 | */ |
306 | public function getDimensionsString( $file ) { |
307 | $pages = $file->pageCount(); |
308 | if ( $pages > 1 ) { |
309 | return wfMessage( 'widthheightpage' ) |
310 | ->numParams( $file->getWidth(), $file->getHeight(), $pages )->text(); |
311 | } |
312 | return wfMessage( 'widthheight' ) |
313 | ->numParams( $file->getWidth(), $file->getHeight() )->text(); |
314 | } |
315 | |
316 | /** |
317 | * @inheritDoc |
318 | * @stable to override |
319 | */ |
320 | public function sanitizeParamsForBucketing( $params ) { |
321 | $params = parent::sanitizeParamsForBucketing( $params ); |
322 | |
323 | // We unset the height parameters in order to let normaliseParams recalculate them |
324 | // Otherwise there might be a height discrepancy |
325 | unset( $params['height'] ); |
326 | unset( $params['physicalHeight'] ); |
327 | |
328 | return $params; |
329 | } |
330 | } |