<?php
/*
* $image
->fromFile('image.jpg') // load image.jpg
->autoOrient() // adjust orientation based on exif data
->resize(320, 200) // resize to 320x200 pixels
->flip('x') // flip horizontally
->colorize('DarkBlue') // tint dark blue
->border('black', 10) // add a 10 pixel black border
->overlay('watermark.png', 'bottom right') // add a watermark image
->toFile('new-image.png', 'image/png') // convert to PNG and save a copy to new-image.png
->toScreen(); // output to the screen
*
*/
class Image_lib {
const
ERR_FILE_NOT_FOUND = 1,
ERR_FONT_FILE = 2,
ERR_FREETYPE_NOT_ENABLED = 3,
ERR_GD_NOT_ENABLED = 4,
ERR_INVALID_COLOR = 5,
ERR_INVALID_DATA_URI = 6,
ERR_INVALID_IMAGE = 7,
ERR_LIB_NOT_LOADED = 8,
ERR_UNSUPPORTED_FORMAT = 9,
ERR_WEBP_NOT_ENABLED = 10,
ERR_WRITE = 11;
private $image, $mimeType, $exif;
public function __construct($image = null) {
// Check for the required GD extension
if (extension_loaded('gd')) {
// Ignore JPEG warnings that cause imagecreatefromjpeg() to fail
ini_set('gd.jpeg_ignore_warning', 1);
} else {
throw new Exception('Required extension GD is not loaded.', self::ERR_GD_NOT_ENABLED);
}
// Load an image through the constructor
/* if(preg_match('/^data:(.*?);/', $image)) {
$this->fromDataUri($image);
} elseif($image) {
$this->fromFile($image);
} */
}
//
// Destroys the image resource
//
public function __destruct() {
if ($this->image !== null && get_resource_type($this->image) === 'gd') {
imagedestroy($this->image);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// Loaders
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// Loads an image from a data URI.
//
// $uri* (string) - A data URI.
//
// Returns a SimpleImage object.
//
public function fromDataUri($uri) {
// Basic formatting check
preg_match('/^data:(.*?);/', $uri, $matches);
if (!count($matches)) {
throw new Exception('Invalid data URI.', self::ERR_INVALID_DATA_URI);
}
// Determine mime type
$this->mimeType = $matches[1];
if (!preg_match('/^image\/(gif|jpeg|png)$/', $this->mimeType)) {
throw new Exception(
'Unsupported format: ' . $this->mimeType, self::ERR_UNSUPPORTED_FORMAT
);
}
// Get image data
$uri = base64_decode(preg_replace('/^data:(.*?);base64,/', '', $uri));
$this->image = imagecreatefromstring($uri);
if (!$this->image) {
throw new Exception("Invalid image data.", self::ERR_INVALID_IMAGE);
}
return $this;
}
//
// Loads an image from a file.
//
// $file* (string) - The image file to load.
//
// Returns a SimpleImage object.
//
public function fromFile($file) {
// Check if the file exists and is readable. We're using fopen() instead of file_exists()
// because not all URL wrappers support the latter.
$handle = @fopen($file, 'r');
if ($handle === false) {
throw new Exception("File not found: $file", self::ERR_FILE_NOT_FOUND);
}
fclose($handle);
// Get image info
$info = getimagesize($file);
if ($info === false) {
throw new Exception("Invalid image file: $file", self::ERR_INVALID_IMAGE);
}
$this->mimeType = $info['mime'];
// Create image object from file
switch ($this->mimeType) {
case 'image/gif':
// Load the gif
$gif = imagecreatefromgif($file);
if ($gif) {
// Copy the gif over to a true color image to preserve its transparency. This is a
// workaround to prevent imagepalettetruecolor() from borking transparency.
$width = imagesx($gif);
$height = imagesy($gif);
$this->image = imagecreatetruecolor($width, $height);
$transparentColor = imagecolorallocatealpha($this->image, 0, 0, 0, 127);
imagecolortransparent($this->image, $transparentColor);
imagefill($this->image, 0, 0, $transparentColor);
imagecopy($this->image, $gif, 0, 0, 0, 0, $width, $height);
imagedestroy($gif);
}
break;
case 'image/jpeg':
$this->image = imagecreatefromjpeg($file);
break;
case 'image/png':
$this->image = imagecreatefrompng($file);
break;
case 'image/webp':
$this->image = imagecreatefromwebp($file);
break;
}
if (!$this->image) {
throw new Exception("Unsupported image: $file", self::ERR_UNSUPPORTED_FORMAT);
}
// Convert pallete images to true color images
imagepalettetotruecolor($this->image);
// Load exif data from JPEG images
if ($this->mimeType === 'image/jpeg' && function_exists('exif_read_data')) {
$this->exif = @exif_read_data($file);
}
return $this;
}
//
// Creates a new image.
//
// $width* (int) - The width of the image.
// $height* (int) - The height of the image.
// $color (string|array) - Optional fill color for the new image (default 'transparent').
//
// Returns a SimpleImage object.
//
public function fromNew($width, $height, $color = 'transparent') {
$this->image = imagecreatetruecolor($width, $height);
// Use PNG for dynamically created images because it's lossless and supports transparency
$this->mimeType = 'image/png';
// Fill the image with color
$this->fill($color);
return $this;
}
//
// Creates a new image from a string.
//
// $string* (string) - The raw image data as a string. Example:
//
// $string = file_get_contents('image.jpg');
//
// Returns a SimpleImage object.
//
public function fromString($string) {
return $this->fromFile('data://;base64,' . base64_encode($string));
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// Savers
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// Generates an image.
//
// $mimeType (string) - The image format to output as a mime type (defaults to the original mime
// type).
// $quality (int) - Image quality as a percentage (default 100).
//
// Returns an array containing the image data and mime type.
//
private function generate($mimeType = null, $quality = 100) {
// Format defaults to the original mime type
$mimeType = $mimeType ?: $this->mimeType;
// Enforce quality range
$quality = self::keepWithin($quality, 0, 100);
// Capture output
ob_start();
// Generate the image
switch ($mimeType) {
case 'image/gif':
imagesavealpha($this->image, true);
imagegif($this->image, null);
break;