内容が画像内に収まるように GD 画像のサイズを変更したいと考えています。
これは明らかに可能ですか?
最大の問題は、テキストのサイズを回復することです。Imagettftext と imagettfbox は、画像内のテキストの位置を表す点の配列を返しますが、画像を論理的にそれに合わせることができる領域は返しません。
ここに私が意味するものがあります:
function demo($text, $size, $angle, $font)
{
$gdh = imagecreatetruecolor(300, 300);
$white = imagecolorallocate($gdh, 255, 255, 255);
imagefill($gdh, 0, 0, $white);
$black = imagecolorallocate($gdh, 0, 0, 0);
$rect = imagettftext($gdh, $size, $angle, 50, 250, $black, $font, $text);
// Display a rectangle using the teturn of imagettftext
$red = imagecolorallocate($gdh, 255, 0, 0);
imageline($gdh, $rect[0], $rect[1], $rect[2], $rect[3], $red);
imageline($gdh, $rect[0], $rect[1], $rect[6], $rect[7], $red);
imageline($gdh, $rect[2], $rect[3], $rect[4], $rect[5], $red);
imageline($gdh, $rect[4], $rect[5], $rect[6], $rect[7], $red);
// Calculate and display the real area we need to fit our image
$blue = imagecolorallocate($gdh, 0, 0, 255);
$minX = min(array ($rect[0], $rect[2], $rect[4], $rect[6]));
$maxX = max(array ($rect[0], $rect[2], $rect[4], $rect[6]));
$minY = min(array ($rect[1], $rect[3], $rect[5], $rect[7]));
$maxY = max(array ($rect[1], $rect[3], $rect[5], $rect[7]));
imageline($gdh, $minX, $minY, $minX, $maxY, $blue);
imageline($gdh, $maxX, $minY, $maxX, $maxY, $blue);
imageline($gdh, $minX, $minY, $maxX, $minY, $blue);
imageline($gdh, $minX, $maxY, $maxX, $maxY, $blue);
header("Content-type: image/png");
imagepng($gdh);
die();
}
を呼び出す場合:
demo("Cheers!", 48, 45, "font.ttf");
この画像を取得します:
imagettfbox によって指定された領域を赤で、テキストに合わせて新しい画像サイズを定義できる計算された領域を青で見ることができます。
テキストを画像に合わせるソリューションを次に示します (もちろん、font.ttf を独自のフォントに置き換えます)。
function fitImageToText($gdh, $text, $size, $angle, $font)
{
// Recover the box size where we will be able to put our text
// Took from the doc http://www.php.net/manual/en/function.imagettfbbox.php#105593
putenv('GDFONTPATH=' . realpath('.'));
$rect = imagettfbbox($size, $angle, $font, $text);
$minX = min(array ($rect[0], $rect[2], $rect[4], $rect[6]));
$maxX = max(array ($rect[0], $rect[2], $rect[4], $rect[6]));
$minY = min(array ($rect[1], $rect[3], $rect[5], $rect[7]));
$maxY = max(array ($rect[1], $rect[3], $rect[5], $rect[7]));
$targetWidth = $maxX - $minX;
$targetHeight = $maxY - $minY;
$srcWidth = imagesx($gdh);
$srcHeight = imagesy($gdh);
// Creating target image
$targetGdh = imagecreatetruecolor($targetWidth, $targetHeight);
imagealphablending($targetGdh, false);
imagesavealpha($targetGdh, true);
imagecopyresampled($targetGdh, $gdh, 0, 0, 0, 0, $targetWidth, $targetHeight, $srcWidth, $srcHeight);
// Writting text inside the new image
$red = imagecolorallocate($targetGdh, 255, 0, 0);
imagettftext($targetGdh, $size, $angle, abs($minX), abs($minY), $red, $font, $text);
return $targetGdh;
}
それを呼び出すには:
$gdh = imagecreatefrompng("cheers.png");
$newGdh = fitImageToText($gdh, "Cheers!", 48, 45, "font.ttf");
imagedestroy($gdh);
// Outputs the image
header("Content-type: image/png");
imagepng($newGdh);
imagedestroy($newGdh);
die();
元の画像:
結果の画像:
注:ソース画像の縦横比は、ロジックなしでテキストサイズに適合します。画像の縦横比を維持したい場合は、次のようなものを使用できます。
function fitImageToText($gdh, $text, $size, $angle, $font)
{
// Recover the box size where we will be able to put our text
// Took from the doc http://www.php.net/manual/en/function.imagettfbbox.php#105593
putenv('GDFONTPATH=' . realpath('.'));
$rect = imagettfbbox($size, $angle, $font, $text);
$minX = min(array ($rect[0], $rect[2], $rect[4], $rect[6]));
$maxX = max(array ($rect[0], $rect[2], $rect[4], $rect[6]));
$minY = min(array ($rect[1], $rect[3], $rect[5], $rect[7]));
$maxY = max(array ($rect[1], $rect[3], $rect[5], $rect[7]));
$targetWidth = $maxX - $minX;
$targetHeight = $maxY - $minY;
$srcWidth = imagesx($gdh);
$srcHeight = imagesy($gdh);
// Recovering new source image size respecting its aspect ratio
$srcRatio = $srcWidth / $srcHeight;
$targetRatio = $targetWidth / $targetHeight;
if ($srcWidth <= $targetWidth && $srcHeight <= $targetHeight)
{
$imgTargetWidth = $srcWidth;
$imgTargetHeight = $srcHeight;
}
else if ($targetRatio > $srcRatio)
{
$imgTargetWidth = (int) ($targetHeight * $srcRatio);
$imgTargetHeight = $targetHeight;
}
else
{
$imgTargetWidth = $targetWidth;
$imgTargetHeight = (int) ($targetHeight / $srcRatio);
}
// Creating target image
$targetGdh = imagecreatetruecolor($targetWidth, $targetHeight);
imagealphablending($targetGdh, false);
imagesavealpha($targetGdh, true);
imagecopyresampled($targetGdh, $gdh, 0, 0, 0, 0, $imgTargetWidth, $imgTargetHeight, $srcWidth, $srcHeight);
// Writting text inside the new image
$red = imagecolorallocate($targetGdh, 255, 0, 0);
imagettftext($targetGdh, $size, $angle, abs($minX), abs($minY), $red, $font, $text);
return $targetGdh;
}
これにより、次のようになります。