Файловый менеджер - Редактировать - /home/avadvi5/calendar.aeronextgen.com/davis/vendor/dantsu/php-image-editor/src/Image.php
Ðазад
<?php namespace DantSu\PHPImageEditor; /** * DantSu\PHPImageEditor\Image is PHP library to easily edit image with GD extension. Resize, crop, merge, draw, and many more options ! * * @package DantSu\PHPImageEditor * @author Franck Alary * @access public * @see https://github.com/DantSu/php-image-editor Github page of this project */ class Image { const ALIGN_LEFT = 'left'; const ALIGN_CENTER = 'center'; const ALIGN_RIGHT = 'right'; const ALIGN_TOP = 'top'; const ALIGN_MIDDLE = 'middle'; const ALIGN_BOTTOM = 'bottom'; /** * @var $image resource|\GdImage */ private $image; /** * @var $type int */ private $type; /** * @var $width int */ private $width; /** * @var $height int */ private $height; public function __clone() { $srcInstance = $this->image; $this ->resetCanvas($this->width, $this->height) ->pasteGdImageOn($srcInstance, $this->width, $this->height, 0, 0); } /** * Return the image width * * @return int Image width */ public function getWidth(): int { return $this->width; } /** * Return the image height * * @return int Image height */ public function getHeight(): int { return $this->height; } /** * Return the image type * Image type : 1 GIF; 2 JPG; 3 PNG * * @return int Image type */ public function getType(): int { return $this->type; } /** * Return image resource * @return resource|\GdImage Image resource */ public function getImage() { return $this->image; } /** * Return true if $image is a resource or a GDImage instance * @param resource|\GdImage A variable to be tested * @return bool True if $image is a resource or a GDImage instance */ public static function isGdImage($image): bool { return \is_resource($image) || (\is_object($image) && $image instanceof \GdImage); } /** * Return true if image is initialized * * @return bool Is image initialized */ public function isImageDefined(): bool { return static::isGdImage($this->image); } //=============================================================================================================================== //============================================================CREATE/DESTROY===================================================== //=============================================================================================================================== /** * (Static method) Create a new image with transparent background * * @param int $width Pixel width of the image * @param int $height Pixel height of the image * @return Image Return Image instance */ public static function newCanvas(int $width, int $height): Image { return (new Image)->resetCanvas($width, $height); } /** * Create a new image with transparent background * * @param int $width Pixel width of the image * @param int $height Pixel height of the image * @return $this Fluent interface */ public function resetCanvas(int $width, int $height): Image { if (($this->image = \imagecreatetruecolor($width, $height)) === false) { $this->resetFields(); return $this; } \imagealphablending($this->image, false); \imagesavealpha($this->image, true); \imagefill($this->image, 0, 0, \imagecolorallocatealpha($this->image, 0, 0, 0, 127)); $this->width = $width; $this->height = $height; return $this; } /** * (Static method) Open image from local path or URL. * * @param string $path Path to the image file * @return Image Return Image instance */ public static function fromPath(string $path): Image { return (new Image)->path($path); } /** * Open image from local path or URL. * * @param string $path Path to the image file * @return $this Fluent interface */ public function path(string $path): Image { $imageSize = \getimagesize($path); if ($imageSize === false) { return $this; } list($this->width, $this->height, $this->type, $attr) = $imageSize; switch ($this->type) { case 1: $this->image = \imagecreatefromgif($path); break; case 2: $this->image = \imagecreatefromjpeg($path); break; case 3: $this->image = \imagecreatefrompng($path); break; } if ($this->image === false) { return $this->resetFields(); } if (!\imageistruecolor($this->image)) { \imagepalettetotruecolor($this->image); } \imagealphablending($this->image, false); \imagesavealpha($this->image, true); return $this; } /** * (Static method) Open an uploaded image from html form (using $file["tmp_name"]). * * @param array $file File array from html form * @return Image Return Image instance */ public static function fromForm(array $file): Image { return (new Image)->form($file); } /** * Open an uploaded image from html form (using $file["tmp_name"]). * * @param array $file File array from html form * @return $this Fluent interface */ public function form(array $file): Image { if (isset($file) && isset($file["name"]) && $file["name"] != "") { $this->path($file["tmp_name"]); } return $this; } /** * (Static method) Create an Image instance from image raw data. * * @param string $data Raw data of the image * @return Image Return Image instance */ public static function fromData(string $data): Image { return (new Image)->data($data); } /** * Create an Image instance from image raw data. * * @param string $data Raw data of the image * @return $this Fluent interface */ public function data(string $data): Image { if (($this->image = \imagecreatefromstring($data)) === false) { return $this->resetFields(); } $this->width = \imagesx($this->image); $this->height = \imagesy($this->image); $this->type = 3; if (!\imageistruecolor($this->image)) { \imagepalettetotruecolor($this->image); } \imagealphablending($this->image, false); \imagesavealpha($this->image, true); return $this; } /** * (Static method) Create an Image instance from base64 image data. * * @param string $base64 Base64 data of the image * @return Image Return Image instance */ public static function fromBase64(string $base64): Image { return (new Image)->base64($base64); } /** * Create an Image instance from base64 image data. * * @param string $base64 Base64 data of the image * @return $this Fluent interface */ public function base64(string $base64): Image { return $this->data(\base64_decode($base64)); } /** * (Static method) Open image from URL with cURL. * * @param string $url Url of the image file * @param array $curlOptions cURL options * @param bool $failOnError If true, throw an exception if the url cannot be loaded * @return Image Return Image instance * @throws \Exception */ public static function fromCurl(string $url, array $curlOptions = [], bool $failOnError = false): Image { return (new Image)->curl($url, $curlOptions, $failOnError); } /** * Open image from URL with cURL. * * @param string $url Url of the image file * @param array $curlOptions cURL options * @param bool $failOnError If true, throw an exception if the url cannot be loaded * @return $this Fluent interface * @throws \Exception */ public function curl(string $url, array $curlOptions = [], bool $failOnError = false): Image { $defaultCurlOptions = [ CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0', CURLOPT_REFERER => \strtolower($_SERVER["REQUEST_SCHEME"] . '://' . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]), CURLOPT_RETURNTRANSFER => 1, CURLOPT_TIMEOUT => 5, ]; $curl = \curl_init(); \curl_setopt($curl, CURLOPT_URL, $url); \curl_setopt_array($curl, $defaultCurlOptions + $curlOptions); $image = \curl_exec($curl); if ($failOnError && \curl_errno($curl)) { throw new \Exception(\curl_error($curl)); } \curl_close($curl); if ($image === false) { return $this->resetFields(); } return $this->data($image); } /** * Destroy image * * @return $this Fluent interface */ public function destroy(): Image { if ($this->isImageDefined()) { \imagedestroy($this->image); } $this->resetFields(); return $this; } /** * Reset private fields * * @return $this Fluent interface */ private function resetFields(): Image { $this->image = null; $this->type = null; $this->width = null; $this->height = null; return $this; } //=============================================================================================================================== //============================================================UTILS============================================================== //=============================================================================================================================== /** * Convert horizontal `Image::ALIGN_...` to int position. * * @param int|string $posX Pixel position or `Image::ALIGN_...` constant * @param int $width Width of the element to align * @return int Horizontal pixel position */ private function convertPosX($posX, int $width = 0): int { switch ($posX) { case static::ALIGN_LEFT: return 0; case static::ALIGN_CENTER: return \round($this->width / 2 - $width / 2); case static::ALIGN_RIGHT: return $this->width - $width; } return \round($posX); } /** * Convert vertical `Image::ALIGN_...` to int position. * * @param int|string $posY Pixel position or `Image::ALIGN_...` constant * @param int $height Height of the element to align * @return int Vertical pixel position */ private function convertPosY($posY, int $height = 0): int { switch ($posY) { case static::ALIGN_TOP: return 0; case static::ALIGN_MIDDLE: return \round($this->height / 2 - $height / 2); case static::ALIGN_BOTTOM: return $this->height - $height; } return \round($posY); } //=============================================================================================================================== //=================================================RESIZING/ROTATE/TRUNCATE====================================================== //=============================================================================================================================== /** * Rotate counterclockwise the image * * @param float $angle Angle in degrees * @return $this Fluent interface */ public function rotate(float $angle): Image { if (!$this->isImageDefined()) { return $this; } if (($image = \imagerotate($this->image, Geometry2D::degrees0to360($angle), $this->colorAllocate('#000000FF'), 0)) !== false) { $this->image = $image; $this->width = \imagesx($this->image); $this->height = \imagesy($this->image); } return $this; } /** * Resize the image keeping the proportions. * * @param int $width Max width * @param int $height Max height * @return $this Fluent interface */ public function resizeProportion(int $width, int $height): Image { $finalWidth = $width; $finalHeight = \round($this->height * $width / $this->width); if ($finalHeight > $height) { $finalWidth = \round($this->width * $height / $this->height); $finalHeight = $height; } return $this->resize($finalWidth, $finalHeight); } /** * Downscale the image keeping the proportions. * * @param int $maxWidth Max width * @param int $maxHeight Max height * @return $this Fluent interface */ public function downscaleProportion(int $maxWidth, int $maxHeight): Image { if ($this->width > $maxWidth || $this->height > $maxHeight) { if ($this->width > $this->height) { $finalHeight = \round($this->height * $maxWidth / $this->width); $finalWidth = $maxWidth; if ($finalHeight > $maxHeight) { $finalWidth = \round($this->width * $maxHeight / $this->height); $finalHeight = $maxHeight; } } else { $finalWidth = \round($this->width * $maxHeight / $this->height); $finalHeight = $maxHeight; } } else { $finalWidth = $this->width; $finalHeight = $this->height; } return $this->resize($finalWidth, $finalHeight); } /** * Resize the image. * * @param int $width Target width * @param int $height Target height * @return $this Fluent interface */ public function resize(int $width, int $height): Image { if (!$this->isImageDefined()) { return $this; } $image = Image::newCanvas($width, $height)->getImage(); if (\imagecopyresampled($image, $this->image, 0, 0, 0, 0, $width, $height, $this->width, $this->height) !== false) { $this->image = $image; $this->width = $width; $this->height = $height; } return $this; } /** * Downscale the image keeping the proportions then crop to fit to $width and $height params. * Use $posX and $posY to select the cropping zone (You can use `Image::ALIGN_...`). * * @param int $width Max width * @param int $height Max height * @param int|string $posX Left crop position in pixel. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` * @param int|string $posY Top crop position in pixel. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` * @return $this Fluent interface */ public function downscaleAndCrop(int $width, int $height, $posX = Image::ALIGN_CENTER, $posY = Image::ALIGN_MIDDLE): Image { if ($this->width < $width) { $width = $this->width; } if ($this->height < $height) { $height = $this->height; } $finalWidth = \round($this->width * $height / $this->height); $finalHeight = $height; if ($finalWidth < $width) { $finalHeight = \round($this->height * $width / $this->width); $finalWidth = $width; } if ($this->downscaleProportion($finalWidth, $finalHeight)) { $this->crop($width, $height, $posX, $posY); } return $this; } /** * Crop to fit to $width and $height params. * Use $posX and $posY to select the cropping zone (You can use `Image::ALIGN_...`). * * @param int $width Target width * @param int $height Target height * @param int|string $posX Left crop position in pixel. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` * @param int|string $posY Top crop position in pixel. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` * @return $this Fluent interface */ public function crop(int $width, int $height, $posX = Image::ALIGN_CENTER, $posY = Image::ALIGN_MIDDLE): Image { if (!$this->isImageDefined()) { return $this; } if ($this->width < $width) { $width = $this->width; } if ($this->height < $height) { $height = $this->height; } //============================================== $posX = $this->convertPosX($posX, $width); $posY = $this->convertPosY($posY, $height); //============================================== if ($posX < 0) { $posX = 0; } if ($posX + $width > $this->width) { $posX = $this->width - $width; } if ($posY < 0) { $posY = 0; } if ($posY + $height > $this->height) { $posY = $this->height - $height; } //============================================== if ( ($image = \imagecreatetruecolor($width, $height)) !== false && \imagealphablending($image, false) !== false && \imagesavealpha($image, true) !== false && ($transparent = $this->colorAllocate('#000000FF')) !== false && \imagefill($image, 0, 0, $transparent) !== false && \imagecopyresampled($image, $this->image, 0, 0, $posX, $posY, $width, $height, $width, $height) !== false ) { $this->image = $image; $this->width = $width; $this->height = $height; } return $this; } //=============================================================================================================================== //==========================================================COLOR================================================================ //=============================================================================================================================== /** * Format the string color. * * @param string $stringColor Hexadecimal string color * @return string Formatted hexadecimal string color */ private static function formatColor(string $stringColor): string { $stringColor = \trim(\str_replace('#', '', $stringColor)); switch (\mb_strlen($stringColor)) { case 3 : $r = \substr($stringColor, 0, 1); $g = \substr($stringColor, 1, 1); $b = \substr($stringColor, 2, 1); return $r . $r . $g . $g . $b . $b . '00'; case 6 : return $stringColor . '00'; case 8 : return $stringColor; default: return '00000000'; } } /** * Allocate a new color to the image. * * @param string $color Hexadecimal string color * @return int|false Color id */ private function colorAllocate(string $color) { $color = static::formatColor($color); $red = \hexdec(\substr($color, 0, 2)); $green = \hexdec(\substr($color, 2, 2)); $blue = \hexdec(\substr($color, 4, 2)); $alpha = \floor(\hexdec(\substr($color, 6, 2)) / 2); $colorId = \imagecolorexactalpha($this->image, $red, $green, $blue, $alpha); if ($colorId === -1) { $colorId = \imagecolorallocatealpha($this->image, $red, $green, $blue, $alpha); } return $colorId; } //=============================================================================================================================== //==========================================================PASTE================================================================ //=============================================================================================================================== /** * Paste the image at $posX and $posY position (You can use `Image::ALIGN_...`). * * @param Image $image Image instance to be paste on * @param int|string $posX Left position in pixel. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` * @param int|string $posY Top position in pixel. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` * @return $this Fluent interface */ public function pasteOn(Image $image, $posX = Image::ALIGN_CENTER, $posY = Image::ALIGN_MIDDLE): Image { if (!$this->isImageDefined() || !$image->isImageDefined()) { return $this; } return $this->pasteGdImageOn($image->getImage(), $image->getWidth(), $image->getHeight(), $posX, $posY); } /** * Paste the image at $posX and $posY position (You can use `Image::ALIGN_...`). * * @param resource|\GdImage $image Image resource * @param int $imageWidth Image width to paste * @param int $imageHeight Image height to paste * @param int|string $posX Left position in pixel. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` * @param int|string $posY Top position in pixel. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` * @return $this Fluent interface */ public function pasteGdImageOn($image, int $imageWidth, int $imageHeight, $posX = Image::ALIGN_CENTER, $posY = Image::ALIGN_MIDDLE): Image { if (!$this->isImageDefined() || !static::isGdImage($image)) { return $this; } $posX = $this->convertPosX($posX, $imageWidth); $posY = $this->convertPosY($posY, $imageHeight); \imagesavealpha($this->image, false); \imagealphablending($this->image, true); \imagecopy($this->image, $image, $posX, $posY, 0, 0, $imageWidth, $imageHeight); \imagealphablending($this->image, false); \imagesavealpha($this->image, true); return $this; } /** * Use a grayscale image (`$mask`) to apply transparency to the image. * * @param Image $mask Image instance of the grayscale alpha mask * @return $this Fluent interface */ public function alphaMask(Image $mask): Image { if (!$this->isImageDefined() || !$mask->isImageDefined()) { return $this; } $this->downscaleAndCrop($mask->getWidth(), $mask->getHeight(), static::ALIGN_CENTER, static::ALIGN_MIDDLE); if (($newImage = \imagecreatetruecolor($mask->getWidth(), $mask->getHeight())) === false) { return $this; } \imagealphablending($newImage, false); \imagesavealpha($newImage, true); for ($i = 0; $i < $this->height; $i++) { for ($j = 0; $j < $this->width; $j++) { $alpha = \floor((255 - \imagecolorat($mask->getImage(), $j, $i) & 0xFF) / 2); $red = 0; $green = 0; $blue = 0; if ($alpha != 127) { $rgb = \imagecolorat($this->image, $j, $i); $alpha = 127 - \ceil((127 - (($rgb >> 24) & 0x7F)) * (127 - $alpha) / 127); } if ($alpha != 127) { $red = ($rgb >> 16) & 0xFF; $green = ($rgb >> 8) & 0xFF; $blue = $rgb & 0xFF; } $newColor = \imagecolorexactalpha($newImage, $red, $green, $blue, $alpha); if ($newColor === -1) { $newColor = \imagecolorallocatealpha($newImage, $red, $green, $blue, $alpha); } if (!\imagesetpixel($newImage, $j, $i, $newColor)) { return $this; } } } \imagedestroy($this->image); $this->image = $newImage; return $this; } /** * change the image opacity * * @param float $opacity Opacity (0 to 1) * @return $this Fluent interface */ public function setOpacity(float $opacity): Image { if (!$this->isImageDefined()) { return $this; } \imagealphablending($this->image, false); \imagesavealpha($this->image, true); \imagefilter($this->image, IMG_FILTER_COLORIZE, 0, 0, 0, \round(127 * (1 - $opacity))); return $this; } //=============================================================================================================================== //=========================================================POST PROD============================================================= //=============================================================================================================================== /** * Apply a grayscale filter on the image. * * @return $this Fluent interface */ public function grayscale(): Image { if (!$this->isImageDefined()) { return $this; } \imagefilter($this->image, IMG_FILTER_GRAYSCALE); return $this; } /** * Write text on the image. * * @param string $string Text to be added on the image * @param string $fontPath Path to the TTF file * @param float $fontSize Font size * @param string $color Hexadecimal string color * @param float|string $posX Left position in pixel. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` * @param float|string $posY Top position in pixel. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` * @param float|string $anchorX Horizontal anchor of the text. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` * @param float|string $anchorY Vertical anchor of the text. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` * @param float $rotation Counterclockwise text rotation in degrees * @param float $letterSpacing add space between letters * @return $this Fluent interface */ public function writeText(string $string, string $fontPath, float $fontSize, string $color = 'ffffff', $posX = 0, $posY = 0, $anchorX = Image::ALIGN_CENTER, $anchorY = Image::ALIGN_MIDDLE, float $rotation = 0, float $letterSpacing = 0): Image { $this->writeTextAndGetBoundingBox($string, $fontPath, $fontSize, $color, $posX, $posY, $anchorX, $anchorY, $rotation, $letterSpacing); return $this; } /** * Write text on the image and get the bounding box of the text in the image. * * @param string $string Text to be added on the image * @param string $fontPath Path to the TTF file * @param float $fontSize Font size * @param string $color Hexadecimal string color * @param float|string $posX Left position in pixel. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` * @param float|string $posY Top position in pixel. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` * @param float|string $anchorX Horizontal anchor of the text. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` * @param float|string $anchorY Vertical anchor of the text. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` * @param float $rotation Counterclockwise text rotation in degrees * @param float $letterSpacing add space between letters * @return array Bounding box positions of the text */ public function writeTextAndGetBoundingBox(string $string, string $fontPath, float $fontSize, string $color = 'ffffff', $posX = 0, $posY = 0, $anchorX = Image::ALIGN_CENTER, $anchorY = Image::ALIGN_MIDDLE, float $rotation = 0, float $letterSpacing = 0): array { if (!$this->isImageDefined()) { return []; } $posX = $this->convertPosX($posX); $posY = $this->convertPosY($posY); \imagesavealpha($this->image, false); \imagealphablending($this->image, true); $color = $this->colorAllocate($color); if ($color === false) { return []; } if ( $anchorX == static::ALIGN_LEFT || $anchorX == static::ALIGN_CENTER || $anchorX == static::ALIGN_RIGHT || $anchorY == static::ALIGN_TOP || $anchorY == static::ALIGN_MIDDLE || $anchorY == static::ALIGN_BOTTOM ) { if ( ($newImg = \imagecreatetruecolor(1, 1)) === false || ($posText = $this->imagettftextWithSpacing($newImg, $fontSize, $rotation, 0, 0, $color, $fontPath, $string, $letterSpacing)) === false ) { return []; } \imagedestroy($newImg); $xMin = 0; $xMax = 0; $yMin = 0; $yMax = 0; for ($i = 0; $i < 8; $i += 2) { if ($posText[$i] < $xMin) { $xMin = $posText[$i]; } if ($posText[$i] > $xMax) { $xMax = $posText[$i]; } if ($posText[$i + 1] < $yMin) { $yMin = $posText[$i + 1]; } if ($posText[$i + 1] > $yMax) { $yMax = $posText[$i + 1]; } } $sizeWidth = $xMax - $xMin; $sizeHeight = $yMax - $yMin; switch ($anchorX) { case static::ALIGN_LEFT : $posX = $posX - $xMin; break; case static::ALIGN_CENTER : $posX = $posX - $sizeWidth / 2 - $xMin; break; case static::ALIGN_RIGHT : $posX = $posX - $sizeWidth - $xMin; break; } switch ($anchorY) { case static::ALIGN_TOP : $posY = $posY - $yMin; break; case static::ALIGN_MIDDLE : $posY = $posY - $sizeHeight / 2 - $yMin; break; case static::ALIGN_BOTTOM : $posY = $posY - $sizeHeight - $yMin; break; } } $posText = $this->imagettftextWithSpacing($this->image, $fontSize, $rotation, $posX, $posY, $color, $fontPath, $string, $letterSpacing); if ($posText === false) { return []; } \imagealphablending($this->image, false); \imagesavealpha($this->image, true); return [ 'top-left' => [ 'x' => $posText[6], 'y' => $posText[7] ], 'top-right' => [ 'x' => $posText[4], 'y' => $posText[5] ], 'bottom-left' => [ 'x' => $posText[0], 'y' => $posText[1] ], 'bottom-right' => [ 'x' => $posText[2], 'y' => $posText[3] ], 'baseline' => [ 'x' => $posX, 'y' => $posY ] ]; } /** * @param $image * @param float $size * @param float $angle * @param float $x * @param float $y * @param int $color * @param string $font * @param string $text * @param float $spacing * @return array|false */ private function imagettftextWithSpacing($image, float $size, float $angle, float $x, float $y, int $color, string $font, string $text, float $spacing = 0) { if ($spacing == 0) { return \imagettftext($image, $size, $angle, \round($x), \round($y), $color, $font, $text); } else { $length = \mb_strlen($text); if ($length == 0) { return false; } $letterPos = ['x' => $x, 'y' => $y]; $textWidth = $spacing * ($length - 1); $top = 0; $bottom = 0; for ($i = 0; $i < $length; ++$i) { $char = \mb_substr($text, $i, 1); \imagettftext($image, $size, $angle, \round($letterPos['x']), \round($letterPos['y']), $color, $font, $char); $bbox = \imagettfbbox($size, 0, $font, $char); $letterPos = Geometry2D::getDstXY($letterPos['x'], $letterPos['y'], $angle, $spacing + $bbox[2]); $textWidth += $bbox[2]; if ($top > $bbox[5]) { $top = $bbox[5]; } if ($bottom < $bbox[1]) { $bottom = $bbox[1]; } } $bottomLeft = Geometry2D::getDstXY($x, $y, $angle - 90, $bottom); $bottomRight = Geometry2D::getDstXY($bottomLeft['x'], $bottomLeft['y'], $angle, $textWidth); $topLeft = Geometry2D::getDstXY($x, $y, $angle + 90, \abs($top)); $topRight = Geometry2D::getDstXY($topLeft['x'], $topLeft['y'], $angle, $textWidth); return [$bottomLeft['x'], $bottomLeft['y'], $bottomRight['x'], $bottomRight['y'], $topRight['x'], $topRight['y'], $topLeft['x'], $topLeft['y']]; } } /** * Draw a rectangle. * * @param int $left Left position in pixel * @param int $top Top position in pixel * @param int $right Right position in pixel * @param int $bottom Bottom position in pixel * @param string $color Hexadecimal string color * @return $this Fluent interface */ public function drawRectangle(int $left, int $top, int $right, int $bottom, string $color): Image { if (!$this->isImageDefined()) { return $this; } $color = $this->colorAllocate($color); if (($bottom - $top) <= 1.5) { \imageline($this->image, $left, $top, $right, $top, $color); } elseif (($right - $left) <= 1.5) { \imageline($this->image, $left, $top, $left, $bottom, $color); } else { \imagefilledrectangle($this->image, $left, $top, $right, $bottom, $color); } return $this; } /** * Draw a polygon. * * @param int[] $points Array of polygon's points [x1, y1, x2, y2, x3, y3...] * @param string $color Hexadecimal string color * @return $this Fluent interface */ public function drawPolygon(array $points, string $color = '000000', $antialias = false): Image { if (!$this->isImageDefined()) { return $this; } $color = $this->colorAllocate($color); if ($color === false) { return $this; } if ($antialias) { \imageantialias($this->image, true); if (PHP_MAJOR_VERSION >= 8) { \imagepolygon($this->image, $points, $color); } else { \imagepolygon($this->image, $points, \count($points) / 2, $color); } } if (PHP_MAJOR_VERSION >= 8) { \imagefilledpolygon($this->image, $points, $color); } else { \imagefilledpolygon($this->image, $points, \count($points) / 2, $color); } if ($antialias) { \imageantialias($this->image, false); } return $this; } /** * Draw a Line from `$originX, $originY` to `$dstX, $dstY`. * * @param int $originX Horizontal start position in pixel * @param int $originY Vertical start position in pixel * @param int $dstX Horizontal destination in pixel * @param int $dstY Vertical destination in pixel * @param int $weight Line weight in pixel * @param string $color Hexadecimal string color * @return $this Fluent interface */ public function drawLine(int $originX, int $originY, int $dstX, int $dstY, int $weight, string $color = '#000000'): Image { if (!$this->isImageDefined()) { return $this; } $angleAndLength = Geometry2D::getAngleAndLengthFromPoints($originX, $originY, $dstX, $dstY); return $this->drawLineWithAngle($originX, $originY, $angleAndLength['angle'], $angleAndLength['length'], $weight, $color); } /** * Draw a line using angle and length. * * @param int $originX Horizontal start position in pixel * @param int $originY Vertical start position in pixel * @param float $angle Counterclockwise angle in degrees * @param float $length Line length in pixel * @param int $weight Line weight in pixel * @param string $color Hexadecimal string color * @return $this Fluent interface */ public function drawLineWithAngle(int $originX, int $originY, float $angle, float $length, int $weight, string $color = '#000000'): Image { $angle = Geometry2D::degrees0to360($angle); $points1 = Geometry2D::getDstXY($originX, $originY, Geometry2D::degrees0to360($angle - 90), \floor($weight / 2)); $points2 = Geometry2D::getDstXY($points1['x'], $points1['y'], $angle, $length); $points4 = Geometry2D::getDstXY($originX, $originY, Geometry2D::degrees0to360($angle + 90), \floor($weight / 2)); $points3 = Geometry2D::getDstXY($points4['x'], $points4['y'], $angle, $length); return $this->drawPolygon( [ \round($points1['x']), \round($points1['y']), \round($points2['x']), \round($points2['y']), \round($points3['x']), \round($points3['y']), \round($points4['x']), \round($points4['y']) ], $color, true ); } /** * Draw an arrow with angle and length. * * @param int $originX Horizontal start position in pixel * @param int $originY Vertical start position in pixel * @param float $angle Counterclockwise angle in degrees * @param float $length Line length in pixel * @param int $weight Line weight in pixel * @param string $color Hexadecimal string color * @return $this Fluent interface */ public function drawArrowWithAngle(int $originX, int $originY, float $angle, float $length, int $weight, string $color = '#000000'): Image { if (!$this->isImageDefined()) { return $this; } $headOrigin = Geometry2D::getDstXYRounded($originX, $originY, Geometry2D::degrees0to360($angle), \round($length - $weight / 2)); $this->drawLineWithAngle($headOrigin['x'], $headOrigin['y'], Geometry2D::degrees0to360($angle + 150), \round($length / 10), $weight, $color); $this->drawLineWithAngle($headOrigin['x'], $headOrigin['y'], Geometry2D::degrees0to360($angle - 150), \round($length / 10), $weight, $color); return $this->drawLineWithAngle($originX, $originY, $angle, $length, $weight, $color); } /** * Draw and arrow from `$originX, $originY` to `$dstX, $dstY`. * * @param int $originX Horizontal start position in pixel * @param int $originY Vertical start position in pixel * @param int $dstX Horizontal destination in pixel * @param int $dstY Vertical destination in pixel * @param int $weight Line weight in pixel * @param string $color Hexadecimal string color * @return $this Fluent interface */ public function drawArrow(int $originX, int $originY, int $dstX, int $dstY, int $weight, string $color = '#000000'): Image { if (!$this->isImageDefined()) { return $this; } $angleAndLength = Geometry2D::getAngleAndLengthFromPoints($originX, $originY, $dstX, $dstY); return $this->drawArrowWithAngle($originX, $originY, $angleAndLength['angle'], $angleAndLength['length'], $weight, $color); } /** * Draw a circle. * * @param int $posX Left position of the circle in pixel * @param int $posY Top position of the circle in pixel * @param int $diameter Circle diameter in pixel * @param string $color Hexadecimal string color * @param string $anchorX Horizontal anchor of the text. You can use `Image::ALIGN_LEFT`, `Image::ALIGN_CENTER`, `Image::ALIGN_RIGHT` * @param string $anchorY Vertical anchor of the text. You can use `Image::ALIGN_TOP`, `Image::ALIGN_MIDDLE`, `Image::ALIGN_BOTTOM` * @return $this Fluent interface */ public function drawCircle(int $posX, int $posY, int $diameter, string $color = '#FFFFFF', string $anchorX = Image::ALIGN_CENTER, string $anchorY = Image::ALIGN_MIDDLE): Image { if (!$this->isImageDefined()) { return $this; } $color = $this->colorAllocate($color); if ($color === false) { return $this; } switch ($anchorX) { case static::ALIGN_LEFT : $posX = \round($posX + $diameter / 2); break; case static::ALIGN_CENTER : break; case static::ALIGN_RIGHT : $posX = \round($posX - $diameter / 2); break; } switch ($anchorY) { case static::ALIGN_TOP : $posY = \round($posY + $diameter / 2); break; case static::ALIGN_MIDDLE : break; case static::ALIGN_BOTTOM : $posY = \round($posY - $diameter / 2); break; } \imagefilledellipse($this->image, $posX, $posY, $diameter, $diameter, $color); return $this; } //=============================================================================================================================== //=========================================================GET PICTURE=========================================================== //=============================================================================================================================== /** * Save the image to PNG file. * * @param string $path Path to the PNG image file * @return bool return true if success */ public function savePNG(string $path): bool { if (!$this->isImageDefined()) { return false; } return \imagepng($this->image, $path); } /** * Save the image to JPG file. * * @param string $path Path to the JPG image file * @param int $quality JPG quality : 0 to 100 * @return bool return true if success */ public function saveJPG(string $path, int $quality = -1): bool { if (!$this->isImageDefined()) { return false; } return \imagejpeg($this->image, $path, $quality); } /** * Save the image to GIF file. * * @param string $path Path to the GIF image file * @return bool return true if success */ public function saveGIF(string $path): bool { if (!$this->isImageDefined()) { return false; } return \imagegif($this->image, $path); } /** * Display in PNG format. */ public function displayPNG() { if ($this->isImageDefined()) { \imagepng($this->image); } } /** * Display in JPG format. * * @param int $quality JPG quality : 0 to 100 */ public function displayJPG(int $quality = -1) { if ($this->isImageDefined()) { \imagejpeg($this->image, null, $quality); } } /** * Display in GIF format. */ public function displayGIF() { if ($this->isImageDefined()) { \imagegif($this->image); } } /** * Get image raw data * * @param callable $imgFunction Image function to be called * @return string Data */ private function getData(callable $imgFunction): string { if (!$this->isImageDefined()) { return ''; } \ob_start(); $imgFunction(); $imageData = \ob_get_contents(); \ob_end_clean(); return $imageData; } /** * Get image PNG raw data * * @return string Data */ public function getDataPNG(): string { return $this->getData(function () { $this->displayPNG(); }); } /** * Get image JPG raw data * * @param int $quality JPG quality : 0 to 100 * @return string Data */ public function getDataJPG(int $quality = -1): string { return $this->getData(function () use ($quality) { $this->displayJPG($quality); }); } /** * Get image GIF raw data * * @return string Data */ public function getDataGIF(): string { return $this->getData(function () { $this->displayGIF(); }); } /** * Get image PNG base64 data * * @return string Data */ public function getBase64PNG(): string { return \base64_encode($this->getDataPNG()); } /** * Get image JPG base64 data * * @param int $quality JPG quality : 0 to 100 * @return string Data */ public function getBase64JPG(int $quality = -1): string { return \base64_encode($this->getDataJPG($quality)); } /** * Get image GIF base64 data * * @return string Data */ public function getBase64GIF(): string { return \base64_encode($this->getDataGIF()); } /** * Get image PNG base64 data for <img src=""> tag. * * @return string Data */ public function getBase64SourcePNG(): string { return 'data:image/png;base64,' . $this->getBase64PNG(); } /** * Get image JPG base64 data for <img src=""> tag. * * @param int $quality JPG quality : 0 to 100 * @return string Data */ public function getBase64SourceJPG(int $quality = -1): string { return 'data:image/jpeg;base64,' . $this->getBase64JPG($quality); } /** * Get image GIF base64 data for <img src=""> tag. * * @return string Data */ public function getBase64SourceGIF(): string { return 'data:image/gif;base64,' . $this->getBase64GIF(); } }
| ver. 1.1 | |
.
| PHP 8.3.30 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка