Skip to content

Instantly share code, notes, and snippets.

@FiveYellowMice
Last active May 3, 2017 00:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FiveYellowMice/40afb435a01d89b4f2bddd88595c74f6 to your computer and use it in GitHub Desktop.
Save FiveYellowMice/40afb435a01d89b4f2bddd88595c74f6 to your computer and use it in GitHub Desktop.
<?php
define('PREPARED_MOONS', [
'apple_new_moon_with_face',
'apple_full_moon_with_face',
'apple_ios10_new_moon_with_face',
'apple_ios10_full_moon_with_face',
'noto_new_moon_with_face',
'noto_full_moon_with_face',
'segoe_new_moon_with_face',
'segoe_full_moon_with_face',
'apple_new_moon',
'apple_full_moon',
'apple_ios10_new_moon',
'apple_ios10_full_moon',
'noto_new_moon',
'noto_full_moon',
'segoe_new_moon',
'segoe_full_moon',
]);
class InvalidParameterException extends Exception {}
function expect_param($name) {
if (!array_key_exists($name, $_GET) || in_array($_GET[$name], [null, ''])) {
throw new InvalidParameterException("Parameter $name is required but not specified.");
}
return $_GET[$name];
}
function rand_float($min, $max) {
return lcg_value() * ($max - $min) + $min;
}
if (!in_array($_SERVER['REQUEST_METHOD'], ['GET', 'HEAD'])) {
http_response_code(405);
header('Cache-Control: no-cache');
header('Content-Type: text/plain');
header('Content-Length: 20');
echo "Method not allowed.\n";
die();
}
try {
$canvas_width = intval(expect_param('width'));
if ($canvas_width <= 0 || $canvas_width > 3840) {
throw new InvalidParameterException("Width must be a number between 0 and 3840.");
}
$canvas_height = intval(expect_param('height'));
if ($canvas_height <= 0 || $canvas_height > 2160) {
throw new InvalidParameterException("Height must be a number between 0 and 2160.");
}
$moon_count = intval(expect_param('count'));
if ($moon_count <= 0 || $moon_count > 512) {
throw new InvalidParameterException("Count must be a number between 0 and 512.");
}
$background = expect_param('background');
if (!in_array($background, ['black', 'white', 'transparent'])) {
throw new InvalidParameterException("Background must be \"black\", \"white\" or \"transparent\".");
}
$output_format = expect_param('format');
if (!in_array($output_format, ['jpeg', 'png', 'webp'])) {
throw new InvalidParameterException("Format must be \"jpeg\", \"png\" or \"webp\".");
}
$moon_settings = array_map(function($w) {
$q = explode(',', $w);
if (sizeof($q) !== 3) {
throw new InvalidParameterException('Each moons must have 3 parameters.');
}
if (!in_array($q[0], PREPARED_MOONS)) {
throw new InvalidParameterException("$q[0] is not a valid moon name.");
}
$q[1] = (float) $q[1];
if ($q[1] <= 0 || $q[1] > 128) {
throw new InvalidParameterException("Moon minimum scale size must be a number between 0 and 128.");
}
$q[2] = (float) $q[2];
if ($q[2] <= 0 || $q[2] > 128) {
throw new InvalidParameterException("Moon maximum scale size must be a number between 0 and 128.");
}
return [
'image_path' => 'prepared-moons/'.$q[0].'.png',
'min_scale' => $q[1],
'max_scale' => $q[2],
];
}, explode(';', expect_param('moons')));
if (sizeof($moon_settings) > 16) {
throw new InvalidParameterException("Too many moons.");
}
} catch (InvalidParameterException $e) {
http_response_code(400);
header('Cache-Control: no-cache');
header('Content-Type: text/plain');
header('Content-Length: '.(strlen($e->getMessage()) + 1));
header('X-Error: '.$e->getMessage());
echo $e->getMessage()."\n";
die();
}
$black = new ImagickPixel('black');
$white = new ImagickPixel('white');
$transparent = new ImagickPixel('transparent');
$moons = array_map(function($moon) {
$moon['image'] = new Imagick($moon['image_path']);
return $moon;
}, $moon_settings);
$canvas = new Imagick();
$canvas->newImage($canvas_width, $canvas_height, [
'black' => $black,
'white' => $white,
'transparent' => $transparent,
][$background]);
for ($i = 0; $i < $moon_count; $i++) {
$moon = $moons[array_rand($moons)];
$changed_moon = clone $moon['image'];
$scale = rand_float($moon['min_scale'], $moon['max_scale']);
$moon_width = round($changed_moon->getImageWidth() * $scale);
$moon_height = round($changed_moon->getImageHeight() * $scale);
$moon_size = min($moon_width, $moon_height);
$changed_moon->scaleImage($moon_width, $moon_height);
$changed_moon->rotateImage($transparent, rand_float(0, 360));
$canvas->compositeImage(
$changed_moon,
imagick::COMPOSITE_OVER,
($moon_size - $changed_moon->getImageWidth()) / 2 + rand(0, $canvas_width - $moon_size),
($moon_size - $changed_moon->getImageHeight()) / 2 + rand(0, $canvas_height - $moon_size)
);
$changed_moon->clear();
}
foreach ($moons as $moon) {
$moon['image']->clear();
}
$canvas->setImageFormat($output_format);
$canvas->setImageCompressionQuality(90);
header('Content-Type: image/'.$output_format);
header('Cache-Control: no-cache');
header('Content-Length: '.strlen($canvas));
echo $canvas;
$canvas->clear();
$black->clear();
$white->clear();
$transparent->clear();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment