237 lines
6.2 KiB
PHP
237 lines
6.2 KiB
PHP
<?php
|
||
|
||
/**
|
||
* Формат для композиции изображений
|
||
*/
|
||
|
||
namespace ctiso\Tools;
|
||
|
||
use ctiso\Tools\Drawing;
|
||
use GdImage;
|
||
|
||
class TemplateImage
|
||
{
|
||
/** @var array<string, string> */
|
||
static array $listfiles = array('jpg' => 'jpeg', 'gif' => 'gif', 'png' => 'png', 'bmp' => 'wbmp');
|
||
/** @var array<string, string> */
|
||
static array $listfonts = array(
|
||
'georgia' => 'georgia.ttf',
|
||
'georgiabd' => 'georgiab.ttf',
|
||
'georgiaz' => 'georgiaz.ttf',
|
||
'times' => 'times.ttf',
|
||
'timesbd' => 'timesbd.ttf',
|
||
'arial' => 'arial.ttf',
|
||
'arialbd' => 'arialbd.ttf',
|
||
'tahoma' => 'tahoma.ttf',
|
||
'calibri' => 'calibri.ttf',
|
||
'calibribd' => 'calibrib.ttf',
|
||
'calibrii' => 'calibrii.ttf',
|
||
'' => 'arial.ttf',
|
||
'dejavu' => 'DejaVuCondensedSerif.ttf',
|
||
'dejavubd' => 'DejaVuCondensedSerifBold.ttf',
|
||
'dejavuz' => 'DejaVuCondensedSerifBoldItalic.ttf',
|
||
'dejavui' => 'DejaVuCondensedSerifItalic.ttf',
|
||
'miriad' => 'MyriadPro-Cond.ttf',
|
||
'miriadbd' => 'MyriadPro-BoldCond.ttf'
|
||
|
||
);
|
||
|
||
/** @var string */
|
||
protected $src;
|
||
protected array $context = [];
|
||
protected array $data = [];
|
||
protected string $base = "c:\\windows\\fonts\\";
|
||
protected GdImage $image;
|
||
/** @var bool */
|
||
protected $_prepare = true;
|
||
/** @var bool */
|
||
public $debug = false;
|
||
public string $resource;
|
||
public string $filename;
|
||
|
||
function __construct(?array $template = null)
|
||
{
|
||
if ($template) {
|
||
$this->data = $template;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Путь к изображению
|
||
*/
|
||
function resourcePath(string $path): void
|
||
{
|
||
$this->resource = $path;
|
||
}
|
||
|
||
/**
|
||
* Путь у шрифтам
|
||
*/
|
||
function fontPath(string $path): void
|
||
{
|
||
$this->base = $path;
|
||
}
|
||
|
||
/**
|
||
* @param string $name
|
||
* @param mixed $value
|
||
*/
|
||
function set(string $name, $value): void
|
||
{
|
||
$this->context['[' . $name . ']'] = $value;
|
||
}
|
||
|
||
function setImage(string $name): void
|
||
{
|
||
$this->filename = $name;
|
||
$this->image = $this->imagefromfile($name);
|
||
}
|
||
|
||
/**
|
||
* Создает пустое изображение
|
||
* @param int<1, max> $width
|
||
* @param int<1, max> $height
|
||
*/
|
||
function setEmptyImage($width, $height): void
|
||
{
|
||
$this->image = imagecreatetruecolor($width, $height);
|
||
}
|
||
|
||
/**
|
||
* Создает изображение из файла
|
||
* @param string $file
|
||
* @return GdImage|null
|
||
*/
|
||
function imagefromfile(string $file)
|
||
{
|
||
$suffix = pathinfo($file, PATHINFO_EXTENSION);
|
||
if (array_key_exists($suffix, self::$listfiles)) {
|
||
return call_user_func('imagecreatefrom' . self::$listfiles[$suffix], $file);
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function getFontFile(string $name): string
|
||
{
|
||
if (array_key_exists(strtolower($name), self::$listfonts)) {
|
||
return $this->base . self::$listfonts[$name];
|
||
}
|
||
return $this->base . 'arial.ttf';
|
||
}
|
||
|
||
function fontSuffix(array $style): string
|
||
{
|
||
if ($style[0] && $style[1]) return "z";
|
||
|
||
if ($style[0]) return "bd";
|
||
if ($style[1]) return "i";
|
||
|
||
return "";
|
||
}
|
||
|
||
/**
|
||
* @param string $text
|
||
* @param object{
|
||
* fontFamily: string,
|
||
* fontSize: int,
|
||
* fontStyle: array{string, string},
|
||
* color: string,
|
||
* align: array,
|
||
* valign: array,
|
||
* left: int,
|
||
* top: int,
|
||
* width: int,
|
||
* height: int
|
||
* } $value
|
||
*/
|
||
function imageText(string $text, object $value): void
|
||
{
|
||
$text = strtr($text, $this->context);
|
||
$size = $value->fontSize;
|
||
$fontfile = $this->getFontFile($value->fontFamily . $this->fontSuffix($value->fontStyle));
|
||
|
||
$color = intval(substr($value->color, 1), 16);
|
||
if ($value->align[0]) {
|
||
$align = Drawing::ALIGN_LEFT;
|
||
} elseif ($value->align[2]) {
|
||
$align = Drawing::ALIGN_RIGHT;
|
||
} else {
|
||
$align = Drawing::ALIGN_CENTER;
|
||
}
|
||
|
||
if ($value->valign[0]) {
|
||
$valign = Drawing::ALIGN_TOP;
|
||
} elseif ($value->valign[1]) {
|
||
$valign = Drawing::ALIGN_CENTER;
|
||
} else {
|
||
$valign = Drawing::ALIGN_BOTTOM;
|
||
}
|
||
|
||
Drawing::imagettftextbox(
|
||
$this->image,
|
||
$size,
|
||
0,
|
||
$value->left,
|
||
$value->top,
|
||
$color,
|
||
$fontfile,
|
||
$text,
|
||
$value->width,
|
||
$value->height,
|
||
$align,
|
||
$valign
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Перекодировка текста
|
||
* @deprecated Можно заменить encode($x) -> $x
|
||
*/
|
||
function encode(string $text): string
|
||
{
|
||
return $text;
|
||
}
|
||
|
||
function setSize(int $new_width, int $new_height): void
|
||
{
|
||
$width = imagesx($this->image);
|
||
$height = imagesy($this->image);
|
||
if ($new_height == null) {
|
||
$new_height = ceil($height * $new_width / $width);
|
||
}
|
||
|
||
// Resample
|
||
$image_p = imagecreatetruecolor($new_width, $new_height);
|
||
imagecopyresampled($image_p, $this->image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
|
||
// imagecopyresized($image_p, $this->image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
|
||
$this->image = $image_p;
|
||
}
|
||
|
||
function prepare(): void
|
||
{
|
||
if ($this->_prepare) {
|
||
$this->_prepare = false;
|
||
foreach ($this->data as $value) {
|
||
$this->imageText($value->text, $value); // break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Генерирует изображение из шаблона
|
||
*/
|
||
function render(?string $file = null): string|bool
|
||
{
|
||
$this->prepare();
|
||
|
||
if ($file == null) {
|
||
ob_start();
|
||
imagejpeg($this->image, $file, 100);
|
||
$result = ob_get_contents();
|
||
ob_clean();
|
||
return $result;
|
||
} else {
|
||
return imagejpeg($this->image, $file, 100);
|
||
}
|
||
}
|
||
}
|