PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception

Value cannot be converted to an image

Error message

Value cannot be converted to an image

What it means

MemoryDrawing::fromString() turns raw binary into a GD resource via @imagecreatefromstring(); when GD returns false, the string is not a decodable image in any format your GD build supports, and the exception is thrown. Common culprits are base64 payloads that were not decoded (or double-encoded) and formats like WEBP/AVIF on a GD compiled without them.

Source

Thrown at src/PhpSpreadsheet/Worksheet/MemoryDrawing.php:143

     * @throws Exception
     */
    public static function fromStream($imageStream): self
    {
        $streamValue = stream_get_contents($imageStream);

        return self::fromString($streamValue);
    }

    /**
     * @param string $imageString String data to be converted to a Memory Drawing
     *
     * @throws Exception
     */
    public static function fromString(string $imageString): self
    {
        $gdImage = @imagecreatefromstring($imageString);
        if ($gdImage === false) {
            throw new Exception('Value cannot be converted to an image');
        }

        $mimeType = self::identifyMimeType($imageString);
        if (imageistruecolor($gdImage) || imagecolortransparent($gdImage) >= 0) {
            imagesavealpha($gdImage, true);
        }
        $renderingFunction = self::identifyRenderingFunction($mimeType);

        $drawing = new self();
        $drawing->setImageResource($gdImage);
        $drawing->setRenderingFunction($renderingFunction);
        $drawing->setMimeType($mimeType);

        return $drawing;
    }

    /** @return callable-string */
    private static function identifyRenderingFunction(string $mimeType): string

View on GitHub (pinned to 65b080eef4)

Solutions

  1. Strip any data-URI prefix and base64_decode() the payload before calling fromString().
  2. Pre-validate with getimagesizefromstring($binary) — it returns false for undecodable data and reports the type otherwise.
  3. Check gd_info() for the formats your inputs need and convert unsupported formats server-side.

Example fix

// before
$drawing = MemoryDrawing::fromString($base64FromApi); // encoded string -> throws

// after
$binary = str_starts_with($base64FromApi, 'data:')
    ? base64_decode(substr($base64FromApi, strpos($base64FromApi, ',') + 1), true)
    : base64_decode($base64FromApi, true);
if ($binary === false || getimagesizefromstring($binary) === false) {
    throw new InvalidArgumentException('payload is not a decodable image');
}
$drawing = MemoryDrawing::fromString($binary);
Defensive patterns

Strategy: validation

Validate before calling

$binary = $data;
if (str_starts_with($data, 'data:')) {
    $binary = base64_decode(substr($data, strpos($data, ',') + 1), true);
}
if ($binary === false || getimagesizefromstring($binary) === false) {
    throw new InvalidArgumentException('payload is not a decodable image');
}
$drawing = MemoryDrawing::fromString($binary);

Type guard

function isDecodableImageString(string $bytes): bool
{
    return getimagesizefromstring($bytes) !== false;
}

Try / catch

try {
    $drawing = MemoryDrawing::fromString($payload);
} catch (PhpSpreadsheetException $e) {
    // payload was not decodable: log, skip the image, or request a re-upload
}

Prevention

When it happens

Trigger: fromString($base64) where the value is still the base64 text or still has the 'data:image/png;base64,' prefix; binary from a truncated download; WEBP bytes on a GD build without webp support.

Common situations: Images pasted from HTML editors or received from APIs as data URIs; reading embedded media from untrusted XLSX files; forgetting base64_decode() or applying it twice; environment differences in GD format support.

Related errors


AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17). Data as JSON: /api/errors/2e3805fbc212a9c6. Report an issue: GitHub.