blessing-skin-server/app/Services/Minecraft.php

215 lines
11 KiB
PHP
Raw Normal View History

2016-07-21 22:01:57 +08:00
<?php
namespace App\Services;
class Minecraft
{
/**
* Cut and resize to get the head part from a skin image.
* HD skin support added by xfl03 <xfl03@hotmail.com>.
2016-07-21 22:01:57 +08:00
*
* @see https://github.com/jamiebicknell/Minecraft-Avatar/blob/master/face.php
* @param string $binary Binary image data or decoded base64 formatted image.
* @param int $height The height of generated image in pixel.
* @param string $view Which side of head to be captured, defaults to 'f' for front view.
2016-07-21 22:01:57 +08:00
* @return resource
*/
public static function generateAvatarFromSkin($binary, $height, $view = 'f')
2016-07-21 22:01:57 +08:00
{
$src = imagecreatefromstring($binary);
$dest = imagecreatetruecolor($height, $height);
$ratio = imagesx($src) / 64;
2016-07-21 22:01:57 +08:00
$x = [
'f' => 8, // Front
'l' => 16, // Left
'r' => 0, // Right
'b' => 24 // Back
];
2016-07-21 22:01:57 +08:00
imagecopyresized($dest, $src, 0, 0, $x[$view] * $ratio, 8 * $ratio, $height, $height, 8 * $ratio, 8 * $ratio); // Face
imagecolortransparent($src, imagecolorat($src, 63 * $ratio, 0)); // Black hat issue
imagecopyresized($dest, $src, 0, 0, ($x[$view] + 32) * $ratio, 8 * $ratio, $height, $height, 8 * $ratio, 8 * $ratio); // Accessories
2016-07-21 22:01:57 +08:00
imagedestroy($src);
return $dest;
}
/**
* Generate a image preview for a skin texture.
2016-07-21 22:01:57 +08:00
*
* @see https://github.com/NC22/Minecraft-HD-skin-viewer-2D/blob/master/SkinViewer2D.class.php
* @param string $binary Binary image data or decoded base64 formatted image.
* @param int $height The height of generated image in pixel.
* @param bool $alex Whether the given skin is in Alex model.
* @param string $side Which side of model to be captured, 'front', 'back' or 'both'.
* @param int $gap Gap size between front & back preview in relative pixel.
2016-07-21 22:01:57 +08:00
* @return resource
*/
public static function generatePreviewFromSkin($binary, $height, $alex = false, $side = 'both', $gap = 4)
2016-07-21 22:01:57 +08:00
{
$src = imagecreatefromstring($binary);
2016-07-21 22:01:57 +08:00
$ratio = imagesx($src) / 64;
2016-08-29 12:19:21 +08:00
// Check if given skin contains double layers
2016-08-29 12:19:21 +08:00
$double = imagesy($src) == 64 * $ratio;
$dest = imagecreatetruecolor((32 + $gap) * $ratio, 32 * $ratio);
2016-08-29 12:19:21 +08:00
if ($side == 'both') {
// The width of front view and gap, the back side view will be drawn on its right.
$half_width = (16 + $gap) * $ratio;
$dest = imagecreatetruecolor((32 + $gap) * $ratio, 32 * $ratio);
} else {
// No need to calculate this if only single side view is required
$half_width = 0;
$dest = imagecreatetruecolor((16 + $gap) * $ratio, 32 * $ratio);
}
2016-07-21 22:01:57 +08:00
$transparent = imagecolorallocatealpha($dest, 255, 255, 255, 127);
imagefill($dest, 0, 0, $transparent);
if ($side == 'both' || $side == 'front') {
2016-08-29 12:19:21 +08:00
imagecopy($dest, $src, 4 * $ratio, 0 * $ratio, 8 * $ratio, 8 * $ratio, 8 * $ratio, 8 * $ratio); // Head - 1
imagecopy($dest, $src, 4 * $ratio, 0 * $ratio, 40 * $ratio, 8 * $ratio, 8 * $ratio, 8 * $ratio); // Head - 2
imagecopy($dest, $src, 4 * $ratio, 8 * $ratio, 20 * $ratio, 20 * $ratio, 8 * $ratio, 12 * $ratio); // Body - 1
imagecopy($dest, $src, 4 * $ratio, 20 * $ratio, 4 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio); // Right Leg - 1
if ($alex) {
imagecopy($dest, $src, 1 * $ratio, 8 * $ratio, 44 * $ratio, 20 * $ratio, 3 * $ratio, 12 * $ratio); // Right Arm - 1
} else {
imagecopy($dest, $src, 0 * $ratio, 8 * $ratio, 44 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio); // Right Arm - 1
}
2016-08-29 12:19:21 +08:00
// Check if given skin is double layer skin.
// If not, flip right arm/leg to generate left arm/leg.
if ($double) {
imagecopy($dest, $src, 8 * $ratio, 20 * $ratio, 20 * $ratio, 52 * $ratio, 4 * $ratio, 12 * $ratio); // Left Leg - 1
// copy second layer
imagecopy($dest, $src, 4 * $ratio, 8 * $ratio, 20 * $ratio, 36 * $ratio, 8 * $ratio, 12 * $ratio); // Body - 2
imagecopy($dest, $src, 4 * $ratio, 20 * $ratio, 4 * $ratio, 36 * $ratio, 4 * $ratio, 12 * $ratio); // Right Leg - 2
imagecopy($dest, $src, 8 * $ratio, 20 * $ratio, 4 * $ratio, 52 * $ratio, 4 * $ratio, 12 * $ratio); // Left Leg - 2
if ($alex) {
imagecopy($dest, $src, 12 * $ratio, 8 * $ratio, 36 * $ratio, 52 * $ratio, 3 * $ratio, 12 * $ratio); // Left Arm - 1
imagecopy($dest, $src, 1 * $ratio, 8 * $ratio, 44 * $ratio, 36 * $ratio, 3 * $ratio, 12 * $ratio); // Right Arm - 2
imagecopy($dest, $src, 11 * $ratio, 8 * $ratio, 50 * $ratio, 52 * $ratio, 3 * $ratio, 12 * $ratio); // Left Arm - 2
} else {
imagecopy($dest, $src, 12 * $ratio, 8 * $ratio, 36 * $ratio, 52 * $ratio, 4 * $ratio, 12 * $ratio); // Left Arm - 1
imagecopy($dest, $src, 0 * $ratio, 8 * $ratio, 44 * $ratio, 36 * $ratio, 4 * $ratio, 12 * $ratio); // Right Arm - 2
imagecopy($dest, $src, 12 * $ratio, 8 * $ratio, 52 * $ratio, 52 * $ratio, 4 * $ratio, 12 * $ratio); // Left Arm - 2
}
2016-08-29 12:19:21 +08:00
} else {
// I am not sure whether there are single layer Alex-model skin.
if ($alex) {
static::imageflip($dest, $src, 12 * $ratio, 8 * $ratio, 44 * $ratio, 20 * $ratio, 3 * $ratio, 12 * $ratio); // Left Arm
} else {
static::imageflip($dest, $src, 12 * $ratio, 8 * $ratio, 44 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio); // Left Arm
}
static::imageflip($dest, $src, 8 * $ratio, 20 * $ratio, 4 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio); // Left Leg
2016-08-29 10:34:54 +08:00
}
2016-08-29 12:19:21 +08:00
2016-07-21 22:01:57 +08:00
}
if ($side == 'both' || $side == 'back') {
imagecopy($dest, $src, $half_width + 4 * $ratio, 8 * $ratio, 32 * $ratio, 20 * $ratio, 8 * $ratio, 12 * $ratio); // Body
imagecopy($dest, $src, $half_width + 4 * $ratio, 0 * $ratio, 24 * $ratio, 8 * $ratio, 8 * $ratio, 8 * $ratio); // Head
imagecopy($dest, $src, $half_width + 8 * $ratio, 20 * $ratio, 12 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio); // Right Leg
imagecopy($dest, $src, $half_width + 4 * $ratio, 0 * $ratio, 56 * $ratio, 8 * $ratio, 8 * $ratio, 8 * $ratio); // Headwear
2018-02-16 17:31:04 +08:00
if ($alex) {
imagecopy($dest, $src, $half_width + 12 * $ratio, 8 * $ratio, 51 * $ratio, 20 * $ratio, 3 * $ratio, 12 * $ratio); // Right Arm
} else {
imagecopy($dest, $src, $half_width + 12 * $ratio, 8 * $ratio, 52 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio); // Right Arm
}
2016-08-29 12:19:21 +08:00
if ($double) {
if ($alex) {
imagecopy($dest, $src, $half_width + 1 * $ratio, 8 * $ratio, 43 * $ratio, 52 * $ratio, 3 * $ratio, 12 * $ratio);
} else {
imagecopy($dest, $src, $half_width + 0 * $ratio, 8 * $ratio, 44 * $ratio, 52 * $ratio, 4 * $ratio, 12 * $ratio);
}
imagecopy($dest, $src, $half_width + 4 * $ratio, 20 * $ratio, 28 * $ratio, 52 * $ratio, 4 * $ratio, 12 * $ratio); // Left Leg
2016-08-29 12:19:21 +08:00
// copy second layer
imagecopy($dest, $src, $half_width + 4 * $ratio, 8 * $ratio, 32 * $ratio, 36 * $ratio, 8 * $ratio, 12 * $ratio);
imagecopy($dest, $src, $half_width + 12 * $ratio, 8 * $ratio, 52 * $ratio, 36 * $ratio, 4 * $ratio, 12 * $ratio);
if ($alex) {
imagecopy($dest, $src, $half_width + 1 * $ratio, 8 * $ratio, 59 * $ratio, 52 * $ratio, 3 * $ratio, 12 * $ratio);
} else {
imagecopy($dest, $src, $half_width + 0 * $ratio, 8 * $ratio, 60 * $ratio, 52 * $ratio, 4 * $ratio, 12 * $ratio);
}
2016-08-29 12:19:21 +08:00
imagecopy($dest, $src, $half_width + 8 * $ratio, 20 * $ratio, 12 * $ratio, 36 * $ratio, 4 * $ratio, 12 * $ratio);
imagecopy($dest, $src, $half_width + 4 * $ratio, 20 * $ratio, 12 * $ratio, 52 * $ratio, 4 * $ratio, 12 * $ratio);
} else {
static::imageflip($dest, $src, $half_width + 0 * $ratio, 8 * $ratio, 52 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio);
static::imageflip($dest, $src, $half_width + 4 * $ratio, 20 * $ratio, 12 * $ratio, 20 * $ratio, 4 * $ratio, 12 * $ratio);
2016-08-29 10:34:54 +08:00
}
2016-07-21 22:01:57 +08:00
}
$width = ($side == 'both') ? $height / 32 * (32 + $gap) : $height / 2;
2016-07-21 22:01:57 +08:00
$fullsize = imagecreatetruecolor($width, $height);
2016-07-21 22:01:57 +08:00
imagesavealpha($fullsize, true);
$transparent = imagecolorallocatealpha($fullsize, 255, 255, 255, 127);
imagefill($fullsize, 0, 0, $transparent);
imagecopyresized($fullsize, $dest, 0, 0, 0, 0, imagesx($fullsize), imagesy($fullsize), imagesx($dest), imagesy($dest));
imagedestroy($dest);
imagedestroy($src);
return $fullsize;
}
/**
* Generate a image preview for a cape texture.
*
* @param string $binary Binary image data or decoded base64 formatted image.
* @param int $height The size of generated image in pixel.
* @param int $fillWidth Create a image with given size, And draw the preview on the center of it.
* @param int $fillHeight Set the value to 0 to disable.
* @return resource
*/
public static function generatePreviewFromCape($binary, $height, $fillWidth = 0, $fillHeight = 0)
2016-07-21 22:01:57 +08:00
{
$src = imagecreatefromstring($binary);
$ratio = imagesx($src) / 64;
$width = $height / 16 * 10;
2016-07-21 22:01:57 +08:00
$dest = imagecreatetruecolor($width, $height);
2016-07-21 22:01:57 +08:00
imagesavealpha($dest, true);
$transparent = imagecolorallocatealpha($dest, 255, 255, 255, 127);
imagefill($dest, 0, 0, $transparent);
imagecopyresized($dest, $src, 0, 0, $ratio, $ratio, $width, $height, imagesx($src)*10/64, imagesy($src)*16/32);
2016-07-21 22:01:57 +08:00
imagedestroy($src);
if ($fillWidth == 0 || $fillHeight == 0) {
return $dest;
}
2016-07-21 22:01:57 +08:00
$filled = imagecreatetruecolor($fillWidth, $fillHeight);
imagesavealpha($filled, true);
$transparent = imagecolorallocatealpha($filled, 255, 255, 255, 127);
imagefill($filled, 0, 0, $transparent);
imagecopyresized($filled, $dest, ($fillWidth-$width)/2, ($fillHeight-$height)/2, 0, 0, $width, $height, $width, $height);
2016-07-21 22:01:57 +08:00
imagedestroy($dest);
return $filled;
}
2016-07-21 22:01:57 +08:00
/**
* Flip the given image.
*/
protected static function imageflip(&$result, &$img, $rx = 0, $ry = 0, $x = 0, $y = 0, $size_x = null, $size_y = null)
{
$size_x = ($size_x < 1) ? $imagesx($img) : $size_x;
$size_y = ($size_y < 1) ? $imagesy($img) : $size_y;
2016-07-21 22:01:57 +08:00
imagecopyresampled($result, $img, $rx, $ry, ($x + $size_x - 1), $y, $size_x, $size_y, 0 - $size_x, $size_y);
2016-07-21 22:01:57 +08:00
}
}