Intervention/image · error · DriverException

Failed to export color

Error message

Failed to export color

What it means

GD's ColorProcessor::export() converts an Intervention Color to a single GD integer, remapping the alpha channel from [0..1] to [127..0] via CanConvertRange::convertRange(). That helper only throws RuntimeException on a degenerate range (min == max, division by zero at src/Traits/CanConvertRange.php:27-28). With the built-in Rgb\Color the alpha range is always 0..1, so in practice this DriverException is a defensive wrapper reachable mainly through custom ColorInterface implementations whose channel() values are inconsistent.

Source

Thrown at src/Drivers/Gd/ColorProcessor.php:58

     * @throws DriverException
     */
    public function export(ColorInterface $color): int
    {
        // convert color to colorspace
        $color = $color->toColorspace($this->colorspace());

        // gd only supports rgb so the channels can be accessed directly
        $r = $color->channel(Red::class)->value();
        $g = $color->channel(Green::class)->value();
        $b = $color->channel(Blue::class)->value();
        $a = $color->channel(Alpha::class)->value();

        try {
            // convert alpha value to gd alpha
            // ([opaque]1-0[transparent]) to ([opaque]0-127[transparent])
            $a = (int) round(self::convertRange($a, Alpha::min(), Alpha::max(), 127, 0));
        } catch (RuntimeException $e) {
            throw new DriverException('Failed to export color', previous: $e);
        }

        return ($a << 24) + ($r << 16) + ($g << 8) + $b;
    }

    /**
     * {@inheritdoc}
     *
     * @see ColorProcessorInterface::import()
     *
     * @throws InvalidArgumentException
     * @throws DriverException
     */
    public function import(mixed $color): ColorInterface
    {
        if (!is_int($color) && !is_array($color)) {
            throw new InvalidArgumentException('GD driver can only decode colors in integer or array format');
        }

View on GitHub (pinned to 5598b9e397)

Solutions

  1. Use the built-in Intervention\Image\Colors\Rgb\Color (or convert via $color->toColorspace(new Rgb())) before exporting
  2. In custom ColorInterface classes, keep Alpha::min() !== Alpha::max() and value() within [min, max]
  3. Catch DriverException and inspect ->getPrevious() to confirm the range-division root cause

Example fix

// before
class BrandColor implements ColorInterface { /* alpha min()==max() == 0 */ }
$gdInt = $processor->export(new BrandColor());

// after
$gdInt = $processor->export($color->toColorspace($processor->colorspace()));
Defensive patterns

Strategy: try-catch

Type guard

function isExportableRgbColor(Intervention\Image\Interfaces\ColorInterface $c): bool
{
    $colorspace = new Intervention\Image\Colors\Rgb\Colorspace();
    $converted = $c->toColorspace($colorspace);

    return $converted->channel(Intervention\Image\Colors\Rgb\Channels\Alpha::class) instanceof Intervention\Image\Colors\Rgb\Channels\Alpha;
}

Try / catch

use Intervention\Image\Exceptions\DriverException;

try {
    $gdColor = $processor->export($color);
} catch (DriverException $e) {
    // custom color implementation broke the range contract; fall back to built-in color
    $gdColor = $processor->export(new Intervention\Image\Colors\Rgb\Color(255, 0, 0));
}

Prevention

When it happens

Trigger: Passing a hand-rolled ColorInterface class into $gdDriver->colorProcessor()->export($color) whose Alpha channel reports identical min()/max() (e.g. both 0); none of the standard library colors can trigger it.

Common situations: Extending the color system with custom color classes (brand palettes, exotic colorspaces) and feeding them to GD-driver text drawing or fills.

Related errors


AI-assisted analysis of Intervention/image@5598b9e397 (2026-08-23). Data as JSON: /api/errors/422f37237f093019. Report an issue: GitHub.