1401a61e7Swikidesign<?php 21affe9b7Swikidesign/** 36e2b7c94Snerun * MonsterID Generator for DokuWiki Avatar Plugin 46e2b7c94Snerun * 56e2b7c94Snerun * Generates identicon-style monster avatars based on a seed. 66e2b7c94Snerun * Requires PHP GD extension. 76e2b7c94Snerun * 8984623feSnerun * 9984623feSnerun * MIT License 10984623feSnerun * 11984623feSnerun * Copyright (c) 2007 Andreas Gohr <andi@splitbrain.org> 12984623feSnerun * @source: https://github.com/splitbrain/monsterID 13984623feSnerun * 14984623feSnerun * Copyright (c) 2009 Gina Häußge <github.com/foosel> 15984623feSnerun * @source: https://github.com/dokufreaks/plugin-avatar 16984623feSnerun * 17984623feSnerun * Copyright (c) 2025 Daniel Dias Rodrigues <danieldiasr@gmail.com> 18984623feSnerun * @source: https://github.com/nerun/dokuwiki-plugin-avatar 19984623feSnerun * 20984623feSnerun * Permission is hereby granted, free of charge, to any person obtaining a copy 21984623feSnerun * of this software and associated documentation files (the "Software"), to deal 22984623feSnerun * in the Software without restriction, including without limitation the rights 23984623feSnerun * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 24984623feSnerun * copies of the Software, and to permit persons to whom the Software is 25984623feSnerun * furnished to do so, subject to the following conditions: 26984623feSnerun * 27984623feSnerun * The above copyright notice and this permission notice shall be included in 28984623feSnerun * all copies or substantial portions of the Software. 29984623feSnerun * 30984623feSnerun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31984623feSnerun * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32984623feSnerun * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 33984623feSnerun * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 34984623feSnerun * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 35984623feSnerun * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 36984623feSnerun * SOFTWARE. 371affe9b7Swikidesign */ 38401a61e7Swikidesign 396e2b7c94Snerundeclare(strict_types=1); 406e2b7c94Snerun 416e2b7c94Snerunif (php_sapi_name() !== 'cli') { 426e2b7c94Snerun $seed = preg_replace('/[^a-f0-9]/i', '', $_GET['seed'] ?? ''); 436e2b7c94Snerun $size = (int) ($_GET['size'] ?? 120); 44*b92285bbSnerun $size = max(20, min(400, $size)); // limits between 20 and 400 pixels 456e2b7c94Snerun 466e2b7c94Snerun header('Content-Type: image/png'); 476e2b7c94Snerun header('Cache-Control: public, max-age=86400'); 486e2b7c94Snerun 496e2b7c94Snerun $image = generate_monster($seed, $size); 506e2b7c94Snerun if ($image) { 516e2b7c94Snerun imagepng($image); 526e2b7c94Snerun imagedestroy($image); 536e2b7c94Snerun } else { 546e2b7c94Snerun http_response_code(500); 55984623feSnerun echo 'Error generating image.'; 566e2b7c94Snerun } 576e2b7c94Snerun exit; 586e2b7c94Snerun} 59401a61e7Swikidesign 601affe9b7Swikidesign/** 616e2b7c94Snerun * Generates monster image based on seed and size 621affe9b7Swikidesign */ 636e2b7c94Snerunfunction generate_monster(string $seed, int $size): ?GdImage 646e2b7c94Snerun{ 656e2b7c94Snerun if (!function_exists('imagecreatetruecolor')) { 666e2b7c94Snerun return null; 676e2b7c94Snerun } 686e2b7c94Snerun 692e0c1c6eSGina Haeussge $hash = md5($seed); 70401a61e7Swikidesign 716e2b7c94Snerun $parts = [ 726e2b7c94Snerun 'legs' => get_part(substr($hash, 0, 2), 1, 5), 736e2b7c94Snerun 'hair' => get_part(substr($hash, 2, 2), 1, 5), 746e2b7c94Snerun 'arms' => get_part(substr($hash, 4, 2), 1, 5), 756e2b7c94Snerun 'body' => get_part(substr($hash, 6, 2), 1, 15), 766e2b7c94Snerun 'eyes' => get_part(substr($hash, 8, 2), 1, 15), 776e2b7c94Snerun 'mouth' => get_part(substr($hash, 10, 2), 1, 10), 786e2b7c94Snerun ]; 79401a61e7Swikidesign 806e2b7c94Snerun $monster = imagecreatetruecolor(120, 120); 816e2b7c94Snerun if (!$monster) return null; 826e2b7c94Snerun 834bc5a549Snerun $white = @imagecolorallocate($monster, 255, 255, 255); 84401a61e7Swikidesign imagefill($monster, 0, 0, $white); 85401a61e7Swikidesign 866e2b7c94Snerun foreach ($parts as $part => $index) { 874bc5a549Snerun $filename = __DIR__ . '/parts/' . $part . '_' . $index . '.png'; 886e2b7c94Snerun if (!file_exists($filename)) continue; 896e2b7c94Snerun $part_img = imagecreatefrompng($filename); 904bc5a549Snerun imageSaveAlpha($part_img, true); 916e2b7c94Snerun if ($part_img) { 926e2b7c94Snerun imagecopy($monster, $part_img, 0, 0, 0, 0, 120, 120); 936e2b7c94Snerun imagedestroy($part_img); 94*b92285bbSnerun 95*b92285bbSnerun // color the body 96*b92285bbSnerun if ($part === 'body') { 97*b92285bbSnerun $r = get_part(substr($hash, 0, 4), 20, 235); 98*b92285bbSnerun $g = get_part(substr($hash, 4, 4), 20, 235); 99*b92285bbSnerun $b = get_part(substr($hash, 8, 4), 20, 235); 100*b92285bbSnerun $color = imagecolorallocate($monster, $r, $g, $b); 101*b92285bbSnerun imagefill($monster, 60, 60, $color); 102*b92285bbSnerun } 103401a61e7Swikidesign } 104401a61e7Swikidesign } 105401a61e7Swikidesign 1066e2b7c94Snerun if ($size !== 120) { 1076e2b7c94Snerun $resized = imagecreatetruecolor($size, $size); 1086e2b7c94Snerun imagefill($resized, 0, 0, $white); 1096e2b7c94Snerun imagecopyresampled($resized, $monster, 0, 0, 0, 0, $size, $size, 120, 120); 110401a61e7Swikidesign imagedestroy($monster); 1116e2b7c94Snerun return $resized; 112401a61e7Swikidesign } 1132e0c1c6eSGina Haeussge 1146e2b7c94Snerun return $monster; 1152e0c1c6eSGina Haeussge} 1162e0c1c6eSGina Haeussge 1176e2b7c94Snerun/** 1186e2b7c94Snerun * Converts part of the hash into an image index 1196e2b7c94Snerun */ 1206e2b7c94Snerunfunction get_part(string $hex, int $min, int $max): int 1216e2b7c94Snerun{ 1226e2b7c94Snerun $val = hexdec($hex); 1236e2b7c94Snerun return ($val % ($max - $min + 1)) + $min; 124401a61e7Swikidesign} 12523415f0dSnerun 126