Localisation updates from https://translatewiki.net.
[mediawiki.git] / tests / phpunit / includes / api / RandomImageGenerator.php
blob2f9996b54cc39415b07ab560cae604337dc3eb4d
1 <?php
3 namespace MediaWiki\Tests\Api;
5 /**
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').
10 * @file
11 * @author Neil Kandalgaonkar <neilk@wikimedia.org>
14 use Exception;
15 use Imagick;
16 use ImagickPixel;
17 use MediaWiki\Shell\Shell;
18 use SimpleXMLElement;
19 use UnexpectedValueException;
21 /**
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 {
26 /** @var int */
27 private $minWidth = 16;
28 /** @var int */
29 private $maxWidth = 16;
30 /** @var int */
31 private $minHeight = 16;
32 /** @var int */
33 private $maxHeight = 16;
35 public function __construct( $options = [] ) {
36 foreach ( [ 'minWidth', 'minHeight',
37 'maxWidth', 'maxHeight' ] as $property
38 ) {
39 if ( isset( $options[$property] ) ) {
40 $this->$property = $options[$property];
45 /**
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 );
61 return $filenames;
64 /**
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.)
69 * @throws Exception
71 private function getImageWriteMethod( string $format ): callable {
72 global $wgUseImageMagick, $wgImageMagickConvertCommand;
73 if ( $format === 'svg' ) {
74 return [ $this, 'writeSvg' ];
75 } else {
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 )
83 ) {
84 return [ $this, 'writeImageWithCommandLine' ];
87 throw new Exception( "RandomImageGenerator: could not find a suitable "
88 . "method to write images in '$format' format" );
91 /**
92 * Return a number of randomly-generated filenames.
94 * Each filename uses follows the pattern "hex_timestamp_1.jpg".
96 * @return string[]
98 private function getRandomFilenames( int $number, string $extension, string $dir ): array {
99 $filenames = [];
100 $prefix = wfRandomString( 3 ) . '_' . gmdate( 'YmdHis' ) . '_';
101 foreach ( range( 1, $number ) as $offset ) {
102 $filename = $prefix . $offset . '.' . $extension;
103 $filenames[] = "$dir/$filename";
106 return $filenames;
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 {
116 return [
117 'width' => mt_rand( $this->minWidth, $this->maxWidth ),
118 'height' => mt_rand( $this->minHeight, $this->maxHeight ),
119 'fill' => '#f0f',
124 * Based on image specification, write a very simple SVG file to disk.
125 * Ignores the background spec because transparency is cool. :)
127 * @throws Exception
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' );
136 if ( !$fh ) {
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;
168 $args = [
169 $wgImageMagickConvertCommand,
170 '-size',
171 $spec['width'] . 'x' . $spec['height'],
172 "xc:{$spec['fill']}",
173 $filename,
175 Shell::command( $args )->execute();
180 /** @deprecated class alias since 1.42 */
181 class_alias( RandomImageGenerator::class, 'RandomImageGenerator' );