MediaWiki  1.23.14
RandomImageGenerator.php
Go to the documentation of this file.
1 <?php
2 
28 
29  private $dictionaryFile;
30  private $minWidth = 400;
31  private $maxWidth = 800;
32  private $minHeight = 400;
33  private $maxHeight = 800;
34  private $shapesToDraw = 5;
35 
42  private static $orientations = array(
43  array(
44  '0thRow' => 'top',
45  '0thCol' => 'left',
46  'exifCode' => 1,
47  'counterRotation' => array( array( 1, 0 ), array( 0, 1 ) )
48  ),
49  array(
50  '0thRow' => 'bottom',
51  '0thCol' => 'right',
52  'exifCode' => 3,
53  'counterRotation' => array( array( -1, 0 ), array( 0, -1 ) )
54  ),
55  array(
56  '0thRow' => 'right',
57  '0thCol' => 'top',
58  'exifCode' => 6,
59  'counterRotation' => array( array( 0, 1 ), array( 1, 0 ) )
60  ),
61  array(
62  '0thRow' => 'left',
63  '0thCol' => 'bottom',
64  'exifCode' => 8,
65  'counterRotation' => array( array( 0, -1 ), array( -1, 0 ) )
66  )
67  );
68 
69  public function __construct( $options = array() ) {
70  foreach ( array( 'dictionaryFile', 'minWidth', 'minHeight', 'maxWidth', 'maxHeight', 'shapesToDraw' ) as $property ) {
71  if ( isset( $options[$property] ) ) {
72  $this->$property = $options[$property];
73  }
74  }
75 
76  // find the dictionary file, to generate random names
77  if ( !isset( $this->dictionaryFile ) ) {
78  foreach (
79  array(
80  '/usr/share/dict/words',
81  '/usr/dict/words',
82  __DIR__ . '/words.txt'
84  ) {
85  if ( is_file( $dictionaryFile ) and is_readable( $dictionaryFile ) ) {
86  $this->dictionaryFile = $dictionaryFile;
87  break;
88  }
89  }
90  }
91  if ( !isset( $this->dictionaryFile ) ) {
92  throw new Exception( "RandomImageGenerator: dictionary file not found or not specified properly" );
93  }
94  }
95 
104  function writeImages( $number, $format = 'jpg', $dir = null ) {
105  $filenames = $this->getRandomFilenames( $number, $format, $dir );
106  $imageWriteMethod = $this->getImageWriteMethod( $format );
107  foreach ( $filenames as $filename ) {
108  $this->{$imageWriteMethod}( $this->getImageSpec(), $format, $filename );
109  }
110 
111  return $filenames;
112  }
113 
122  function getImageWriteMethod( $format ) {
123  global $wgUseImageMagick, $wgImageMagickConvertCommand;
124  if ( $format === 'svg' ) {
125  return 'writeSvg';
126  } else {
127  // figure out how to write images
128  global $wgExiv2Command;
129  if ( class_exists( 'Imagick' ) && $wgExiv2Command && is_executable( $wgExiv2Command ) ) {
130  return 'writeImageWithApi';
131  } elseif ( $wgUseImageMagick && $wgImageMagickConvertCommand && is_executable( $wgImageMagickConvertCommand ) ) {
132  return 'writeImageWithCommandLine';
133  }
134  }
135  throw new Exception( "RandomImageGenerator: could not find a suitable method to write images in '$format' format" );
136  }
137 
147  private function getRandomFilenames( $number, $extension = 'jpg', $dir = null ) {
148  if ( is_null( $dir ) ) {
149  $dir = getcwd();
150  }
151  $filenames = array();
152  foreach ( $this->getRandomWordPairs( $number ) as $pair ) {
153  $basename = $pair[0] . '_' . $pair[1];
154  if ( !is_null( $extension ) ) {
155  $basename .= '.' . $extension;
156  }
157  $basename = preg_replace( '/\s+/', '', $basename );
158  $filenames[] = "$dir/$basename";
159  }
160 
161  return $filenames;
162  }
163 
170  public function getImageSpec() {
171  $spec = array();
172 
173  $spec['width'] = mt_rand( $this->minWidth, $this->maxWidth );
174  $spec['height'] = mt_rand( $this->minHeight, $this->maxHeight );
175  $spec['fill'] = $this->getRandomColor();
176 
177  $diagonalLength = sqrt( pow( $spec['width'], 2 ) + pow( $spec['height'], 2 ) );
178 
179  $draws = array();
180  for ( $i = 0; $i <= $this->shapesToDraw; $i++ ) {
181  $radius = mt_rand( 0, $diagonalLength / 4 );
182  if ( $radius == 0 ) {
183  continue;
184  }
185  $originX = mt_rand( -1 * $radius, $spec['width'] + $radius );
186  $originY = mt_rand( -1 * $radius, $spec['height'] + $radius );
187  $angle = mt_rand( 0, ( 3.141592 / 2 ) * $radius ) / $radius;
188  $legDeltaX = round( $radius * sin( $angle ) );
189  $legDeltaY = round( $radius * cos( $angle ) );
190 
191  $draw = array();
192  $draw['fill'] = $this->getRandomColor();
193  $draw['shape'] = array(
194  array( 'x' => $originX, 'y' => $originY - $radius ),
195  array( 'x' => $originX + $legDeltaX, 'y' => $originY + $legDeltaY ),
196  array( 'x' => $originX - $legDeltaX, 'y' => $originY + $legDeltaY ),
197  array( 'x' => $originX, 'y' => $originY - $radius )
198  );
199  $draws[] = $draw;
200  }
201 
202  $spec['draws'] = $draws;
203 
204  return $spec;
205  }
206 
214  static function shapePointsToString( $shape ) {
215  $points = array();
216  foreach ( $shape as $point ) {
217  $points[] = $point['x'] . ',' . $point['y'];
218  }
219 
220  return join( " ", $points );
221  }
222 
233  public function writeSvg( $spec, $format, $filename ) {
234  $svg = new SimpleXmlElement( '<svg/>' );
235  $svg->addAttribute( 'xmlns', 'http://www.w3.org/2000/svg' );
236  $svg->addAttribute( 'version', '1.1' );
237  $svg->addAttribute( 'width', $spec['width'] );
238  $svg->addAttribute( 'height', $spec['height'] );
239  $g = $svg->addChild( 'g' );
240  foreach ( $spec['draws'] as $drawSpec ) {
241  $shape = $g->addChild( 'polygon' );
242  $shape->addAttribute( 'fill', $drawSpec['fill'] );
243  $shape->addAttribute( 'points', self::shapePointsToString( $drawSpec['shape'] ) );
244  }
245 
246  if ( !$fh = fopen( $filename, 'w' ) ) {
247  throw new Exception( "couldn't open $filename for writing" );
248  }
249  fwrite( $fh, $svg->asXML() );
250  if ( !fclose( $fh ) ) {
251  throw new Exception( "couldn't close $filename" );
252  }
253  }
254 
261  public function writeImageWithApi( $spec, $format, $filename ) {
262  // this is a hack because I can't get setImageOrientation() to work. See below.
263  global $wgExiv2Command;
264 
265  $image = new Imagick();
270  $orientation = self::$orientations[0]; // default is normal orientation
271  if ( $format == 'jpg' ) {
272  $orientation = self::$orientations[array_rand( self::$orientations )];
273  $spec = self::rotateImageSpec( $spec, $orientation['counterRotation'] );
274  }
275 
276  $image->newImage( $spec['width'], $spec['height'], new ImagickPixel( $spec['fill'] ) );
277 
278  foreach ( $spec['draws'] as $drawSpec ) {
279  $draw = new ImagickDraw();
280  $draw->setFillColor( $drawSpec['fill'] );
281  $draw->polygon( $drawSpec['shape'] );
282  $image->drawImage( $draw );
283  }
284 
285  $image->setImageFormat( $format );
286 
287  // this doesn't work, even though it's documented to do so...
288  // $image->setImageOrientation( $orientation['exifCode'] );
289 
290  $image->writeImage( $filename );
291 
292  // because the above setImageOrientation call doesn't work... nor can I get an external imagemagick binary to do this either...
293  // hacking this for now (only works if you have exiv2 installed, a program to read and manipulate exif)
294  if ( $wgExiv2Command ) {
295  $cmd = wfEscapeShellArg( $wgExiv2Command )
296  . " -M "
297  . wfEscapeShellArg( "set Exif.Image.Orientation " . $orientation['exifCode'] )
298  . " "
299  . wfEscapeShellArg( $filename );
300 
301  $retval = 0;
302  $err = wfShellExec( $cmd, $retval );
303  if ( $retval !== 0 ) {
304  print "Error with $cmd: $retval, $err\n";
305  }
306  }
307  }
308 
316  private static function rotateImageSpec( &$spec, $matrix ) {
317  $tSpec = array();
318  $dims = self::matrixMultiply2x2( $matrix, $spec['width'], $spec['height'] );
319  $correctionX = 0;
320  $correctionY = 0;
321  if ( $dims['x'] < 0 ) {
322  $correctionX = abs( $dims['x'] );
323  }
324  if ( $dims['y'] < 0 ) {
325  $correctionY = abs( $dims['y'] );
326  }
327  $tSpec['width'] = abs( $dims['x'] );
328  $tSpec['height'] = abs( $dims['y'] );
329  $tSpec['fill'] = $spec['fill'];
330  $tSpec['draws'] = array();
331  foreach ( $spec['draws'] as $draw ) {
332  $tDraw = array(
333  'fill' => $draw['fill'],
334  'shape' => array()
335  );
336  foreach ( $draw['shape'] as $point ) {
337  $tPoint = self::matrixMultiply2x2( $matrix, $point['x'], $point['y'] );
338  $tPoint['x'] += $correctionX;
339  $tPoint['y'] += $correctionY;
340  $tDraw['shape'][] = $tPoint;
341  }
342  $tSpec['draws'][] = $tDraw;
343  }
344 
345  return $tSpec;
346  }
347 
355  private static function matrixMultiply2x2( $matrix, $x, $y ) {
356  return array(
357  'x' => $x * $matrix[0][0] + $y * $matrix[0][1],
358  'y' => $x * $matrix[1][0] + $y * $matrix[1][1]
359  );
360  }
361 
378  public function writeImageWithCommandLine( $spec, $format, $filename ) {
379  global $wgImageMagickConvertCommand;
380  $args = array();
381  $args[] = "-size " . wfEscapeShellArg( $spec['width'] . 'x' . $spec['height'] );
382  $args[] = wfEscapeShellArg( "xc:" . $spec['fill'] );
383  foreach ( $spec['draws'] as $draw ) {
384  $fill = $draw['fill'];
385  $polygon = self::shapePointsToString( $draw['shape'] );
386  $drawCommand = "fill $fill polygon $polygon";
387  $args[] = '-draw ' . wfEscapeShellArg( $drawCommand );
388  }
389  $args[] = wfEscapeShellArg( $filename );
390 
391  $command = wfEscapeShellArg( $wgImageMagickConvertCommand ) . " " . implode( " ", $args );
392  $retval = null;
394 
395  return ( $retval === 0 );
396  }
397 
403  public function getRandomColor() {
404  $components = array();
405  for ( $i = 0; $i <= 2; $i++ ) {
406  $components[] = mt_rand( 0, 255 );
407  }
408 
409  return 'rgb(' . join( ', ', $components ) . ')';
410  }
411 
418  private function getRandomWordPairs( $number ) {
419  $lines = $this->getRandomLines( $number * 2 );
420  // construct pairs of words
421  $pairs = array();
422  $count = count( $lines );
423  for ( $i = 0; $i < $count; $i += 2 ) {
424  $pairs[] = array( $lines[$i], $lines[$i + 1] );
425  }
426 
427  return $pairs;
428  }
429 
440  private function getRandomLines( $number_desired ) {
441  $filepath = $this->dictionaryFile;
442 
443  // initialize array of lines
444  $lines = array();
445  for ( $i = 0; $i < $number_desired; $i++ ) {
446  $lines[] = null;
447  }
448 
449  /*
450  * This algorithm obtains N random lines from a file in one single pass. It does this by replacing elements of
451  * a fixed-size array of lines, less and less frequently as it reads the file.
452  */
453  $fh = fopen( $filepath, "r" );
454  if ( !$fh ) {
455  throw new Exception( "couldn't open $filepath" );
456  }
457  $line_number = 0;
458  $max_index = $number_desired - 1;
459  while ( !feof( $fh ) ) {
460  $line = fgets( $fh );
461  if ( $line !== false ) {
462  $line_number++;
463  $line = trim( $line );
464  if ( mt_rand( 0, $line_number ) <= $max_index ) {
465  $lines[mt_rand( 0, $max_index )] = $line;
466  }
467  }
468  }
469  fclose( $fh );
470  if ( $line_number < $number_desired ) {
471  throw new Exception( "not enough lines in $filepath" );
472  }
473 
474  return $lines;
475  }
476 }
wfShellExec
wfShellExec( $cmd, &$retval=null, $environ=array(), $limits=array(), $options=array())
Execute a shell command, with time and memory limits mirrored from the PHP configuration if supported...
Definition: GlobalFunctions.php:2851
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
RandomImageGenerator\$maxHeight
$maxHeight
Definition: RandomImageGenerator.php:33
RandomImageGenerator
RandomImageGenerator: does what it says on the tin.
Definition: RandomImageGenerator.php:27
RandomImageGenerator\$shapesToDraw
$shapesToDraw
Definition: RandomImageGenerator.php:34
RandomImageGenerator\$maxWidth
$maxWidth
Definition: RandomImageGenerator.php:31
$property
$property
Definition: styleTest.css.php:44
$points
$points
Definition: profileinfo.php:361
RandomImageGenerator\writeImages
writeImages( $number, $format='jpg', $dir=null)
Writes random images with random filenames to disk in the directory you specify, or current working d...
Definition: RandomImageGenerator.php:104
$lines
$lines
Definition: router.php:65
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
RandomImageGenerator\getRandomFilenames
getRandomFilenames( $number, $extension='jpg', $dir=null)
Return a number of randomly-generated filenames Each filename uses two words randomly drawn from the ...
Definition: RandomImageGenerator.php:147
RandomImageGenerator\__construct
__construct( $options=array())
Definition: RandomImageGenerator.php:69
RandomImageGenerator\rotateImageSpec
static rotateImageSpec(&$spec, $matrix)
Given an image specification, produce rotated version This is used when simulating a rotated image ca...
Definition: RandomImageGenerator.php:316
$options
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 & $options
Definition: hooks.txt:1530
RandomImageGenerator\writeImageWithApi
writeImageWithApi( $spec, $format, $filename)
Based on an image specification, write such an image to disk, using Imagick PHP extension.
Definition: RandomImageGenerator.php:261
$command
$command
Definition: cdb.php:63
$line
$line
Definition: cdb.php:57
RandomImageGenerator\$dictionaryFile
$dictionaryFile
Definition: RandomImageGenerator.php:29
RandomImageGenerator\$minWidth
$minWidth
Definition: RandomImageGenerator.php:30
RandomImageGenerator\getImageWriteMethod
getImageWriteMethod( $format)
Figure out how we write images.
Definition: RandomImageGenerator.php:122
wfEscapeShellArg
wfEscapeShellArg()
Windows-compatible version of escapeshellarg() Windows doesn't recognise single-quotes in the shell,...
Definition: GlobalFunctions.php:2752
RandomImageGenerator\getImageSpec
getImageSpec()
Generate data representing an image of random size (within limits), consisting of randomly colored an...
Definition: RandomImageGenerator.php:170
RandomImageGenerator\getRandomLines
getRandomLines( $number_desired)
Return N random lines from a file.
Definition: RandomImageGenerator.php:440
RandomImageGenerator\$minHeight
$minHeight
Definition: RandomImageGenerator.php:32
$count
$count
Definition: UtfNormalTest2.php:96
RandomImageGenerator\$orientations
static $orientations
Orientations: 0th row, 0th column, Exif orientation code, rotation 2x2 matrix that is opposite of ori...
Definition: RandomImageGenerator.php:42
RandomImageGenerator\shapePointsToString
static shapePointsToString( $shape)
Given array( array('x' => 10, 'y' => 20), array( 'x' => 30, y=> 5 ) ) returns "10,...
Definition: RandomImageGenerator.php:214
$args
if( $line===false) $args
Definition: cdb.php:62
$dir
if(count( $args)==0) $dir
Definition: importImages.php:49
RandomImageGenerator\getRandomWordPairs
getRandomWordPairs( $number)
Get an array of random pairs of random words, like array( array( 'foo', 'bar' ), array( 'quux',...
Definition: RandomImageGenerator.php:418
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
RandomImageGenerator\writeImageWithCommandLine
writeImageWithCommandLine( $spec, $format, $filename)
Based on an image specification, write such an image to disk, using the command line ImageMagick prog...
Definition: RandomImageGenerator.php:378
RandomImageGenerator\writeSvg
writeSvg( $spec, $format, $filename)
Based on image specification, write a very simple SVG file to disk.
Definition: RandomImageGenerator.php:233
$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:237
RandomImageGenerator\matrixMultiply2x2
static matrixMultiply2x2( $matrix, $x, $y)
Given a matrix and a pair of images, return new position.
Definition: RandomImageGenerator.php:355
RandomImageGenerator\getRandomColor
getRandomColor()
Generate a string of random colors for ImageMagick or SVG, like "rgb(12, 37, 98)".
Definition: RandomImageGenerator.php:403