r74111 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r74110‎ | r74111 | r74112 >
Date:21:39, 1 October 2010
Author:neilk
Status:deferred
Tags:
Comment:
split random image generation in library and script
Modified paths:
  • /branches/uploadwizard/extensions/UploadWizard/test/php/scripts/RandomImageGenerator.php (modified) (history)
  • /branches/uploadwizard/extensions/UploadWizard/test/php/scripts/generateRandomImages.php (modified) (history)

Diff [purge]

Index: branches/uploadwizard/extensions/UploadWizard/test/php/scripts/RandomImageGenerator.php
@@ -1,7 +1,7 @@
22 <?php
33
44 /*
5 - * generateRandomImages -- does what it says on the tin.
 5+ * RandomImageGenerator -- does what it says on the tin.
66 *
77 * Because MediaWiki tests the uniqueness of media upload content, and filenames, it is sometimes useful to generate
88 * files that are guaranteed (or at least very likely) to be unique in both those ways.
@@ -13,169 +13,191 @@
1414 * @author Neil Kandalgaonkar <neilk@wikimedia.org>
1515 */
1616
17 -$defaults = array(
18 - 'dict' => "/usr/share/dict/words",
19 - 'number' => 10,
20 - 'minWidth' => 400,
21 - 'maxWidth' => 800,
22 - 'minHeight' => 400,
23 - 'maxHeight' => 800,
24 - 'format' => 'jpg'
25 -);
2617
27 -writeRandomImages( getOptions( $defaults ) );
 18+/**
 19+ * Does what it says on the tin.
 20+ * Can fetch a random image, or also write a number of them to disk with random filenames.
 21+ */
 22+class RandomImageGenerator {
2823
29 -
30 -
31 -
32 -/**
33 - * Override defaults with command-line options
34 - *
35 - * @param {Array} key-value default values
36 - * @return {Array} defaults with CLI overrides
37 - */
38 -function getOptions( $defaults ) {
 24+ private $dictionaryFile;
 25+ private $minWidth = 400;
 26+ private $maxWidth = 800;
 27+ private $minHeight = 400;
 28+ private $maxHeight = 800;
 29+ private $circlesToDraw = 5;
3930
40 - // all options are optional, so append '::' to spec
41 - $getoptSpec = array_map( function($s) { return $s . "::"; }, array_keys( $defaults ) );
42 - $cliOptions = getopt( null, $getoptSpec );
 31+ public function __construct( $options ) {
 32+ foreach ( array( 'dictionaryFile', 'minWidth', 'minHeight', 'maxHeight', 'circlesToDraw' ) as $property ) {
 33+ if ( isset( $options[$property] ) ) {
 34+ $this->$property = $options[$property];
 35+ }
 36+ }
 37+
 38+ if ( !isset( $this->dictionaryFile ) ) {
 39+ foreach ( array( '/usr/share/dict/words', '/usr/dict/words' ) as $dictionaryFile ) {
 40+ if ( is_file( $dictionaryFile ) and is_readable( $dictionaryFile ) ) {
 41+ $this->dictionaryFile = $dictionaryFile;
 42+ break;
 43+ }
 44+ }
 45+ }
 46+ if ( !isset( $this->dictionaryFile ) ) {
 47+ die( "dictionary file not found or not specified properly" );
 48+ }
 49+ if ( !is_file( $this->dictionaryFile ) or !file_exists( $this->dictionaryFile ) ) {
 50+ die( "can't read dictionary file, or it doesn't exist." );
 51+ }
 52+ }
4353
44 - $options = array();
45 - foreach ( $defaults as $key => $value ) {
46 - $options[$key] = array_key_exists( $key, $cliOptions ) ? $cliOptions[$key] : $defaults[$key];
 54+ /**
 55+ * Writes random images with random filenames to disk in current working directory
 56+ *
 57+ * @param {Integer} number of filenames to write
 58+ * @param {String} format understood by ImageMagick, such as 'jpg' or 'gif'
 59+ * @return {Array} filenames we just wrote
 60+ */
 61+ function writeImages( $number, $format ) {
 62+ $filenames = $this->getRandomFilenames( $number, $format );
 63+ foreach( $filenames as $filename ) {
 64+ $image = $this->getImage();
 65+ $image->setImageFormat( $format );
 66+ $image->writeImage( $filename );
 67+ }
 68+ return $filenames;
4769 }
4870
49 - return $options;
50 -}
5171
 72+ /**
 73+ * Return a number of randomly-generated filenames
 74+ * Each filename uses two words randomly drawn from the dictionary, like foo_bar.jpg
 75+ *
 76+ * @param {Integer} number of filenames to generate
 77+ * @param {String} extension, if desired
 78+ * @return {Array} of filenames
 79+ */
 80+ private function getRandomFilenames( $number, $extension=null ) {
 81+ $filenames = array();
5282
53 -
54 -/**
55 - * writes random images with random files to disk in current working directory
56 - *
57 - * @param {Array} key-value options
58 - */
59 -function writeRandomImages( $options ) {
60 - global $dictionary;
61 -
62 - // each filename uses two words from the dictionary
63 - $wordsDesired = $options['number'] * 2;
64 -
65 - foreach( getPairs( getRandomLines( $wordsDesired, $options['dict'] ) ) as $pair ) {
66 - $filename = $pair[0] . '_' . $pair[1] . '.' . $options['format'];
 83+ foreach( $this->getRandomWordPairs( $number ) as $pair ) {
 84+ $filename = $pair[0] . '_' . $pair[1];
 85+ if ( !is_null( $extension ) ) {
 86+ $filename .= '.' . $extension;
 87+ }
 88+ $filename = preg_replace( '/\s+/', '', $filename );
 89+ $filenames[] = $filename;
 90+ }
 91+
 92+ return $filenames;
6793
68 - // strip all whitespace (in case we somehow have inner whitespace)
69 - $filename = preg_replace( '/\s+/', '', $filename );
70 -
71 - $image = getRandomImage( $options['minWidth'], $options['maxWidth'], $options['minHeight'], $options['maxHeight'] );
72 - $image->setImageFormat( $options['format'] );
73 - $image->writeImage( $filename );
7494 }
75 -}
7695
7796
78 -/**
79 - * Generate an image consisting of randomly colored and sized circles
80 - * @return {Image}
81 - */
82 -function getRandomImage($minWidth, $maxWidth, $minHeight, $maxHeight) {
83 - global $options;
 97+ /**
 98+ * Generate an image consisting of randomly colored and sized circles
 99+ * @return {Image}
 100+ */
 101+ public function getImage() {
84102
85 - $imageWidth = mt_rand( $minWidth, $maxWidth );
86 - $imageHeight = mt_rand( $minHeight, $maxHeight );
 103+ $imageWidth = mt_rand( $this->minWidth, $this->maxWidth );
 104+ $imageHeight = mt_rand( $this->minHeight, $this->maxHeight );
87105
88 - $image = new Imagick();
89 - $image->newImage( $imageWidth, $imageHeight, new ImagickPixel( getRandomColor() ) );
 106+ $image = new Imagick();
 107+ $image->newImage( $imageWidth, $imageHeight, new ImagickPixel( $this->getRandomColor() ) );
90108
 109+ $diagonalLength = sqrt( pow( $imageWidth, 2 ) + pow( $imageHeight, 2 ) );
91110
92 - $diagonalLength = sqrt( pow( $imageWidth, 2 ) + pow( $imageHeight, 2 ) );
 111+ for ( $i = 0; $i <= $this->circlesToDraw; $i++ ) {
 112+ $radius = mt_rand( 0, $diagonalLength / 4 );
 113+ $originX = mt_rand( -1 * $radius, $imageWidth + $radius );
 114+ $originY = mt_rand( -1 * $radius, $imageHeight + $radius );
 115+ $perimeterX = $originX + $radius;
 116+ $perimeterY = $originY + $radius;
93117
94 - for ( $i = 0; $i <= 5; $i++ ) {
95 - $radius = mt_rand( 0, $diagonalLength / 4 );
96 - $originX = mt_rand( -1 * $radius, $imageWidth + $radius );
97 - $originY = mt_rand( -1 * $radius, $imageHeight + $radius );
98 - $perimeterX = $originX + $radius;
99 - $perimeterY = $originY + $radius;
 118+ $draw = new ImagickDraw();
 119+ $draw->setFillColor( $this->getRandomColor() );
 120+ $draw->circle( $originX, $originY, $perimeterX, $perimeterY );
 121+ $image->drawImage( $draw );
 122+
 123+ }
100124
101 - $draw = new ImagickDraw();
102 - $draw->setFillColor( getRandomColor() );
103 - $draw->circle( $originX, $originY, $perimeterX, $perimeterY );
104 - $image->drawImage( $draw );
105 -
 125+ return $image;
106126 }
107127
108 - return $image;
109 -}
 128+
110129
111 -
112 -
113 -/**
114 - * Generate a string of random colors for ImageMagick, like "rgb(12, 37, 98)"
115 - *
116 - * @return {String}
117 - */
118 -function getRandomColor() {
119 - $components = array();
120 - for ($i = 0; $i <= 2; $i++ ) {
121 - $components[] = mt_rand( 0, 255 );
 130+ /**
 131+ * Generate a string of random colors for ImageMagick, like "rgb(12, 37, 98)"
 132+ *
 133+ * @return {String}
 134+ */
 135+ public function getRandomColor() {
 136+ $components = array();
 137+ for ($i = 0; $i <= 2; $i++ ) {
 138+ $components[] = mt_rand( 0, 255 );
 139+ }
 140+ return 'rgb(' . join(', ', $components) . ')';
122141 }
123 - return 'rgb(' . join(', ', $components) . ')';
124 -}
125142
126 -/**
127 - * Turn an array into an array of pairs.
128 - *
129 - * @param {Array} an array
130 - * @return {Array} of two-element arrays
131 - */
132 -function getPairs( $arr ) {
133 - // construct pairs of words
134 - $pairs = array();
135 - $count = count( $arr );
136 - for( $i = 0; $i < $count; $i += 2 ) {
137 - $pairs[] = array( $arr[$i], $arr[$i+1] );
 143+ /**
 144+ * Get an array of random pairs of random words, like array( array( 'foo', 'bar' ), array( 'quux', 'baz' ) );
 145+ *
 146+ * @param {Integer} number of pairs
 147+ * @return {Array} of two-element arrays
 148+ */
 149+ private function getRandomWordPairs( $number ) {
 150+ $lines = $this->getRandomLines( $number * 2 );
 151+ // construct pairs of words
 152+ $pairs = array();
 153+ $count = count( $lines );
 154+ for( $i = 0; $i < $count; $i += 2 ) {
 155+ $pairs[] = array( $lines[$i], $lines[$i+1] );
 156+ }
 157+ return $pairs;
138158 }
139 - return $pairs;
140 -}
141159
142 -/**
143 - * Return N random lines from a file
144 - *
145 - * Will die if the file could not be read or if it had fewer lines than requested.
146 - *
147 - * @param {Integer} number of lines desired
148 - * @string {String} path to file
149 - * @return {Array} of exactly n elements, drawn randomly from lines the file
150 - */
151 -function getRandomLines( $number_desired, $filepath ) {
152 - $lines = array();
153 - for ( $i = 0; $i < $number_desired; $i++ ) {
154 - $lines[] = null;
155 - }
 160+
 161+ /**
 162+ * Return N random lines from a file
 163+ *
 164+ * Will die if the file could not be read or if it had fewer lines than requested.
 165+ *
 166+ * @param {Integer} number of lines desired
 167+ * @string {String} path to file
 168+ * @return {Array} of exactly n elements, drawn randomly from lines the file
 169+ */
 170+ private function getRandomLines( $number_desired ) {
 171+ $filepath = $this->dictionaryFile;
156172
157 - /*
158 - * This algorithm obtains N random lines from a file in one single pass. It does this by replacing elements of
159 - * a fixed-size array of lines, less and less frequently as it reads the file.
160 - */
161 - $fh = fopen( $filepath, "r" ) or die( "couldn't open $filepath" ) ;
162 - $line_number = 0;
163 - $max_index = $number_desired - 1;
164 - while( !feof( $fh ) ) {
165 - $line = fgets( $fh );
166 - if ( $line !== false ) {
167 - $line_number++;
168 - $line = trim( $line );
169 - if ( mt_rand( 0, $line_number ) <= $max_index ) {
170 - $lines[ mt_rand( 0, $max_index ) ] = $line;
 173+ // initialize array of lines
 174+ $lines = array();
 175+ for ( $i = 0; $i < $number_desired; $i++ ) {
 176+ $lines[] = null;
 177+ }
 178+
 179+ /*
 180+ * This algorithm obtains N random lines from a file in one single pass. It does this by replacing elements of
 181+ * a fixed-size array of lines, less and less frequently as it reads the file.
 182+ */
 183+ $fh = fopen( $filepath, "r" ) or die( "couldn't open $filepath" ) ;
 184+ $line_number = 0;
 185+ $max_index = $number_desired - 1;
 186+ while( !feof( $fh ) ) {
 187+ $line = fgets( $fh );
 188+ if ( $line !== false ) {
 189+ $line_number++;
 190+ $line = trim( $line );
 191+ if ( mt_rand( 0, $line_number ) <= $max_index ) {
 192+ $lines[ mt_rand( 0, $max_index ) ] = $line;
 193+ }
171194 }
172195 }
 196+ fclose( $fh );
 197+ if ( $line_number < $number_desired ) {
 198+ die( "not enough lines in $filepath" );
 199+ }
 200+
 201+ return $lines;
173202 }
174 - fclose( $fh );
175 - if ( $line_number < $number_desired ) {
176 - die( "not enough lines in $filepath" );
177 - }
178 -
179 - return $lines;
 203+
180204 }
181 -
182 -?>
Index: branches/uploadwizard/extensions/UploadWizard/test/php/scripts/generateRandomImages.php
@@ -1,181 +1,25 @@
22 <?php
33
4 -/*
5 - * generateRandomImages -- does what it says on the tin.
6 - *
7 - * Because MediaWiki tests the uniqueness of media upload content, and filenames, it is sometimes useful to generate
8 - * files that are guaranteed (or at least very likely) to be unique in both those ways.
9 - * This generates a number of filenames with random names and random content (colored circles)
10 - *
11 - * Requires Imagick, the ImageMagick library for PHP.
12 - *
13 - * @file
14 - * @author Neil Kandalgaonkar <neilk@wikimedia.org>
15 - */
 4+require("RandomImageGenerator.php");
165
17 -$defaults = array(
18 - 'dict' => "/usr/share/dict/words",
19 - 'number' => 10,
20 - 'minWidth' => 400,
21 - 'maxWidth' => 800,
22 - 'minHeight' => 400,
23 - 'maxHeight' => 800,
24 - 'format' => 'jpg'
 6+$getOptSpec = array(
 7+ 'dictionaryFile::',
 8+ 'minWidth::',
 9+ 'maxWidth::',
 10+ 'minHeight::',
 11+ 'maxHeight::',
 12+ 'circlesToDraw::',
 13+
 14+ 'number::',
 15+ 'format::'
2516 );
 17+$options = getopt( null, $getOptSpec );
2618
27 -writeRandomImages( getOptions( $defaults ) );
 19+$format = isset( $options['format'] ) ? $options['format'] : 'jpg';
 20+unset( $options['format'] );
2821
 22+$number = isset( $options['number'] ) ? int( $options['number'] ) : 10;
 23+unset( $options['number'] );
2924
30 -
31 -
32 -/**
33 - * Override defaults with command-line options
34 - *
35 - * @param {Array} key-value default values
36 - * @return {Array} defaults with CLI overrides
37 - */
38 -function getOptions( $defaults ) {
39 -
40 - // all options are optional, so append '::' to spec
41 - $getoptSpec = array_map( function($s) { return $s . "::"; }, array_keys( $defaults ) );
42 - $cliOptions = getopt( null, $getoptSpec );
43 -
44 - $options = array();
45 - foreach ( $defaults as $key => $value ) {
46 - $options[$key] = array_key_exists( $key, $cliOptions ) ? $cliOptions[$key] : $defaults[$key];
47 - }
48 -
49 - return $options;
50 -}
51 -
52 -
53 -
54 -/**
55 - * writes random images with random files to disk in current working directory
56 - *
57 - * @param {Array} key-value options
58 - */
59 -function writeRandomImages( $options ) {
60 - global $dictionary;
61 -
62 - // each filename uses two words from the dictionary
63 - $wordsDesired = $options['number'] * 2;
64 -
65 - foreach( getPairs( getRandomLines( $wordsDesired, $options['dict'] ) ) as $pair ) {
66 - $filename = $pair[0] . '_' . $pair[1] . '.' . $options['format'];
67 -
68 - // strip all whitespace (in case we somehow have inner whitespace)
69 - $filename = preg_replace( '/\s+/', '', $filename );
70 -
71 - $image = getRandomImage( $options['minWidth'], $options['maxWidth'], $options['minHeight'], $options['maxHeight'] );
72 - $image->setImageFormat( $options['format'] );
73 - $image->writeImage( $filename );
74 - }
75 -}
76 -
77 -
78 -/**
79 - * Generate an image consisting of randomly colored and sized circles
80 - * @return {Image}
81 - */
82 -function getRandomImage($minWidth, $maxWidth, $minHeight, $maxHeight) {
83 - global $options;
84 -
85 - $imageWidth = mt_rand( $minWidth, $maxWidth );
86 - $imageHeight = mt_rand( $minHeight, $maxHeight );
87 -
88 - $image = new Imagick();
89 - $image->newImage( $imageWidth, $imageHeight, new ImagickPixel( getRandomColor() ) );
90 -
91 -
92 - $diagonalLength = sqrt( pow( $imageWidth, 2 ) + pow( $imageHeight, 2 ) );
93 -
94 - for ( $i = 0; $i <= 5; $i++ ) {
95 - $radius = mt_rand( 0, $diagonalLength / 4 );
96 - $originX = mt_rand( -1 * $radius, $imageWidth + $radius );
97 - $originY = mt_rand( -1 * $radius, $imageHeight + $radius );
98 - $perimeterX = $originX + $radius;
99 - $perimeterY = $originY + $radius;
100 -
101 - $draw = new ImagickDraw();
102 - $draw->setFillColor( getRandomColor() );
103 - $draw->circle( $originX, $originY, $perimeterX, $perimeterY );
104 - $image->drawImage( $draw );
105 -
106 - }
107 -
108 - return $image;
109 -}
110 -
111 -
112 -
113 -/**
114 - * Generate a string of random colors for ImageMagick, like "rgb(12, 37, 98)"
115 - *
116 - * @return {String}
117 - */
118 -function getRandomColor() {
119 - $components = array();
120 - for ($i = 0; $i <= 2; $i++ ) {
121 - $components[] = mt_rand( 0, 255 );
122 - }
123 - return 'rgb(' . join(', ', $components) . ')';
124 -}
125 -
126 -/**
127 - * Turn an array into an array of pairs.
128 - *
129 - * @param {Array} an array
130 - * @return {Array} of two-element arrays
131 - */
132 -function getPairs( $arr ) {
133 - // construct pairs of words
134 - $pairs = array();
135 - $count = count( $arr );
136 - for( $i = 0; $i < $count; $i += 2 ) {
137 - $pairs[] = array( $arr[$i], $arr[$i+1] );
138 - }
139 - return $pairs;
140 -}
141 -
142 -/**
143 - * Return N random lines from a file
144 - *
145 - * Will die if the file could not be read or if it had fewer lines than requested.
146 - *
147 - * @param {Integer} number of lines desired
148 - * @string {String} path to file
149 - * @return {Array} of exactly n elements, drawn randomly from lines the file
150 - */
151 -function getRandomLines( $number_desired, $filepath ) {
152 - $lines = array();
153 - for ( $i = 0; $i < $number_desired; $i++ ) {
154 - $lines[] = null;
155 - }
156 -
157 - /*
158 - * This algorithm obtains N random lines from a file in one single pass. It does this by replacing elements of
159 - * a fixed-size array of lines, less and less frequently as it reads the file.
160 - */
161 - $fh = fopen( $filepath, "r" ) or die( "couldn't open $filepath" ) ;
162 - $line_number = 0;
163 - $max_index = $number_desired - 1;
164 - while( !feof( $fh ) ) {
165 - $line = fgets( $fh );
166 - if ( $line !== false ) {
167 - $line_number++;
168 - $line = trim( $line );
169 - if ( mt_rand( 0, $line_number ) <= $max_index ) {
170 - $lines[ mt_rand( 0, $max_index ) ] = $line;
171 - }
172 - }
173 - }
174 - fclose( $fh );
175 - if ( $line_number < $number_desired ) {
176 - die( "not enough lines in $filepath" );
177 - }
178 -
179 - return $lines;
180 -}
181 -
182 -?>
 25+$randomImageGenerator = new RandomImageGenerator( $options );
 26+$randomImageGenerator->writeImages( $number, $format );

Status & tagging log