goforit/image-gd

PHP8 Image processing library, based on DDD and SOLID design principles.

0.4.0 2022-12-25 19:16 UTC

This package is not auto-updated.

Last update: 2024-04-29 05:11:20 UTC


README

coverage report pipeline status

Requirements: PHP 8.1 or higher and the activated GD extension.

Introduction

Library for image processing based on the image GD extension. This code is 100% unit tested and based on DDD and SOLID
design princibles. It supports processing such as resizing, sharpen or croping of images.

// Resize an image to 50% 
$image   = Image::fromFile('bladerunner_art.jpg');
$resized = ResizeProcessor::fromPercentage(50)->process($image) 

It is also possible to render components such as fonts, rectangles, polygones, lines or images onto an existing image
with an easy CSS like positioning syntax. Percental and absolute alignment values such as "100px" or "50%" are
supported both for vertical and horizontal alignments.

// Render a .ttf font with a copyright text into the bottom right corner
$font16 = FreeTypeFont::fromFontFile('./BladeRunner.ttf', 16);
$image  = Image::fromFile('./bladerunner_art.jpg');

$image->applyRenderer(
    FreeTypeFontRenderer::fromFont($font16, ImageColor::fromHex('#FFFFFF'), '(c) 2019 Deckard Inc'),
    HorizontalAlignment::right('15px'),
    VerticalAlignment::bottom('15px')
);

// Send the image as a jpg with the correct HTTP header to the browser 
HttpWriter::create()->writeJpg($image);

Code structure

The code is vertically sliced into four subdomains:

1. Processor: Everything related to processing and changing an image.
2. Renderer: Everything related to rendering a component on an image.
3. Writer: Everything related to writing an image to the file system or sending it to the browser with correct headers.
4. Align: Everything related to align the renderer onto the image.

Installation

Install the latest version with

$ composer require goforit/image-gd

Processors

Processors are responsible to manipulate the passed image. They performing tasks such as resizing, sharpening,
rotating or cropping of images. Use the ProcessorChain class to chain multiple processors to one image
processor programm.

Chaining

Chain processors to resize and sharpen an image.

$image = Image::fromFile('./mosel.jpg');

$processorChain = new ProcessorChain();
$processorChain->addProcessor(ResizeProcessor::fromPercentage(50));
$processorChain->addProcessor(SharpenProcessor::fromPercentage(60));

HttpWriter::create()->writeJpg($processorChain->process($image));

Resizing

Resize a jpg image to 25%.

$image   = Image::fromFile('./bladerunner_art.jpg');
$resized = ResizeProcessor::fromPercentage(25)->process($image);

HttpWriter::create()->writeJpg($resized);

Resize a jpg image proportional until it fits into a bounding box of 100px x 100px.

$image   = Image::fromFile('./bladerunner.jpg');
$resized = ResizeProcessor::fromDimensionProportional(Dimension::fromInt(100, 100))->process($image);

HttpWriter::create()->writeJpg($resized);

Rotation

Rotate an image by 120 degree and use a black background color.

$image   = Image::fromFile('./bladerunner.jpg');
$rotated = RotateProcessor::fromAngle(120, ImageColor::black())->process($image);

HttpWriter::create()->writeJpg($rotated);

Cropping

Crop an image at position x=80, y=15 with a dimension from 320x130 pixel.

$image   = Image::fromFile('../fixtures/images/f95-fcb.jpg');
$cropped = CropProcessor::fromDimension(Dimension::fromInt(320, 130), Position::fromInt(80, 15))->process($image)

HttpWriter::create()->writeJpg($cropped);

Sharpening

Sharpen an image with a filter amount of 60%.

$image    = Image::fromFile('./mosel.jpg');
$shapened = SharpenProcessor::fromPercentage(60)->process($image);

HttpWriter::create()->writeJpg($shapened);

Filtering

Filter to colorize a image.

$image = Image::fromFile('../Fixtures/images/mosel.jpg');

HttpWriter::create()->writeJpg(
    FilterProcessor::forColorize(ImageColor::fromHex('#009999'))->process($image)
);

Filter to increase the contrast of a image for 10 points (-100 = max contrast, +100 = min contrast (note the direction!))

$image = Image::fromFile('../Fixtures/images/mosel.jpg');

HttpWriter::create()->writeJpg(
    FilterProcessor::forContrast(-10)->process($image)
);

The processor class provides a dedicated named constructor method for each specific type of filter, such as grayscale,
brightness, edge detection and contrast.

Flipping

Flip an image horizontal.

$image   = Image::fromFile('./bladerunner.jpg');
$flipped = FlipProcessor::forHorizontal()->process($image);

HttpWriter::create()->writeJpg($flipped);

Renderer

Renderer are responsible to draw a component onto the passed image. For each component such as fonts, rectangles, polygons,
lines or images exist a matching renderer. We use an easy and convenient CSS like positioning syntax to alingn these
components onto the target image. Percental and absolute alignment values such as "100px" or "50%" are supported both for
vertical and horizontal alignments. Use the RendererChain class to chain multiple renderer.

Line

Render a centered black 160px line with a thickness of 6px onto an image.

$image = Image::fromFile('./bladerunner.jpg');
$line   = Line::forHorizontalAlign(160, 6);

$image->applyRenderer(
    LineRenderer::fromLine($line, ImageColor::black()),
    HorizontalAlignment::center(),
    VerticalAlignment::middle()
);

HttpWriter::create()->writeJpg($image);

Polygon

Render a polygon in the top left corner of an image.

$image = Image::fromFile('./bladerunner.jpg');

$polygon = new Polygon();
$polygon->addPosition(Position::fromInt(0, 49));
$polygon->addPosition(Position::fromInt(49, 0));
$polygon->addPosition(Position::fromInt(99, 0));
$polygon->addPosition(Position::fromInt(49, 99));

$image->applyRenderer(
    PolygonRenderer::fromPolygon($polygon, ImageColor::fromHex('#990099'), true),
    HorizontalAlignment::left('15px'),
    VerticalAlignment::top('15px')
);

HttpWriter::create()->writeJpg($image);

Rectangle

Render a filled rectangle in the bottom left corner of an image.

$image = Image::fromFile('./bladerunner.jpg');
$rectangle = Rectangle::fromDimension(Dimension::fromInt(150, 150), true);

$image->applyRenderer(
    RectangleRenderer::fromRectangle($rectangle, ImageColor::black()),
    HorizontalAlignment::left('5px'),
    VerticalAlignment::bottom('5px')
);

HttpWriter::create()->writeJpg($image);

Image

Render a centered image as a watermark onto an image.

$image = Image::fromFile('../fixtures/images/bladerunner_art.jpg');

$image->applyRenderer(
    ImageRenderer::fromImage(Image::fromFile('./deckard.jpg')),
    HorizontalAlignment::center(),
    VerticalAlignment::middle()
);

HttpWriter::create()->writeJpg($image);

Chaining

Chain renderer to draw a centered watermark image and a text in the bottom right corner.

class CopyrightWithWatermark extends RendererChain
{
    private function __construct(string $year)
    {
        $font = FreeTypeFont::fromFontFile('./BladeRunner.ttf', 12);

        $this->addRenderer(
            ImageRenderer::fromImage(Image::fromFile('./deckard.jpg')),
            HorizontalAlignment::center(),
            VerticalAlignment::middle()
        );

        $this->addRenderer(
            FreeTypeFontRenderer::fromFont($font, ImageColor::white(), "(C) $year Deckard inc"),
            HorizontalAlignment::right('10px'),
            VerticalAlignment::bottom('10px')
        );
    }

    public static function fromYear(string $year): self
    {
        return new self($year);
    }
}

$image     = Image::fromFile('../fixtures/images/bladerunner_art.jpg');
$copyright = CopyrightWithWatermark::fromYear(date('Y'));

HttpWriter::create()->writeJpg($copyright->render($image));

Writer

Anything related to write an image to the file system or send it to the browser with correct HTTP content headers. All supported
php protocols and wrappers like ftp://example.com/image.png are allowed. See: Supported Protocols and Wrappers

HTTP

Write an image as jpg to the output stream

$image    = Image::fromFile('./mosel.jpg');
$shapened = SharpenProcessor::fromPercentage(60)->process($image);

HttpWriter::create()->writeJpg($shapened);

Filesystem

Write an image as png into the filesystem

$image    = Image::fromFile('./mosel.jpg');
$shapened = SharpenProcessor::fromPercentage(60)->process($image);

FileWriter::create()->write($shapened, ./sharpened/mosel.png);

// Free memmory assosiacated withe the images at runtime 
$image = null;
$shapened = null;

Write an image as png to a remote ftp server with custom stream options

 $image     = Image::fromFile('./mosel.jpg');
 $sharpened = SharpenProcessor::fromPercentage(60)->process($image);
 
 // Allow overwriting of existing files on the remote FTP server
 $streamOptions = array('ftp' => array('overwrite' => true));
 $streamContext = stream_context_create($streamOptions);
 $fileObject    = new SplFileObject( "ftp://username:password@example.com/mosel.png", 'w+', false, $streamContext);
 
 FileWriter::create()->writeFileObject($sharpened, $fileObject);