r92279 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r92278‎ | r92279 | r92280 >
Date:19:03, 15 July 2011
Author:btongminh
Status:resolved (Comments)
Tags:
Comment:
(bug 28762) Resizing to specified height broken for very thin images

Restructure and comment of ImageHandler::normaliseParams(). ImageHandler::normaliseParams() will now output both width/height as physicalWidth/Height, where width/height are the dimensions used by the browser, and physicalWidth/Height are the dimensions of the thumbnail that will be created. This allows keeping the use of unique dimensions for a specified thumbnail width, by forcing client side resizing of 1px-wide images with non corresponding height.
Also fixed a bug where the check for mustRender() was in an if statement where it should not have been.
Modified paths:
  • /trunk/phase3/includes/media/Bitmap.php (modified) (history)
  • /trunk/phase3/includes/media/DjVu.php (modified) (history)
  • /trunk/phase3/includes/media/Generic.php (modified) (history)
  • /trunk/phase3/includes/media/SVG.php (modified) (history)
  • /trunk/phase3/tests/phpunit/includes/media/BitmapScalingTest.php (added) (history)

Diff [purge]

Index: trunk/phase3/tests/phpunit/includes/media/BitmapScalingTest.php
@@ -0,0 +1,96 @@
 2+<?php
 3+
 4+class BitmapScalingTest extends MediaWikiTestCase {
 5+ /**
 6+ * @dataProvider provideNormaliseParams
 7+ */
 8+ function testNormaliseParams( $fileDimensions, $expectedParams, $params, $msg ) {
 9+ $file = new FakeDimensionFile( $fileDimensions );
 10+ $handler = new BitmapHandler;
 11+ $handler->normaliseParams( $file, $params );
 12+ $this->assertEquals( $expectedParams, $params, $msg );
 13+ }
 14+
 15+ function provideNormaliseParams() {
 16+ return array(
 17+ /* Regular resize operations */
 18+ array(
 19+ array( 1024, 768 ),
 20+ array(
 21+ 'width' => 512, 'height' => 384,
 22+ 'physicalWidth' => 512, 'physicalHeight' => 384,
 23+ 'page' => 1,
 24+ ),
 25+ array( 'width' => 512 ),
 26+ 'Resizing with width set',
 27+ ),
 28+ array(
 29+ array( 1024, 768 ),
 30+ array(
 31+ 'width' => 512, 'height' => 384,
 32+ 'physicalWidth' => 512, 'physicalHeight' => 384,
 33+ 'page' => 1,
 34+ ),
 35+ array( 'width' => 512, 'height' => 768 ),
 36+ 'Resizing with height set too high',
 37+ ),
 38+ array(
 39+ array( 1024, 768 ),
 40+ array(
 41+ 'width' => 512, 'height' => 384,
 42+ 'physicalWidth' => 512, 'physicalHeight' => 384,
 43+ 'page' => 1,
 44+ ),
 45+ array( 'width' => 1024, 'height' => 384 ),
 46+ 'Resizing with height set',
 47+ ),
 48+
 49+ /* Very tall images */
 50+ array(
 51+ array( 1000, 100 ),
 52+ array(
 53+ 'width' => 5, 'height' => 1,
 54+ 'physicalWidth' => 5, 'physicalHeight' => 1,
 55+ 'page' => 1,
 56+ ),
 57+ array( 'width' => 5 ),
 58+ 'Very wide image',
 59+ ),
 60+
 61+ array(
 62+ array( 100, 1000 ),
 63+ array(
 64+ 'width' => 1, 'height' => 10,
 65+ 'physicalWidth' => 1, 'physicalHeight' => 10,
 66+ 'page' => 1,
 67+ ),
 68+ array( 'width' => 1 ),
 69+ 'Very high image',
 70+ ),
 71+ array(
 72+ array( 100, 1000 ),
 73+ array(
 74+ 'width' => 1, 'height' => 5,
 75+ 'physicalWidth' => 1, 'physicalHeight' => 10,
 76+ 'page' => 1,
 77+ ),
 78+ array( 'width' => 10, 'height' => 5 ),
 79+ 'Very high image with height set',
 80+ ),
 81+ );
 82+ }
 83+}
 84+
 85+class FakeDimensionFile extends File {
 86+ public function __construct( $dimensions ) {
 87+ parent::__construct( Title::makeTitle( NS_FILE, 'Test' ), null );
 88+
 89+ $this->dimensions = $dimensions;
 90+ }
 91+ public function getWidth( $page = 1 ) {
 92+ return $this->dimensions[0];
 93+ }
 94+ public function getHeight( $page = 1 ) {
 95+ return $this->dimensions[1];
 96+ }
 97+}
\ No newline at end of file
Property changes on: trunk/phase3/tests/phpunit/includes/media/BitmapScalingTest.php
___________________________________________________________________
Added: svn:eol-style
198 + native
Index: trunk/phase3/includes/media/SVG.php
@@ -59,8 +59,6 @@
6060 return false;
6161 }
6262 # Don't make an image bigger than wgMaxSVGSize
63 - $params['physicalWidth'] = $params['width'];
64 - $params['physicalHeight'] = $params['height'];
6563 if ( $params['physicalWidth'] > $wgSVGMaxSize ) {
6664 $srcWidth = $image->getWidth( $params['page'] );
6765 $srcHeight = $image->getHeight( $params['page'] );
Index: trunk/phase3/includes/media/DjVu.php
@@ -147,7 +147,8 @@
148148
149149 # Use a subshell (brackets) to aggregate stderr from both pipeline commands
150150 # before redirecting it to the overall stdout. This works in both Linux and Windows XP.
151 - $cmd = '(' . wfEscapeShellArg( $wgDjvuRenderer ) . " -format=ppm -page={$page} -size={$width}x{$height} " .
 151+ $cmd = '(' . wfEscapeShellArg( $wgDjvuRenderer ) . " -format=ppm -page={$page}" .
 152+ " -size={$params['physicalWidth']}x{$params['physicalHeight']} " .
152153 wfEscapeShellArg( $srcPath );
153154 if ( $wgDjvuPostProcessor ) {
154155 $cmd .= " | {$wgDjvuPostProcessor}";
Index: trunk/phase3/includes/media/Bitmap.php
@@ -35,16 +35,14 @@
3636 wfDebug( __METHOD__ . ": Swapping width and height because the file will be rotated $rotation degrees\n" );
3737
3838 $swapDimensions = true;
39 - $width = $params['width'];
40 - $params['width'] = $params['height'];
41 - $params['height'] = $width;
 39+ list( $params['width'], $params['height'] ) =
 40+ array( $params['width'], $params['height'] );
 41+ list( $params['physicalWidth'], $params['physicalHeight'] ) =
 42+ array( $params['physicalWidth'], $params['physicalHeight'] );
4243 }
4344 }
4445
4546 # Don't make an image bigger than the source
46 - $params['physicalWidth'] = $params['width'];
47 - $params['physicalHeight'] = $params['height'];
48 -
4947 if ( $params['physicalWidth'] >= $srcWidth ) {
5048 if ( $swapDimensions ) {
5149 $params['physicalWidth'] = $srcHeight;
@@ -53,10 +51,11 @@
5452 $params['physicalWidth'] = $srcWidth;
5553 $params['physicalHeight'] = $srcHeight;
5654 }
57 - # Skip scaling limit checks if no scaling is required
58 - if ( !$image->mustRender() )
59 - return true;
6055 }
 56+
 57+ # Skip scaling limit checks if no scaling is required
 58+ if ( !$image->mustRender() )
 59+ return true;
6160
6261 # Don't thumbnail an image so big that it will fill hard drives and send servers into swap
6362 # JPEG has the handy property of allowing thumbnailing without full decompression, so we make
Index: trunk/phase3/includes/media/Generic.php
@@ -570,13 +570,44 @@
571571
572572 $srcWidth = $image->getWidth( $params['page'] );
573573 $srcHeight = $image->getHeight( $params['page'] );
 574+
574575 if ( isset( $params['height'] ) && $params['height'] != -1 ) {
 576+ # Height & width were both set
575577 if ( $params['width'] * $srcHeight > $params['height'] * $srcWidth ) {
 578+ # Height is the relative smaller dimension, so scale width accordingly
576579 $params['width'] = wfFitBoxWidth( $srcWidth, $srcHeight, $params['height'] );
 580+
 581+ if ( $params['width'] == 0 ) {
 582+ # Very small image, so we need to rely on client side scaling :(
 583+ $params['width'] = 1;
 584+ }
 585+
 586+ $params['physicalWidth'] = $params['width'];
 587+ } else {
 588+ # Height was crap, unset it so that it will be calculated later
 589+ unset( $params['height'] );
577590 }
578591 }
579 - $params['height'] = File::scaleHeight( $srcWidth, $srcHeight, $params['width'] );
580 - if ( !$this->validateThumbParams( $params['width'], $params['height'], $srcWidth, $srcHeight, $mimeType ) ) {
 592+
 593+ if ( !isset( $params['physicalWidth'] ) ) {
 594+ # Passed all validations, so set the physicalWidth
 595+ $params['physicalWidth'] = $params['width'];
 596+ }
 597+
 598+ # Because thumbs are only referred to by width, the height always needs
 599+ # to be scaled by the width to keep the thumbnail sizes consistent,
 600+ # even if it was set inside the if block above
 601+ $params['physicalHeight'] = File::scaleHeight( $srcWidth, $srcHeight,
 602+ $params['physicalWidth'] );
 603+
 604+ # Set the height if it was not validated in the if block higher up
 605+ if ( !isset( $params['height'] ) || $params['height'] == -1 ) {
 606+ $params['height'] = $params['physicalHeight'];
 607+ }
 608+
 609+
 610+ if ( !$this->validateThumbParams( $params['physicalWidth'],
 611+ $params['physicalHeight'], $srcWidth, $srcHeight, $mimeType ) ) {
581612 return false;
582613 }
583614 return true;
@@ -613,6 +644,10 @@
614645 }
615646
616647 $height = File::scaleHeight( $srcWidth, $srcHeight, $width );
 648+ if ( $height == 0 ) {
 649+ # Force height to be at least 1 pixel
 650+ $height = 1;
 651+ }
617652 return true;
618653 }
619654

Follow-up revisions

RevisionCommit summaryAuthorDate
r92282RELEASE-NOTES for r92279btongminh19:11, 15 July 2011
r96687(bug 30640; follow-up r92279) Rotating images was making skewed images...bawolff20:13, 9 September 2011
r97671* (bug 6672, 31024) Fixes for handling of images with an EXIF orientation...brion22:13, 20 September 2011

Comments

#Comment by Aaron Schulz (talk | contribs)   20:28, 7 September 2011
				$swapDimensions = true;
+				list( $params['width'], $params['height'] ) = 
+					array(  $params['width'], $params['height'] );
+				list( $params['physicalWidth'], $params['physicalHeight'] ) = 
+					array( $params['physicalWidth'], $params['physicalHeight'] );

What does this do?

#Comment by Bryan (talk | contribs)   21:38, 7 September 2011

That's definitely wrong, see bug 30640. This bug also has a patch, but I think there should be proper unit tests as well.

#Comment by Bawolff (talk | contribs)   21:05, 8 September 2011
+		# Because thumbs are only referred to by width, the height always needs
+		# to be scaled by the width to keep the thumbnail sizes consistent,
+		# even if it was set inside the if block above
+		$params['physicalHeight'] = File::scaleHeight( $srcWidth, $srcHeight, 
+			$params['physicalWidth'] );

Isn't the exact same thing done as a side effect of validateThumbParams a couple lines down?

-			# Skip scaling limit checks if no scaling is required
-			if ( !$image->mustRender() )
-				return true;
 		}
+		
+		# Skip scaling limit checks if no scaling is required
+		if ( !$image->mustRender() )
+			return true;	

I think this was correct before. We only want to skip the scaling checks if we don't have to render the image, thus we should return true only if we don't have to downscale image and rendering the image isn't required. (Otherwise people could request way too big png thumbnails for example)

#Comment by Bryan (talk | contribs)   19:02, 21 September 2011

You're right. Don't know what I was thinking.

#Comment by Bawolff (talk | contribs)   13:06, 22 September 2011

If you're marking this fixme on account of the mustRender check move, that has already been fixed by a follow-up.

#Comment by Bryan (talk | contribs)   13:13, 22 September 2011

Oops

Status & tagging log