-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathnoise.php
513 lines (480 loc) · 17.4 KB
/
noise.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
<?php
/**
* noise.php
*
* A script for generating (random) noise background images.
*
* @author RundesBalli <[email protected]>
* @copyright 2022 RundesBalli
* @version 1.2
* @see https://github.com/RundesBalli/php-noise
*/
/**
* Default configuration
*/
$tiles = 50; // $tiles x $tiles tiles
$tileSize = 7; // Pixels per tile
$borderWidth = 0; // Width of the grid between tiles
$mode = "brightness"; // Color calculation mode: brightness, around
$multiplicator = 1.5; // Multiplicator for calculation in brightness mode
$steps = 5; // Number of colors above and below the reference color in brightness mode
/**
* Into text
*/
$introText = " __
/\\ \\ __
_____\\ \\ \\___ _____ ___ ___ /\\_\\ ____ __
/\\ '__`\\ \\ _ `\\/\\ '__`\\ _______ /' _ `\\ / __`\\/\\ \\ /',__\\ /'__`\\
\\ \\ \\L\\ \\ \\ \\ \\ \\ \\ \\L\\ \\/\\______\\/\\ \\/\\ \\/\\ \\L\\ \\ \\ \\/\\__, `\\/\\ __/
\\ \\ ,__/\\ \\_\\ \\_\\ \\ ,__/\\/______/\\ \\_\\ \\_\\ \\____/\\ \\_\\/\\____/\\ \\____\\
\\ \\ \\/ \\/_/\\/_/\\ \\ \\/ \\/_/\\/_/\\/___/ \\/_/\\/___/ \\/____/
\\ \\_\\ \\ \\_\\
\\/_/ \\/_/\n\n";
// http://www.network-science.de/ascii/ Font: larry3d
$introText.= "PHP noise image generator v1.2\n\n";
$introText.= "Visit: https://RundesBalli.com\n";
$introText.= " https://github.com/RundesBalli/php-noise\n\n";
/**
* Help text
*/
$help = "Usage:\n";
$help.= "All parameters are optional.\n";
$help.= "-h, --help\n\tShows this help text and exits the script.\n";
$help.= "--hex <value>\n\tColor HEX Code\n\tPossible values: #000000-#FFFFFF\n\tThe hash (#) must not be provided. If the parameter is provided, the -r -g -b parameters will be ignored.\n\tIf the Hex-Code is invalid, a random color will be generated.\n";
$help.= "-r <value>, -g <value>, -b <value>\n\tRed, green, blue\n\tPossible values: 0-255\n\tIf one of the parameters is invalid or not provided, it will be generated randomly.\n\tIf the --hex parameter is provided, all three of these parameters will be ignored.\n";
$help.= "--tiles <value>\n\tNumber of tiles per row and column.\n\tThe image is square, therefore it hast \$tiles x \$tiles tiles.\n\tDefault: ".$tiles."\n\tIn CLI this value isn't capped. Outside of the CLI its capped to 50.\n";
$help.= "--tileSize <value>\n\tWidth and height of one tile in pixels.\n\tDefault: ".$tileSize."\n\tIn CLI this value isn't capped. Outside of the CLI its capped to 20.\n";
$help.= "--borderWidth <value>\n\tWidth of the grid which is drawed between tiles in pixels.\n\tDefault: ".$borderWidth."\n\tIn CLI this value isn't capped. Outside of the CLI its capped to 15.\n";
$help.= "--mode <value>\n\tColor calculation mode.\n\t1. brightness:\tCalculates the colors by brightness adjustments based on the reference color.\n\t2. around:\tCalculates the colors randomly around the reference color.\n\tDefault: ".$mode."\n";
$help.= "--multi <value> (only in brightness mode)\n\tIncreases or decreases the percentage spacing between colors.\n\tAllowed values are positive floating point numbers with one decimal place.\n\tDefault: ".$multiplicator."\n";
$help.= "--steps <value> (only in brightness mode)\n\tIncreases or decreases the number of possible colors above and below the reference color.\n\tDefault: ".$steps."\n\tIn CLI this value isn't capped. Outside of the CLI its capped to 50.\n";
$help.= "--json\n\tSaves the image and returns a JSON-String with the filename.\n\tOnly via GET in browsermode.\n";
$help.= "--base64\n\tOnly in combination with the JSON output.\n\tExports the base64 string of the image in the base64 field in the JSON output.";
$help.= "\n";
/**
* colorPicker function
*
* @param array The provided $paramColors from the user.
*
* @return array The validated or randomly generated colors.
*/
function colorPicker(array $paramColors = array()) {
$arg = array();
$arg['r'] = (((isset($paramColors['r']) AND is_numeric($paramColors['r'])) AND (intval($paramColors['r']) >= 0 AND intval($paramColors['r']) <= 255)) ? intval($paramColors['r']) : random_int(0, 255));
$arg['g'] = (((isset($paramColors['g']) AND is_numeric($paramColors['g'])) AND (intval($paramColors['g']) >= 0 AND intval($paramColors['g']) <= 255)) ? intval($paramColors['g']) : random_int(0, 255));
$arg['b'] = (((isset($paramColors['b']) AND is_numeric($paramColors['b'])) AND (intval($paramColors['b']) >= 0 AND intval($paramColors['b']) <= 255)) ? intval($paramColors['b']) : random_int(0, 255));
return $arg;
}
/**
* hex2rgb function
*
* Calculates a hex code (3 or 6 digit) to RGB.
*
* @author RundesBalli <[email protected]>
* @copyright 2020 RundesBalli
* @version 1.0
* @license MIT-License
* @see https://gist.github.com/RundesBalli/32f5491df25abb7fe0864e6447a26b75
* @see https://www.php.net/manual/en/function.hexdec.php#99478
* @see https://stackoverflow.com/questions/1636350/how-to-identify-a-given-string-is-hex-color-format/1637260#1637260
*
* @param string $hex The hex string to be calculated.
*
* @return array or boolean The RGB array or false.
*/
function hex2rgb($hex) {
if(preg_match("/^(?:(?:[0-9a-f]{2}){3}|(?:[0-9a-f]){3})$/i", preg_replace("/[^0-9a-f]/i", "", $hex), $result) === 1) {
if(strlen($result[0]) == 6) {
return array(
"r" => hexdec(substr($result[0], 0, 2)),
"g" => hexdec(substr($result[0], 2, 2)),
"b" => hexdec(substr($result[0], 4, 2)),
"hex" => $result[0]
);
} elseif(strlen($result[0]) == 3) {
return array(
"r" => hexdec(str_repeat(substr($result[0], 0, 1), 2)),
"g" => hexdec(str_repeat(substr($result[0], 1, 1), 2)),
"b" => hexdec(str_repeat(substr($result[0], 2, 1), 2)),
"hex" => $result[0]
);
} else {
return FALSE;
}
} else {
return FALSE;
}
}
/**
* Check if the script is called via CLI or via browser.
*/
if(php_sapi_name() == 'cli') {
/**
* Script is called via CLI.
*/
$verbose = 1;
echo $introText;
/**
* Read arguments provided by CLI script call.
*/
$options = getopt("hr:g:b:", array("help", "tiles:", "tileSize:", "borderWidth:", "mode:", "json", "hex:", "multi:", "steps:"));
/**
* If the JSON parameter is provided via CLI, a note will be shown.
*/
if(isset($options['json'])) {
die("Error: JSON only in browsermode!\n");
}
/**
* If help is called, show help text and exit script.
*/
if(isset($options['h']) OR isset($options['help'])) {
die($help);
}
/**
* Checks the color calculation mode
*/
if(!empty($options['mode'])) {
if($options['mode'] == "brightness") {
$mode = "brightness";
} elseif($options['mode'] == "around") {
$mode = "around";
}
// No else: Mode is set by default options.
}
/**
* Check parameters for brightness mode.
*/
if($mode == "brightness") {
if(!empty($options['multi'])) {
/**
* Check if the provided multiplicator is above 0.
*/
$newMulti = round(floatval($options['multi']), 1);
if($newMulti > 0) {
$multiplicator = $newMulti;
}
}
if(!empty($options['steps'])) {
/**
* Check if the provided steps value is above 0.
*/
$newSteps = intval($options['steps']);
if($newSteps > 0) {
$steps = $newSteps;
}
}
}
/**
* If a hex code is provided, use the hex code and ignore the rgb values.
*/
if(!empty($options['hex'])) {
$hex = hex2rgb($options['hex']);
if($hex) {
$arg = colorPicker($hex);
$filename = "noise_hex-".$hex['hex']."-t".$tiles."-tS".$tileSize."-bW".$borderWidth."-m".($mode == "around" ? "A" : "B-mu".$multiplicator."-st".$steps)."_".md5(date("Y-m-d_H-i-s").microtime()).".png";
} else {
$arg = colorPicker($options);
}
} else {
$arg = colorPicker($options);
}
$tiles = ((isset($options['tiles']) AND is_numeric($options['tiles'])) ? intval($options['tiles']) : $tiles);
$tileSize = ((isset($options['tileSize']) AND is_numeric($options['tileSize'])) ? intval($options['tileSize']) : $tileSize);
$borderWidth = ((isset($options['borderWidth']) AND is_numeric($options['borderWidth'])) ? intval($options['borderWidth']) : $borderWidth);
unset($options);
} else {
/**
* Script is called via browser.
*/
$verbose = 0;
if(isset($_GET['h']) OR isset($_GET['help'])) {
header("Content-Type: text/plain");
echo $introText;
echo $help;
echo "In a browser, you can simply provide those parameters via GET.\n\n";
echo "Please report bugs to:\nhttps://github.com/RundesBalli/php-noise/issues\n";
die();
}
/**
* Checks the color calculation mode
*/
if(!empty($_GET['mode'])) {
if($_GET['mode'] == "brightness") {
$mode = "brightness";
} elseif($_GET['mode'] == "around") {
$mode = "around";
}
// No else: Mode is set by default options.
}
/**
* Check parameters for brightness mode.
*/
if($mode == "brightness") {
if(!empty($_GET['multi'])) {
/**
* Check if the provided multiplicator is above 0.
*/
$newMulti = round(floatval($_GET['multi']), 1);
if($newMulti > 0) {
$multiplicator = $newMulti;
}
}
if(!empty($_GET['steps'])) {
/**
* Check if the provided steps value is above 0 and below or equal to 50.
*/
$newSteps = intval($_GET['steps']);
if($newSteps > 0 AND $newSteps <= 50) {
$steps = $newSteps;
}
}
}
/**
* If a hex code is provided, use the hex code and ignore the rgb values.
*/
if(!empty($_GET['hex'])) {
$hex = hex2rgb($_GET['hex']);
if($hex) {
$arg = colorPicker($hex);
$filename = "noise_hex-".$hex['hex']."-t".$tiles."-tS".$tileSize."-bW".$borderWidth."-m".($mode == "around" ? "A" : "B-mu".$multiplicator."-st".$steps)."_".md5(date("Y-m-d_H-i-s").microtime()).".png";
} else {
$arg = colorPicker($_GET);
}
} else {
$arg = colorPicker($_GET);
}
$tiles = (((isset($_GET['tiles']) AND is_numeric($_GET['tiles'])) AND (intval($_GET['tiles']) > 0 AND intval($_GET['tiles']) <= 50)) ? intval($_GET['tiles']) : $tiles);
$tileSize = (((isset($_GET['tileSize']) AND is_numeric($_GET['tileSize'])) AND (intval($_GET['tileSize']) > 0 AND intval($_GET['tileSize']) <= 20)) ? intval($_GET['tileSize']) : $tileSize);
$borderWidth = (((isset($_GET['borderWidth']) AND is_numeric($_GET['borderWidth'])) AND (intval($_GET['borderWidth']) >= 0 AND intval($_GET['borderWidth']) <= 15)) ? intval($_GET['borderWidth']) : $borderWidth);
$json = (isset($_GET['json']) ? 1 : 0);
}
/**
* Image parameters
*/
$x = ($tiles*$tileSize)+($tiles*$borderWidth);
$y = $x;
/**
* Color calculation mode
*/
if($mode == "around") {
/**
* "around" mode
*
* Calculates the colors randomly around the reference color.
* Every color should have 20 possible values around the provided parameter value.
* If the value exceeds the minimum (0) or maximum (255), it will be set to the immediate maximum or minimum value instead.
*/
if($verbose == 1) {
echo "Selected/generated colors (min|max):\n";
}
$color = array();
foreach($arg AS $key => $val) {
if($verbose == 1) {
echo strtoupper($key).": ".$val." ";
}
if($val < 10) {
$color[$key]['min'] = 0;
$color[$key]['max'] = 19;
} elseif($val > 245) {
$color[$key]['min'] = 236;
$color[$key]['max'] = 255;
} else {
/**
* If the given value is within the enforced minimum (0) / maximum (255) boundaries (including an additional
* padding of 10 units from the min/max), a new boundary for the given value is calculated based on a random
* approximation towards the initial lower or upper boundary, thus, yielding new minima/maxima for further
* calculations.
*/
if(random_int(0, 1)) {
$color[$key]['min'] = $val-9;
$color[$key]['max'] = $val+10;
} else {
$color[$key]['min'] = $val-10;
$color[$key]['max'] = $val+9;
}
}
if($verbose == 1) {
echo "(".$color[$key]['min']."|".$color[$key]['max'].")\n";
}
}
if($verbose == 1) {
echo "\n";
}
/**
* Generate all possible color arrays.
*/
$colors = array();
for($i = $color['r']['min']; $i <= $color['r']['max']; $i++) {
for($j = $color['g']['min']; $j <= $color['g']['max']; $j++) {
for($k = $color['b']['min']; $k <= $color['b']['max']; $k++) {
$colors[] = [$i, $j, $k];
}
}
}
if($verbose == 1) {
echo "Possible colors generated: ".count($colors)."\n\n";
}
/**
* Generate the random border color.
*/
if($verbose == 1) {
echo "Generated border color:\n";
}
$borderColor = array();
foreach($color AS $key => $val) {
$borderColor[$key] = random_int($val['min'], $val['max']);
if($verbose == 1) {
echo strtoupper($key).": ".$borderColor[$key]."\n";
}
}
if($verbose == 1) {
echo "\n";
}
/**
* Delete the border color from the possible colors array.
*/
if(isset($colors[array_search([$borderColor['r'], $borderColor['g'], $borderColor['b']], $colors, true)])) {
unset($colors[array_search([$borderColor['r'], $borderColor['g'], $borderColor['b']], $colors, true)]);
if($verbose == 1) {
echo "Info: Border color deleted from possible colors array.\n\n";
}
}
} else {
/**
* "brightness" mode
*
* Calculates the colors by brightness adjustments based on the reference color.
*/
/**
* User selected or random generated color
*/
$r = $arg['r'];
$g = $arg['g'];
$b = $arg['b'];
if($verbose == 1) {
echo "Reference color:\nR: ".$r."\nG: ".$g."\nB: ".$b."\n\n";
}
$colors = array();
/**
* Generate color shades beyond the reference color.
*/
for($i=$steps;$i>=1;$i--) {
$r1 = round($r-($r/100*($i*$multiplicator)), 0);
if($r1 < 0) {
$r1 = 0;
}
$g1 = round($g-($g/100*($i*$multiplicator)), 0);
if($g1 < 0) {
$g1 = 0;
}
$b1 = round($b-($b/100*($i*$multiplicator)), 0);
if($b1 < 0) {
$b1 = 0;
}
$colors[] = [$r1, $g1, $b1];
}
/**
* If there are no borders, the script can use the reference color in the color spectre.
* Otherwise the reference color is used as $borderColor.
*/
if($borderWidth == 0) {
$colors[] = [$r, $g, $b];
} else {
if($verbose == 1) {
echo "Border color: same as reference color.\nR: ".$r."\nG: ".$g."\nB: ".$b."\n\n";
}
$borderColor = ["r" => $r, "g" => $g, "b" => $b];
}
/**
* Generate color shades above the reference color.
*/
for($i=1;$i<=$steps;$i++) {
$r1 = round($r+($r/100*($i*$multiplicator)), 0);
if($r1 > 255) {
$r1 = 255;
}
$g1 = round($g+($g/100*($i*$multiplicator)), 0);
if($g1 > 255) {
$g1 = 255;
}
$b1 = round($b+($b/100*($i*$multiplicator)), 0);
if($b1 > 255) {
$b1 = 255;
}
$colors[] = [$r1,$g1,$b1];
}
/**
* It is possible by percentage calculation that there are duplicate values in the array. These are cleaned up here.
*/
$colors = array_unique($colors, SORT_REGULAR);
if($verbose == 1) {
echo "Possible colors generated: ".count($colors)."\n\n";
}
}
/**
* Create image resource
*/
$im = imagecreatetruecolor($x, $y);
/**
* Draw grid between tiles, if borderWidth > 0
*/
if($borderWidth > 0) {
$draw_x = 0;
$draw_y = 0;
while($draw_x < $x) {
$draw_x = $draw_x + $tileSize;
imagefilledrectangle($im, $draw_x, 0, ($draw_x + ($borderWidth-1)), $y, imagecolorallocate($im, $borderColor['r'], $borderColor['g'], $borderColor['b']));
$draw_x = $draw_x + $borderWidth;
}
while($draw_y < $y) {
$draw_y = $draw_y + $tileSize;
imagefilledrectangle($im, 0, $draw_y, $x, ($draw_y + ($borderWidth-1)), imagecolorallocate($im, $borderColor['r'], $borderColor['g'], $borderColor['b']));
$draw_y = $draw_y + $borderWidth;
}
}
/**
* Draw the tiles
*/
$draw_x = 0;
$draw_y = 0;
while($draw_x < $x) {
$draw_y = 0;
while($draw_y < $y) {
$randomColor = $colors[array_rand($colors)];
$tileColor = imagecolorallocate($im, $randomColor[0], $randomColor[1], $randomColor[2]);
imagefilledrectangle($im, $draw_x, $draw_y, $draw_x+$tileSize-1, $draw_y+$tileSize-1, $tileColor);
$draw_y = $draw_y+$tileSize+$borderWidth;
}
$draw_x = $draw_x+$tileSize+$borderWidth;
}
/**
* Save/Output the imagefile
*/
if(empty($filename)) {
/**
* If a valid hex value is provided, the filename will be generated above.
*/
$filename = "noise_r".$arg['r']."-g".$arg['g']."-b".$arg['b']."-t".$tiles."-tS".$tileSize."-bW".$borderWidth."-m".($mode == "around" ? "A" : "B-mu".$multiplicator."-st".$steps)."_".md5(date("Y-m-d_H-i-s").microtime()).".png";
}
if($verbose == 1) {
imagePNG($im, "./images/".$filename);
echo "Output to:\n".realpath("./images/".$filename)."\n\n";
echo "Please report bugs to:\nhttps://github.com/RundesBalli/php-noise/issues\n";
} else {
if($json == 1) {
imagePNG($im, "./images/".$filename);
header('Content-Type: application/json');
$output = array(
"uri" => "https://".$_SERVER['HTTP_HOST']."/images/".pathinfo($filename)['basename'],
);
if(isset($_GET['base64'])) {
$output['base64'] = "data:image/png;base64,".base64_encode(file_get_contents("./images/".$filename));
}
die(json_encode($output));
} else {
header('Content-Type: image/png');
imagePNG($im);
}
}
imagedestroy($im);
?>