Seditio Source
Root |
./othercms/xenForo 2.2.8/src/XF/Image/Gd.php
<?php

namespace XF\Image;

use
InvalidArgumentException;
use
XF;

class
Gd extends AbstractDriver
{
    protected
$image;

    protected function
_imageFromFile($file, $type)
    {
       
$this->image = null;

       
$image = null;

       
// approximately 5 bytes per pixel, times a 1.2 fudge factor, times 2 to support a second copy
        // (such as for rotation via EXIF data)
       
$memoryBuffer = ($this->width * $this->height * 5) * 1.2 * 2;
       
$availableMemory = XF::getAvailableMemory();
        if (
$availableMemory && $availableMemory < $memoryBuffer)
        {
           
XF::increaseMemoryLimit($memoryBuffer - $availableMemory);
        }

        switch (
$type)
        {
            case
IMAGETYPE_GIF:
                if (!
function_exists('imagecreatefromgif'))
                {
                    return
false;
                }
               
$image = @imagecreatefromgif($file);
                break;

            case
IMAGETYPE_JPEG:
                if (!
function_exists('imagecreatefromjpeg'))
                {
                    return
false;
                }
                @
ini_set('gd.jpeg_ignore_warning', 1); // not default until PHP 7.1
               
$image = @imagecreatefromjpeg($file);
                break;

            case
IMAGETYPE_PNG:
                if (!
function_exists('imagecreatefrompng'))
                {
                    return
false;
                }
               
$image = @imagecreatefrompng($file);
                break;

            default:
                throw new
InvalidArgumentException("Unknown image type '$type'");
        }

        if (!
$image)
        {
            return
false;
        }

       
$this->setImage($image);

        return
true;
    }

    protected function
_createImage($width, $height)
    {
       
$this->image = null;

       
$image = imagecreatetruecolor($width, $height);
       
$this->preallocateBackground($image);

       
$this->setImage($image);

        return
$this;
    }

    public function
resizeTo($width, $height)
    {
       
$newImage = imagecreatetruecolor($width, $height);
       
$this->preallocateBackground($newImage);

       
imagecopyresampled(
           
$newImage, $this->image,
           
0, 0, 0, 0,
           
$width, $height, $this->width, $this->height
       
);
       
$this->setImage($newImage);

        return
$this;
    }

    public function
crop($width, $height, $x = 0, $y = 0, $srcWidth = null, $srcHeight = null)
    {
       
$newImage = imagecreatetruecolor($width, $height);
       
$this->preallocateBackground($newImage);

       
imagecopyresampled(
           
$newImage, $this->image,
           
0, 0, $x, $y,
           
$width, $height,
           
$srcWidth ?: $width, $srcHeight ?: $height
       
);
       
$this->setImage($newImage);

        return
$this;
    }

    public function
rotate($angle)
    {
       
$newImage = imagerotate($this->image, $angle * -1, 0);
       
$this->setImage($newImage);

        return
$this;
    }

    public function
flip($mode)
    {
       
$srcX = 0;
       
$srcY = 0;
       
$srcWidth = $this->width;
       
$srcHeight = $this->height;

        switch (
$mode)
        {
            case
self::FLIP_HORIZONTAL:
               
$srcX = $this->width - 1;
               
$srcWidth = -$this->width;
                break;

            case
self::FLIP_VERTICAL:
               
$srcY = $this->height - 1;
               
$srcHeight = -$this->height;
                break;

            case
self::FLIP_BOTH:
               
$srcX = $this->width - 1;
               
$srcWidth = -$this->width;
               
$srcY = $this->height - 1;
               
$srcHeight = -$this->height;
                break;

            default:
                throw new
InvalidArgumentException("Unknown flip mode");
        }

       
$newImage = imagecreatetruecolor($this->width, $this->height);
       
imagealphablending($newImage, false);
       
imagesavealpha($newImage, true);
       
imagecopyresampled(
           
$newImage, $this->image,
           
0, 0, $srcX, $srcY,
           
$this->width, $this->height, $srcWidth, $srcHeight
       
);

       
$this->setImage($newImage);

        return
$this;
    }

    public function
setOpacity($opacity)
    {
       
imagealphablending($this->image, false);
       
imagesavealpha($this->image, true);

       
$opacity = 1 - $opacity;
       
imagefilter($this->image, IMG_FILTER_COLORIZE, 0,0,0,127 * $opacity);

       
$this->setImage($this->image);

        return
$this;
    }

    public function
appendImageAt($x, $y, $toAppend)
    {
       
imagecopy($this->image, $toAppend, $x, $y, 0, 0, imagesx($toAppend), imagesy($toAppend));

       
$this->setImage($this->image);

        return
$this;
    }

   
/**
     * Unsharp mask algorithm
     *
     * @copyright 2003-2007 Torstein Hønsi
     * @author thoensi_at_netcom_dot_no
     *
     * @param $amount
     * @param $radius
     * @param $threshold
     */
   
protected function _unsharpMask($radius, $sigma, $amount, $threshold)
    {
       
// Attempt to calibrate the parameters to Photoshop:
       
$amount = min($amount, 500) * 0.016;
       
$radius = abs(round(min(50, $radius) * 2)); // Only integers make sense.
       
$threshold = min(255, $threshold);

        if (!
$radius || !function_exists('imageconvolution'))
        {
            return
$this;
        }

       
$w = $this->width;
       
$h = $this->height;

       
$imageCanvas = imagecreatetruecolor($w, $h);
       
$imageBlur = imagecreatetruecolor($w, $h);

       
$image = $this->image;

       
// Gaussian blur matrix
       
$matrix = [
            [
1, 2, 1],
            [
2, 4, 2],
            [
1, 2, 1]
        ];
       
imagecopy ($imageBlur, $image, 0, 0, 0, 0, $w, $h);
       
imageconvolution($imageBlur, $matrix, 16, 0);

        if (
$threshold > 0)
        {
           
// Calculate the difference between the blurred pixels and the original and set the pixels
           
for ($x = 0; $x < $w-1; $x++)
            {
               
// each row
               
for ($y = 0; $y < $h; $y++)
                {
                   
// each pixel
                   
$rgbOrig = imagecolorat($image, $x, $y);
                   
$rOrig = (($rgbOrig >> 16) & 0xFF);
                   
$gOrig = (($rgbOrig >> 8) & 0xFF);
                   
$bOrig = ($rgbOrig & 0xFF);

                   
$rgbBlur = imagecolorat($imageBlur, $x, $y);

                   
$rBlur = (($rgbBlur >> 16) & 0xFF);
                   
$gBlur = (($rgbBlur >> 8) & 0xFF);
                   
$bBlur = ($rgbBlur & 0xFF);

                   
// When the masked pixels differ less from the original than the threshold specifies, they are set to their original value.
                   
$rNew = (abs($rOrig - $rBlur) >= $threshold)
                        ?
max(0, min(255, ($amount * ($rOrig - $rBlur)) + $rOrig))
                        :
$rOrig;

                   
$gNew = (abs($gOrig - $gBlur) >= $threshold)
                        ?
max(0, min(255, ($amount * ($gOrig - $gBlur)) + $gOrig))
                        :
$gOrig;

                   
$bNew = (abs($bOrig - $bBlur) >= $threshold)
                        ?
max(0, min(255, ($amount * ($bOrig - $bBlur)) + $bOrig))
                        :
$bOrig;

                    if ((
$rOrig != $rNew) || ($gOrig != $gNew) || ($bOrig != $bNew))
                    {
                       
$pixCol = imagecolorallocate($image, $rNew, $gNew, $bNew);
                       
imagesetpixel($image, $x, $y, $pixCol);
                    }
                }
            }
        }
        else
        {
            for (
$x = 0; $x < $w; $x++)
            {
               
// each row
               
for ($y = 0; $y < $h; $y++)
                {
                   
// each pixel
                   
$rgbOrig = imagecolorat($image, $x, $y);
                   
$rOrig = (($rgbOrig >> 16) & 0xFF);
                   
$gOrig = (($rgbOrig >> 8) & 0xFF);
                   
$bOrig = ($rgbOrig & 0xFF);

                   
$rgbBlur = imagecolorat($imageBlur, $x, $y);

                   
$rBlur = (($rgbBlur >> 16) & 0xFF);
                   
$gBlur = (($rgbBlur >> 8) & 0xFF);
                   
$bBlur = ($rgbBlur & 0xFF);

                   
$rNew = ($amount * ($rOrig - $rBlur)) + $rOrig;
                    if (
$rNew > 255)
                    {
                       
$rNew = 255;
                    }
                    else if (
$rNew < 0)
                    {
                       
$rNew = 0;
                    }
                   
$gNew = ($amount * ($gOrig - $gBlur)) + $gOrig;
                    if(
$gNew > 255)
                    {
                       
$gNew = 255;
                    }
                    else if (
$gNew < 0)
                    {
                       
$gNew = 0;
                    }
                   
$bNew = ($amount * ($bOrig - $bBlur)) + $bOrig;
                    if (
$bNew > 255)
                    {
                       
$bNew = 255;
                    }
                    else if (
$bNew < 0)
                    {
                       
$bNew = 0;
                    }
                   
$rgbNew = ($rNew << 16) + ($gNew << 8) + $bNew;
                   
imagesetpixel($image, $x, $y, $rgbNew);
                }
            }
        }

       
imagedestroy($imageCanvas);
       
imagedestroy($imageBlur);

       
$this->setImage($image);

        return
$this;
    }

    protected function
getPixelColorArray($x, $y)
    {
       
$index = imagecolorat($this->image, $x, $y);
        return
imagecolorsforindex($this->image, $index);
    }

    public function
save($file, $format = null, $quality = null)
    {
        if (
$format === null)
        {
           
$format = $this->type;
        }

        if (
$quality === null)
        {
           
$quality = 85;
        }

        switch (
$format)
        {
            case
IMAGETYPE_GIF:
                return
imagegif($this->image, $file);

            case
IMAGETYPE_JPEG:
                return
imagejpeg($this->image, $file, $quality);

            case
IMAGETYPE_PNG:
               
imagealphablending($this->image, false);
               
imagesavealpha($this->image, true);
                return
imagepng($this->image, $file, 9, PNG_ALL_FILTERS); // "quality" seems to be misleading, always force 9

           
default:
                throw new
InvalidArgumentException('Invalid format given. Expects IMAGETYPE_XXX constant.');
        }
    }

    public function
output($format = null, $quality = null)
    {
        if (
$format === null)
        {
           
$format = $this->type;
        }

        if (
$quality === null)
        {
           
$quality = 85;
        }

        switch (
$format)
        {
            case
IMAGETYPE_GIF:
                return
imagegif($this->image);

            case
IMAGETYPE_JPEG:
                return
imagejpeg($this->image, null, $quality);

            case
IMAGETYPE_PNG:
               
imagealphablending($this->image, false);
               
imagesavealpha($this->image, true);
                return
imagepng($this->image, null, 9, PNG_ALL_FILTERS); // "quality" seems to be misleading, always force 9

           
default:
                throw new
InvalidArgumentException('Invalid format given. Expects IMAGETYPE_XXX constant.');
        }
    }

    public function
isValid()
    {
        return
$this->image ? true : false;
    }

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

    protected function
setImage($image)
    {
       
$this->image = $image;
       
$this->width = imagesx($image);
       
$this->height = imagesy($image);
    }

    protected function
preallocateBackground($image)
    {
       
imagesavealpha($image, true);
       
$color = imagecolorallocatealpha($image, 255, 255, 255, 127);
       
imagecolortransparent($image, $color);
       
imagefill($image, 0, 0, $color);
    }

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