Current File : //var/www/vinorea/modules/psxdesign/src/Converter/TextToLogoConverter.php |
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
declare(strict_types=1);
namespace PrestaShop\Module\PsxDesign\Converter;
if (!defined('_PS_VERSION_')) {
exit;
}
use GdImage;
use PrestaShop\Module\PsxDesign\Config\PsxDesignConfig;
use PrestaShop\Module\PsxDesign\DTO\PsxDesignLogoTextData;
use PrestaShop\Module\PsxDesign\Exception\PsxDesignTextToImageConvertException;
use PrestaShop\Module\PsxDesign\Provider\FontDataProvider;
class TextToLogoConverter implements TextToImageConverterInterface
{
private const TRANSPARENT_OPACITY = 127;
private const WHITE_RGB = ['r' => 255, 'g' => 255, 'b' => 255];
private const HORIZONTAL_ANGLE = 0;
private const PADDING_FOR_BOX = 20;
private const TMP_IMAGE_NAME = 'tmp_logo';
private const EXTENSION = '.png';
/**
* @var false|resource|GdImage
*/
private $image;
/**
* @var int
*/
private $boxWidth;
/**
* @var int
*/
private $boxHeight;
/**
* @var string
*/
protected $fontPath;
/**
* @var int
*/
protected $textAngle = self::HORIZONTAL_ANGLE;
/**
* A value between 0 and 127.
* 0 indicates completely opaque while
* 127 indicates completely transparent.
*
* @var int
*/
protected $backgroundOpacity = self::TRANSPARENT_OPACITY;
/**
* Background color defined with rgb colors.
*
* @var array{r: int, g: int, b: int}
*/
protected $backgroundColor = self::WHITE_RGB;
public function __construct()
{
$path = realpath(_PS_MODULE_DIR_ . 'psxdesign/' . PsxDesignConfig::TMP_DIR_NAME . '/' . FontDataProvider::TEMPORARY_FONT_NAME);
$this->fontPath = $path !== false ? $path : '';
}
/**
* @param PsxDesignLogoTextData $logoData
*
* @return string
*
* @throws PsxDesignTextToImageConvertException
*/
public function convertToImage(PsxDesignLogoTextData $logoData): string
{
$this
->initImageCreation($logoData->getSize(), $logoData->getText())
->renderTextOnImage(
$logoData->getSize(),
$logoData->getText(),
$logoData->getColor()
)
;
$imagePath = $this->createImage();
$this->destroyImageFromMemory();
return $imagePath;
}
/**
* Initializes image bounds by font width and height.
*
* @param int $fontSize
* @param string $text
*
* @return TextToLogoConverter
*
* @throws PsxDesignTextToImageConvertException
*/
private function initImageCreation(int $fontSize, string $text): self
{
$typeSpace = imageftbbox($fontSize, $this->textAngle, $this->fontPath, $text);
// Determine image width and height by text width with padding
$this->boxWidth = abs($typeSpace[4] - $typeSpace[0]) + self::PADDING_FOR_BOX;
$this->boxHeight = abs($typeSpace[5] - $typeSpace[1]) + self::PADDING_FOR_BOX;
$this->image = imagecreatetruecolor((int) $this->boxWidth, (int) $this->boxHeight);
if (!$this->image) {
throw new PsxDesignTextToImageConvertException('Cannot Initialize new GD image stream', PsxDesignTextToImageConvertException::FAILED_INIT_GD_STREAM);
}
return $this;
}
/**
* Apply background for created image box.
*
* @return TextToLogoConverter
*
* @throws PsxDesignTextToImageConvertException
*/
private function setBackgroundColor(): self
{
imagealphablending($this->image, false);
$color = imagecolorallocatealpha($this->image, $this->backgroundColor['r'], $this->backgroundColor['g'], $this->backgroundColor['b'], $this->backgroundOpacity);
imagefill($this->image, 0, 0, $color);
imagesavealpha($this->image, true);
return $this;
}
/**
* @param int $logoSize
* @param string $text
* @param string $logoColor
*
* @return void
*
* @throws PsxDesignTextToImageConvertException
*/
private function renderTextOnImage(int $logoSize, string $text, string $logoColor): void
{
$textColor = $this->getTextColor($logoColor);
$this->setBackgroundColor();
$coordinates = $this->getCoordinatesForText($logoSize, $text);
$isTextAdded = imagettftext(
$this->image,
$logoSize,
$this->textAngle,
(int) $coordinates['x'],
(int) $coordinates['y'],
$textColor,
$this->fontPath,
$text);
if (!$isTextAdded) {
throw new PsxDesignTextToImageConvertException('Cannot add text into image', PsxDesignTextToImageConvertException::FAILED_ADD_TEXT);
}
}
/**
* Coordinates determine where should text start be rendered on the image
*
* @param int $logoSize
* @param string $text
*
* @return array{x: float, y: float}
*/
private function getCoordinatesForText(int $logoSize, string $text): array
{
$dimensions = imagettfbbox($logoSize, 0, $this->fontPath, $text);
$ascent = abs($dimensions[7]);
$descent = abs($dimensions[1]);
$height = $ascent + $descent;
$coordinates['x'] = ($this->boxWidth - $dimensions[2]) / 2;
$coordinates['y'] = (($this->boxHeight / 2) - ($height / 2)) + $ascent;
return $coordinates;
}
/**
* Converts hex to rgb and returns color id
*
* @param string $logoColor
*
* @return int
*/
private function getTextColor(string $logoColor): int
{
[$r, $g, $b] = sscanf($logoColor, '#%02x%02x%02x'); //converts hex to rgb
return (int) imagecolorallocate($this->image, $r, $g, $b);
}
/**
* Save created image into temporary folder
*
* @return string
*
* @throws PsxDesignTextToImageConvertException
*/
private function createImage(): string
{
$path = _PS_TMP_IMG_DIR_ . self::TMP_IMAGE_NAME . self::EXTENSION;
$isCreated = imagepng($this->image, $path);
if (!$isCreated) {
throw new PsxDesignTextToImageConvertException('Failed to convert the image', PsxDesignTextToImageConvertException::FAILED_TO_CONVERT);
}
return $path;
}
/**
* Destroys image from memory
*
* @return void
*/
private function destroyImageFromMemory(): void
{
imagedestroy($this->image);
}
}