jeudi 19 juillet 2018

PHP Image Transformations using Dependency Injection and SOLID

This is a challenge for me and since I did not code for more than 3 years, so, look for advice.

The idea is to design a basic but expendable application to perform several actions on the image such resize and rotate.

Per SOLID Single Responsibility (SRP), each action is needed to be coded as a separate class. Another important task is to implement presets as separated classes including one or more of the implemented actions.

The following is what I did, unfortunately it violates the rules and seems not expandable.

This is the Action class, the parent class for actions such as Resize and Watermark:

<?php

class Action
{
    protected $image;
    protected $mimeType;
    protected $extension;
    protected $w, $h;

    public function __construct($source)
    {
        if ($source) {
            $info           = getimagesize($source);
            $this->mimeType = $info['mime'];
            $this->w        = $info[0];
            $this->h        = $info[1];

            $this->extension = substr(strrchr($source, '.'), 0);
            $this->loadImage($source);
        }
    }

    public function getImage()
    {
        return $this->image;
    }

    public function loadImage($source)
    {

        switch ($this->mimeType) {
            case 'image/jpeg':
                $this->image = imagecreatefromjpeg($source);
                break;
            case 'image/png':
                $this->image = imagecreatefrompng($source);
                break;
            case 'image/gif':
                $this->image = imagecreatefromgif($source);
                break;
            default:
                throw new Exception('Invalid image: ' . $source);
                break;
        }
    }

    public function saveImage($filename, $quality = 80)
    {
        header('Content-type: ' . $this->mimeType);
        $filename .= $this->extension;

        switch ($this->mimeType) {
            case 'image/jpeg':
                $result = imagejpeg($this->image, $filename, round($quality));
                break;
            case 'image/png':
                $result = imagepng($this->image, $filename, round(9 * $quality / 100));
                break;
            case 'image/gif':
                $result = imagegif($this->image, $filename);
                break;
            default:
                throw new Exception('Unsupported format');
        }
        if (!$result) {
            throw new Exception('Unable to save image: ' . $filename);
        }
    }

    public function __destruct()
    {
        if ($this->image) {
            imagedestroy($this->image);
        }
    }
}

This is the Watermark action class:

    <?php
require_once("Action.php");

class WaterMark extends Action {
    private $text;
    private $x, $y;
    private $fontSize;
    private $font;
    private $color;

    public function __construct($source, $fontSize, $x, $y, $text) {
        parent::__construct($source);
        $this->fontSize = $fontSize;
        $this->x = $x;
        $this->y = $y;
        $this->text = $text;
    }

    public function setFont($path = './fonts/ChelaOne-Regular.ttf') {
        $this->font = $path;
    }

    public function setColor($red = 200, $green = 150, $blue = 240) {
        // setup the text color
        $this->color = imagecolorallocate($this->image, $red, $green, $blue);
    }

    public function watermark() {
        imagettftext($this->image, $this->fontSize, 0, $this->x, $this->y, $this->color, $this->font, $this->text);
        // imagefilter($this->image, IMG_FILTER_GRAYSCALE);
        // parent::saveImage('watermark aaaaa');
    }

}

This is the Rotate action class:

    <?php

require_once("Action.php");

class Rotate extends Action {
    private $angle;

    public function __construct($source, $angle = 45) {
        parent::__construct($source);
        $this->angle = $angle;
    }

    public function rotate() {
        $this->image = imagerotate($this->image, $this->angle, 0);
        //parent::saveImage('rotate');
    }

}

I have other action classes. These are working charmingly individually using the following CLI command:

php apply.php source.jpg watermarkImage

Here is the apply.php

 <?php

    require_once("Watermark.php");

    $source = $argv[1];
    $filename = $argv[2];

    $watermark = new Watermark($source, 40, 100, 150, "Copyright 2018");
    $watermark->setFont();
    $watermark->watermark();
    $watermark->saveImage($filename);

?>

I would like to have your feedback improving the above scenario as well as the default presets classes including one or more of the actions to be used like this:

php apply.php PresetName source.jpg watermarkImage

I am sure these sort of challenges improve the capacity building of others interested to design and code better.

Thank you in advance,

Aucun commentaire:

Enregistrer un commentaire