Current Path : /var/www/www-root/data/www.catalog.monolith-realty.ru/bitrix/modules/main/lib/File/Image/ |
Current File : /var/www/www-root/data/www.catalog.monolith-realty.ru/bitrix/modules/main/lib/File/Image/Gd.php |
<?php /** * Bitrix Framework * @package bitrix * @subpackage main * @copyright 2001-2023 Bitrix */ namespace Bitrix\Main\File\Image; use Bitrix\Main\File; class Gd extends Engine { protected $resource; protected $format; /** * @inheritDoc */ public function load() { $this->clear(); $info = $this->getInfo(); if ($info && $info->isSupported()) { $this->format = $info->getFormat(); $resource = null; switch ($this->format) { case File\Image::FORMAT_GIF: $resource = imagecreatefromgif($this->file); break; case File\Image::FORMAT_PNG: $resource = imagecreatefrompng($this->file); break; case File\Image::FORMAT_WEBP: $resource = imagecreatefromwebp($this->file); break; case File\Image::FORMAT_BMP: $resource = imagecreatefrombmp($this->file); break; case File\Image::FORMAT_JPEG: ini_set('gd.jpeg_ignore_warning', 1); $resource = imagecreatefromjpeg($this->file); break; } if ($resource) { $this->resource = $resource; return true; } } return false; } /** * @inheritDoc */ public function rotate($angle, Color $bgColor) { if ($this->resource === null) { return false; } $angle = 360 - $angle; $alpha = (1.0 - $bgColor->getAlpha()) * 127; $color = imagecolorallocatealpha($this->resource, $bgColor->getRed(), $bgColor->getGreen(), $bgColor->getBlue(), $alpha); $resource = imagerotate($this->resource, $angle, $color); if ($resource === false) { return false; } $this->clear(); $this->resource = $resource; return true; } /** * @inheritDoc */ public function flipVertical() { if ($this->resource === null) { return false; } return imageflip($this->resource, IMG_FLIP_VERTICAL); } /** * @inheritDoc */ public function flipHorizontal() { if ($this->resource === null) { return false; } return imageflip($this->resource, IMG_FLIP_HORIZONTAL); } /** * @inheritDoc */ public function setOrientation($orientation) { // not implemented return true; } /** * @inheritDoc */ public function resize(Rectangle $source, Rectangle $destination) { if ($this->resource === null) { return false; } $destinationWidth = $destination->getWidth(); $destinationHeight = $destination->getHeight(); if (($picture = imagecreatetruecolor($destinationWidth, $destinationHeight))) { $transparentColor = -1; imagealphablending($picture, false); if ($this->format == File\Image::FORMAT_PNG || $this->format == File\Image::FORMAT_WEBP) { $color = imagecolorallocatealpha($picture, 0, 0, 0, 127); imagefilledrectangle($picture, 0, 0, $destinationWidth, $destinationHeight, $color); } elseif ($this->format == File\Image::FORMAT_GIF) { // save transparency $transparentColor = $this->getTransparentColor(); if ($transparentColor >= 0) { $rgb = imagecolorsforindex($this->resource, $transparentColor); $transparentColor = imagecolorallocatealpha($picture, $rgb['red'], $rgb['green'], $rgb['blue'], 127); imagefilledrectangle($picture, 0, 0, $destinationWidth, $destinationHeight, $transparentColor); } } if (imagecopyresampled($picture, $this->resource, 0, 0, $source->getX(), $source->getY(), $destinationWidth, $destinationHeight, $source->getWidth(), $source->getHeight())) { $this->clear(); $this->resource = $picture; // restore transparency if ($transparentColor >= 0) { $this->restoreTransparency($transparentColor); } return true; } } return false; } /** * @inheritDoc */ public function filter(Mask $mask) { if ($this->resource === null) { return false; } $transparentColor = -1; if ($this->format == File\Image::FORMAT_GIF) { // Process transparency for GIFs $transparentColor = $this->getTransparentColor(); } // Fix left top corner $newPixel = $this->calculatePixel($mask, 0, 0); $result = imageconvolution($this->resource, $mask->getValue(), 1, 0); if ($result) { // Fix left top corner imagealphablending($this->resource, false); imagesetpixel($this->resource, 0, 0, $newPixel); // restore transparency if ($transparentColor >= 0) { $this->restoreTransparency($transparentColor); } } return $result; } protected function getTransparentColor(): int { $transparentColor = imagecolortransparent($this->resource); if ($transparentColor < 0 || $transparentColor >= imagecolorstotal($this->resource)) { return -1; } return $transparentColor; } protected function restoreTransparency($transparentColor) { imagecolortransparent($this->resource, $transparentColor); $width = $this->getWidth(); $height = $this->getHeight(); for ($y = 0; $y < $height; ++$y) { for ($x = 0; $x < $width; ++$x) { if (((imagecolorat($this->resource, $x, $y) >> 24) & 0x7F) >= 100) { imagesetpixel($this->resource, $x, $y, $transparentColor); } } } } /** * @param Mask $mask * @param int $x * @param int $y * @return false|int */ protected function calculatePixel($mask, $x, $y) { $width = $this->getWidth(); $height = $this->getHeight(); $alpha = (imagecolorat($this->resource, $x, $y) >> 24) & 0xFF; $newR = $newG = $newB = 0; for ($j = 0; $j < 3; ++$j) { $yv = $y - 1 + $j; if ($yv < 0) { $yv = 0; } elseif ($yv >= $height) { $yv = $height - 1; } for ($i = 0; $i < 3; ++$i) { $xv = $x - 1 + $i; if ($xv < 0) { $xv = 0; } elseif ($xv >= $width) { $xv = $width - 1; } $m = $mask[$j][$i]; $rgb = imagecolorat($this->resource, $xv, $yv); $newR += (($rgb >> 16) & 0xFF) * $m; $newG += (($rgb >> 8) & 0xFF) * $m; $newB += ($rgb & 0xFF) * $m; } } $newR = ($newR > 255 ? 255 : ($newR < 0 ? 0 : $newR)); $newG = ($newG > 255 ? 255 : ($newG < 0 ? 0 : $newG)); $newB = ($newB > 255 ? 255 : ($newB < 0 ? 0 : $newB)); return imagecolorallocatealpha($this->resource, $newR, $newG, $newB, $alpha); } /** * @inheritDoc */ public function drawTextWatermark(TextWatermark $watermark) { if ($this->resource === null) { return false; } $font = $watermark->getFont(); if (!file_exists($font)) { return false; } $utfText = $watermark->getUtfText(); $width = $this->getWidth(); $height = $this->getHeight(); if (($textWidth = $watermark->getWidth()) > 0) { $textBox = imagettfbbox(20, 0, $font, $utfText); if (!is_array($textBox)) { return false; } $scale = $textWidth / ($textBox[2] - $textBox[0]); $fontSize = 20 * $scale; $position = new Rectangle($textWidth, ($textBox[0] - $textBox[7]) * $scale); } else { $fontSize = $watermark->getFontSize($width); $textBox = imagettfbbox($fontSize, 0, $font, $utfText); $position = new Rectangle(($textBox[2] - $textBox[0]), ($textBox[0] - $textBox[7])); } $watermark->alignPosition($width, $height, $position); $color = $watermark->getColor(); $textColor = imagecolorallocate($this->resource, $color->getRed(), $color->getGreen(), $color->getBlue()); if ($watermark->getVerticalAlignment() == Watermark::ALIGN_BOTTOM) { // Try to take into consideration font's descenders. // Coordinates in imagettftext are for font's *baseline*. // Let the descenders be 20% of the font size. $descender = $fontSize * 0.2; $y = $position->getY() + $position->getHeight() - $descender; // baseline } else { $y = $position->getY() + $fontSize; // baseline } $result = imagettftext($this->resource, $fontSize, 0, $position->getX(), $y, $textColor, $font, $utfText); return ($result !== false); } /** * @inheritDoc */ public function drawImageWatermark(ImageWatermark $watermark) { if ($this->resource === null) { return false; } if (($image = $this->loadWatermark($watermark)) === null) { return false; } $width = $this->getWidth(); $height = $this->getHeight(); $watermarkWidth = $image->getWidth(); $watermarkHeight = $image->getHeight(); $position = new Rectangle($watermarkWidth, $watermarkHeight); $watermark->alignPosition($width, $height, $position); $watermarkX = $position->getX(); $watermarkY = $position->getY(); $watermarkAlpha = $watermark->getAlpha(); $repeat = ($watermark->getMode() == ImageWatermark::MODE_REPEAT); for ($y = 0; $y < $watermarkHeight; $y++) { for ($x = 0; $x < $watermarkWidth; $x++) { $posY = $watermarkY + $y; while (true) { $posX = $watermarkX + $x; while (true) { $alpha = $watermarkAlpha; $mainRgb = imagecolorsforindex($this->resource, imagecolorat($this->resource, $posX, $posY)); $watermarkRgb = imagecolorsforindex($image->resource, imagecolorat($image->resource, $x, $y)); if ($watermarkRgb['alpha'] == 127) { $pixel = $mainRgb; } else { if ($watermarkRgb['alpha']) { $alpha = round((( 127 - $watermarkRgb['alpha']) / 127), 2); $alpha = $alpha * $watermarkAlpha; } $pixel = []; foreach (['red', 'green', 'blue', 'alpha'] as $k) { $pixel[$k] = round(($mainRgb[$k] * (1 - $alpha)) + ($watermarkRgb[$k] * $alpha)); } } $color = imagecolorexactalpha($this->resource, $pixel['red'], $pixel['green'], $pixel['blue'], $pixel['alpha']); if ($color == -1) { $color = imagecolorallocatealpha($this->resource, $pixel['red'], $pixel['green'], $pixel['blue'], $pixel['alpha']); if ($color === false) { $color = imagecolorclosestalpha($this->resource, $pixel['red'], $pixel['green'], $pixel['blue'], $pixel['alpha']); } } imagesetpixel($this->resource, $posX, $posY, $color); $posX += $watermarkWidth; if (!$repeat || $posX > $width) { break; } } $posY += $watermarkHeight; if (!$repeat || $posY > $height) { break; } } } } $image->clear(); return true; } /** * @inheritDoc */ public function save($file, $quality = 95, $format = null) { if ($this->resource === null) { return false; } if ($format === null) { $format = $this->format; } $result = false; switch ($format) { case File\Image::FORMAT_GIF: $result = imagegif($this->resource, $file); break; case File\Image::FORMAT_PNG: imagealphablending($this->resource, true); imagesavealpha($this->resource, true); $result = imagepng($this->resource, $file); break; case File\Image::FORMAT_WEBP: imagealphablending($this->resource, true); imagesavealpha($this->resource, true); $result = imagewebp($this->resource, $file, $quality); break; case File\Image::FORMAT_BMP: $result = imagebmp($this->resource, $file); break; case File\Image::FORMAT_JPEG: $result = imagejpeg($this->resource, $file, $quality); break; } return $result; } /** * @inheritDoc */ public function getWidth() { return imagesx($this->resource); } /** * @inheritDoc */ public function getHeight() { return imagesy($this->resource); } /** * @inheritDoc */ public function clear() { if ($this->resource !== null) { imagedestroy($this->resource); $this->resource = null; } } /** * @internal * @param resource $resource */ public function setResource($resource) { $this->resource = $resource; } /** * @internal */ public function getResource() { return $this->resource; } }