<?php
/*
* File: SimpleImage.php (Not Really)
* Author: Rumverse, Simon Jarvis
* Copyright: 2006 Simon Jarvis, 2011-2012 Rumverse
* Date: 08/11/06
* Last Modified: 02/16/2012
* Link: http://www.white-hat-web-design.co.uk/articles/php-image-resizing.php
* Link: http://ulaptech.blogspot.com/2012/03/not-so-simple-image-php-object.html
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details:
* http://www.gnu.org/licenses/gpl.html
*
* rumverse: added support for daisy-chaining via making sure that there's always
* a version of the original, added additional get methods, added background, added
* layer support
*
*/
class SimpleImage {
/**
* Originally loaded image
*
* @var resource
*/
protected $_imageOri;
/**
* Transformed image buffer
*
* @var resource
*/
protected $_image;
/**
* List of SimpleImage instances which can be used as
*
* @var array
*/
protected $_layers;
/**
* Should be used as the background of the image
*
* @var SimpleImage
*/
protected $_background;
/**
* In layered mode, is image centered or not?
* It's true by default.
*
* @var bool
*/
protected $_centered = true;
/**
* Horizontal alignment, center, left, right
*
* @var string
*/
protected $_align;
/**
* Vertical alignment, center, top, bottom
*
* @var string
*/
protected $_valign;
/**
* Image type - IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG
*
* @var int
*/
protected $_image_type;
protected $_sizeInfo;
protected $_validMime = array('image/jpeg' => self::IMAGEJPEG,
'image/jpg' => self::IMAGEJPEG,
'image/png' => self::IMAGEPNG,
'image/gif' => self::IMAGEGIF);
const IMAGEJPEG = 'image/jpeg';
const IMAGEGIF = 'image/gif';
const IMAGEPNG = 'image/png';
/**
* x-point position relative to destination image xy plane if object
* is used as a layer by another instance of SimpleImage
*
* @var int
*/
protected $_layer_xpos = 0;
/**
* y-point position relative to destination image xy plane if object
* is used as a layer by another instance of SimpleImage
*
* @var int
*/
protected $_layer_ypos = 0;
/**
* x-point position of this object's xy plane to start copying from when
* used as a layer of another instance of SimpleImage
*
* @var int
*/
protected $_layer_xOffset = 0;
/**
* y-point position of this object's xy plane to start copying from when
* used as a layer of another instance of SimpleImage
*
* @var int
*/
protected $_layer_yOffset = 0;
public function __construct($filename = null)
{
if (!empty($filename) && is_string($filename)) {
$this->load($filename);
}
}
public function load($filename)
{
if (!is_file($filename)) {
trigger_error("Warning: $filename not found", E_USER_WARNING);
return false;
}
$image_info = getimagesize($filename, $additional_info);
if (!isset($this->_validMime[$image_info['mime']])) {
trigger_error("Warning: file type {$image_info['mime']} not yet supported.", E_USER_WARNING);
return false;
}
$this->_sizeInfo = array_merge($image_info, $additional_info);
$this->_image_type = $image_info[2];
if( $this->_image_type == IMAGETYPE_JPEG ) {
try {
$resource = imagecreatefromjpeg($filename);
if(!is_resource($resource)) {
trigger_error("Failed to load image but no exceptions raised: {$filename}\n", E_USER_WARNING);
return false;
}
} catch(Exception $e) {
trigger_error("Invalid image: {$filename} - {$e->getMessage}\n", E_USER_ERROR);
return false;
}
$this->_image = $resource;
$this->_imageOri = imagecreatefromjpeg($filename);
} elseif( $this->_image_type == IMAGETYPE_GIF ) {
try {
$resource = imagecreatefromgif($filename);
if(!is_resource($resource)) {
trigger_error("Failed to load image but no exceptions raised: {$filename}\n", E_USER_WARNING);
return false;
}
} catch(Exception $e) {
trigger_error("Invalid image: {$filename} - {$e->getMessage}\n", E_USER_ERROR);
return false;
}
$this->_image = $resource;
$this->_imageOri = imagecreatefromgif($filename);
} elseif( $this->_image_type == IMAGETYPE_PNG ) {
try {
$resource = imagecreatefrompng($filename);
if(!is_resource($resource)) {
error_log($filename . "\n", 3, 'failed-load-image.txt');
trigger_error("Failed to load image but no exceptions raised: {$filename}\n", E_USER_WARNING);
return false;
}
} catch(Exception $e) {
trigger_error("Invalid image: {$filename} - {$e->getMessage}\n", E_USER_ERROR);
return false;
}
$this->_image = $resource;
$this->_imageOri = imagecreatefrompng($filename);
}
return true;
}
public function addLayer(SimpleImage $layer = null)
{
if (!empty($layer) && $layer instanceof SimpleImage) {
$this->_layers[] = $layer;
}
return $this;
}
public function hasLayers()
{
if (!empty($this->_layers) && $this->_layers[0] instanceof SimpleImage ) {
return true;
}
}
public function getValign()
{
return $this->_valign;
}
public function setValign($valign = 'center')
{
if (!empty($valign) && is_string($valign) && in_array($valign, array('center','top','bottom'))) {
$this->_valign = $valign;
}
return $this;
}
public function getAlign()
{
return $this->_align;
}
public function setAlign($valign = 'center')
{
if (!empty($valign) && is_string($valign) && in_array($valign, array('center','left','right'))) {
$this->_align = $valign;
}
return $this;
}
public function isCentered()
{
if ($this->_centered) {
return true;
}
}
public function setCentered($enable = true)
{
$this->_centered = $enable;
return $this;
}
/**
* Set the x-position of this object to the destination object
* where it is being used as a layer.
*
* @param int $x
* @return $this
*/
public function setLayerXpos($x)
{
if (!empty($x)) {
$this->_layer_xpos = (integer) $x;
}
return $this;
}
/**
* Set the y-position of this object to the destination object
* where it is being used as a layer.
*
* @param int $y
* @return $this;
*/
public function setLayerYpos($y)
{
if (!empty($y)) {
$this->_layer_ypos = (integer) $y;
}
return $this;
}
/**
* Get the x-position of this object based on the destination object
* where it is being used as a layer.
*
* @return int
*/
public function getLayerXpos($reference = null)
{
if (empty($this->_layer_xpos)) {
if (empty($reference) && $reference instanceof SimpleImage ) {
$reference = $this;
}
//check, for centering, will be overwritten by other positional properties like valign, align, xpos, ypos
if ($this->isCentered()) {
$xDelta = $reference->getWidth() - $this->getWidth(false);
$destXpos = ceil($xDelta/2);
}
if ($this->getAlign()) {
$align = $this->getAlign();
switch ($align) {
case 'left':
$destXpos = 0;
break;
case 'center':
$xDelta = $reference->getWidth() - $this->getWidth(false);
$destXpos = ceil($xDelta/2);
break;
case 'right':
$destXpos = $reference->getWidth() - $this->getWidth(false);
break;
}
}
$this->_layer_xpos = $destXpos;
}
return $this->_layer_xpos;
}
/**
* Set the y-position of this object to the destination object
* where it is being used as a layer.
*
*
* @param SimpleImage $reference The image where it belongs to as a layer. NULL indicates that it is not a layer of anything but itself.
* @return int
*/
public function getLayerYpos($reference = null)
{
if (empty($this->_layer_ypos)) {
if (empty($reference) && $reference instanceof SimpleImage ) {
$reference = $this;
}
//check, for centering, will be overwritten by other positional properties like valign, align, xpos, ypos
if ($this->isCentered()) {
$yDelta = $reference->getHeight() - $this->getHeight(false);
$destYpos = floor($yDelta/2);
}
if ($this->getValign()) {
$valign = $this->getValign();
switch ($valign) {
case 'top':
$destYpos = 0;
break;
case 'center':
$yDelta = $reference->getHeight() - $this->getHeight(false);
$destYpos = floor($yDelta/2);
break;
case 'bottom':
$destYpos = $reference->getHeight() - $this->getHeight(false);
}
}
$this->_layer_ypos = $destYpos;
}
return $this->_layer_ypos;
}
/**
* Get the x-position where to start copying on the xy plane of this object
* when treated as layer of another SimpleImage object
*
* @return int
*/
public function getLayerXOffset()
{
return $this->_layer_xOffset;
}
/**
* Get the y-position where to start copying on the xy plane of this object
* when treated as layer of another SimpleImage object
*
* @return int
*/
public function getLayerYOffset()
{
return $this->_layer_yOffset;
}
/**
* Set the x-position where to start copying on the xy plane of this object
* when treated as layer of another SimpleImage object
*
* @return $this
*/
public function setLayerXOffset($x)
{
if (!empty($x)) {
$this->_layer_xOffset = (integer) $x;
}
return $this;
}
/**
* Set the x-position where to start copying on the xy plane of this object
* when treated as layer of another SimpleImage object
*
* @return $this
*/
public function setLayerYOffset($y)
{
if (!empty($y)) {
$this->_layer_yOffset = (integer) $y;
}
return $this;
}
public function getImgResourceOri()
{
return $this->_imageOri;
}
public function getImgResource()
{
return $this->_image;
}
public function getSizeInfo()
{
return $this->_sizeInfo;
}
/**
* buffer for merged image resource
*
* @var resource
*/
protected $_imageMerged;
/**
* When there are layers, return a merge version of the image
*
* @param bool $useSource
* @return resource
*/
public function getImageResourceMerged($useSource = true)
{
if ($this->hasLayers()) {
$new_layered_image = imagecreatetruecolor($this->getWidth(), $this->getHeight());
$old_image = ($useSource) ? $this->_imageOri : $this->_image;
imagecopyresampled($new_layered_image, $old_image, 0, 0, 0, 0, $this->getWidth(), $this->getHeight(), $this->getWidth(), $this->getHeight());
foreach ($this->_layers as $key=>$layer) {
if ($layer instanceof SimpleImage) {
$destXpos = 0;
$destYpos = 0;
$destXpos = $layer->getLayerXpos($this);
$destYpos = $layer->getLayerYpos($this);
imagecopymerge($new_layered_image, //dest
$layer->getImgResource(), //source of what to copy
$destXpos, //dest x-pos
$destYpos, //dest y-pos
$layer->getLayerXOffset(), //src x-pos
$layer->getLayerYOffset(), //src y-pos
$layer->getWidth(false), //src width
$layer->getHeight(false), //src height
100); //pct is percent merge which affects transparency etc
}
}
$this->_imageMerged = $new_layered_image;
} else {
return $this->_image;
}
return $this->_imageMerged;
}
public function save($filename, $image_type=IMAGETYPE_JPEG, $compression=75, $permissions=null)
{
if( $image_type == IMAGETYPE_JPEG ) {
try {
if ($this->hasLayers()) {
imagejpeg($this->getImageResourceMerged(), $filename, $compression);
} else {
imagejpeg($this->getImgResource(), $filename, $compression);
}
return true;
} catch(Exception $e) {
echo "Failed to save image: {$filename} - {$e->getMessage}\n";
trigger_error("Failed to save image: {$filename} - {$e->getMessage}\n", E_USER_ERROR);
return false;
}
} elseif( $image_type == IMAGETYPE_GIF ) {
try {
if ($this->hasLayers()) {
imagegif($this->getImageResourceMerged(), $filename);
} else {
imagegif($this->getImgResource(), $filename);
}
return true;
} catch(Exception $e) {
echo "Failed to save image: {$filename} - {$e->getMessage}\n";
trigger_error("Failed to save image: {$filename} - {$e->getMessage}\n", E_USER_ERROR);
return false;
}
} elseif( $image_type == IMAGETYPE_PNG ) {
try {
if ($this->hasLayers()) {
imagepng($this->getImageResourceMerged(), $filename);
} else {
imagepng($this->getImgResource(), $filename);
}
return true;
} catch(Exception $e) {
echo "Failed to save image: {$filename} - {$e->getMessage}\n";
trigger_error("Failed to save image: {$filename} - {$e->getMessage}\n", E_USER_ERROR);
return false;
}
}
if( $permissions != null) {
chmod($filename, $permissions);
}
if (is_file($filename)) {
//if saved, the original file resource will then be removed from buffer and the newly saved one becomes the original
$this->refresh();
return true;
}
return false;
}
public function refresh()
{
imagedestroy($this->_imageOri);
$this->_imageOri = $this->_image;
}
public function output($image_type=IMAGETYPE_JPEG)
{
if( $image_type == IMAGETYPE_JPEG ) {
header("Content-Type: ". self::IMAGEJPEG);
imagejpeg($this->_image);
} elseif( $image_type == IMAGETYPE_GIF ) {
header("Content-Type: ". self::IMAGEGIF);
imagegif($this->_image);
} elseif( $image_type == IMAGETYPE_PNG ) {
header("Content-Type: ". self::IMAGEPNG);
imagepng($this->_image);
}
}
public function getWidth($useSource = true)
{
if ($useSource) {
return imagesx($this->_imageOri);
} else {
return imagesx($this->_image);
}
}
public function getHeight($useSource = true)
{
if ($useSource) {
return imagesy($this->_imageOri);
} else {
return imagesy($this->_image);
}
}
public function resizeToHeight($height, $useSource = true)
{
$ratio = $height / $this->getHeight();
$width = $this->getWidth() * $ratio;
$this->resize($width,
$height,
$useSource);
return $this;
}
public function resizeToWidth($width, $useSource = true)
{
$ratio = $width / $this->getWidth();
$height = $this->getHeight() * $ratio;
$this->resize($width,
$height,
$useSource);
return $this;
}
public function scale($scale, $useSource = true)
{
$width = $this->getWidth() * $scale/100;
$height = $this->getheight() * $scale/100;
$this->resize($width,
$height,
$useSource);
return $this;
}
public function resize($width, $height, $useSource = true)
{
$new_image = imagecreatetruecolor($width, $height);
$old_image = ($useSource) ? $this->_imageOri : $this->_image;
imagecopyresampled($new_image, $old_image, 0, 0, 0, 0, $width, $height, $this->getWidth(), $this->getHeight());
$this->_image = $new_image;
return $this;
}
}
?>
Tuesday, March 20, 2012
A Not So Simple Image PHP Object
Extending the functionality of the original SimpleImage.php PHP class to include method daisy-chaining, n-level layering using different object instances and background image support, SimpleImage is can be not so simple anymore. Here's the code:
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment