Skip to content

Instantly share code, notes, and snippets.

@mpratt
Created July 20, 2012 18:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mpratt/3152284 to your computer and use it in GitHub Desktop.
Save mpratt/3152284 to your computer and use it in GitHub Desktop.
Aprendiendo con Memes: Tenso | Learning with Memes: Tenso Image Generator | URL: http://www.michael-pratt.com/blog/9/Aprendiendo-con-Memes-Tenso/
<?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();
?>
<?php
// Coge la imágen
list ($width, $height) = getimagesize('lorito.jpg');
$image = imagecreatefromjpeg('lorito.jpg');
// Texto y fuente
$text = 'Hola';
$font = 'impact.ttf';
// Los colores para nuestro texto
$white = imagecolorallocate($image, 255, 255, 255);
$black = imagecolorallocate($image, 0, 0, 0);
// Centramos el texto en el eje X
$x = (($width - (imagefontwidth(40) * strlen($text)))/2) - 40;
// Primero escribimos el texto en negro moviendolos un pixel a cada lado
// De esta forma creamos el efecto de una márgen
// El 20 es la distancia del texto al final de la imagen en el eje Y
imagettftext($image, 40, 0, ($x-1), ($height - 20)-1, $black, $font, $text);
imagettftext($image, 40, 0, ($x+1), ($height - 20)+1, $black, $font, $text);
// Encima de la margen en negro escribimos el texto en blanco
imagettftext($image, 40, 0, $x, ($height - 20), $white, $font, $text);
if (file_exists('lorito-text.png'))
unlink('lorito-text.png');
// Guardamos la imágen
imagepng($image, 'lorito-text.png');
?>
<?php
// Datos de la imágen
list ($width, $height) = getimagesize('lorito.jpg');
$image = imagecreatefromjpeg('lorito.jpg');
// Encontramos el centro de la imágen
$centerX = ceil($width/2);
$centerY = ceil($height/2);
// Dividimos la imágen por el factor de zoom. En este caso 2X
$zoomFactor = 2;
$zoomWidth = ceil($width/$zoomFactor);
$zoomHeight = ceil($height/$zoomFactor);
// Para la función imagecopyresampled necesitamos especificar la coordenada que se encuentra en
// la parte superior izquierda. Ya tenemos la coordenada del centro, usemosla para nuestro objetivo.
$topLeftX = round($centerX - ($zoomWidth/2));
$topLeftY = round($centerY - ($zoomHeight/2));
// Recortamos la imagen apartir de esa coordenada.
$croppedImage = imagecreatetruecolor($zoomWidth, $zoomHeight);
imagecopyresampled($croppedImage, $image, 0, 0, $topLeftX, $topLeftY, $width, $height, $width, $height);
// La imagén recortada, la agrandamos al tamaño de la imágen original
$zoomedImage = imagecreatetruecolor($width, $height);
imagecopyresampled($zoomedImage, $croppedImage, 0, 0, 0, 0, $width, $height, $zoomWidth, $zoomHeight);
imagedestroy($croppedImage);
if (file_exists('lorito-zoomed.png'))
unlink('lorito-zoomed.png');
// Guardamos la imágen
imagepng($zoomedImage, 'lorito-zoomed.png');
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment