Skip to content

Image Processing Guide

Image Processing Guide

Cbox images include three powerful image processing libraries plus Browsershot support for PDF generation.

Quick Start

// GD - Simple operations
$img = imagecreatefrompng('input.png');
imagejpeg($img, 'output.jpg', 90);

// ImageMagick - Advanced operations
$im = new Imagick('input.heic');
$im->setImageFormat('jpeg');
$im->writeImage('output.jpg');

// libvips - High-performance
$image = vips_image_new_from_file('input.jpg');
vips_image_write_to_file($image, 'output.webp');

Library Comparison

Feature GD ImageMagick libvips
Memory usage Medium High Low
Speed Medium Medium Fast
HEIC/HEIF -
PDF read/write - -
SVG support -
Color profiles -
Streaming - -
Laravel Integration intervention/image intervention/image -

Recommendation:

  • GD: Simple thumbnails, basic operations
  • ImageMagick: Complex manipulations, format conversions, PDF
  • libvips: High-volume processing, memory-constrained environments

GD Library

Best for simple operations with good Laravel/Intervention support.

Basic Operations

// Create thumbnail
$src = imagecreatefromjpeg('photo.jpg');
$thumb = imagescale($src, 300, 200);
imagejpeg($thumb, 'thumbnail.jpg', 85);
imagedestroy($src);
imagedestroy($thumb);

// Convert formats
$png = imagecreatefrompng('input.png');
imagewebp($png, 'output.webp', 80);
imagedestroy($png);

// Add watermark
$photo = imagecreatefromjpeg('photo.jpg');
$watermark = imagecreatefrompng('watermark.png');
imagecopy($photo, $watermark, 10, 10, 0, 0, imagesx($watermark), imagesy($watermark));
imagejpeg($photo, 'watermarked.jpg');

Check GD Capabilities

$info = gd_info();
echo "GD Version: " . $info['GD Version'] . "\n";
echo "JPEG: " . ($info['JPEG Support'] ? 'Yes' : 'No') . "\n";
echo "PNG: " . ($info['PNG Support'] ? 'Yes' : 'No') . "\n";
echo "WebP: " . ($info['WebP Support'] ? 'Yes' : 'No') . "\n";
echo "AVIF: " . ($info['AVIF Support'] ? 'Yes' : 'No') . "\n";

ImageMagick (Imagick)

Best for complex operations, format conversions, and PDF handling.

Basic Operations

// Resize with aspect ratio
$im = new Imagick('photo.jpg');
$im->thumbnailImage(800, 0); // Width 800, auto height
$im->writeImage('resized.jpg');

// Convert to WebP
$im = new Imagick('photo.jpg');
$im->setImageFormat('webp');
$im->setImageCompressionQuality(80);
$im->writeImage('output.webp');

// Strip metadata (privacy)
$im = new Imagick('photo.jpg');
$im->stripImage();
$im->writeImage('stripped.jpg');

HEIC/HEIF Conversion (iPhone Photos)

// Convert iPhone HEIC to JPEG
$im = new Imagick('IMG_1234.HEIC');
$im->setImageFormat('jpeg');
$im->setImageCompressionQuality(90);
$im->writeImage('photo.jpg');

// Batch convert all HEIC files
foreach (glob('*.HEIC') as $heic) {
    $im = new Imagick($heic);
    $im->setImageFormat('jpeg');
    $im->writeImage(str_replace('.HEIC', '.jpg', $heic));
    $im->clear();
}

PDF Operations

// Generate PDF from image
$im = new Imagick('document.jpg');
$im->setImageFormat('pdf');
$im->writeImage('document.pdf');

// Read PDF page as image
$im = new Imagick();
$im->setResolution(150, 150); // Set BEFORE reading
$im->readImage('document.pdf[0]'); // First page
$im->setImageFormat('png');
$im->writeImage('page1.png');

// Multi-page PDF to images
$im = new Imagick();
$im->setResolution(150, 150);
$im->readImage('document.pdf');
foreach ($im as $i => $page) {
    $page->setImageFormat('png');
    $page->writeImage("page_{$i}.png");
}

SVG Rendering

// SVG to PNG (read-only for security)
$im = new Imagick();
$im->setBackgroundColor(new ImagickPixel('transparent'));
$im->readImage('icon.svg');
$im->setImageFormat('png');
$im->writeImage('icon.png');

// SVG at specific size
$im = new Imagick();
$im->setResolution(300, 300);
$im->readImage('icon.svg');
$im->resizeImage(512, 512, Imagick::FILTER_LANCZOS, 1);
$im->writeImage('icon-512.png');

Check ImageMagick Capabilities

// List supported formats
$formats = Imagick::queryFormats();
echo "Supported formats: " . count($formats) . "\n";

// Check specific format
$hasHeic = in_array('HEIC', $formats);
$hasPdf = in_array('PDF', $formats);
$hasSvg = in_array('SVG', $formats);

echo "HEIC: " . ($hasHeic ? 'Yes' : 'No') . "\n";
echo "PDF: " . ($hasPdf ? 'Yes' : 'No') . "\n";
echo "SVG: " . ($hasSvg ? 'Yes' : 'No') . "\n";

libvips

Best for high-performance, memory-efficient processing.

Basic Operations

use Jcupitt\Vips\Image;

// Simple resize / thumbnail
$thumb = Image::thumbnail('input.jpg', 300);
$thumb->writeToFile('output.jpg');

// Convert format
$image = Image::newFromFile('input.png');
$image->writeToFile('output.webp', ['Q' => 80]);

// Crop
$image = Image::newFromFile('input.jpg');
$cropped = $image->crop(100, 100, 500, 500);
$cropped->writeToFile('cropped.jpg');

Memory-Efficient Processing

use Jcupitt\Vips\Image;

// Process large image without loading entirely into memory
$image = Image::newFromFile('huge-image.tiff', [
    'access' => 'sequential', // Stream processing
]);

// Apply operations
$processed = $image->resize(0.5);
$processed->writeToFile('output.jpg', ['Q' => 85]);

Check libvips Capabilities

use Jcupitt\Vips\Image;

if (extension_loaded('vips')) {
    echo 'libvips version: ' . phpversion('vips') . "\n";

    // Test operation
    $test = Image::newFromArray([[255, 0], [0, 255]]);
    echo 'libvips working: ' . ($test instanceof Image ? 'Yes' : 'No') . "\n";
}

Browsershot (PDF Generation)

Cbox includes Chromium for Browsershot PDF/screenshot generation.

Installation

composer require spatie/browsershot

Generate PDF from HTML

use Spatie\Browsershot\Browsershot;

// Simple PDF
Browsershot::html('<h1>Hello World</h1>')
    ->save('document.pdf');

// From URL
Browsershot::url('https://example.com')
    ->save('page.pdf');

// With options
Browsershot::html($html)
    ->format('A4')
    ->margins(20, 20, 20, 20)
    ->showBackground()
    ->save('styled.pdf');

Generate Screenshots

use Spatie\Browsershot\Browsershot;

// Full page screenshot
Browsershot::url('https://example.com')
    ->fullPage()
    ->save('screenshot.png');

// Specific viewport
Browsershot::url('https://example.com')
    ->windowSize(1920, 1080)
    ->save('desktop.png');

// Mobile viewport
Browsershot::url('https://example.com')
    ->windowSize(375, 812)
    ->device('iPhone X')
    ->save('mobile.png');

Browsershot Configuration

Cbox sets these environment variables automatically:

PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser

If needed manually:

Browsershot::html($html)
    ->setChromePath('/usr/bin/chromium-browser')
    ->noSandbox()
    ->save('output.pdf');

Laravel Integration

Intervention Image (GD/ImageMagick)

composer require intervention/image
use Intervention\Image\ImageManager;
use Intervention\Image\Drivers\Gd\Driver as GdDriver;
use Intervention\Image\Drivers\Imagick\Driver as ImagickDriver;

// Using GD
$manager = new ImageManager(new GdDriver());
$image = $manager->read('photo.jpg');
$image->scale(width: 300);
$image->save('thumbnail.jpg');

// Using ImageMagick (for HEIC, PDF, etc.)
$manager = new ImageManager(new ImagickDriver());
$image = $manager->read('photo.HEIC');
$image->toJpeg(90)->save('photo.jpg');

Spatie Media Library

composer require spatie/laravel-medialibrary
// Model setup
class Post extends Model implements HasMedia
{
    use InteractsWithMedia;

    public function registerMediaConversions(Media $media = null): void
    {
        $this->addMediaConversion('thumb')
            ->width(300)
            ->height(200);

        $this->addMediaConversion('webp')
            ->format('webp')
            ->quality(80);
    }
}

// Usage
$post->addMedia($request->file('image'))->toMediaCollection();

Common Tasks

Optimize Images for Web

// ImageMagick optimization
$im = new Imagick('photo.jpg');
$im->setImageCompressionQuality(85);
$im->stripImage();  // Remove metadata
$im->gaussianBlurImage(0.05, 0.5);  // Slight blur helps compression
$im->writeImage('optimized.jpg');

// Convert to modern formats
$im->setImageFormat('webp');
$im->writeImage('photo.webp');

$im->setImageFormat('avif');
$im->writeImage('photo.avif');

Generate Responsive Images

$sizes = [320, 640, 1024, 1920];
$im = new Imagick('original.jpg');
$originalWidth = $im->getImageWidth();

foreach ($sizes as $width) {
    if ($width < $originalWidth) {
        $resized = clone $im;
        $resized->thumbnailImage($width, 0);
        $resized->writeImage("image-{$width}w.jpg");
    }
}

Extract Image Metadata

// Using PHP EXIF
$exif = exif_read_data('photo.jpg');
echo "Camera: " . ($exif['Make'] ?? 'Unknown') . "\n";
echo "Date: " . ($exif['DateTimeOriginal'] ?? 'Unknown') . "\n";

// Using exiftool (command line)
$output = shell_exec('exiftool -json photo.jpg');
$metadata = json_decode($output, true)[0];

Troubleshooting

HEIC Not Working

// Check HEIC support
$formats = Imagick::queryFormats('HEIC');
if (empty($formats)) {
    echo "HEIC not supported - libheif may be missing\n";
}

// Verify in container
// docker exec myapp php -r "print_r(Imagick::queryFormats('HEI*'));"

PDF Operations Fail

// Check Ghostscript
$gs = shell_exec('gs --version 2>&1');
echo "Ghostscript: " . ($gs ?: 'NOT INSTALLED') . "\n";

// Check ImageMagick policy
// docker exec myapp cat /etc/ImageMagick-7/policy.xml | grep PDF

Memory Issues with Large Images

// Increase memory limit
ini_set('memory_limit', '512M');

// Use libvips for large images (streams, doesn't load full image)
$image = vips_image_new_from_file('huge.tiff', ['access' => 'sequential']);

// Or process in chunks with ImageMagick
$im = new Imagick();
$im->setResourceLimit(Imagick::RESOURCETYPE_MEMORY, 256 * 1024 * 1024);

Check What's Installed

# In container
docker exec myapp php -m | grep -E "gd|imagick|vips"
docker exec myapp php -r "print_r(gd_info());"
docker exec myapp php -r "print_r(Imagick::queryFormats());"
docker exec myapp chromium-browser --version
docker exec myapp exiftool -ver
docker exec myapp gs --version

Related Guides: Available Extensions | Laravel Guide | Performance Tuning