|
<?php |
|
/** |
|
* Tenso.php |
|
* |
|
* @author Michael Pratt <pratt@hablarmierda.net> |
|
* @version 1.0 |
|
* @link http://www.michael-pratt.com/blog/9/Aprendiendo-con-Memes-Tenso/ |
|
* @demo http://www.michael-pratt.com/Lab/tenso/ |
|
* |
|
* @License: MIT |
|
* Copyright (C) 2012 by Michael Pratt <pratt@hablarmierda.net> |
|
* |
|
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
* of this software and associated documentation files (the "Software"), to deal |
|
* in the Software without restriction, including without limitation the rights |
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
* copies of the Software, and to permit persons to whom the Software is |
|
* furnished to do so, subject to the following conditions: |
|
* |
|
* The above copyright notice and this permission notice shall be included in |
|
* all copies or substantial portions of the Software. |
|
* |
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
* THE SOFTWARE. |
|
*/ |
|
|
|
class Tenso |
|
{ |
|
protected $image, $output, $width, $height, $extension, $tmpfile; |
|
protected $font = 'impact.ttf'; |
|
protected $text = ''; |
|
protected $frames = 4; |
|
protected $zoomFactor = 2; |
|
protected $center = array(); |
|
protected $start = array(); |
|
protected $destiny = array(); |
|
protected $debug = array(); |
|
|
|
/** |
|
* Constructor |
|
* |
|
* @param string $image Location of the image |
|
* @return void |
|
*/ |
|
public function __construct($image) |
|
{ |
|
$this->tmpfile = $image; |
|
list ($this->width, $this->height) = getimagesize($this->tmpfile); |
|
|
|
if (empty($this->width) ||empty($this->height)) |
|
throw new Exception('Invalid Image'); |
|
|
|
$this->extension = strtolower(pathinfo($image, PATHINFO_EXTENSION)); |
|
switch ($this->extension) |
|
{ |
|
case 'jpg': |
|
$this->image = imagecreatefromjpeg($this->tmpfile); |
|
break; |
|
|
|
case 'png': |
|
$this->image = imagecreatefrompng($this->tmpfile); |
|
break; |
|
|
|
case 'gif': |
|
$this->image = imagecreatefromgif($this->tmpfile); |
|
break; |
|
|
|
default: |
|
throw new Exception('Unknown extension'); |
|
} |
|
|
|
// Get the center of the image! |
|
$this->center = array('x' => round($this->width/2), 'y' => round($this->height/2)); |
|
} |
|
|
|
/** |
|
* Zooms the frame given the center coordinates. |
|
* |
|
* @param int $centerX X center coordinate of the frame |
|
* @param int $centerY Y center coordinate of the frame |
|
* @return resource The frame |
|
*/ |
|
protected function zoom($centerX, $centerY) |
|
{ |
|
$zoom = intval($this->zoomFactor - 1); |
|
$topLeftX = $topLeftY = 0; |
|
while(true) |
|
{ |
|
$zoom++; |
|
$width = ceil($this->width/$zoom); |
|
$height = ceil($this->height/$zoom); |
|
|
|
// Get the top left coordinates of the zoom |
|
$topLeftX = round($centerX - ($width/2)); |
|
$topLeftY = round($centerY - ($height/2)); |
|
|
|
// Validate that X and Y are inside the range of the image! |
|
$validateX = ($topLeftY <= $this->width && ($topLeftX + $width) <= $this->width && $topLeftX >= 0); |
|
$validateY = ($topLeftY <= $this->height && ($topLeftY + $height) <= $this->height && $topLeftY >= 0); |
|
|
|
// Stop zooming if the coordinates are good OR if we have tried too many times. |
|
if (($validateX && $validateY) || $zoom >= 50) |
|
break; |
|
} |
|
|
|
$this->debug['zoom'][] = array('x' => $topLeftX, |
|
'y' => $topLeftY, |
|
'height' => $height, |
|
'width' => $width, |
|
'factor' => $zoom); |
|
|
|
// Zoom the area |
|
$croppedImage = imagecreatetruecolor($width, $height); |
|
imagecopyresampled($croppedImage, $this->image, 0, 0, $topLeftX, $topLeftY, $this->width, $this->height, $this->width, $this->height); |
|
|
|
// Enhance it! |
|
$frame = imagecreatetruecolor($this->width, $this->height); |
|
imagecopyresampled($frame, $croppedImage, 0, 0, 0, 0, $this->width, $this->height, $width, $height); |
|
imagedestroy($croppedImage); |
|
|
|
return $frame; |
|
} |
|
|
|
/** |
|
* Generates the image |
|
* |
|
* @return void |
|
*/ |
|
public function create() |
|
{ |
|
$this->debug['center'] = $this->center; $this->debug['destiny'] = $this->destiny; |
|
|
|
// If no starting point was defined, we use the center coordinates. |
|
if (!empty($this->start['x']) && !empty($this->start['y'])) |
|
{ |
|
$x = $this->start['x']; |
|
$y = $this->start['y']; |
|
} |
|
else |
|
{ |
|
$x = $this->center['x']; |
|
$y = $this->center['y']; |
|
} |
|
|
|
$this->debug['starting_point'] = array('x' => $x, 'y' => $y); |
|
|
|
// The first frame is always the original file. |
|
$this->output = imagecreatetruecolor($this->width, ($this->height * $this->frames)); |
|
imagealphablending($this->output, true); |
|
imagecopy($this->output, $this->image, 0, 0, 0, 0, $this->width, $this->height); |
|
|
|
// The remaining Frames |
|
$rFrames = ($this->frames-1); |
|
|
|
// Calculate the distance between the starting point and the destination, in relation to the number of frames |
|
$distanceX = round(($this->destiny['x'] - $x)/$rFrames); |
|
$distanceY = round(($this->destiny['y'] - $y)/$rFrames); |
|
|
|
// Start with 1 because we already have the first frame - Get the remaining ones! |
|
for ($i=1; $i<=$rFrames; $i++) |
|
{ |
|
$x += $distanceX; |
|
$y += $distanceY; |
|
|
|
$frame = $this->zoom($x, $y); |
|
imagecopy($this->output, $frame, 0, ($this->height * $i), 0, 0, $this->width, $this->height); |
|
imagedestroy($frame); |
|
|
|
$this->debug['creation_points'][] = array('x' => $x, 'y' => $y); |
|
} |
|
|
|
$this->writeText(); |
|
} |
|
|
|
/** |
|
* Writes text on the end of the image |
|
* |
|
* @return void |
|
*/ |
|
protected function writeText() |
|
{ |
|
if (empty($this->text) || empty($this->font)) |
|
return ; |
|
else if (!is_file($this->font)) |
|
throw new Exception($this->font . ' was not found!'); |
|
|
|
$white = imagecolorallocate($this->output, 255, 255, 255); |
|
$black = imagecolorallocate($this->output, 0, 0, 0); |
|
|
|
// centering text horizontally |
|
$x = (($this->width - (imagefontwidth(40) * strlen($this->text)))/2) - 40; |
|
imagettftext($this->output, 40, 0, ($x-1), (($this->height * $this->frames) - 20)-1, $black, $this->font, $this->text); |
|
imagettftext($this->output, 40, 0, ($x+1), (($this->height * $this->frames) - 20)+1, $black, $this->font, $this->text); |
|
imagettftext($this->output, 40, 0, $x, (($this->height * $this->frames) - 20), $white, $this->font, $this->text); |
|
} |
|
|
|
/** |
|
* Show the image in jpg format in the browser |
|
* |
|
* @return void |
|
*/ |
|
public function show() |
|
{ |
|
header('Cache-Control: no-store, no-cache'); |
|
header('Content-type: image/jpg'); |
|
imagejpeg($this->output, null, 99); |
|
} |
|
|
|
/** |
|
* Returns important data for debugging |
|
* |
|
* @return array |
|
*/ |
|
public function debug() { return $this->debug; } |
|
|
|
/** |
|
* Setter Method |
|
* |
|
* @return void |
|
*/ |
|
public function set($key, $value) |
|
{ |
|
if (property_exists($this, $key) && !in_array(strtolower($key), array('image', 'tmpfile'))) |
|
$this->$key = $value; |
|
} |
|
|
|
/** |
|
* Clean the environment on object destruction |
|
* |
|
* @return void |
|
*/ |
|
public function __destruct() { imagedestroy($this->output); } |
|
} |
|
|
|
// Usage |
|
$Tenso = new Tenso('lorito.jpg'); |
|
$Tenso->set('text', 'Tenso'); |
|
$Tenso->set('destiny', array('x' => 300, 'y' => 250); |
|
$Tenso->create(); |
|
$Tenso->show(); |
|
?> |