Index: trunk/phase3/docs/hooks.txt |
— | — | @@ -624,6 +624,11 @@ |
625 | 625 | &$scalerParams: Array with scaler parameters |
626 | 626 | &$mto: null, set to a MediaTransformOutput |
627 | 627 | |
| 628 | +'BitmapHandlerCheckImageArea': by BitmapHandler::normaliseParams, after all normalizations have been performed, except for the $wgMaxImageArea check |
| 629 | +$image: File |
| 630 | +&$params: Array of parameters |
| 631 | +&$checkImageAreaHookResult: null, set to true or false to override the $wgMaxImageArea check result |
| 632 | + |
628 | 633 | 'PerformRetroactiveAutoblock': called before a retroactive autoblock is applied to a user |
629 | 634 | $block: Block object (which is set to be autoblocking) |
630 | 635 | &$blockIds: Array of block IDs of the autoblock |
Index: trunk/phase3/RELEASE-NOTES-1.19 |
— | — | @@ -76,6 +76,7 @@ |
77 | 77 | syntax. |
78 | 78 | * The default user signature now contains a talk link in addition to the user link. |
79 | 79 | * (bug 25306) Add link of old page title to MediaWiki:Delete_and_move_reason |
| 80 | +* Added hook BitmapHandlerCheckImageArea |
80 | 81 | |
81 | 82 | === Bug fixes in 1.19 === |
82 | 83 | * $wgUploadNavigationUrl should be used for file redlinks if |
Index: trunk/phase3/tests/phpunit/includes/media/BitmapScalingTest.php |
— | — | @@ -119,6 +119,12 @@ |
120 | 120 | $this->assertEquals( 'TransformParameterError', |
121 | 121 | get_class( $handler->doTransform( $file, 'dummy path', '', $params ) ) ); |
122 | 122 | } |
| 123 | + |
| 124 | + function testImageArea() { |
| 125 | + $file = new FakeDimensionFile( array( 7, 9 ) ); |
| 126 | + $handler = new BitmapHandler; |
| 127 | + $this->assertEquals( 63, $handler->getImageArea( $file ) ); |
| 128 | + } |
123 | 129 | } |
124 | 130 | |
125 | 131 | class FakeDimensionFile extends File { |
Index: trunk/phase3/includes/media/GIF.php |
— | — | @@ -50,17 +50,16 @@ |
51 | 51 | |
52 | 52 | /** |
53 | 53 | * @param $image File |
54 | | - * @param $width |
55 | | - * @param $height |
56 | | - * @return |
| 54 | + * @todo unittests |
| 55 | + * @return bool |
57 | 56 | */ |
58 | | - function getImageArea( $image, $width, $height ) { |
| 57 | + function getImageArea( $image ) { |
59 | 58 | $ser = $image->getMetadata(); |
60 | 59 | if ( $ser ) { |
61 | 60 | $metadata = unserialize( $ser ); |
62 | | - return $width * $height * $metadata['frameCount']; |
| 61 | + return $image->getWidth() * $image->getHeight() * $metadata['frameCount']; |
63 | 62 | } else { |
64 | | - return $width * $height; |
| 63 | + return $image->getWidth() * $image->getHeight(); |
65 | 64 | } |
66 | 65 | } |
67 | 66 | |
Index: trunk/phase3/includes/media/Bitmap.php |
— | — | @@ -12,7 +12,6 @@ |
13 | 13 | * @ingroup Media |
14 | 14 | */ |
15 | 15 | class BitmapHandler extends ImageHandler { |
16 | | - |
17 | 16 | /** |
18 | 17 | * @param $image File |
19 | 18 | * @param $params array Transform parameters. Entries with the keys 'width' |
— | — | @@ -21,7 +20,6 @@ |
22 | 21 | * @return bool |
23 | 22 | */ |
24 | 23 | function normaliseParams( $image, &$params ) { |
25 | | - |
26 | 24 | if ( !parent::normaliseParams( $image, $params ) ) { |
27 | 25 | return false; |
28 | 26 | } |
— | — | @@ -41,44 +39,29 @@ |
42 | 40 | return true; |
43 | 41 | } |
44 | 42 | } |
| 43 | + |
45 | 44 | |
| 45 | + # Check if the file is smaller than the maximum image area for thumbnailing |
| 46 | + $checkImageAreaHookResult = null; |
| 47 | + wfRunHooks( 'BitmapHandlerCheckImageArea', array( $image, &$params, &$checkImageAreaHookResult ) ); |
| 48 | + if ( is_null( $checkImageAreaHookResult ) ) { |
| 49 | + global $wgMaxImageArea; |
| 50 | + |
| 51 | + if ( $this->getImageArea( $image ) > $wgMaxImageArea && |
| 52 | + !( $image->getMimeType() == 'image/jpeg' && |
| 53 | + self::getScalerType( false, false ) == 'im' ) ) { |
| 54 | + # Only ImageMagick can efficiently downsize jpg images without loading |
| 55 | + # the entire file in memory |
| 56 | + return false; |
| 57 | + } |
| 58 | + } else { |
| 59 | + return $checkImageAreaHookResult; |
| 60 | + } |
| 61 | + |
46 | 62 | return true; |
47 | 63 | } |
48 | 64 | |
49 | | - /** |
50 | | - * Check if the file is smaller than the maximum image area for |
51 | | - * thumbnailing. Check will always pass if the scaler is 'hookaborted' or |
52 | | - * if the scaler is 'im' and the mime type is 'image/jpeg' |
53 | | - * |
54 | | - * @param File $image |
55 | | - * @param string $scaler |
56 | | - */ |
57 | | - function checkImageArea( $image, $scaler ) { |
58 | | - global $wgMaxImageArea; |
59 | | - # Don't thumbnail an image so big that it will fill hard drives and send servers into swap |
60 | | - # JPEG has the handy property of allowing thumbnailing without full decompression, so we make |
61 | | - # an exception for it. |
62 | 65 | |
63 | | - |
64 | | - if ( $image->getMimeType() == 'image/jpeg' && $scaler == 'im' ) |
65 | | - { |
66 | | - # ImageMagick can efficiently downsize jpg images without loading |
67 | | - # the entire file in memory |
68 | | - return true; |
69 | | - } |
70 | | - |
71 | | - if ( $scaler == 'hookaborted' ) |
72 | | - { |
73 | | - # If a hook wants to transform the image, it is responsible for |
74 | | - # checking the image size, so abort here |
75 | | - return true; |
76 | | - } |
77 | | - |
78 | | - # Do the actual check |
79 | | - return $this->getImageArea( $image, $image->getWidth(), $image->getHeight() ) <= $wgMaxImageArea; |
80 | | - } |
81 | | - |
82 | | - |
83 | 66 | /** |
84 | 67 | * Extracts the width/height if the image will be scaled before rotating |
85 | 68 | * |
— | — | @@ -104,10 +87,15 @@ |
105 | 88 | } |
106 | 89 | |
107 | 90 | |
108 | | - // Function that returns the number of pixels to be thumbnailed. |
109 | | - // Intended for animated GIFs to multiply by the number of frames. |
110 | | - function getImageArea( $image, $width, $height ) { |
111 | | - return $width * $height; |
| 91 | + /** |
| 92 | + * Function that returns the number of pixels to be thumbnailed. |
| 93 | + * Intended for animated GIFs to multiply by the number of frames. |
| 94 | + * |
| 95 | + * @param File $image |
| 96 | + * @return int |
| 97 | + */ |
| 98 | + function getImageArea( $image ) { |
| 99 | + return $image->getWidth() * $image->getHeight(); |
112 | 100 | } |
113 | 101 | |
114 | 102 | /** |
— | — | @@ -143,7 +131,10 @@ |
144 | 132 | 'dstUrl' => $dstUrl, |
145 | 133 | ); |
146 | 134 | |
147 | | - wfDebug( __METHOD__ . ": creating {$scalerParams['physicalDimensions']} thumbnail at $dstPath\n" ); |
| 135 | + # Determine scaler type |
| 136 | + $scaler = self::getScalerType( $dstPath ); |
| 137 | + |
| 138 | + wfDebug( __METHOD__ . ": creating {$scalerParams['physicalDimensions']} thumbnail at $dstPath using scaler $scaler\n" ); |
148 | 139 | |
149 | 140 | if ( !$image->mustRender() && |
150 | 141 | $scalerParams['physicalWidth'] == $scalerParams['srcWidth'] |
— | — | @@ -154,9 +145,6 @@ |
155 | 146 | return $this->getClientScalingThumbnailImage( $image, $scalerParams ); |
156 | 147 | } |
157 | 148 | |
158 | | - # Determine scaler type |
159 | | - $scaler = self::getScalerType( $dstPath ); |
160 | | - wfDebug( __METHOD__ . ": scaler $scaler\n" ); |
161 | 149 | |
162 | 150 | if ( $scaler == 'client' ) { |
163 | 151 | # Client-side image scaling, use the source URL |
— | — | @@ -184,12 +172,6 @@ |
185 | 173 | $scaler = 'hookaborted'; |
186 | 174 | } |
187 | 175 | |
188 | | - # Check max image area |
189 | | - if ( !$this->checkImageArea( $image, $scaler ) ) |
190 | | - { |
191 | | - return new TransformParameterError( $params ); |
192 | | - } |
193 | | - |
194 | 176 | switch ( $scaler ) { |
195 | 177 | case 'hookaborted': |
196 | 178 | # Handled by the hook above |