diff options
author | Pierre Schmitz <pierre@archlinux.de> | 2014-12-27 15:41:37 +0100 |
---|---|---|
committer | Pierre Schmitz <pierre@archlinux.de> | 2014-12-31 11:43:28 +0100 |
commit | c1f9b1f7b1b77776192048005dcc66dcf3df2bfb (patch) | |
tree | 2b38796e738dd74cb42ecd9bfd151803108386bc /includes/media/SVG.php | |
parent | b88ab0086858470dd1f644e64cb4e4f62bb2be9b (diff) |
Update to MediaWiki 1.24.1
Diffstat (limited to 'includes/media/SVG.php')
-rw-r--r-- | includes/media/SVG.php | 202 |
1 files changed, 161 insertions, 41 deletions
diff --git a/includes/media/SVG.php b/includes/media/SVG.php index 72a9696c..74e5e048 100644 --- a/includes/media/SVG.php +++ b/includes/media/SVG.php @@ -29,10 +29,22 @@ class SvgHandler extends ImageHandler { const SVG_METADATA_VERSION = 2; + /** @var array A list of metadata tags that can be converted + * to the commonly used exif tags. This allows messages + * to be reused, and consistent tag names for {{#formatmetadata:..}} + */ + private static $metaConversion = array( + 'originalwidth' => 'ImageWidth', + 'originalheight' => 'ImageLength', + 'description' => 'ImageDescription', + 'title' => 'ObjectName', + ); + function isEnabled() { global $wgSVGConverters, $wgSVGConverter; if ( !isset( $wgSVGConverters[$wgSVGConverter] ) ) { wfDebug( "\$wgSVGConverter is invalid, disabling SVG rendering.\n" ); + return false; } else { return true; @@ -48,11 +60,11 @@ class SvgHandler extends ImageHandler { } /** - * @param $file File + * @param File $file * @return bool */ function isAnimatedImage( $file ) { - # TODO: detect animated SVGs + # @todo Detect animated SVGs $metadata = $file->getMetadata(); if ( $metadata ) { $metadata = $this->unpackMetadata( $metadata ); @@ -60,19 +72,60 @@ class SvgHandler extends ImageHandler { return $metadata['animated']; } } + return false; } /** + * Which languages (systemLanguage attribute) is supported. + * + * @note This list is not guaranteed to be exhaustive. + * To avoid OOM errors, we only look at first bit of a file. + * Thus all languages on this list are present in the file, + * but its possible for the file to have a language not on + * this list. + * + * @param File $file + * @return array Array of language codes, or empty if no language switching supported. + */ + public function getAvailableLanguages( File $file ) { + $metadata = $file->getMetadata(); + $langList = array(); + if ( $metadata ) { + $metadata = $this->unpackMetadata( $metadata ); + if ( isset( $metadata['translations'] ) ) { + foreach ( $metadata['translations'] as $lang => $langType ) { + if ( $langType === SvgReader::LANG_FULL_MATCH ) { + $langList[] = $lang; + } + } + } + } + return $langList; + } + + /** + * What language to render file in if none selected. + * + * @param File $file + * @return string Language code. + */ + public function getDefaultRenderLanguage( File $file ) { + return 'en'; + } + + /** * We do not support making animated svg thumbnails + * @param File $file + * @return bool */ - function canAnimateThumb( $file ) { + function canAnimateThumbnail( $file ) { return false; } /** - * @param $image File - * @param $params + * @param File $image + * @param array $params * @return bool */ function normaliseParams( $image, &$params ) { @@ -96,14 +149,15 @@ class SvgHandler extends ImageHandler { $params['physicalHeight'] = $wgSVGMaxSize; } } + return true; } /** - * @param $image File - * @param $dstPath - * @param $dstUrl - * @param $params + * @param File $image + * @param string $dstPath + * @param string $dstUrl + * @param array $params * @param int $flags * @return bool|MediaTransformError|ThumbnailImage|TransformParameterError */ @@ -115,7 +169,7 @@ class SvgHandler extends ImageHandler { $clientHeight = $params['height']; $physicalWidth = $params['physicalWidth']; $physicalHeight = $params['physicalHeight']; - $lang = isset( $params['lang'] ) ? $params['lang'] : 'en'; + $lang = isset( $params['lang'] ) ? $params['lang'] : $this->getDefaultRenderLanguage( $image ); if ( $flags & self::TRANSFORM_LATER ) { return new ThumbnailImage( $image, $dstUrl, $dstPath, $params ); @@ -124,6 +178,7 @@ class SvgHandler extends ImageHandler { $metadata = $this->unpackMetadata( $image->getMetadata() ); if ( isset( $metadata['error'] ) ) { // sanity check $err = wfMessage( 'svg-long-error', $metadata['error']['message'] )->text(); + return new MediaTransformError( 'thumbnail_error', $clientWidth, $clientHeight, $err ); } @@ -133,7 +188,40 @@ class SvgHandler extends ImageHandler { } $srcPath = $image->getLocalRefPath(); - $status = $this->rasterize( $srcPath, $dstPath, $physicalWidth, $physicalHeight, $lang ); + if ( $srcPath === false ) { // Failed to get local copy + wfDebugLog( 'thumbnail', + sprintf( 'Thumbnail failed on %s: could not get local copy of "%s"', + wfHostname(), $image->getName() ) ); + + return new MediaTransformError( 'thumbnail_error', + $params['width'], $params['height'], + wfMessage( 'filemissing' )->text() + ); + } + + // Make a temp dir with a symlink to the local copy in it. + // This plays well with rsvg-convert policy for external entities. + // https://git.gnome.org/browse/librsvg/commit/?id=f01aded72c38f0e18bc7ff67dee800e380251c8e + $tmpDir = wfTempDir() . '/svg_' . wfRandomString( 24 ); + $lnPath = "$tmpDir/" . basename( $srcPath ); + $ok = mkdir( $tmpDir, 0771 ) && symlink( $srcPath, $lnPath ); + $cleaner = new ScopedCallback( function () use ( $tmpDir, $lnPath ) { + wfSuppressWarnings(); + unlink( $lnPath ); + rmdir( $tmpDir ); + wfRestoreWarnings(); + } ); + if ( !$ok ) { + wfDebugLog( 'thumbnail', + sprintf( 'Thumbnail failed on %s: could not link %s to %s', + wfHostname(), $lnPath, $srcPath ) ); + return new MediaTransformError( 'thumbnail_error', + $params['width'], $params['height'], + wfMessage( 'thumbnail-temp-create' )->text() + ); + } + + $status = $this->rasterize( $lnPath, $dstPath, $physicalWidth, $physicalHeight, $lang ); if ( $status === true ) { return new ThumbnailImage( $image, $dstUrl, $dstPath, $params ); } else { @@ -148,7 +236,7 @@ class SvgHandler extends ImageHandler { * @param string $dstPath * @param string $width * @param string $height - * @param string $lang Language code of the language to render the SVG in + * @param bool|string $lang Language code of the language to render the SVG in * @throws MWException * @return bool|MediaTransformError */ @@ -192,10 +280,10 @@ class SvgHandler extends ImageHandler { } $removed = $this->removeBadFile( $dstPath, $retval ); if ( $retval != 0 || $removed ) { - wfDebugLog( 'thumbnail', sprintf( 'thumbnail failed on %s: error %d "%s" from "%s"', - wfHostname(), $retval, trim( $err ), $cmd ) ); + $this->logErrorForExternalProcess( $retval, $err, $cmd ); return new MediaTransformError( 'thumbnail_error', $width, $height, $err ); } + return true; } @@ -214,9 +302,9 @@ class SvgHandler extends ImageHandler { } /** - * @param $file File - * @param $path - * @param bool $metadata + * @param File $file + * @param string $path Unused + * @param bool|array $metadata * @return array */ function getImageSize( $file, $path, $metadata = false ) { @@ -227,7 +315,7 @@ class SvgHandler extends ImageHandler { if ( isset( $metadata['width'] ) && isset( $metadata['height'] ) ) { return array( $metadata['width'], $metadata['height'], 'SVG', - "width=\"{$metadata['width']}\" height=\"{$metadata['height']}\"" ); + "width=\"{$metadata['width']}\" height=\"{$metadata['height']}\"" ); } else { // error return array( 0, 0, 'SVG', "width=\"0\" height=\"0\"" ); } @@ -243,7 +331,7 @@ class SvgHandler extends ImageHandler { * a "nominal" resolution, and not a fixed one, * as well as so animation can be denoted. * - * @param $file File + * @param File $file * @return string */ function getLongDesc( $file ) { @@ -267,6 +355,11 @@ class SvgHandler extends ImageHandler { return $msg->parse(); } + /** + * @param File $file + * @param string $filename + * @return string Serialised metadata + */ function getMetadata( $file, $filename ) { $metadata = array( 'version' => self::SVG_METADATA_VERSION ); try { @@ -279,6 +372,7 @@ class SvgHandler extends ImageHandler { ); wfDebug( __METHOD__ . ': ' . $e->getMessage() . "\n" ); } + return serialize( $metadata ); } @@ -306,16 +400,18 @@ class SvgHandler extends ImageHandler { // Old but compatible return self::METADATA_COMPATIBLE; } + return self::METADATA_GOOD; } - function visibleMetadataFields() { + protected function visibleMetadataFields() { $fields = array( 'objectname', 'imagedescription' ); + return $fields; } /** - * @param $file File + * @param File $file * @return array|bool */ function formatMetadata( $file ) { @@ -332,7 +428,7 @@ class SvgHandler extends ImageHandler { return false; } - /* TODO: add a formatter + /* @todo Add a formatter $format = new FormatSVG( $metadata ); $formatted = $format->getFormattedData(); */ @@ -340,19 +436,11 @@ class SvgHandler extends ImageHandler { // Sort fields into visible and collapsed $visibleFields = $this->visibleMetadataFields(); - // Rename fields to be compatible with exif, so that - // the labels for these fields work and reuse existing messages. - $conversion = array( - 'originalwidth' => 'imagewidth', - 'originalheight' => 'imagelength', - 'description' => 'imagedescription', - 'title' => 'objectname', - ); $showMeta = false; foreach ( $metadata as $name => $value ) { $tag = strtolower( $name ); - if ( isset( $conversion[$tag] ) ) { - $tag = $conversion[$tag]; + if ( isset( self::$metaConversion[$tag] ) ) { + $tag = strtolower( self::$metaConversion[$tag] ); } else { // Do not output other metadata not in list continue; @@ -365,13 +453,13 @@ class SvgHandler extends ImageHandler { $value ); } + return $showMeta ? $result : false; } - /** * @param string $name Parameter name - * @param $string $value Parameter value + * @param mixed $value Parameter value * @return bool Validity */ function validateParam( $name, $value ) { @@ -380,18 +468,21 @@ class SvgHandler extends ImageHandler { return ( $value > 0 ); } elseif ( $name == 'lang' ) { // Validate $code - if ( !Language::isValidBuiltinCode( $value ) ) { + if ( $value === '' || !Language::isValidBuiltinCode( $value ) ) { wfDebug( "Invalid user language code\n" ); + return false; } + return true; } + // Only lang, width and height are acceptable keys return false; } /** - * @param array $params name=>value pairs of parameters + * @param array $params Name=>value pairs of parameters * @return string Filename to use */ function makeParamString( $params ) { @@ -403,6 +494,7 @@ class SvgHandler extends ImageHandler { if ( !isset( $params['width'] ) ) { return false; } + return "$lang{$params['width']}px"; } @@ -422,13 +514,41 @@ class SvgHandler extends ImageHandler { } /** - * @param $params + * @param array $params * @return array */ function getScriptParams( $params ) { - return array( - 'width' => $params['width'], - 'lang' => $params['lang'], - ); + $scriptParams = array( 'width' => $params['width'] ); + if ( isset( $params['lang'] ) ) { + $scriptParams['lang'] = $params['lang']; + } + + return $scriptParams; + } + + public function getCommonMetaArray( File $file ) { + $metadata = $file->getMetadata(); + if ( !$metadata ) { + return array(); + } + $metadata = $this->unpackMetadata( $metadata ); + if ( !$metadata || isset( $metadata['error'] ) ) { + return array(); + } + $stdMetadata = array(); + foreach ( $metadata as $name => $value ) { + $tag = strtolower( $name ); + if ( $tag === 'originalwidth' || $tag === 'originalheight' ) { + // Skip these. In the exif metadata stuff, it is assumed these + // are measured in px, which is not the case here. + continue; + } + if ( isset( self::$metaConversion[$tag] ) ) { + $tag = self::$metaConversion[$tag]; + $stdMetadata[$tag] = $value; + } + } + + return $stdMetadata; } } |