summaryrefslogtreecommitdiff
path: root/includes/media
diff options
context:
space:
mode:
Diffstat (limited to 'includes/media')
-rw-r--r--includes/media/BMP.php2
-rw-r--r--includes/media/Bitmap.php14
-rw-r--r--includes/media/BitmapMetadataHandler.php2
-rw-r--r--includes/media/DjVu.php5
-rw-r--r--includes/media/DjVuImage.php16
-rw-r--r--includes/media/Exif.php2
-rw-r--r--includes/media/ExifBitmap.php5
-rw-r--r--includes/media/FormatMetadata.php98
-rw-r--r--includes/media/GIF.php5
-rw-r--r--includes/media/GIFMetadataExtractor.php2
-rw-r--r--includes/media/IPTC.php2
-rw-r--r--includes/media/ImageHandler.php6
-rw-r--r--includes/media/Jpeg.php4
-rw-r--r--includes/media/JpegMetadataExtractor.php4
-rw-r--r--includes/media/MediaHandler.php34
-rw-r--r--includes/media/MediaTransformInvalidParametersException.php26
-rw-r--r--includes/media/MediaTransformOutput.php40
-rw-r--r--includes/media/PNG.php10
-rw-r--r--includes/media/SVG.php9
-rw-r--r--includes/media/SVGMetadataExtractor.php20
-rw-r--r--includes/media/Tiff.php2
-rw-r--r--includes/media/TransformationalImageHandler.php75
-rw-r--r--includes/media/XCF.php2
-rw-r--r--includes/media/XMP.php13
-rw-r--r--includes/media/XMPInfo.php2
25 files changed, 262 insertions, 138 deletions
diff --git a/includes/media/BMP.php b/includes/media/BMP.php
index d8b0ba64..52f9518f 100644
--- a/includes/media/BMP.php
+++ b/includes/media/BMP.php
@@ -71,7 +71,7 @@ class BmpHandler extends BitmapHandler {
try {
$w = wfUnpack( 'V', $w, 4 );
$h = wfUnpack( 'V', $h, 4 );
- } catch ( MWException $e ) {
+ } catch ( Exception $e ) {
return false;
}
diff --git a/includes/media/Bitmap.php b/includes/media/Bitmap.php
index e81b37de..eadcf94b 100644
--- a/includes/media/Bitmap.php
+++ b/includes/media/Bitmap.php
@@ -142,7 +142,7 @@ class BitmapHandler extends TransformationalImageHandler {
$env['MAGICK_TMPDIR'] = $wgImageMagickTempDir;
}
- $rotation = $this->getRotation( $image );
+ $rotation = isset( $params['disableRotation'] ) ? 0 : $this->getRotation( $image );
list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
$cmd = call_user_func_array( 'wfEscapeShellArg', array_merge(
@@ -169,10 +169,8 @@ class BitmapHandler extends TransformationalImageHandler {
array( $this->escapeMagickOutput( $params['dstPath'] ) ) ) );
wfDebug( __METHOD__ . ": running ImageMagick: $cmd\n" );
- wfProfileIn( 'convert' );
$retval = 0;
$err = wfShellExecWithStderr( $cmd, $retval, $env );
- wfProfileOut( 'convert' );
if ( $retval !== 0 ) {
$this->logErrorForExternalProcess( $retval, $err, $cmd );
@@ -204,7 +202,7 @@ class BitmapHandler extends TransformationalImageHandler {
/ ( $params['srcWidth'] + $params['srcHeight'] )
< $wgSharpenReductionThreshold
) {
- // Hack, since $wgSharpenParamater is written specifically for the command line convert
+ // Hack, since $wgSharpenParameter is written specifically for the command line convert
list( $radius, $sigma ) = explode( 'x', $wgSharpenParameter );
$im->sharpenImage( $radius, $sigma );
}
@@ -223,7 +221,7 @@ class BitmapHandler extends TransformationalImageHandler {
}
}
- $rotation = $this->getRotation( $image );
+ $rotation = isset( $params['disableRotation'] ) ? 0 : $this->getRotation( $image );
list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
$im->setImageBackgroundColor( new ImagickPixel( 'white' ) );
@@ -280,10 +278,8 @@ class BitmapHandler extends TransformationalImageHandler {
$cmd = str_replace( '%h', wfEscapeShellArg( $params['physicalHeight'] ),
str_replace( '%w', wfEscapeShellArg( $params['physicalWidth'] ), $cmd ) ); # Size
wfDebug( __METHOD__ . ": Running custom convert command $cmd\n" );
- wfProfileIn( 'convert' );
$retval = 0;
$err = wfShellExecWithStderr( $cmd, $retval );
- wfProfileOut( 'convert' );
if ( $retval !== 0 ) {
$this->logErrorForExternalProcess( $retval, $err, $cmd );
@@ -344,7 +340,7 @@ class BitmapHandler extends TransformationalImageHandler {
$src_image = call_user_func( $loader, $params['srcPath'] );
- $rotation = function_exists( 'imagerotate' ) ? $this->getRotation( $image ) : 0;
+ $rotation = function_exists( 'imagerotate' ) && !isset( $params['disableRotation'] ) ? $this->getRotation( $image ) : 0;
list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
$dst_image = imagecreatetruecolor( $width, $height );
@@ -457,10 +453,8 @@ class BitmapHandler extends TransformationalImageHandler {
" -rotate " . wfEscapeShellArg( "-$rotation" ) . " " .
wfEscapeShellArg( $this->escapeMagickOutput( $params['dstPath'] ) );
wfDebug( __METHOD__ . ": running ImageMagick: $cmd\n" );
- wfProfileIn( 'convert' );
$retval = 0;
$err = wfShellExecWithStderr( $cmd, $retval );
- wfProfileOut( 'convert' );
if ( $retval !== 0 ) {
$this->logErrorForExternalProcess( $retval, $err, $cmd );
diff --git a/includes/media/BitmapMetadataHandler.php b/includes/media/BitmapMetadataHandler.php
index 1d790155..c8d37bbb 100644
--- a/includes/media/BitmapMetadataHandler.php
+++ b/includes/media/BitmapMetadataHandler.php
@@ -61,7 +61,7 @@ class BitmapMetadataHandler {
private function doApp13( $app13 ) {
try {
$this->iptcType = JpegMetadataExtractor::doPSIR( $app13 );
- } catch ( MWException $e ) {
+ } catch ( Exception $e ) {
// Error reading the iptc hash information.
// This probably means the App13 segment is something other than what we expect.
// However, still try to read it, and treat it as if the hash didn't exist.
diff --git a/includes/media/DjVu.php b/includes/media/DjVu.php
index daeb475f..1b0eb492 100644
--- a/includes/media/DjVu.php
+++ b/includes/media/DjVu.php
@@ -221,11 +221,9 @@ class DjVuHandler extends ImageHandler {
$cmd .= " | {$wgDjvuPostProcessor}";
}
$cmd .= ' > ' . wfEscapeShellArg( $dstPath ) . ') 2>&1';
- wfProfileIn( 'ddjvu' );
wfDebug( __METHOD__ . ": $cmd\n" );
$retval = '';
$err = wfShellExec( $cmd, $retval );
- wfProfileOut( 'ddjvu' );
$removed = $this->removeBadFile( $dstPath, $retval );
if ( $retval != 0 || $removed ) {
@@ -266,6 +264,7 @@ class DjVuHandler extends ImageHandler {
*
* @param File $file The DjVu file in question
* @return string XML metadata as a string.
+ * @throws MWException
*/
private function getUnserializedMetadata( File $file ) {
$metadata = $file->getMetadata();
@@ -312,7 +311,6 @@ class DjVuHandler extends ImageHandler {
return false;
}
- wfProfileIn( __METHOD__ );
wfSuppressWarnings();
try {
@@ -338,7 +336,6 @@ class DjVuHandler extends ImageHandler {
wfDebug( "Bogus multipage XML metadata on '{$image->getName()}'\n" );
}
wfRestoreWarnings();
- wfProfileOut( __METHOD__ );
if ( $gettext ) {
return $image->djvuTextTree;
} else {
diff --git a/includes/media/DjVuImage.php b/includes/media/DjVuImage.php
index 6ff19c90..e8faa70a 100644
--- a/includes/media/DjVuImage.php
+++ b/includes/media/DjVuImage.php
@@ -265,37 +265,34 @@ class DjVuImage {
/**
* Return an XML string describing the DjVu image
- * @return string
+ * @return string|bool
*/
function retrieveMetaData() {
global $wgDjvuToXML, $wgDjvuDump, $wgDjvuTxt;
- wfProfileIn( __METHOD__ );
+
+ if ( !$this->isValid() ) {
+ return false;
+ }
if ( isset( $wgDjvuDump ) ) {
# djvudump is faster as of version 3.5
# http://sourceforge.net/tracker/index.php?func=detail&aid=1704049&group_id=32953&atid=406583
- wfProfileIn( 'djvudump' );
$cmd = wfEscapeShellArg( $wgDjvuDump ) . ' ' . wfEscapeShellArg( $this->mFilename );
$dump = wfShellExec( $cmd );
$xml = $this->convertDumpToXML( $dump );
- wfProfileOut( 'djvudump' );
} elseif ( isset( $wgDjvuToXML ) ) {
- wfProfileIn( 'djvutoxml' );
$cmd = wfEscapeShellArg( $wgDjvuToXML ) . ' --without-anno --without-text ' .
wfEscapeShellArg( $this->mFilename );
$xml = wfShellExec( $cmd );
- wfProfileOut( 'djvutoxml' );
} else {
$xml = null;
}
# Text layer
if ( isset( $wgDjvuTxt ) ) {
- wfProfileIn( 'djvutxt' );
$cmd = wfEscapeShellArg( $wgDjvuTxt ) . ' --detail=page ' . wfEscapeShellArg( $this->mFilename );
wfDebug( __METHOD__ . ": $cmd\n" );
$retval = '';
$txt = wfShellExec( $cmd, $retval, array(), array( 'memory' => self::DJVUTXT_MEMORY_LIMIT ) );
- wfProfileOut( 'djvutxt' );
if ( $retval == 0 ) {
# Strip some control characters
$txt = preg_replace( "/[\013\035\037]/", "", $txt );
@@ -316,14 +313,13 @@ EOR;
$xml = $xml . $txt . '</mw-djvu>';
}
}
- wfProfileOut( __METHOD__ );
return $xml;
}
function pageTextCallback( $matches ) {
# Get rid of invalid UTF-8, strip control characters
- $val = htmlspecialchars( UtfNormal::cleanUp( stripcslashes( $matches[1] ) ) );
+ $val = htmlspecialchars( UtfNormal\Validator::cleanUp( stripcslashes( $matches[1] ) ) );
$val = str_replace( array( "\n", '�' ), array( '&#10;', '' ), $val );
return '<PAGE value="' . $val . '" />';
}
diff --git a/includes/media/Exif.php b/includes/media/Exif.php
index 018b58c5..33868689 100644
--- a/includes/media/Exif.php
+++ b/includes/media/Exif.php
@@ -477,7 +477,7 @@ class Exif {
} else {
// if valid utf-8, assume that, otherwise assume windows-1252
$valCopy = $val;
- UtfNormal::quickIsNFCVerify( $valCopy ); //validates $valCopy.
+ UtfNormal\Validator::quickIsNFCVerify( $valCopy ); //validates $valCopy.
if ( $valCopy !== $val ) {
wfSuppressWarnings();
$val = iconv( 'Windows-1252', 'UTF-8//IGNORE', $val );
diff --git a/includes/media/ExifBitmap.php b/includes/media/ExifBitmap.php
index b7657cb3..f56a947f 100644
--- a/includes/media/ExifBitmap.php
+++ b/includes/media/ExifBitmap.php
@@ -125,15 +125,16 @@ class ExifBitmapHandler extends BitmapHandler {
/**
* @param File $image
+ * @param bool|IContextSource $context Context to use (optional)
* @return array|bool
*/
- function formatMetadata( $image ) {
+ function formatMetadata( $image, $context = false ) {
$meta = $this->getCommonMetaArray( $image );
if ( count( $meta ) === 0 ) {
return false;
}
- return $this->formatMetadataHelper( $meta );
+ return $this->formatMetadataHelper( $meta, $context );
}
public function getCommonMetaArray( File $file ) {
diff --git a/includes/media/FormatMetadata.php b/includes/media/FormatMetadata.php
index 43569539..501bb9c2 100644
--- a/includes/media/FormatMetadata.php
+++ b/includes/media/FormatMetadata.php
@@ -1595,11 +1595,8 @@ class FormatMetadata extends ContextSource {
public function fetchExtendedMetadata( File $file ) {
global $wgMemc;
- wfProfileIn( __METHOD__ );
-
// If revision deleted, exit immediately
if ( $file->isDeleted( File::DELETED_FILE ) ) {
- wfProfileOut( __METHOD__ );
return array();
}
@@ -1614,7 +1611,7 @@ class FormatMetadata extends ContextSource {
$cachedValue = $wgMemc->get( $cacheKey );
if (
$cachedValue
- && wfRunHooks( 'ValidateExtendedMetadataCache', array( $cachedValue['timestamp'], $file ) )
+ && Hooks::run( 'ValidateExtendedMetadataCache', array( $cachedValue['timestamp'], $file ) )
) {
$extendedMetadata = $cachedValue['data'];
} else {
@@ -1624,17 +1621,16 @@ class FormatMetadata extends ContextSource {
if ( $this->singleLang ) {
$this->resolveMultilangMetadata( $extendedMetadata );
}
+ $this->discardMultipleValues( $extendedMetadata );
// Make sure the metadata won't break the API when an XML format is used.
// This is an API-specific function so it would be cleaner to call it from
// outside fetchExtendedMetadata, but this way we don't need to redo the
// computation on a cache hit.
- $this->sanitizeArrayForXml( $extendedMetadata );
+ $this->sanitizeArrayForAPI( $extendedMetadata );
$valueToCache = array( 'data' => $extendedMetadata, 'timestamp' => wfTimestampNow() );
$wgMemc->set( $cacheKey, $valueToCache, $maxCacheTime );
}
- wfProfileOut( __METHOD__ );
-
return $extendedMetadata;
}
@@ -1656,8 +1652,6 @@ class FormatMetadata extends ContextSource {
return $file->getExtendedMetadata() ?: array();
}
- wfProfileIn( __METHOD__ );
-
$uploadDate = wfTimestamp( TS_ISO_8601, $file->getTimestamp() );
$fileMetadata = array(
@@ -1685,19 +1679,6 @@ class FormatMetadata extends ContextSource {
);
}
- $common = $file->getCommonMetaArray();
-
- if ( $common !== false ) {
- foreach ( $common as $key => $value ) {
- $fileMetadata[$key] = array(
- 'value' => $value,
- 'source' => 'file-metadata',
- );
- }
- }
-
- wfProfileOut( __METHOD__ );
-
return $fileMetadata;
}
@@ -1714,9 +1695,8 @@ class FormatMetadata extends ContextSource {
protected function getExtendedMetadataFromHook( File $file, array $extendedMetadata,
&$maxCacheTime
) {
- wfProfileIn( __METHOD__ );
- wfRunHooks( 'GetExtendedMetadata', array(
+ Hooks::run( 'GetExtendedMetadata', array(
&$extendedMetadata,
$file,
$this->getContext(),
@@ -1731,8 +1711,6 @@ class FormatMetadata extends ContextSource {
}
}
- wfProfileOut( __METHOD__ );
-
return $extendedMetadata;
}
@@ -1777,6 +1755,32 @@ class FormatMetadata extends ContextSource {
}
/**
+ * Turns an XMP-style multivalue array into a single value by dropping all but the first value.
+ * If the value is not a multivalue array (or a multivalue array inside a multilang array), it is returned unchanged.
+ * See mediawiki.org/wiki/Manual:File_metadata_handling#Multi-language_array_format
+ * @param mixed $value
+ * @return mixed The value, or the first value if there were multiple ones
+ * @since 1.25
+ */
+ protected function resolveMultivalueValue( $value ) {
+ if ( !is_array( $value ) ) {
+ return $value;
+ } elseif ( isset( $value['_type'] ) && $value['_type'] === 'lang' ) { // if this is a multilang array, process fields separately
+ $newValue = array();
+ foreach ( $value as $k => $v ) {
+ $newValue[$k] = $this->resolveMultivalueValue( $v );
+ }
+ return $newValue;
+ } else { // _type is 'ul' or 'ol' or missing in which case it defaults to 'ul'
+ list( $k, $v ) = each( $value );
+ if ( $k === '_type' ) {
+ $v = current( $value );
+ }
+ return $v;
+ }
+ }
+
+ /**
* Takes an array returned by the getExtendedMetadata* functions,
* and resolves multi-language values in it.
* @param array $metadata
@@ -1794,18 +1798,40 @@ class FormatMetadata extends ContextSource {
}
/**
+ * Takes an array returned by the getExtendedMetadata* functions,
+ * and turns all fields into single-valued ones by dropping extra values.
+ * @param array $metadata
+ * @since 1.25
+ */
+ protected function discardMultipleValues( &$metadata ) {
+ if ( !is_array( $metadata ) ) {
+ return;
+ }
+ foreach ( $metadata as $key => &$field ) {
+ if ( $key === 'Software' || $key === 'Contact' ) {
+ // we skip some fields which have composite values. They are not particularly interesting
+ // and you can get them via the metadata / commonmetadata APIs anyway.
+ continue;
+ }
+ if ( isset( $field['value'] ) ) {
+ $field['value'] = $this->resolveMultivalueValue( $field['value'] );
+ }
+ }
+
+ }
+
+ /**
* Makes sure the given array is a valid API response fragment
- * (can be transformed into XML)
* @param array $arr
*/
- protected function sanitizeArrayForXml( &$arr ) {
+ protected function sanitizeArrayForAPI( &$arr ) {
if ( !is_array( $arr ) ) {
return;
}
$counter = 1;
foreach ( $arr as $key => &$value ) {
- $sanitizedKey = $this->sanitizeKeyForXml( $key );
+ $sanitizedKey = $this->sanitizeKeyForAPI( $key );
if ( $sanitizedKey !== $key ) {
if ( isset( $arr[$sanitizedKey] ) ) {
// Make the sanitized keys hopefully unique.
@@ -1819,20 +1845,24 @@ class FormatMetadata extends ContextSource {
unset( $arr[$key] );
}
if ( is_array( $value ) ) {
- $this->sanitizeArrayForXml( $value );
+ $this->sanitizeArrayForAPI( $value );
}
}
+
+ // Handle API metadata keys (particularly "_type")
+ $keys = array_filter( array_keys( $arr ), 'ApiResult::isMetadataKey' );
+ if ( $keys ) {
+ ApiResult::setPreserveKeysList( $arr, $keys );
+ }
}
/**
- * Turns a string into a valid XML identifier.
- * Used to ensure that keys of an associative array in the
- * API response do not break the XML formatter.
+ * Turns a string into a valid API identifier.
* @param string $key
* @return string
* @since 1.23
*/
- protected function sanitizeKeyForXml( $key ) {
+ protected function sanitizeKeyForAPI( $key ) {
// drop all characters which are not valid in an XML tag name
// a bunch of non-ASCII letters would be valid but probably won't
// be used so we take the easy way
diff --git a/includes/media/GIF.php b/includes/media/GIF.php
index 5992be11..e3621fbd 100644
--- a/includes/media/GIF.php
+++ b/includes/media/GIF.php
@@ -44,15 +44,16 @@ class GIFHandler extends BitmapHandler {
/**
* @param File $image
+ * @param bool|IContextSource $context Context to use (optional)
* @return array|bool
*/
- function formatMetadata( $image ) {
+ function formatMetadata( $image, $context = false ) {
$meta = $this->getCommonMetaArray( $image );
if ( count( $meta ) === 0 ) {
return false;
}
- return $this->formatMetadataHelper( $meta );
+ return $this->formatMetadataHelper( $meta, $context );
}
/**
diff --git a/includes/media/GIFMetadataExtractor.php b/includes/media/GIFMetadataExtractor.php
index 178b0bf7..5c370465 100644
--- a/includes/media/GIFMetadataExtractor.php
+++ b/includes/media/GIFMetadataExtractor.php
@@ -158,7 +158,7 @@ class GIFMetadataExtractor {
// assume its that, otherwise assume its windows-1252 (iso-8859-1)
$dataCopy = $data;
// quickIsNFCVerify has the side effect of replacing any invalid characters
- UtfNormal::quickIsNFCVerify( $dataCopy );
+ UtfNormal\Validator::quickIsNFCVerify( $dataCopy );
if ( $dataCopy !== $data ) {
wfSuppressWarnings();
diff --git a/includes/media/IPTC.php b/includes/media/IPTC.php
index 478249fe..0eb27cc8 100644
--- a/includes/media/IPTC.php
+++ b/includes/media/IPTC.php
@@ -456,7 +456,7 @@ class IPTC {
//treat as utf-8 if is valid utf-8. otherwise pretend its windows-1252
// most of the time if there is no 1:90 tag, it is either ascii, latin1, or utf-8
$oldData = $data;
- UtfNormal::quickIsNFCVerify( $data ); //make $data valid utf-8
+ UtfNormal\Validator::quickIsNFCVerify( $data ); //make $data valid utf-8
if ( $data === $oldData ) {
return $data; //if validation didn't change $data
} else {
diff --git a/includes/media/ImageHandler.php b/includes/media/ImageHandler.php
index 6dd0453e..968e4243 100644
--- a/includes/media/ImageHandler.php
+++ b/includes/media/ImageHandler.php
@@ -57,7 +57,7 @@ abstract class ImageHandler extends MediaHandler {
} elseif ( isset( $params['width'] ) ) {
$width = $params['width'];
} else {
- throw new MWException( 'No width specified to ' . __METHOD__ );
+ throw new MediaTransformInvalidParametersException( 'No width specified to ' . __METHOD__ );
}
# Removed for ProofreadPage
@@ -245,11 +245,11 @@ abstract class ImageHandler extends MediaHandler {
if ( $pages === false || $pages <= 1 ) {
$msg = wfMessage( 'file-info-size' )->numParams( $file->getWidth(),
$file->getHeight() )->params( $size,
- $file->getMimeType() )->parse();
+ '<span class="mime-type">' . $file->getMimeType() . '</span>' )->parse();
} else {
$msg = wfMessage( 'file-info-size-pages' )->numParams( $file->getWidth(),
$file->getHeight() )->params( $size,
- $file->getMimeType() )->numParams( $pages )->parse();
+ '<span class="mime-type">' . $file->getMimeType() . '</span>' )->numParams( $pages )->parse();
}
return $msg;
diff --git a/includes/media/Jpeg.php b/includes/media/Jpeg.php
index fbdbdfe3..5463922b 100644
--- a/includes/media/Jpeg.php
+++ b/includes/media/Jpeg.php
@@ -106,7 +106,7 @@ class JpegHandler extends ExifBitmapHandler {
$meta['MEDIAWIKI_EXIF_VERSION'] = Exif::version();
return serialize( $meta );
- } catch ( MWException $e ) {
+ } catch ( Exception $e ) {
// BitmapMetadataHandler throws an exception in certain exceptional
// cases like if file does not exist.
wfDebug( __METHOD__ . ': ' . $e->getMessage() . "\n" );
@@ -143,10 +143,8 @@ class JpegHandler extends ExifBitmapHandler {
" -outfile " . wfEscapeShellArg( $params['dstPath'] ) .
" " . wfEscapeShellArg( $params['srcPath'] );
wfDebug( __METHOD__ . ": running jpgtran: $cmd\n" );
- wfProfileIn( 'jpegtran' );
$retval = 0;
$err = wfShellExecWithStderr( $cmd, $retval );
- wfProfileOut( 'jpegtran' );
if ( $retval !== 0 ) {
$this->logErrorForExternalProcess( $retval, $err, $cmd );
diff --git a/includes/media/JpegMetadataExtractor.php b/includes/media/JpegMetadataExtractor.php
index aaa9930a..ae4af8d1 100644
--- a/includes/media/JpegMetadataExtractor.php
+++ b/includes/media/JpegMetadataExtractor.php
@@ -98,7 +98,7 @@ class JpegMetadataExtractor {
// First see if valid utf-8,
// if not try to convert it to windows-1252.
$com = $oldCom = trim( self::jpegExtractMarker( $fh ) );
- UtfNormal::quickIsNFCVerify( $com );
+ UtfNormal\Validator::quickIsNFCVerify( $com );
// turns $com to valid utf-8.
// thus if no change, its utf-8, otherwise its something else.
if ( $com !== $oldCom ) {
@@ -108,7 +108,7 @@ class JpegMetadataExtractor {
}
// Try it again, if its still not a valid string, then probably
// binary junk or some really weird encoding, so don't extract.
- UtfNormal::quickIsNFCVerify( $com );
+ UtfNormal\Validator::quickIsNFCVerify( $com );
if ( $com === $oldCom ) {
$segments["COM"][] = $oldCom;
} else {
diff --git a/includes/media/MediaHandler.php b/includes/media/MediaHandler.php
index 64ca0115..33aed34f 100644
--- a/includes/media/MediaHandler.php
+++ b/includes/media/MediaHandler.php
@@ -162,7 +162,7 @@ abstract class MediaHandler {
*/
static function getMetadataVersion() {
$version = array( '2' ); // core metadata version
- wfRunHooks( 'GetMetadataVersion', array( &$version ) );
+ Hooks::run( 'GetMetadataVersion', array( &$version ) );
return implode( ';', $version );
}
@@ -507,9 +507,10 @@ abstract class MediaHandler {
* to some standard. That makes it possible to do things like visual
* indication of grouped and chained streams in ogg container files.
* @param File $image
+ * @param bool|IContextSource $context Context to use (optional)
* @return array|bool
*/
- function formatMetadata( $image ) {
+ function formatMetadata( $image, $context = false ) {
return false;
}
@@ -520,15 +521,16 @@ abstract class MediaHandler {
* This is used by the media handlers that use the FormatMetadata class
*
* @param array $metadataArray Metadata array
+ * @param bool|IContextSource $context Context to use (optional)
* @return array Array for use displaying metadata.
*/
- function formatMetadataHelper( $metadataArray ) {
+ function formatMetadataHelper( $metadataArray, $context = false ) {
$result = array(
'visible' => array(),
'collapsed' => array()
);
- $formatted = FormatMetadata::getFormattedData( $metadataArray );
+ $formatted = FormatMetadata::getFormattedData( $metadataArray, $context );
// Sort fields into visible and collapsed
$visibleFields = $this->visibleMetadataFields();
foreach ( $formatted as $name => $value ) {
@@ -637,7 +639,7 @@ abstract class MediaHandler {
*/
static function getGeneralLongDesc( $file ) {
return wfMessage( 'file-info' )->sizeParams( $file->getSize() )
- ->params( $file->getMimeType() )->parse();
+ ->params( '<span class="mime-type">' . $file->getMimeType() . '</span>' )->parse();
}
/**
@@ -859,4 +861,26 @@ abstract class MediaHandler {
public function sanitizeParamsForBucketing( $params ) {
return $params;
}
+
+ /**
+ * Gets configuration for the file warning message. Return value of
+ * the following structure:
+ * array(
+ * 'module' => 'example.filewarning.messages', // Required, module with messages loaded for the client
+ * 'messages' => array( // Required, array of names of messages
+ * 'main' => 'example-filewarning-main', // Required, main warning message
+ * 'header' => 'example-filewarning-header', // Optional, header for warning dialog
+ * 'footer' => 'example-filewarning-footer', // Optional, footer for warning dialog
+ * 'info' => 'example-filewarning-info', // Optional, text for more-information link (see below)
+ * ),
+ * 'link' => 'http://example.com', // Optional, link for more information
+ * )
+ *
+ * Returns null if no warning is necessary.
+ * @param File $file
+ * @return array|null
+ */
+ public function getWarningConfig( $file ) {
+ return null;
+ }
}
diff --git a/includes/media/MediaTransformInvalidParametersException.php b/includes/media/MediaTransformInvalidParametersException.php
new file mode 100644
index 00000000..15a2ca55
--- /dev/null
+++ b/includes/media/MediaTransformInvalidParametersException.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * MediaWiki exception thrown by some methods when the transform parameter array is invalid
+ *
+ * @ingroup Exception
+ */
+class MediaTransformInvalidParametersException extends MWException {}
diff --git a/includes/media/MediaTransformOutput.php b/includes/media/MediaTransformOutput.php
index bc9e9173..1dd85191 100644
--- a/includes/media/MediaTransformOutput.php
+++ b/includes/media/MediaTransformOutput.php
@@ -348,9 +348,14 @@ class ThumbnailImage extends MediaTransformOutput {
throw new MWException( __METHOD__ . ' called in the old style' );
}
- $alt = empty( $options['alt'] ) ? '' : $options['alt'];
+ $alt = isset( $options['alt'] ) ? $options['alt'] : '';
- $query = empty( $options['desc-query'] ) ? '' : $options['desc-query'];
+ $query = isset( $options['desc-query'] ) ? $options['desc-query'] : '';
+
+ $attribs = array(
+ 'alt' => $alt,
+ 'src' => $this->url,
+ );
if ( !empty( $options['custom-url-link'] ) ) {
$linkAttribs = array( 'href' => $options['custom-url-link'] );
@@ -381,13 +386,11 @@ class ThumbnailImage extends MediaTransformOutput {
$linkAttribs = array( 'href' => $this->file->getURL() );
} else {
$linkAttribs = false;
+ if ( !empty( $options['title'] ) ) {
+ $attribs['title'] = $options['title'];
+ }
}
- $attribs = array(
- 'alt' => $alt,
- 'src' => $this->url,
- );
-
if ( empty( $options['no-dimensions'] ) ) {
$attribs['width'] = $this->width;
$attribs['height'] = $this->height;
@@ -410,7 +413,7 @@ class ThumbnailImage extends MediaTransformOutput {
$attribs['srcset'] = Html::srcSet( $this->responsiveUrls );
}
- wfRunHooks( 'ThumbnailBeforeProduceHTML', array( $this, &$attribs, &$linkAttribs ) );
+ Hooks::run( 'ThumbnailBeforeProduceHTML', array( $this, &$attribs, &$linkAttribs ) );
return $this->linkWrap( $linkAttribs, Xml::element( 'img', $attribs ) );
}
@@ -474,3 +477,24 @@ class TransformParameterError extends MediaTransformError {
wfMessage( 'thumbnail_invalid_params' )->text() );
}
}
+
+/**
+ * Shortcut class for parameter file size errors
+ *
+ * @ingroup Media
+ * @since 1.25
+ */
+class TransformTooBigImageAreaError extends MediaTransformError {
+ function __construct( $params, $maxImageArea ) {
+ $msg = wfMessage( 'thumbnail_toobigimagearea' );
+
+ parent::__construct( 'thumbnail_error',
+ max( isset( $params['width'] ) ? $params['width'] : 0, 120 ),
+ max( isset( $params['height'] ) ? $params['height'] : 0, 120 ),
+ $msg->rawParams(
+ $msg->getLanguage()->formatComputingNumbers(
+ $maxImageArea, 1000, "size-$1pixel" )
+ )->text()
+ );
+ }
+}
diff --git a/includes/media/PNG.php b/includes/media/PNG.php
index 7b3ddb51..5f1aca57 100644
--- a/includes/media/PNG.php
+++ b/includes/media/PNG.php
@@ -49,15 +49,16 @@ class PNGHandler extends BitmapHandler {
/**
* @param File $image
+ * @param bool|IContextSource $context Context to use (optional)
* @return array|bool
*/
- function formatMetadata( $image ) {
+ function formatMetadata( $image, $context = false ) {
$meta = $this->getCommonMetaArray( $image );
if ( count( $meta ) === 0 ) {
return false;
}
- return $this->formatMetadataHelper( $meta );
+ return $this->formatMetadataHelper( $meta, $context );
}
/**
@@ -174,7 +175,10 @@ class PNGHandler extends BitmapHandler {
return $wgLang->commaList( $info );
}
+ // PNGs should be easy to support, but it will need some sharpening applied
+ // and another user test to check if the perceived quality change is noticeable
+
public function supportsBucketing() {
- return true;
+ return false;
}
}
diff --git a/includes/media/SVG.php b/includes/media/SVG.php
index 74e5e048..8fdfa474 100644
--- a/includes/media/SVG.php
+++ b/includes/media/SVG.php
@@ -272,10 +272,8 @@ class SvgHandler extends ImageHandler {
$env['LANG'] = $lang;
}
- wfProfileIn( 'rsvg' );
wfDebug( __METHOD__ . ": $cmd\n" );
$err = wfShellExecWithStderr( $cmd, $retval, $env );
- wfProfileOut( 'rsvg' );
}
}
$removed = $this->removeBadFile( $dstPath, $retval );
@@ -364,7 +362,7 @@ class SvgHandler extends ImageHandler {
$metadata = array( 'version' => self::SVG_METADATA_VERSION );
try {
$metadata += SVGMetadataExtractor::getMetadata( $filename );
- } catch ( MWException $e ) { // @todo SVG specific exceptions
+ } catch ( Exception $e ) { // @todo SVG specific exceptions
// File not found, broken, etc.
$metadata['error'] = array(
'message' => $e->getMessage(),
@@ -412,9 +410,10 @@ class SvgHandler extends ImageHandler {
/**
* @param File $file
+ * @param bool|IContextSource $context Context to use (optional)
* @return array|bool
*/
- function formatMetadata( $file ) {
+ function formatMetadata( $file, $context = false ) {
$result = array(
'visible' => array(),
'collapsed' => array()
@@ -488,7 +487,7 @@ class SvgHandler extends ImageHandler {
function makeParamString( $params ) {
$lang = '';
if ( isset( $params['lang'] ) && $params['lang'] !== 'en' ) {
- $params['lang'] = mb_strtolower( $params['lang'] );
+ $params['lang'] = strtolower( $params['lang'] );
$lang = "lang{$params['lang']}-";
}
if ( !isset( $params['width'] ) ) {
diff --git a/includes/media/SVGMetadataExtractor.php b/includes/media/SVGMetadataExtractor.php
index 2a1091d8..2037c331 100644
--- a/includes/media/SVGMetadataExtractor.php
+++ b/includes/media/SVGMetadataExtractor.php
@@ -138,7 +138,7 @@ class SVGReader {
$keepReading = $this->reader->read();
/* Skip until first element */
- while ( $keepReading && $this->reader->nodeType != XmlReader::ELEMENT ) {
+ while ( $keepReading && $this->reader->nodeType != XMLReader::ELEMENT ) {
$keepReading = $this->reader->read();
}
@@ -158,7 +158,7 @@ class SVGReader {
$this->debug( "$tag" );
- if ( $isSVG && $tag == 'svg' && $type == XmlReader::END_ELEMENT
+ if ( $isSVG && $tag == 'svg' && $type == XMLReader::END_ELEMENT
&& $this->reader->depth <= $exitDepth
) {
break;
@@ -166,7 +166,7 @@ class SVGReader {
$this->readField( $tag, 'title' );
} elseif ( $isSVG && $tag == 'desc' ) {
$this->readField( $tag, 'description' );
- } elseif ( $isSVG && $tag == 'metadata' && $type == XmlReader::ELEMENT ) {
+ } elseif ( $isSVG && $tag == 'metadata' && $type == XMLReader::ELEMENT ) {
$this->readXml( $tag, 'metadata' );
} elseif ( $isSVG && $tag == 'script' ) {
// We normally do not allow scripted svgs.
@@ -199,17 +199,17 @@ class SVGReader {
*/
private function readField( $name, $metafield = null ) {
$this->debug( "Read field $metafield" );
- if ( !$metafield || $this->reader->nodeType != XmlReader::ELEMENT ) {
+ if ( !$metafield || $this->reader->nodeType != XMLReader::ELEMENT ) {
return;
}
$keepReading = $this->reader->read();
while ( $keepReading ) {
if ( $this->reader->localName == $name
&& $this->reader->namespaceURI == self::NS_SVG
- && $this->reader->nodeType == XmlReader::END_ELEMENT
+ && $this->reader->nodeType == XMLReader::END_ELEMENT
) {
break;
- } elseif ( $this->reader->nodeType == XmlReader::TEXT ) {
+ } elseif ( $this->reader->nodeType == XMLReader::TEXT ) {
$this->metadata[$metafield] = trim( $this->reader->value );
}
$keepReading = $this->reader->read();
@@ -224,7 +224,7 @@ class SVGReader {
*/
private function readXml( $metafield = null ) {
$this->debug( "Read top level metadata" );
- if ( !$metafield || $this->reader->nodeType != XmlReader::ELEMENT ) {
+ if ( !$metafield || $this->reader->nodeType != XMLReader::ELEMENT ) {
return;
}
// @todo Find and store type of xml snippet. metadata['metadataType'] = "rdf"
@@ -246,7 +246,7 @@ class SVGReader {
*/
private function animateFilterAndLang( $name ) {
$this->debug( "animate filter for tag $name" );
- if ( $this->reader->nodeType != XmlReader::ELEMENT ) {
+ if ( $this->reader->nodeType != XMLReader::ELEMENT ) {
return;
}
if ( $this->reader->isEmptyElement ) {
@@ -256,11 +256,11 @@ class SVGReader {
$keepReading = $this->reader->read();
while ( $keepReading ) {
if ( $this->reader->localName == $name && $this->reader->depth <= $exitDepth
- && $this->reader->nodeType == XmlReader::END_ELEMENT
+ && $this->reader->nodeType == XMLReader::END_ELEMENT
) {
break;
} elseif ( $this->reader->namespaceURI == self::NS_SVG
- && $this->reader->nodeType == XmlReader::ELEMENT
+ && $this->reader->nodeType == XMLReader::ELEMENT
) {
$sysLang = $this->reader->getAttribute( 'systemLanguage' );
diff --git a/includes/media/Tiff.php b/includes/media/Tiff.php
index bea6cab3..750528f0 100644
--- a/includes/media/Tiff.php
+++ b/includes/media/Tiff.php
@@ -88,7 +88,7 @@ class TiffHandler extends ExifBitmapHandler {
$meta['MEDIAWIKI_EXIF_VERSION'] = Exif::version();
return serialize( $meta );
- } catch ( MWException $e ) {
+ } catch ( Exception $e ) {
// BitmapMetadataHandler throws an exception in certain exceptional
// cases like if file does not exist.
wfDebug( __METHOD__ . ': ' . $e->getMessage() . "\n" );
diff --git a/includes/media/TransformationalImageHandler.php b/includes/media/TransformationalImageHandler.php
index 3e3be3d1..fd8d81d2 100644
--- a/includes/media/TransformationalImageHandler.php
+++ b/includes/media/TransformationalImageHandler.php
@@ -61,29 +61,6 @@ abstract class TransformationalImageHandler extends ImageHandler {
}
}
- # Check if the file is smaller than the maximum image area for thumbnailing
- # For historical reasons, hook starts with BitmapHandler
- $checkImageAreaHookResult = null;
- wfRunHooks(
- 'BitmapHandlerCheckImageArea',
- array( $image, &$params, &$checkImageAreaHookResult )
- );
-
- if ( is_null( $checkImageAreaHookResult ) ) {
- global $wgMaxImageArea;
-
- if ( $srcWidth * $srcHeight > $wgMaxImageArea
- && !( $image->getMimeType() == 'image/jpeg'
- && $this->getScalerType( false, false ) == 'im' )
- ) {
- # Only ImageMagick can efficiently downsize jpg images without loading
- # the entire file in memory
- return false;
- }
- } else {
- return $checkImageAreaHookResult;
- }
-
return true;
}
@@ -190,6 +167,11 @@ abstract class TransformationalImageHandler extends ImageHandler {
return $this->getClientScalingThumbnailImage( $image, $scalerParams );
}
+ if ( !$this->isImageAreaOkForThumbnaling( $image, $params ) ) {
+ global $wgMaxImageArea;
+ return new TransformTooBigImageAreaError( $params, $wgMaxImageArea );
+ }
+
if ( $flags & self::TRANSFORM_LATER ) {
wfDebug( __METHOD__ . ": Transforming later per flags.\n" );
$newParams = array(
@@ -216,6 +198,12 @@ abstract class TransformationalImageHandler extends ImageHandler {
# Transform functions and binaries need a FS source file
$thumbnailSource = $this->getThumbnailSource( $image, $params );
+ // If the source isn't the original, disable EXIF rotation because it's already been applied
+ if ( $scalerParams['srcWidth'] != $thumbnailSource['width']
+ || $scalerParams['srcHeight'] != $thumbnailSource['height'] ) {
+ $scalerParams['disableRotation'] = true;
+ }
+
$scalerParams['srcPath'] = $thumbnailSource['path'];
$scalerParams['srcWidth'] = $thumbnailSource['width'];
$scalerParams['srcHeight'] = $thumbnailSource['height'];
@@ -234,7 +222,7 @@ abstract class TransformationalImageHandler extends ImageHandler {
# Try a hook. Called "Bitmap" for historical reasons.
/** @var $mto MediaTransformOutput */
$mto = null;
- wfRunHooks( 'BitmapHandlerTransform', array( $this, $image, &$scalerParams, &$mto ) );
+ Hooks::run( 'BitmapHandlerTransform', array( $this, $image, &$scalerParams, &$mto ) );
if ( !is_null( $mto ) ) {
wfDebug( __METHOD__ . ": Hook to BitmapHandlerTransform created an mto\n" );
$scaler = 'hookaborted';
@@ -590,4 +578,43 @@ abstract class TransformationalImageHandler extends ImageHandler {
public function mustRender( $file ) {
return $this->canRotate() && $this->getRotation( $file ) != 0;
}
+
+ /**
+ * Check if the file is smaller than the maximum image area for thumbnailing.
+ *
+ * Runs the 'BitmapHandlerCheckImageArea' hook.
+ *
+ * @param File $file
+ * @param array $params
+ * @return bool
+ * @since 1.25
+ */
+ public function isImageAreaOkForThumbnaling( $file, &$params ) {
+ global $wgMaxImageArea;
+
+ # For historical reasons, hook starts with BitmapHandler
+ $checkImageAreaHookResult = null;
+ Hooks::run(
+ 'BitmapHandlerCheckImageArea',
+ array( $file, &$params, &$checkImageAreaHookResult )
+ );
+
+ if ( !is_null( $checkImageAreaHookResult ) ) {
+ // was set by hook, so return that value
+ return (bool)$checkImageAreaHookResult;
+ }
+
+ $srcWidth = $file->getWidth( $params['page'] );
+ $srcHeight = $file->getHeight( $params['page'] );
+
+ if ( $srcWidth * $srcHeight > $wgMaxImageArea
+ && !( $file->getMimeType() == 'image/jpeg'
+ && $this->getScalerType( false, false ) == 'im' )
+ ) {
+ # Only ImageMagick can efficiently downsize jpg images without loading
+ # the entire file in memory
+ return false;
+ }
+ return true;
+ }
}
diff --git a/includes/media/XCF.php b/includes/media/XCF.php
index 48b7a47c..6544d5cf 100644
--- a/includes/media/XCF.php
+++ b/includes/media/XCF.php
@@ -130,7 +130,7 @@ class XCFHandler extends BitmapHandler {
"/Nbase_type", # /
$binaryHeader
);
- } catch ( MWException $mwe ) {
+ } catch ( Exception $mwe ) {
return false;
}
diff --git a/includes/media/XMP.php b/includes/media/XMP.php
index a3f45e6c..50f04ae9 100644
--- a/includes/media/XMP.php
+++ b/includes/media/XMP.php
@@ -195,7 +195,7 @@ class XMPReader {
$data = $this->results;
- wfRunHooks( 'XMPGetResults', array( &$data ) );
+ Hooks::run( 'XMPGetResults', array( &$data ) );
if ( isset( $data['xmp-special']['AuthorsPosition'] )
&& is_string( $data['xmp-special']['AuthorsPosition'] )
@@ -331,7 +331,7 @@ class XMPReader {
// could declare entities unsafe to parse with xml_parse (T85848/T71210).
if ( $this->parsable !== self::PARSABLE_OK ) {
if ( $this->parsable === self::PARSABLE_NO ) {
- throw new MWException( 'Unsafe doctype declaration in XML.' );
+ throw new Exception( 'Unsafe doctype declaration in XML.' );
}
$content = $this->xmlParsableBuffer . $content;
@@ -344,7 +344,7 @@ class XMPReader {
$msg = ( $this->parsable === self::PARSABLE_NO ) ?
'Unsafe doctype declaration in XML.' :
'No root element found in XML.';
- throw new MWException( $msg );
+ throw new Exception( $msg );
}
}
@@ -359,7 +359,7 @@ class XMPReader {
$this->results = array(); // blank if error.
return false;
}
- } catch ( MWException $e ) {
+ } catch ( Exception $e ) {
wfDebugLog( 'XMP', 'XMP parse error: ' . $e );
$this->results = array();
@@ -501,6 +501,10 @@ class XMPReader {
);
$oldDisable = libxml_disable_entity_loader( true );
+ $reset = new ScopedCallback(
+ 'libxml_disable_entity_loader',
+ array( $oldDisable )
+ );
$reader->setParserProperty( XMLReader::SUBST_ENTITIES, false );
// Even with LIBXML_NOWARNING set, XMLReader::read gives a warning
@@ -520,7 +524,6 @@ class XMPReader {
}
}
wfRestoreWarnings();
- libxml_disable_entity_loader( $oldDisable );
if ( !is_null( $result ) ) {
return $result;
diff --git a/includes/media/XMPInfo.php b/includes/media/XMPInfo.php
index 7e47ec14..e0a491cb 100644
--- a/includes/media/XMPInfo.php
+++ b/includes/media/XMPInfo.php
@@ -34,7 +34,7 @@ class XMPInfo {
if ( !self::$ranHooks ) {
// This is for if someone makes a custom metadata extension.
// For example, a medical wiki might want to decode DICOM xmp properties.
- wfRunHooks( 'XMPGetInfo', array( &self::$items ) );
+ Hooks::run( 'XMPGetInfo', array( &self::$items ) );
self::$ranHooks = true; // Only want to do this once.
}