MediaWiki  REL1_31
Jpeg.php
Go to the documentation of this file.
1 <?php
34  const SRGB_EXIF_COLOR_SPACE = 'sRGB';
35  const SRGB_ICC_PROFILE_DESCRIPTION = 'sRGB IEC61966-2.1';
36 
37  function normaliseParams( $image, &$params ) {
38  if ( !parent::normaliseParams( $image, $params ) ) {
39  return false;
40  }
41  if ( isset( $params['quality'] ) && !self::validateQuality( $params['quality'] ) ) {
42  return false;
43  }
44  return true;
45  }
46 
47  public function validateParam( $name, $value ) {
48  if ( $name === 'quality' ) {
49  return self::validateQuality( $value );
50  } else {
51  return parent::validateParam( $name, $value );
52  }
53  }
54 
59  private static function validateQuality( $value ) {
60  return $value === 'low';
61  }
62 
63  public function makeParamString( $params ) {
64  // Prepend quality as "qValue-". This has to match parseParamString() below
65  $res = parent::makeParamString( $params );
66  if ( $res && isset( $params['quality'] ) ) {
67  $res = "q{$params['quality']}-$res";
68  }
69  return $res;
70  }
71 
72  public function parseParamString( $str ) {
73  // $str contains "qlow-200px" or "200px" strings because thumb.php would strip the filename
74  // first - check if the string begins with "qlow-", and if so, treat it as quality.
75  // Pass the first portion, or the whole string if "qlow-" not found, to the parent
76  // The parsing must match the makeParamString() above
77  $res = false;
78  $m = false;
79  if ( preg_match( '/q([^-]+)-(.*)$/', $str, $m ) ) {
80  $v = $m[1];
81  if ( self::validateQuality( $v ) ) {
82  $res = parent::parseParamString( $m[2] );
83  if ( $res ) {
84  $res['quality'] = $v;
85  }
86  }
87  } else {
88  $res = parent::parseParamString( $str );
89  }
90  return $res;
91  }
92 
93  function getScriptParams( $params ) {
94  $res = parent::getScriptParams( $params );
95  if ( isset( $params['quality'] ) ) {
96  $res['quality'] = $params['quality'];
97  }
98  return $res;
99  }
100 
101  function getMetadata( $image, $filename ) {
102  try {
103  $meta = BitmapMetadataHandler::Jpeg( $filename );
104  if ( !is_array( $meta ) ) {
105  // This should never happen, but doesn't hurt to be paranoid.
106  throw new MWException( 'Metadata array is not an array' );
107  }
108  $meta['MEDIAWIKI_EXIF_VERSION'] = Exif::version();
109 
110  return serialize( $meta );
111  } catch ( Exception $e ) {
112  // BitmapMetadataHandler throws an exception in certain exceptional
113  // cases like if file does not exist.
114  wfDebug( __METHOD__ . ': ' . $e->getMessage() . "\n" );
115 
116  /* This used to use 0 (ExifBitmapHandler::OLD_BROKEN_FILE) for the cases
117  * * No metadata in the file
118  * * Something is broken in the file.
119  * However, if the metadata support gets expanded then you can't tell if the 0 is from
120  * a broken file, or just no props found. A broken file is likely to stay broken, but
121  * a file which had no props could have props once the metadata support is improved.
122  * Thus switch to using -1 to denote only a broken file, and use an array with only
123  * MEDIAWIKI_EXIF_VERSION to denote no props.
124  */
125 
127  }
128  }
129 
137  public function rotate( $file, $params ) {
139 
140  $rotation = ( $params['rotation'] + $this->getRotation( $file ) ) % 360;
141 
142  if ( $wgJpegTran && is_executable( $wgJpegTran ) ) {
143  $cmd = wfEscapeShellArg( $wgJpegTran ) .
144  " -rotate " . wfEscapeShellArg( $rotation ) .
145  " -outfile " . wfEscapeShellArg( $params['dstPath'] ) .
146  " " . wfEscapeShellArg( $params['srcPath'] );
147  wfDebug( __METHOD__ . ": running jpgtran: $cmd\n" );
148  $retval = 0;
149  $err = wfShellExecWithStderr( $cmd, $retval );
150  if ( $retval !== 0 ) {
151  $this->logErrorForExternalProcess( $retval, $err, $cmd );
152 
153  return new MediaTransformError( 'thumbnail_error', 0, 0, $err );
154  }
155 
156  return false;
157  } else {
158  return parent::rotate( $file, $params );
159  }
160  }
161 
162  public function supportsBucketing() {
163  return true;
164  }
165 
166  public function sanitizeParamsForBucketing( $params ) {
167  $params = parent::sanitizeParamsForBucketing( $params );
168 
169  // Quality needs to be cleared for bucketing. Buckets need to be default quality
170  if ( isset( $params['quality'] ) ) {
171  unset( $params['quality'] );
172  }
173 
174  return $params;
175  }
176 
180  protected function transformImageMagick( $image, $params ) {
182 
183  $ret = parent::transformImageMagick( $image, $params );
184 
185  if ( $ret ) {
186  return $ret;
187  }
188 
190  // T100976 If the profile embedded in the JPG is sRGB, swap it for the smaller
191  // (and free) TinyRGB
192 
202  $colorSpaces = [ self::SRGB_EXIF_COLOR_SPACE, '-' ];
203  $profiles = [ self::SRGB_ICC_PROFILE_DESCRIPTION ];
204 
205  // we'll also add TinyRGB profile to images lacking a profile, but
206  // only if they're not low quality (which are meant to save bandwith
207  // and we don't want to increase the filesize by adding a profile)
208  if ( isset( $params['quality'] ) && $params['quality'] > 30 ) {
209  $profiles[] = '-';
210  }
211 
212  $this->swapICCProfile(
213  $params['dstPath'],
214  $colorSpaces,
215  $profiles,
216  realpath( __DIR__ ) . '/tinyrgb.icc'
217  );
218  }
219 
220  return false;
221  }
222 
234  public function swapICCProfile( $filepath, array $colorSpaces,
235  array $oldProfileStrings, $profileFilepath
236  ) {
238 
239  if ( !$wgExiftool || !is_executable( $wgExiftool ) ) {
240  return false;
241  }
242 
244  '-EXIF:ColorSpace',
245  '-ICC_Profile:ProfileDescription',
246  '-S',
247  '-T',
248  $filepath
249  );
250 
252 
253  // Explode EXIF data into an array with [0 => Color Space, 1 => Device Model Desc]
254  $data = explode( "\t", trim( $output ) );
255 
256  if ( $retval !== 0 ) {
257  return false;
258  }
259 
260  // Make a regex out of the source data to match it to an array of color
261  // spaces in a case-insensitive way
262  $colorSpaceRegex = '/'.preg_quote( $data[0], '/' ).'/i';
263  if ( empty( preg_grep( $colorSpaceRegex, $colorSpaces ) ) ) {
264  // We can't establish that this file matches the color space, don't process it
265  return false;
266  }
267 
268  $profileRegex = '/'.preg_quote( $data[1], '/' ).'/i';
269  if ( empty( preg_grep( $profileRegex, $oldProfileStrings ) ) ) {
270  // We can't establish that this file has the expected ICC profile, don't process it
271  return false;
272  }
273 
275  '-overwrite_original',
276  '-icc_profile<=' . $profileFilepath,
277  $filepath
278  );
279 
281 
282  if ( $retval !== 0 ) {
283  $this->logErrorForExternalProcess( $retval, $output, $cmd );
284 
285  return false;
286  }
287 
288  return true;
289  }
290 }
JpegHandler\getMetadata
getMetadata( $image, $filename)
Get handler-specific metadata which will be saved in the img_metadata field.
Definition: Jpeg.php:101
ExifBitmapHandler
Stuff specific to JPEG and (built-in) TIFF handler.
Definition: ExifBitmap.php:30
MediaTransformError
Basic media transform error class.
Definition: MediaTransformOutput.php:441
array
the array() calling protocol came about after MediaWiki 1.4rc1.
$output
static configuration should be added through ResourceLoaderGetConfigVars instead can be used to get the real title after the basic globals have been set but before ordinary actions take place $output
Definition: hooks.txt:2255
$wgExiftool
$wgExiftool
Path to exiftool binary.
Definition: DefaultSettings.php:1120
$ret
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:2005
JpegHandler\SRGB_EXIF_COLOR_SPACE
const SRGB_EXIF_COLOR_SPACE
Definition: Jpeg.php:34
$params
$params
Definition: styleTest.css.php:40
serialize
serialize()
Definition: ApiMessage.php:184
JpegHandler\getScriptParams
getScriptParams( $params)
Definition: Jpeg.php:93
$res
$res
Definition: database.txt:21
JpegHandler\validateParam
validateParam( $name, $value)
Validate a thumbnail parameter at parse time.
Definition: Jpeg.php:47
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:37
JpegHandler\supportsBucketing
supportsBucketing()
Returns whether or not this handler supports the chained generation of thumbnails according to bucket...
Definition: Jpeg.php:162
MWException
MediaWiki exception.
Definition: MWException.php:26
Exif\version
static version()
#-
Definition: Exif.php:582
JpegHandler\SRGB_ICC_PROFILE_DESCRIPTION
const SRGB_ICC_PROFILE_DESCRIPTION
Definition: Jpeg.php:35
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:95
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:994
JpegHandler\normaliseParams
normaliseParams( $image, &$params)
Definition: Jpeg.php:37
$value
$value
Definition: styleTest.css.php:45
JpegHandler\swapICCProfile
swapICCProfile( $filepath, array $colorSpaces, array $oldProfileStrings, $profileFilepath)
Swaps an embedded ICC profile for another, if found.
Definition: Jpeg.php:234
JpegHandler\sanitizeParamsForBucketing
sanitizeParamsForBucketing( $params)
Returns a normalised params array for which parameters have been cleaned up for bucketing purposes.
Definition: Jpeg.php:166
wfEscapeShellArg
wfEscapeShellArg()
Version of escapeshellarg() that works better on Windows.
Definition: GlobalFunctions.php:2209
JpegHandler
JPEG specific handler.
Definition: Jpeg.php:33
$wgJpegTran
$wgJpegTran
used for lossless jpeg rotation
Definition: DefaultSettings.php:1086
ExifBitmapHandler\getRotation
getRotation( $file)
On supporting image formats, try to read out the low-level orientation of the file and return the ang...
Definition: ExifBitmap.php:204
JpegHandler\rotate
rotate( $file, $params)
Definition: Jpeg.php:137
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:302
$image
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output modifiable modifiable after all normalizations have been except for the $wgMaxImageArea check $image
Definition: hooks.txt:895
$wgUseTinyRGBForJPGThumbnails
$wgUseTinyRGBForJPGThumbnails
When this variable is true and JPGs use the sRGB ICC profile, swaps it for the more lightweight (and ...
Definition: DefaultSettings.php:1480
MediaHandler\logErrorForExternalProcess
logErrorForExternalProcess( $retval, $err, $cmd)
Log an error that occurred in an external process.
Definition: MediaHandler.php:763
JpegHandler\validateQuality
static validateQuality( $value)
Validate and normalize quality value to be between 1 and 100 (inclusive).
Definition: Jpeg.php:59
ExifBitmapHandler\BROKEN_FILE
const BROKEN_FILE
Definition: ExifBitmap.php:31
BitmapMetadataHandler\Jpeg
static Jpeg( $filename)
Main entry point for jpeg's.
Definition: BitmapMetadataHandler.php:158
$retval
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account incomplete not yet checked for validity & $retval
Definition: hooks.txt:266
$e
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException' returning false will NOT prevent logging $e
Definition: hooks.txt:2171
JpegHandler\makeParamString
makeParamString( $params)
Merge a parameter array into a string appropriate for inclusion in filenames.
Definition: Jpeg.php:63
wfShellExecWithStderr
wfShellExecWithStderr( $cmd, &$retval=null, $environ=[], $limits=[])
Execute a shell command, returning both stdout and stderr.
Definition: GlobalFunctions.php:2303
JpegHandler\transformImageMagick
transformImageMagick( $image, $params)
@inheritDoc
Definition: Jpeg.php:180
JpegHandler\parseParamString
parseParamString( $str)
Parse a param string made with makeParamString back into an array.
Definition: Jpeg.php:72