Intervention/image · error · ModifierException

Failed to build watermark image

Error message

Failed to build watermark image

What it means

When insert() is called with transparency below 1.0, the GD driver builds a faded copy of the watermark on a new truecolor canvas of the same dimensions (imagecreatetruecolor). That call returns false when PHP cannot allocate the memory - roughly width x height x 4 bytes per canvas - and the modifier turns it into ModifierException 'Failed to build watermark image'. With the default transparency of 1.0 this code path is skipped entirely, so the error is specific to faded watermarks.

Source

Thrown at src/Drivers/Gd/Modifiers/InsertModifier.php:78

        }
    }

    /**
     * Build a faded copy of the watermark by scaling each pixel's alpha
     * by the requested transparency factor of the modifier. Created once
     * and reused for every frame.
     *
     * @throws ModifierException
     */
    private function fadeWatermark(ImageInterface $watermark): ImageInterface
    {
        $width = $watermark->width();
        $height = $watermark->height();

        $faded = imagecreatetruecolor($width, $height);

        if ($faded === false) {
            throw new ModifierException('Failed to build watermark image');
        }

        imagealphablending($faded, false);
        imagesavealpha($faded, true);

        $watermarkNative = $watermark->core()->native();

        for ($y = 0; $y < $height; $y++) {
            for ($x = 0; $x < $width; $x++) {
                $color = imagecolorat($watermarkNative, $x, $y);
                $alpha = ($color >> 24) & 0x7F;
                // GD stores alpha as 0 (opaque) … 127 (transparent), so scale
                // the opacity (127 - alpha) and flip back to GD's convention.
                $newAlpha = 127 - (int) round((127 - $alpha) * $this->transparency);
                imagesetpixel($faded, $x, $y, ($newAlpha << 24) | ($color & 0xFFFFFF));
            }
        }

View on GitHub (pinned to 5598b9e397)

Solutions

  1. Pre-scale the watermark to its real display size before inserting it
  2. Raise the memory limit for the job: ini_set('memory_limit', '512M')
  3. Skip fading (transparency 1.0) - no extra canvas is allocated
  4. Catch ModifierException and fall back to inserting without transparency

Example fix

// before: fading a 6000x4000 watermark on a small memory limit
$image->insert($watermarkPath, transparency: 0.5);

// after: pre-scale the watermark, then fade it
use Intervention\Image\ImageManager;
use Intervention\Image\Drivers\Gd\Driver as GdDriver;

$manager = new ImageManager(GdDriver::class);
$watermark = $manager->decode(file_get_contents($watermarkPath))->scale(600);
$image->insert($watermark, transparency: 0.5);
Defensive patterns

Strategy: fallback

Validate before calling

// rough memory check before fading a large watermark
$info = is_string($watermarkPath) ? getimagesize($watermarkPath) : false;

if ($info !== false) {
    [$width, $height] = $info;
    $requiredBytes = $width * $height * 4 * 2; // watermark + faded copy
    $limitBytes = parse_size_shorthand(ini_get('memory_limit')); // e.g. '128M' -> bytes

    if (memory_get_usage(true) + $requiredBytes > $limitBytes) {
        // pre-scale to avoid the allocation failure
        $watermark = $manager->decode(file_get_contents($watermarkPath))->scale(600);
        $image->insert($watermark, transparency: 0.5);
        return;
    }
}

$image->insert($watermarkPath, transparency: 0.5);

Try / catch

use Intervention\Image\Exceptions\ModifierException;

try {
    $image->insert($watermark, transparency: 0.5);
} catch (ModifierException $e) {
    // memory allocation failed: insert without the fade effect
    $image->insert($watermark);
}

Prevention

When it happens

Trigger: $image->insert($hugeImage, transparency: 0.5) with dimensions large relative to memory_limit (e.g. 8000x6000 needs about 183 MB per canvas); low memory_limit on shared hosting or CLI workers; pipelines already holding a large base image plus the watermark.

Common situations: Full-resolution watermarks on print-sized images; default 128M memory_limit with large assets; batch jobs processing many images in one process without freeing memory.

Related errors


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