http://www.mediawiki.org/wiki/Special:Code/MediaWiki/97676
Revision: 97676
Author: brion
Date: 2011-09-20 22:41:58 +0000 (Tue, 20 Sep 2011)
Log Message:
-----------
Merge from REL1_18 r97675 -- exif rotation fixes
Modified Paths:
--------------
branches/wmf/1.18wmf1/includes/media/Bitmap.php
branches/wmf/1.18wmf1/includes/media/ExifBitmap.php
branches/wmf/1.18wmf1/resources/mediawiki.special/mediawiki.special.upload.js
branches/wmf/1.18wmf1/tests/phpunit/includes/media/ExifRotationTest.php
Modified: branches/wmf/1.18wmf1/includes/media/Bitmap.php
===================================================================
--- branches/wmf/1.18wmf1/includes/media/Bitmap.php 2011-09-20 22:40:32 UTC
(rev 97675)
+++ branches/wmf/1.18wmf1/includes/media/Bitmap.php 2011-09-20 22:41:58 UTC
(rev 97676)
@@ -42,20 +42,6 @@
return true;
}
}
-
-
- if ( self::canRotate() ) {
- $rotation = $this->getRotation( $image );
- if ( $rotation == 90 || $rotation == 270 ) {
- wfDebug( __METHOD__ . ": Swapping width and
height because the file will be rotated $rotation degrees\n" );
-
- list( $params['width'], $params['height'] ) =
- array( $params['height'],
$params['width'] );
- list( $params['physicalWidth'],
$params['physicalHeight'] ) =
- array( $params['physicalHeight'],
$params['physicalWidth'] );
- }
- }
-
# Don't thumbnail an image so big that it will fill hard drives
and send servers into swap
# JPEG has the handy property of allowing thumbnailing without
full decompression, so we make
@@ -73,6 +59,11 @@
/**
* Extracts the width/height if the image will be scaled before rotating
*
+ * This will match the physical size/aspect ratio of the original image
+ * prior to application of the rotation -- so for a portrait image
that's
+ * stored as raw landscape with 90-degress rotation, the resulting size
+ * will be wider than it is tall.
+ *
* @param $params array Parameters as returned by normaliseParams
* @param $rotation int The rotation angle that will be applied
* @return array ($width, $height) array
@@ -249,6 +240,8 @@
* @param $image File File associated with this thumbnail
* @param $params array Array with scaler params
* @return ThumbnailImage
+ *
+ * @fixme no rotation support
*/
protected function getClientScalingThumbnailImage( $image, $params ) {
return new ThumbnailImage( $image, $image->getURL(),
@@ -685,33 +678,21 @@
}
/**
- * Try to read out the orientation of the file and return the angle that
- * the file needs to be rotated to be viewed
+ * On supporting image formats, try to read out the low-level
orientation
+ * of the file and return the angle that the file needs to be rotated to
+ * be viewed.
*
+ * This information is only useful when manipulating the original file;
+ * the width and height we normally work with is logical, and will match
+ * any produced output views.
+ *
+ * The base BitmapHandler doesn't understand any metadata formats, so
this
+ * is left up to child classes to implement.
+ *
* @param $file File
* @return int 0, 90, 180 or 270
*/
public function getRotation( $file ) {
- $data = $file->getMetadata();
- if ( !$data ) {
- return 0;
- }
- wfSuppressWarnings();
- $data = unserialize( $data );
- wfRestoreWarnings();
- if ( isset( $data['Orientation'] ) ) {
- # See http://sylvana.net/jpegcrop/exif_orientation.html
- switch ( $data['Orientation'] ) {
- case 8:
- return 90;
- case 3:
- return 180;
- case 6:
- return 270;
- default:
- return 0;
- }
- }
return 0;
}
Modified: branches/wmf/1.18wmf1/includes/media/ExifBitmap.php
===================================================================
--- branches/wmf/1.18wmf1/includes/media/ExifBitmap.php 2011-09-20 22:40:32 UTC
(rev 97675)
+++ branches/wmf/1.18wmf1/includes/media/ExifBitmap.php 2011-09-20 22:41:58 UTC
(rev 97676)
@@ -124,5 +124,77 @@
function getMetadataType( $image ) {
return 'exif';
}
+
+ /**
+ * Wrapper for base classes ImageHandler::getImageSize() that checks for
+ * rotation reported from metadata and swaps the sizes to match.
+ *
+ * @param File $image
+ * @param string $path
+ * @return array
+ */
+ function getImageSize( $image, $path ) {
+ $gis = parent::getImageSize( $image, $path );
+
+ // Don't just call $image->getMetadata();
File::getPropsFromPath() calls us with a bogus object.
+ // This may mean we read EXIF data twice on initial upload.
+ $meta = $this->getMetadata( $image, $path );
+ $rotation = $this->getRotationForExif( $meta );
+
+ if ($rotation == 90 || $rotation == 270) {
+ $width = $gis[0];
+ $gis[0] = $gis[1];
+ $gis[1] = $width;
+ }
+ return $gis;
+ }
+
+ /**
+ * On supporting image formats, try to read out the low-level
orientation
+ * of the file and return the angle that the file needs to be rotated to
+ * be viewed.
+ *
+ * This information is only useful when manipulating the original file;
+ * the width and height we normally work with is logical, and will match
+ * any produced output views.
+ *
+ * @param $file File
+ * @return int 0, 90, 180 or 270
+ */
+ public function getRotation( $file ) {
+ $data = $file->getMetadata();
+ return $this->getRotationForExif( $data );
+ }
+
+ /**
+ * Given a chunk of serialized Exif metadata, return the orientation as
+ * degrees of rotation.
+ *
+ * @param string $data
+ * @return int 0, 90, 180 or 270
+ * @fixme orientation can include flipping as well; see if this is an
issue!
+ */
+ protected function getRotationForExif( $data ) {
+ if ( !$data ) {
+ return 0;
+ }
+ wfSuppressWarnings();
+ $data = unserialize( $data );
+ wfRestoreWarnings();
+ if ( isset( $data['Orientation'] ) ) {
+ # See http://sylvana.net/jpegcrop/exif_orientation.html
+ switch ( $data['Orientation'] ) {
+ case 8:
+ return 90;
+ case 3:
+ return 180;
+ case 6:
+ return 270;
+ default:
+ return 0;
+ }
+ }
+ return 0;
+ }
}
Modified:
branches/wmf/1.18wmf1/resources/mediawiki.special/mediawiki.special.upload.js
===================================================================
---
branches/wmf/1.18wmf1/resources/mediawiki.special/mediawiki.special.upload.js
2011-09-20 22:40:32 UTC (rev 97675)
+++
branches/wmf/1.18wmf1/resources/mediawiki.special/mediawiki.special.upload.js
2011-09-20 22:41:58 UTC (rev 97676)
@@ -83,7 +83,7 @@
}
img.onload = function() {
- var width, height, x, y, dx, dy;
+ var width, height, x, y, dx, dy, logicalWidth,
logicalHeight;
// Fit the image within the
previewSizexpreviewSize box
if ( img.width > img.height ) {
width = previewSize;
@@ -103,19 +103,27 @@
case 0:
x = dx;
y = dy;
+ logicalWidth = img.width;
+ logicalHeight = img.height;
break;
case 90:
x = dx;
y = dy - previewSize;
+ logicalWidth = img.height;
+ logicalHeight = img.width;
break;
case 180:
x = dx - previewSize;
y = dy - previewSize;
+ logicalWidth = img.width;
+ logicalHeight = img.height;
break;
case 270:
x = dx - previewSize;
y = dy;
+ logicalWidth = img.height;
+ logicalHeight = img.width;
break;
}
@@ -124,7 +132,7 @@
ctx.drawImage( img, x, y, width, height );
// Image size
- var info = mw.msg( 'widthheight', img.width,
img.height ) +
+ var info = mw.msg( 'widthheight', logicalWidth,
logicalHeight ) +
', ' + prettySize( file.size );
$( '#mw-upload-thumbnail .fileinfo' ).text(
info );
};
Modified:
branches/wmf/1.18wmf1/tests/phpunit/includes/media/ExifRotationTest.php
===================================================================
--- branches/wmf/1.18wmf1/tests/phpunit/includes/media/ExifRotationTest.php
2011-09-20 22:40:32 UTC (rev 97675)
+++ branches/wmf/1.18wmf1/tests/phpunit/includes/media/ExifRotationTest.php
2011-09-20 22:41:58 UTC (rev 97676)
@@ -9,41 +9,74 @@
parent::setUp();
$this->filePath = dirname( __FILE__ ) . '/../../data/media/';
$this->handler = new BitmapHandler();
+ $this->repo = new FSRepo(array(
+ 'name' => 'temp',
+ 'directory' => wfTempDir() . '/exif-test-' . time(),
+ 'url' => 'http://localhost/thumbtest'
+ ));
+ if ( !wfDl( 'exif' ) ) {
+ $this->markTestSkipped( "This test needs the exif
extension." );
+ }
+ global $wgShowEXIF;
+ $this->show = $wgShowEXIF;
+ $wgShowEXIF = true;
}
+ public function tearDown() {
+ global $wgShowEXIF;
+ $wgShowEXIF = $this->show;
+ }
/**
*
* @dataProvider providerFiles
*/
function testMetadata( $name, $type, $info ) {
- # Force client side resizing
- $params = array( 'width' => 10000, 'height' => 10000 );
$file = UnregisteredLocalFile::newFromPath( $this->filePath .
$name, $type );
-
- # Normalize parameters
- $this->assertTrue( $this->handler->normaliseParams( $file,
$params ) );
- $rotation = $this->handler->getRotation( $file );
-
- # Check if pre-rotation dimensions are still good
- list( $width, $height ) =
$this->handler->extractPreRotationDimensions( $params, $rotation );
- $this->assertEquals( $file->getWidth(), $width,
- "$name: pre-rotation width check, $rotation:$width" );
- $this->assertEquals( $file->getHeight(), $height,
- "$name: pre-rotation height check, $rotation" );
-
- # Any further test require a scaler that can rotate
- if ( !BitmapHandler::canRotate() ) {
- $this->markTestIncomplete( 'Scaler does not support
rotation' );
- return;
+ $this->assertEquals( $info['width'], $file->getWidth(), "$name:
width check" );
+ $this->assertEquals( $info['height'], $file->getHeight(),
"$name: height check" );
+ }
+
+ /**
+ *
+ * @dataProvider providerFiles
+ */
+ function testRotationRendering( $name, $type, $info, $thumbs ) {
+ foreach( $thumbs as $size => $out ) {
+ if( preg_match('/^(\d+)px$/', $size, $matches ) ) {
+ $params = array(
+ 'width' => $matches[1],
+ );
+ } elseif ( preg_match( '/^(\d+)x(\d+)px$/', $size,
$matches ) ) {
+ $params = array(
+ 'width' => $matches[1],
+ 'height' => $matches[2]
+ );
+ } else {
+ throw new MWException('bogus test data format '
. $size);
+ }
+
+ $file = $this->localFile( $name, $type );
+ $thumb = $file->transform( $params, File::RENDER_NOW );
+
+ $this->assertEquals( $out[0], $thumb->getWidth(),
"$name: thumb reported width check for $size" );
+ $this->assertEquals( $out[1], $thumb->getHeight(),
"$name: thumb reported height check for $size" );
+
+ $gis = getimagesize( $thumb->getPath() );
+ if ($out[0] > $info['width']) {
+ // Physical image won't be scaled bigger than
the original.
+ $this->assertEquals( $info['width'], $gis[0],
"$name: thumb actual width check for $size");
+ $this->assertEquals( $info['height'], $gis[1],
"$name: thumb actual height check for $size");
+ } else {
+ $this->assertEquals( $out[0], $gis[0], "$name:
thumb actual width check for $size");
+ $this->assertEquals( $out[1], $gis[1], "$name:
thumb actual height check for $size");
+ }
}
-
- # Check post-rotation width
- $this->assertEquals( $params['physicalWidth'], $info['width'],
- "$name: post-rotation width check" );
- $this->assertEquals( $params['physicalHeight'],
$info['height'],
- "$name: post-rotation height check" );
}
+ private function localFile( $name, $type ) {
+ return new UnregisteredLocalFile( false, $this->repo,
$this->filePath . $name, $type );
+ }
+
function providerFiles() {
return array(
array(
@@ -52,6 +85,12 @@
array(
'width' => 1024,
'height' => 768,
+ ),
+ array(
+ '800x600px' => array( 800, 600 ),
+ '9999x800px' => array( 1067, 800 ),
+ '800px' => array( 800, 600 ),
+ '600px' => array( 600, 450 ),
)
),
array(
@@ -60,6 +99,12 @@
array(
'width' => 768, // as rotated
'height' => 1024, // as rotated
+ ),
+ array(
+ '800x600px' => array( 450, 600 ),
+ '9999x800px' => array( 600, 800 ),
+ '800px' => array( 800, 1067 ),
+ '600px' => array( 600, 800 ),
)
)
);
@@ -100,22 +145,5 @@
),
);
}
-
- function testWidthFlipping() {
- $file = UnregisteredLocalFile::newFromPath( $this->filePath .
'portrait-rotated.jpg', 'image/jpeg' );
- $params = array( 'width' => '50' );
- $this->assertTrue( $this->handler->normaliseParams( $file,
$params ) );
-
- $this->assertEquals( 50, $params['height'] );
- $this->assertEquals( round( (768/1024)*50 ), $params['width'],
'', 0.1 );
- }
- function testWidthNotFlipping() {
- $file = UnregisteredLocalFile::newFromPath( $this->filePath .
'landscape-plain.jpg', 'image/jpeg' );
- $params = array( 'width' => '50' );
- $this->assertTrue( $this->handler->normaliseParams( $file,
$params ) );
-
- $this->assertEquals( 50, $params['width'] );
- $this->assertEquals( round( (768/1024)*50 ), $params['height'],
'', 0.1 );
- }
}
_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs