{"record":{"id":"05768c3c1ff802e9","repo":"PHPOffice/PhpSpreadsheet","slug":"could-not-clone-image-resource","errorCode":null,"errorMessage":"Could not clone image resource","messagePattern":"Could not clone image resource","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Worksheet/MemoryDrawing.php","lineNumber":89,"sourceCode":"    public function __clone()\n    {\n        parent::__clone();\n        $this->cloneResource();\n    }\n\n    private function cloneResource(): void\n    {\n        if (!$this->imageResource) {\n            return;\n        }\n\n        $width = (int) imagesx($this->imageResource);\n        $height = (int) imagesy($this->imageResource);\n\n        if (imageistruecolor($this->imageResource)) {\n            $clone = imagecreatetruecolor($width, $height);\n            if (!$clone) {\n                throw new Exception('Could not clone image resource');\n            }\n\n            imagealphablending($clone, false);\n            imagesavealpha($clone, true);\n        } else {\n            $clone = imagecreate($width, $height);\n            if (!$clone) {\n                throw new Exception('Could not clone image resource');\n            }\n\n            // If the image has transparency...\n            $transparent = imagecolortransparent($this->imageResource);\n            if ($transparent >= 0) {\n                // Starting with Php8.0, next function throws rather than return false\n                $rgb = imagecolorsforindex($this->imageResource, $transparent);\n\n                imagesavealpha($clone, true);\n                $color = imagecolorallocatealpha($clone, $rgb['red'], $rgb['green'], $rgb['blue'], $rgb['alpha']);","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php#L71-L107","documentation":"MemoryDrawing holds a live GD image resource. When it is cloned — directly, or indirectly via clone $worksheet, Worksheet::copy(), or copying a whole spreadsheet — cloneResource() rebuilds the canvas with imagecreatetruecolor() for truecolor images. If GD returns false (zero width/height from a broken source, or memory exhausted allocating a large bitmap) it throws 'Could not clone image resource'.","triggerScenarios":"clone $worksheet containing a MemoryDrawing; template flows calling $sheet->copy() once per data set; a GD resource whose width or height is 0 because the image partially decoded; a 6000x6000 truecolor canvas exceeding memory_limit during allocation.","commonSituations":"Report generators duplicating a styled template sheet; memory_limit pressure because cloning doubles each bitmap (~4 bytes/pixel twice); MemoryDrawing objects built from truncated strings.","solutions":["Raise PHP memory_limit to cover roughly width*height*8 bytes for the largest drawing.","Avoid cloning the drawing: rebuild it from its rendered bytes with MemoryDrawing::fromString($drawing->getContents()).","Validate sources (getimagesize / non-zero imagesx-imagesy) before they become MemoryDrawings so clones never see 0-size resources."],"exampleFix":"// before\n$newSheet = clone $sheet; // contains a MemoryDrawing -> Could not clone image resource\n\n// after\n$bytes = $drawing->getContents();\n$drawing2 = MemoryDrawing::fromString($bytes); // fresh resource, no GD clone","handlingStrategy":"try-catch","validationCode":"$gd = $memoryDrawing->getImageResource();\nif ($gd === null || imagesx($gd) < 1 || imagesy($gd) < 1) {\n    $memoryDrawing = MemoryDrawing::fromString($memoryDrawing->getContents()); // rebuild a valid resource\n}\n// cloning now has non-zero dimensions to work with","typeGuard":null,"tryCatchPattern":"try {\n    $copy = clone $worksheet; // or $sheet->copy()\n} catch (PhpSpreadsheetException $e) {\n    // GD could not allocate the clone canvas: free memory or rebuild the drawing\n    $bytes = $memoryDrawing->getContents();\n    // re-attach as MemoryDrawing::fromString($bytes), then retry the copy\n}","preventionTips":["Cloning doubles each bitmap — budget roughly width*height*8 bytes and check memory_limit","Never build a MemoryDrawing from undecodable or zero-size sources","Prefer rebuilding drawings from rendered bytes over deep-cloning whole sheets"],"tags":["php","phpspreadsheet","gd","clone","memory-limit"],"backgroundTag":"gd-image-allocation-failed","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}