diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 037ee997..b209e822 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -5920,16 +5920,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Worksheet/Iterator.php - - - message: "#^Parameter \\#1 \\$im of function imagesx expects resource, GdImage\\|resource given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/MemoryDrawing.php - - - - message: "#^Parameter \\#1 \\$im of function imagesy expects resource, GdImage\\|resource given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/MemoryDrawing.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:\\$pageOrder has no typehint specified\\.$#" count: 1 diff --git a/phpstan.neon.dist b/phpstan.neon.dist index dd39aa34..b7a4fca8 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -16,6 +16,8 @@ parameters: - '~^Return typehint of method .* has invalid type GdImage\.$~' - '~^Property .* has unknown class GdImage as its type\.$~' - '~^Parameter .* of method .* has invalid typehint type GdImage\.$~' + - '~^Parameter \#1 \$im of function (imagedestroy|imageistruecolor|imagealphablending|imagesavealpha|imagecolortransparent|imagecolorsforindex|imagesavealpha|imagesx|imagesy) expects resource, GdImage\|resource given\.$~' + - '~^Parameter \#2 \$src_im of function imagecopy expects resource, GdImage\|resource given\.$~' # Accept a bit anything for assert methods - '~^Parameter \#2 .* of static method PHPUnit\\Framework\\Assert\:\:assert\w+\(\) expects .*, .* given\.$~' - '~^Method PhpOffice\\PhpSpreadsheetTests\\.*\:\:test.*\(\) has parameter \$args with no typehint specified\.$~' diff --git a/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php b/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php index cde23c96..7789543a 100644 --- a/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php +++ b/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Worksheet; use GdImage; +use PhpOffice\PhpSpreadsheet\Exception; class MemoryDrawing extends BaseDrawing { @@ -21,7 +22,7 @@ class MemoryDrawing extends BaseDrawing /** * Image resource. * - * @var GdImage|resource + * @var null|GdImage|resource */ private $imageResource; @@ -60,10 +61,71 @@ class MemoryDrawing extends BaseDrawing parent::__construct(); } + public function __destruct() + { + if ($this->imageResource) { + imagedestroy($this->imageResource); + $this->imageResource = null; + } + } + + public function __clone() + { + parent::__clone(); + $this->cloneResource(); + } + + private function cloneResource(): void + { + if (!$this->imageResource) { + return; + } + + $width = imagesx($this->imageResource); + $height = imagesy($this->imageResource); + + if (imageistruecolor($this->imageResource)) { + $clone = imagecreatetruecolor($width, $height); + if (!$clone) { + throw new Exception('Could not clone image resource'); + } + + imagealphablending($clone, false); + imagesavealpha($clone, true); + } else { + $clone = imagecreate($width, $height); + if (!$clone) { + throw new Exception('Could not clone image resource'); + } + + // If the image has transparency... + $transparent = imagecolortransparent($this->imageResource); + if ($transparent >= 0) { + $rgb = imagecolorsforindex($this->imageResource, $transparent); + if ($rgb === false) { + throw new Exception('Could not get image colors'); + } + + imagesavealpha($clone, true); + $color = imagecolorallocatealpha($clone, $rgb['red'], $rgb['green'], $rgb['blue'], $rgb['alpha']); + if ($color === false) { + throw new Exception('Could not get image alpha color'); + } + + imagefill($clone, 0, 0, $color); + } + } + + //Create the Clone!! + imagecopy($clone, $this->imageResource, 0, 0, 0, 0, $width, $height); + + $this->imageResource = $clone; + } + /** * Get image resource. * - * @return GdImage|resource + * @return null|GdImage|resource */ public function getImageResource() { diff --git a/src/PhpSpreadsheet/Writer/Html.php b/src/PhpSpreadsheet/Writer/Html.php index 4ee94114..b694d4ef 100644 --- a/src/PhpSpreadsheet/Writer/Html.php +++ b/src/PhpSpreadsheet/Writer/Html.php @@ -690,18 +690,21 @@ class Html extends BaseWriter $drawing->getWidth() . 'px; height: ' . $drawing->getHeight() . 'px;" src="' . $imageData . '" alt="' . $filedesc . '" />'; } elseif ($drawing instanceof MemoryDrawing) { - ob_start(); // Let's start output buffering. - imagepng($drawing->getImageResource()); // This will normally output the image, but because of ob_start(), it won't. - $contents = ob_get_contents(); // Instead, output above is saved to $contents - ob_end_clean(); // End the output buffer. + $imageResource = $drawing->getImageResource(); + if ($imageResource) { + ob_start(); // Let's start output buffering. + imagepng($imageResource); // This will normally output the image, but because of ob_start(), it won't. + $contents = ob_get_contents(); // Instead, output above is saved to $contents + ob_end_clean(); // End the output buffer. - $dataUri = 'data:image/jpeg;base64,' . base64_encode($contents); + $dataUri = 'data:image/jpeg;base64,' . base64_encode($contents); - // Because of the nature of tables, width is more important than height. - // max-width: 100% ensures that image doesnt overflow containing cell - // width: X sets width of supplied image. - // As a result, images bigger than cell will be contained and images smaller will not get stretched - $html .= '' . $filedesc . ''; + // Because of the nature of tables, width is more important than height. + // max-width: 100% ensures that image doesnt overflow containing cell + // width: X sets width of supplied image. + // As a result, images bigger than cell will be contained and images smaller will not get stretched + $html .= '' . $filedesc . ''; + } } }