Skip to content

Instantly share code, notes, and snippets.

@ViskoB
Last active December 18, 2015 02:09
Show Gist options
  • Save ViskoB/d263d9f668dbe9c97718 to your computer and use it in GitHub Desktop.
Save ViskoB/d263d9f668dbe9c97718 to your computer and use it in GitHub Desktop.
An attempt to colour Guild Wars 2 guild emblems using PHP and the Imagick library
<?php
/* Guild Wars 2 Emblem Creator Script by Moturdrn.2837
Special thanks to:
- Cliff Spradlin and ArenaNet for making available the API and information
- smiley.1438 and Think.8042 with PHP colour conversion
- smiley.1438 for the gw2_api_request function
- Dr Ishmael.9685 for providing information and downloads of the emblem parts and backgrounds, and the idea to split the matrix and colour conversion functions
- Killer Rhino.6794 for the extra advanced information on working out how to decode the API colour information into something useable
- The general Guild Wars 2 development community for being a bunch of guys and gals ready and willing to help one another out
- Apologies if I've left you out, please contact me and I'll add you in here :)
Please feel free to use this code and make modifications. Apologies in advance if the coding seems all over the place.*/
$pathToBackgrounds = './backgrounds/';
$pathToEmblems = './emblems/';
$pathToGenerated = './generated/';
if(isset($_GET['guild_id'])){
$guild_id = $_GET['guild_id'];
$guildInfo = gw2_api_request("guild_details.json?guild_id={$guild_id}");
if(!$guildInfo)
displayUnknown();
}elseif(isset($_GET['guild_name'])){
$guild_name = $_GET['guild_name'];
$guild_name = str_replace(' ', '%20', $guild_name);
$guildInfo = gw2_api_request("guild_details.json?guild_name={$guild_name}");
if(!$guildInfo)
displayUnknown();
}else{
displayUnknown();
}
if(!$guildInfo['emblem'])
displayUnknown();
$background_id = $guildInfo['emblem']['background_id'];
$foreground_id = $guildInfo['emblem']['foreground_id'];
$background_color_id = $guildInfo['emblem']['background_color_id'];
$foreground_primary_color_id = $guildInfo['emblem']['foreground_primary_color_id'];
$foreground_secondary_color_id = $guildInfo['emblem']['foreground_secondary_color_id'];
$flags = $guildInfo['emblem']['flags'];
$hash = array($background_id,$foreground_id,$background_color_id,$foreground_primary_color_id,$foreground_secondary_color_id,serialize($flags));
$hash = hash('sha256', serialize($hash));
$generatedFile = "{$pathToGenerated}{$hash}.png";
if(file_exists($generatedFile)){
try
{
$image = new Imagick($generatedFile);
header("Content-Type: image/png");
echo $image;
}
catch(Exception $e)
{
echo $e->getMessage();
}
exit();
}
$colorsArray = gw2_api_request('colors.json');
if(!$colorsArray)
displayUnknown();
$colorsArray = $colorsArray['colors'];
$background = $colorsArray[$background_color_id]['cloth'];
$primary = $colorsArray[$foreground_primary_color_id]['cloth'];
$secondary = $colorsArray[$foreground_secondary_color_id]['cloth'];
$background_path = "{$pathToBackgrounds}{$background_id}.png";
$primary_path = "{$pathToEmblems}{$foreground_id}a.png";
$secondary_path = "{$pathToEmblems}{$foreground_id}b.png";
// Try and generate the image, fail with message if error
try
{
// Fetch the background image
$imagebk = new Imagick($background_path);
$matrix = getColorMatrix($background);
// Re-colour background image
$it = $imagebk->getPixelIterator();
foreach( $it as $row => $pixels )
{
foreach ( $pixels as $column => $pixel )
{
$alpha = $pixel->getColorValue(imagick::COLOR_ALPHA);
if($alpha>0){
$color = $pixel->getColor();
$baseRGB = array($color['r'],$color['g'],$color['b']);
list($r,$g,$b) = applyColorTransform($matrix, $baseRGB);
$pixel->setColor( "rgba($r,$g,$b,$alpha)" );
}
}
$it->syncIterator();
}
$image = imagecreatefromstring($imagebk->getImageBlob());
imagefilter($image, IMG_FILTER_CONTRAST, $background['contrast']);
imagefilter($image, IMG_FILTER_COLORIZE, $background['rgb'][0], $background['rgb'][1],$background['rgb'][2]);
imagealphablending($image, true);
imagesavealpha($image, true);
ob_start();
imagepng($image);
$blob = ob_get_clean();
imagedestroy($image);
$imagebk->readImageBlob($blob);
// Fetch the primary emblem image
$image1 = new Imagick($primary_path);
$matrix = getColorMatrix($primary);
// Re-colour primary emblem image
$it = $image1->getPixelIterator();
foreach( $it as $row => $pixels )
{
foreach ( $pixels as $column => $pixel )
{
$alpha = $pixel->getColorValue(imagick::COLOR_ALPHA);
if($alpha>0){
$color = $pixel->getColor();
$baseRGB = array($color['r'],$color['g'],$color['b']);
list($r,$g,$b) = applyColorTransform($matrix, $baseRGB);
$pixel->setColor( "rgba($r,$g,$b,$alpha)" );
}
}
$it->syncIterator();
}
// Fetch the secondary emblem image
$image2 = new Imagick($secondary_path);
$matrix = getColorMatrix($secondary);
// Re-colour secondary emblem image
$it = $image2->getPixelIterator();
foreach( $it as $row => $pixels )
{
foreach ( $pixels as $column => $pixel )
{
$alpha = $pixel->getColorValue(imagick::COLOR_ALPHA);
if($alpha>0){
$color = $pixel->getColor();
$baseRGB = array($color['r'],$color['g'],$color['b']);
list($r,$g,$b) = applyColorTransform($matrix, $baseRGB);
$pixel->setColor( "rgba($r,$g,$b,$alpha)" );
}
}
$it->syncIterator();
}
$image1->compositeImage( $image2, $image2->getImageCompose(), 0, 0 );
foreach($flags as $flag){
switch($flag){
case 'FlipBackgroundHorizontal':
$imagebk->flopImage();
break;
case 'FlipBackgroundVertical':
$imagebk->flipImage();
break;
case 'FlipForegroundHorizontal':
$image1->flopImage();
break;
case 'FlipForegroundVertical':
$image1->flipImage();
break;
}
}
$imagebk->compositeImage( $image1, $image1->getImageCompose(), 0, 0 );
$imagebk->writeImage($generatedFile);
header("Content-Type: image/png");
echo $imagebk;
}
catch(Exception $e)
{
echo $e->getMessage();
}
// Function matrix_multiply by smiley: https://gist.github.com/codemasher/b869faa7603e1934c28d
function matrix_multiply($m1, $m2){
$r = count($m1);
$c = count($m2[0]);
$p = count($m2);
if(count($m1[0]) != $p){
return false; //incompatible matrix
}
$m3 = array();
for($i = 0; $i < $r; $i++){
for($j = 0; $j < $c; $j++){
$m3[$i][$j] = 0;
for($k = 0; $k < $p; $k++){
$m3[$i][$j] += $m1[$i][$k]*$m2[$k][$j];
}
}
}
return ($m3);
}
// Function getColorMatrix adapted from smiley's code: https://gist.github.com/codemasher/b869faa7603e1934c28d
function getColorMatrix($hslbc){
//colors from the response .json -> material
$h = ($hslbc['hue']*pi())/180;
$s = $hslbc['saturation'];
$l = $hslbc['lightness'];
$b = $hslbc['brightness']/128;
$c = $hslbc['contrast'];
// 4x4 identity matrix
$matrix = array(
array(1, 0, 0, 0),
array(0, 1, 0, 0),
array(0, 0, 1, 0),
array(0, 0, 0, 1)
);
if($b != 0 || $c != 1){
// process brightness and contrast
$t = 128*(2*$b+1-$c);
$mult = array(
array($c, 0, 0, $t),
array( 0, $c, 0, $t),
array( 0, 0, $c, $t),
array( 0, 0, 0, 1)
);
$matrix = matrix_multiply($mult, $matrix);
}
if($h != 0 || $s != 1 || $l != 1){
// transform to HSL
$multRgbToHsl = array(
array( 0.707107, 0, -0.707107, 0),
array(-0.408248, 0.816497, -0.408248, 0),
array( 0.577350, 0.577350, 0.577350, 0),
array( 0, 0, 0, 1)
);
$matrix = matrix_multiply($multRgbToHsl, $matrix);
// process adjustments
$cosHue = cos($h);
$sinHue = sin($h);
$mult = array(
array( $cosHue * $s, $sinHue * $s, 0, 0),
array(-$sinHue * $s, $cosHue * $s, 0, 0),
array( 0, 0, $l, 0),
array( 0, 0, 0, 1)
);
$matrix = matrix_multiply($mult, $matrix);
// transform back to RGB
$multHslToRgb = array(
array( 0.707107, -0.408248, 0.577350, 0),
array( 0, 0.816497, 0.577350, 0),
array(-0.707107, -0.408248, 0.577350, 0),
array( 0, 0, 0, 1)
);
$matrix = matrix_multiply($multHslToRgb, $matrix);
}
return $matrix;
}
// Function applyColorTransform adapted from smiley's code: https://gist.github.com/codemasher/b869faa7603e1934c28d
function applyColorTransform($matrix, $base){
// apply the color transformation
$bgrVector = array(
array($base[2]),
array($base[1]),
array($base[0]),
array(1)
);
$bgrVector = matrix_multiply($matrix,$bgrVector);
// clamp the values
$rgb = array(
floor(max(0, min(255, $bgrVector[2][0]))),
floor(max(0, min(255, $bgrVector[1][0]))),
floor(max(0, min(255, $bgrVector[0][0])))
);
return $rgb;
}
// Function gw2_api_request from https://gist.github.com/codemasher/4d30a47df24195ac509f
function gw2_api_request($request){
$url = parse_url('https://api.guildwars2.com/v1/'.$request);
if(!$fp = @fsockopen('ssl://'.$url['host'], 443, $errno, $errstr, 5)){
return 'connection error: '.$errno.', '.$errstr;
}
$nl = "\r\n";
$header = 'GET '.$url['path'].'?'.$url['query'].' HTTP/1.1'.$nl.'Host: '.$url['host'].$nl.'Connection: Close'.$nl.$nl;
fwrite($fp, $header);
stream_set_timeout($fp, 5);
$response = '';
do{
if(strlen($in = fread($fp,1024))==0){
break;
}
$response.= $in;
}
while(true);
$response = explode($nl,$response);
if(isset($response[0]) && $response[0] == 'HTTP/1.1 200 OK'){
$response = json_decode($response[count($response)-1],true);
}
return $response;
}
function displayUnknown(){
global $pathToEmblems;
try{
$image = new Imagick("{$pathToEmblems}unknown_guild.png");
header("Content-Type: image/png");
echo $image;
}
catch(Exception $e)
{
echo $e->getMessage();
}
exit();
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment