3 namespace MediaWiki\Tests\Api
;
6 * RandomImageGenerator -- does what it says on the tin.
7 * Requires Imagick, the ImageMagick library for PHP, or the command line
8 * equivalent (usually 'convert').
11 * @author Neil Kandalgaonkar <neilk@wikimedia.org>
17 use MediaWiki\Shell\Shell
;
19 use UnexpectedValueException
;
22 * RandomImageGenerator: does what it says on the tin.
23 * Can fetch a random image, or also write a number of them to disk with random filenames.
25 class RandomImageGenerator
{
27 private $minWidth = 16;
29 private $maxWidth = 16;
31 private $minHeight = 16;
33 private $maxHeight = 16;
35 public function __construct( $options = [] ) {
36 foreach ( [ 'minWidth', 'minHeight',
37 'maxWidth', 'maxHeight' ] as $property
39 if ( isset( $options[$property] ) ) {
40 $this->$property = $options[$property];
46 * Writes random images with random filenames to disk in the directory you
47 * specify, or current working directory.
49 * @param int $number Number of filenames to write
50 * @param string $format Optional, must be understood by ImageMagick, such as 'jpg' or 'gif'
51 * @param string|null $dir Directory, optional (will default to current working directory)
52 * @return string[] Filenames we just wrote
54 public function writeImages( int $number, string $format = 'svg', ?
string $dir = null ): array {
55 $filenames = $this->getRandomFilenames( $number, $format, $dir ??
getcwd() );
56 $imageWriteMethod = $this->getImageWriteMethod( $format );
57 foreach ( $filenames as $filename ) {
58 $imageWriteMethod( $this->getImageSpec(), $format, $filename );
65 * Figure out how we write images. This is a factor of both format and the local system
67 * @param string $format (a typical extension like 'svg', 'jpg', etc.)
71 private function getImageWriteMethod( string $format ): callable
{
72 global $wgUseImageMagick, $wgImageMagickConvertCommand;
73 if ( $format === 'svg' ) {
74 return [ $this, 'writeSvg' ];
76 // figure out how to write images
77 global $wgExiv2Command;
78 if ( class_exists( Imagick
::class ) && $wgExiv2Command && is_executable( $wgExiv2Command ) ) {
79 return [ $this, 'writeImageWithApi' ];
80 } elseif ( $wgUseImageMagick
81 && $wgImageMagickConvertCommand
82 && is_executable( $wgImageMagickConvertCommand )
84 return [ $this, 'writeImageWithCommandLine' ];
87 throw new Exception( "RandomImageGenerator: could not find a suitable "
88 . "method to write images in '$format' format" );
92 * Return a number of randomly-generated filenames.
94 * Each filename uses follows the pattern "hex_timestamp_1.jpg".
98 private function getRandomFilenames( int $number, string $extension, string $dir ): array {
100 $prefix = wfRandomString( 3 ) . '_' . gmdate( 'YmdHis' ) . '_';
101 foreach ( range( 1, $number ) as $offset ) {
102 $filename = $prefix . $offset . '.' . $extension;
103 $filenames[] = "$dir/$filename";
110 * Generate data representing an image of random size (within limits),
111 * consisting of randomly colored and sized upward pointing triangles
112 * against a random background color. (This data is used in the
113 * writeImage* methods).
115 private function getImageSpec(): array {
117 'width' => mt_rand( $this->minWidth
, $this->maxWidth
),
118 'height' => mt_rand( $this->minHeight
, $this->maxHeight
),
124 * Based on image specification, write a very simple SVG file to disk.
125 * Ignores the background spec because transparency is cool. :)
129 private function writeSvg( array $spec, string $format, string $filename ): void
{
130 $svg = new SimpleXmlElement( '<svg/>' );
131 $svg->addAttribute( 'xmlns', 'http://www.w3.org/2000/svg' );
132 $svg->addAttribute( 'width', $spec['width'] );
133 $svg->addAttribute( 'height', $spec['height'] );
135 $fh = fopen( $filename, 'w' );
137 throw new UnexpectedValueException( "couldn't open $filename for writing" );
139 fwrite( $fh, $svg->asXML() );
140 if ( !fclose( $fh ) ) {
141 throw new UnexpectedValueException( "couldn't close $filename" );
146 * Based on an image specification, write such an image to disk, using Imagick PHP extension
148 private function writeImageWithApi( array $spec, string $format, string $filename ): void
{
149 $image = new Imagick();
150 $image->newImage( $spec['width'], $spec['height'], new ImagickPixel( $spec['fill'] ) );
151 $image->setImageFormat( $format );
152 $image->writeImage( $filename );
156 * Based on an image specification, write such an image to disk, using the
157 * command line ImageMagick program ('convert').
159 * Sample command line:
160 * $ convert -size 100x60 xc:rgb(90,87,45) \
161 * -draw 'fill rgb(12,34,56) polygon 41,39 44,57 50,57 41,39' \
162 * -draw 'fill rgb(99,123,231) circle 59,39 56,57' \
163 * -draw 'fill rgb(240,12,32) circle 50,21 50,3' filename.png
165 private function writeImageWithCommandLine( array $spec, string $format, string $filename ): void
{
166 global $wgImageMagickConvertCommand;
169 $wgImageMagickConvertCommand,
171 $spec['width'] . 'x' . $spec['height'],
172 "xc:{$spec['fill']}",
175 Shell
::command( $args )->execute();
180 /** @deprecated class alias since 1.42 */
181 class_alias( RandomImageGenerator
::class, 'RandomImageGenerator' );