Skip to content

Instantly share code, notes, and snippets.

@maxpert
Last active October 29, 2017 06:40
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maxpert/eb4d8c588808276c6393 to your computer and use it in GitHub Desktop.
Save maxpert/eb4d8c588808276c6393 to your computer and use it in GitHub Desktop.
PHP Long shadow icon generator.
# for neater URLS like /{text}/{size}/{bg}
RewriteEngine on
RewriteRule ^img/([^/]+)/(\d+)/([a-fA-F0-9]{6})$ i/index.php?text=$1&size=$2&bg=$3 [NC,QSA]
RewriteRule ^img/([^/]+)/(\d+)$ i/index.php?text=$1&size=$2 [NC,QSA]
RewriteRule ^img/([^/]+)$ i/index.php?text=$1 [NC,QSA]
RewriteRule ^img/([^/]+)/.+$ i/index.php?text=$1 [NC,QSA]
<?php
/**
* Copyright 2014 Zohaib Sibte Hassan
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// --------------------------------- Configuration variables
// These are configuration variables that you can modify
// Customize them as much as you want
// Here are list of parameters you can pass:
// - size: Size of image
// - font: font name to use
// - text: text value to render
// - bg: background color
// - fg: foreground color
// - sh: shadow color
// - slope_x: shadow slope along x-axis (1 towards right, -1 towards left)
// - slope_y: shadow slope along y-axis (1 towards bottom, -1 towards top)
// Cache path
// Make it NULL in case you don't want to cache the results
$ImageCacheDir = realpath(__DIR__.'/../cached');
// Default image size
$DefaultImageSize = 128;
// Maximum size of image in pixels
// Use a decent value to throttle CPU/memory usage
$MaxImageSize = 512;
// Directory containing fonts
$FontDirectory = __DIR__.'/../fonts';
// List of supported fonts
// It's a map of name => font file path that is used to render initials
// Font name is passed as ```font``` query parameter
$FontsList = array(
// Source sans by adobe, available at https://github.com/adobe-fonts/source-sans-pro/releases
's' => 'SourceSansVariable-Roman.ttf',
// Gidolinya available at http://gidole.github.io/
'g' => 'Gidolinya-Regular.otf',
// Opensans
'o' => 'OpenSans-Regulare.ttf',
// PT Sans Narrow
'p' => 'PTN77F.ttf',
// Multilingual NotoSans font
'n' => array (
'common' => 'NotoSans-Regular.ttf',
'latin' => 'NotoSans-Regular.ttf',
'arabic' => 'script/NotoNaskhArabic-Regular.ttf',
'armenian' => 'script/NotoSans-Armenian-Regular.ttf',
'bengali' => 'script/NotoSans-Bengali-Regular.ttf',
'han' => 'script/Noto-CJKJP-Regular.otf',
'hiragana' => 'script/Noto-CJKJP-Regular.otf',
'katakana' => 'script/Noto-CJKJP-Regular.otf',
'thai' => 'script/NotoSans-Thai-Regular.ttf',
'georgian' => 'script/NotoSans-Georgian-Regular.ttf',
'mongolian' => 'script/NotoSans-Mongolian-Regular.ttf',
'hebrew' => 'script/NotoSans-Hebrew-Regular.ttf',
'tibetan' => 'script/NotoSans-Tibetan-Regular.ttf',
),
);
// Default font name if the parameter is not specified
$DefaultFontName = 'n';
// Font scaled size (it's used as ImageSize * FontScaledSize)
// Each font might have different value due to ligature
$FontScaledSize = 0.35;
// Default background color auto or hex value without # e.g. ffaa11
$DefaultBackgroundColor = 'auto';
// Color pallete for auto selecting colors
$ColorPalette = array(
'1abc9c', '3498db', '9b59b6',
'34495e', 'f1c40f', 'e67e22',
'e74c3c', '8764B8');
// Default text
$DefaultText = 'HI';
// Default shadow slope along x-axis
$DefaultSlopeX = 1;
// Default shadow slope along y-axis
$DefaultSlopeY = 1;
// ---------------------- Only modify beyond this if you know what you are doing :)
// --------------------------------------------------------------------------------
mb_language('uni');
mb_internal_encoding('UTF-8');
// Supported language ligatures
$LanguageFontNamePrefix = array(
'Arabic',
'Armenian',
'Bengali',
'Bopomofo',
'Braille',
'Buhid',
'Canadian_Aboriginal',
'Cherokee',
'Cyrillic',
'Devanagari',
'Ethiopic',
'Georgian',
'Greek',
'Gujarati',
'Gurmukhi',
'Han',
'Hangul',
'Hanunoo',
'Hebrew',
'Hiragana',
'Inherited',
'Kannada',
'Katakana',
'Khmer',
'Lao',
'Latin',
'Limbu',
'Malayalam',
'Mongolian',
'Myanmar',
'Ogham',
'Oriya',
'Runic',
'Sinhala',
'Syriac',
'Tagalog',
'Tagbanwa',
'Tai_Le',
'Tamil',
'Telugu',
'Thaana',
'Thai',
'Tibetan',
'Yi',
'Common'
);
function req_get($name, $default = null) {
return isset($_GET[$name]) ? $_GET[$name] : $default;
}
function hex2rgb($hex) {
if (is_array($hex)){
return $hex;
}
$hex = str_replace("#", "", $hex);
if(strlen($hex) == 3) {
$r = hexdec(substr($hex,0,1).substr($hex,0,1));
$g = hexdec(substr($hex,1,1).substr($hex,1,1));
$b = hexdec(substr($hex,2,1).substr($hex,2,1));
} else {
$r = hexdec(substr($hex,0,2));
$g = hexdec(substr($hex,2,2));
$b = hexdec(substr($hex,4,2));
}
$rgb = array($r, $g, $b);
return $rgb; // returns an array with the rgb values
}
function brighten($color, $steps) {
list($r, $g, $b) = $color;
$r = max(0,min(255,$r + $steps));
$g = max(0,min(255,$g + $steps));
$b = max(0,min(255,$b + $steps));
return array($r, $g, $b);
}
function normalize_slope($p) {
if($p > 1) {
return 1;
}
if($p < -1) {
return -1;
}
return $p;
}
function get_str_lang($txt) {
global $LanguageFontNamePrefix;
foreach ($LanguageFontNamePrefix as $lang) {
$exp = '/\p{'.$lang.'}/u';
if (preg_match($exp, $txt)) {
return $lang;
}
}
return 'Latin';
}
function get_font_file($txt, $name) {
global $FontsList, $FontDirectory;
if (!isset($FontsList[$name])) {
throw new Exception("No font defined for $name");
}
$info = $FontsList[$name];
if (is_string($info)) {
return $FontDirectory.'/'.$info;
}
$lang = strtolower(get_str_lang($txt));
if (isset($info[$lang])) {
return $FontDirectory.'/'.$info[$lang];
}
if (isset($info['common'])) {
return $FontDirectory.'/'.$info['common'];
}
return $FontDirectory.'/'.$info['latin'];
}
function get_cache_path($ids) {
global $ImageCacheDir;
if (is_null($ImageCacheDir)) {
return null;
}
return $ImageCacheDir . '/' . hash('sha256', serialize($ids)) . '.png';
}
function render_image($string, $image_width, $image_height, $font_size, $font_file, $bg_color, $fg_color, $shadow_color, $x_slope, $y_slope) {
$cache_path = get_cache_path(func_get_args());
// If already cached return that
if ($cache_path !== NULL && file_exists($cache_path)) {
return file_get_contents($cache_path);
}
// Create image
$im = imagecreatetruecolor($image_width, $image_height);
imageantialias($im, true);
// Create fill brushes
$fg_fill = imagecolorallocate($im, $fg_color[0], $fg_color[1], $fg_color[2]);
$bg_fill = imagecolorallocate($im, $bg_color[0], $bg_color[1], $bg_color[2]);
$sh_fill = imagecolorallocate($im, $shadow_color[0], $shadow_color[1], $shadow_color[2]);
// Find the bounding box of text
$text_bounding_box = imagettfbbox($font_size, 0, $font_file, $string);
$xLeft = $text_bounding_box[0]; // (lower|upper) left corner, X position
$xRight = $text_bounding_box[2]; // (lower|upper) right corner, X position
$yLower = $text_bounding_box[1]; // lower (left|right) corner, Y position
$yUpper = $text_bounding_box[5]; // upper (left|right) corner, Y position
$tail_length = max(abs($xLower), abs($xRight), abs($xLeft), abs($yUpper));
$text_size = array(
($xRight - $xLeft),
($yLower - $yUpper)
);
if ($xLeft > 2) {
$text_size[0] = abs($xRight);
}
if ($yLower > 2) {
$text_size[1] = abs($yUpper);
}
$text_position = array(
($image_width / 2) - ($text_size[0] / 2),
($image_height / 2) + ($text_size[1] / 2)
);
// Fill background
imagefill($im, 0, 0, $bg_fill);
// Really inefficent version of draw shadow
if ($x_slope != 0 && $y_slope != 0) {
$max_i = $image_height - $text_position[1] + $tail_length;
for($i=1; $i <= $max_i; $i++) {
imagettftext($im,
$font_size ,
0 ,
$text_position[0] + $x_slope * $i,
$text_position[1] + $y_slope * $i,
$sh_fill,
$font_file,
$string);
}
}
// Draw text
imagettftext($im, $font_size , 0 , $text_position[0] , $text_position[1], $fg_fill , $font_file, $string);
// Start buffering if not cached
if ($cache_path === NULL) {
ob_start();
}
imagepng($im, $cache_path, 9);
imagedestroy($im);
// flush path from buffer if no cache path
if ($cache_path === NULL) {
$ret = ob_get_contents();
ob_end_clean();
return $ret;
}
// Save CPU do IO
return file_get_contents($cache_path);
}
// Read request
$ImageSize = (int)req_get('size', $DefaultImageSize);
if ($ImageSize > $MaxImageSize){
$ImageSize = $MaxImageSize;
}
// Text
$text = mb_strtoupper(req_get('text', $DefaultText));
if (mb_strlen($text) > 2) {
$text = mb_substr($text, 0, 2);
}
// Background color
if ($DefaultBackgroundColor == 'auto') {
$index = (crc32(req_get('text', $DefaultText)) >> 16) % count($ColorPalette);
$DefaultBackgroundColor = $ColorPalette[$index];
}
$bg_color = hex2rgb(req_get('bg', $DefaultBackgroundColor));
// Render
$imgContent = render_image(
$text,
$ImageSize,
$ImageSize,
(int)($ImageSize * $FontScaledSize),
get_font_file($text, req_get('font', $DefaultFontName)),
$bg_color,
hex2rgb(req_get('fg', brighten($bg_color, 150))),
hex2rgb(req_get('sh', brighten($bg_color, -100))),
normalize_slope((float)req_get('slope_x', $DefaultSlopeX)),
normalize_slope((float)req_get('slope_y', $DefaultSlopeY))
);
header("Content-type: image/png");
echo $imgContent;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment