Hize una clase que permite el redimensionado de imágenes con opciones para guardar las proporciones del tamaño de la imágen. Soporta todos los formatos que aguanta php y no hace perdida de calidad ni pixelados como imagick.
<?php
if($_SERVER['SCRIPT_FILENAME'] == __file__) exit; /* Not included */
class gdp{
var $lastError;
var $imageHandle;
var $imageSize;
function getImageHandle($filepath = false){
if($this->lastError)
return false;
if(!$filepath){
$this->lastError = 50; /* Necesita proporcionar mas datos */
return false;
}
/* Verifica si el archivo existe */
if(!file_exists($filepath)){
$this->lastError = 2; /* El archivo no existe */
return false;
}
/* Verifica si el archivo es una imágen o no */
if(!exif_imagetype($filepath)){
$this->lastError = 3; /* EL archivo no es una imágen */
return false;
}
/* Verifica si GD es capaz de cargar la imágen */
if(!$this->imageHandle = imagecreatefromstring(file_get_contents($filepath))){
$this->lastError = 4; /* La imágen no pudo ser procesada */
return false;
}
/* Verifica si el sistema es capaz de obtener sus dimensiones */
if(!$this->imageSize = getimagesize($filepath)){
$this->lastError = 5; /* Fué imposible obtener sus propiedades */
return false;
}
}
function saveImageHandle($savepath = false, $makePathRecursive = true){
if($this->lastError)
return false;
if(!$savepath){
$this->lastError = 51; /* Necesita proporcionar mas datos */
return false;
}
/* Crea el directorio de forma recursiva si es necesario (php5 solamente) */
if(!is_dir(dirname($savepath))){
if(!mkdir(dirname($savepath), 0775, $makePathRecursive)){
$this->lastError = 6; /* No fué posible crear el directorio para guardar la imágen */
return false;
}
}
if(!imagejpeg($this->imageHandle, $savepath, 100)){
$this->lastError = 7; /* Imposible guardar imágen */
return false;
}
/* Guardado correctamente */
return true;
}
function copyImage($filepath = false, $savepath = false, $makePathRecursive = true){
if($this->lastError)
return false;
if((!$filepath) or (!$savepath)){
$this->lastError = 52; /* Necesita proporcionar mas datos */
return false;
}
$this->getImageHandle($filepath);
$this->saveImageHandle($savepath, $makePathRecursive);
if($this->lastError)
return false;
else
return true;
}
function sizeAspectRatio($w, $h, $maxW, $maxH){
/* Cast */
$w = (int)$w; $h = (int)$h; $maxW = (int)$maxW; $maxH = (int)$maxH;
/* Matris con el nuevo tamaño */
$newSize = array(
'oldW' => (int)$w,
'oldH' => (int)$h,
'w' => (int)$w,
'h' => (int)$h,
'maxW' => (int)$maxW,
'maxH' => (int)$maxH,
'%newW' => (((int)$maxW * 100) / (int)$w),
'%newH' => (((int)$maxH * 100) / (int)$h),
);
/* Calcula el redimensionado principal */
/* El ancho necesita ser redimensionado */
if($w > $maxW){
/* Establece el nuevo valor para el ancho */
$newSize['w'] = $maxW;
/* Establece el nuevo valor para la altura */
$newSize['h'] = (($h * $newSize['%newW']) / 100); // Float
}
/* El alto necesita ser redimensionado */
if($h > $maxH){
/* Establece el nuevo valor para la altura */
$newSize['h'] = $maxH;
/* Establece el nuevo valor para el ancho */
$newSize['w'] = (($w * $newSize['%newH']) / 100); // Float
}
/* Redundancia para evitar una recursividad (disminuye el uso de CPU) */
/* El ancho necesita ser redimensionado */
if(($newSize['w'] > 0) and ($newSize['w'] > $maxW) or (($newSize['w'] == 0) and ($w > $maxW))){ // Calculo de valores flotantes
/* Establece el nuevo valor para el ancho */
$newSize['w'] = $maxW;
/* Establece el nuevo valor para la altura */
$newSize['h'] = (($h * $newSize['%newW']) / 100); // Float
}
/* Recalcula el porcentaje de redimensionado total (no es el aspecto de radio) */
$newSize['%newW'] = (($newSize['w'] * 100) / $w);
$newSize['%newH'] = (($newSize['h'] * 100) / $h);
/* Cast (transforma los valores Flotantes a Integers) */
$newSize = array(
'oldW' => (int)$newSize['oldW'],
'oldH' => (int)$newSize['oldH'],
'w' => (int)$newSize['w'],
'h' => (int)$newSize['h'],
'maxW' => (int)$newSize['maxW'],
'maxH' => (int)$newSize['maxH'],
'%newW' => $newSize['%newW'], // Valor flotante
'%newH' => $newSize['%newH'] // Valor flotante
);
return $newSize;
}
function resize($filepath = false, $savepath = false, $maxW = false, $maxH = false, $makePathRecursive = true){
if($this->lastError)
return false;
if((!$filepath) or (!$savepath) or (!$maxW) or (!$maxH)){
$this->lastError = 53; /* Necesita proporcionar mas datos */
return false;
}
$this->getImageHandle($filepath);
if($this->lastError)
return false;
/* Calcula el redimensionado manteniendo la relación de aspecto */
$newSize = $this->sizeAspectRatio((int)$this->imageSize[0], (int)$this->imageSize[1], (int)$maxW, (int)$maxH);
print_r($newSize); exit;
/* Redimensiona la imágen */
if(((int)$this->imageSize[0] > (int)$maxW) or ((int)$this->imageSize[1] > (int)$maxH)){
$handleOutImg = imagecreatetruecolor((int)$newSize['w'], (int)$newSize['h']);
imagecopyresampled($handleOutImg, $this->imageHandle, 0, 0, 0, 0, (int)$newSize['w'], (int)$newSize['h'], (int)$this->imageSize[0], (int)$this->imageSize[1]);
imagedestroy($this->imageHandle);
$this->imageHandle = $handleOutImg;
}
/* Guarda la imágen */
$this->saveImageHandle($savepath, $makePathRecursive);
if($this->lastError)
return false;
/* Guardado correctamente */
return $newSize;
}
}
Uso:
<?php
$this->gdp = new gdp();
if(!$this->gdp->resize(
$_POST['files']['photo']['tmp_name'],
'/var/www/uploads/galerias/'.($outpath = md5(microtime()).'.jpg'),
700,
700
) and ($this->gdp->lastError)){
/* Argumentos faltantes? esto no debería pasar jamás, pero de todas formas se controlará */
if(($this->gdp->lastError > 49) and ($this->gdp->lastError < 60))
$lastError = 'Hubo un error al intentar guardar la imágen. Contáctese con su Administrador.';
/*
* El archivo se ha enviado pero el servidor no la ha guardado.
* Generalmente sucede debido al mod security del apache con alguna regla de seguridad que evitó
* el guardado de un archivo potencialmente peligroso.
* También sucede cuando se está utilizando algún antivirus en el servidor y se ha detectado
* algún código malicioso.
* De todas formas no debería causar mayor problema debido a que no se guardará el archivo original
* sino que se procesará su duplicado evitando la subida de códigos o binarios arbitrários.
* En este caso dicha regla o antivirus queda obsoleto para este procesamiento.
**/
elseif($this->gdp->lastError == 2)
$this->lastError = 'El archivo enviado no pudo ser procesado. Contáctese con el Administrador.';
elseif($this->gdp->lastError == 3)
$this->lastError = 'El archivo proporcionado no es una imágen.';
elseif(($this->gdp->lastError == 4) or ($this->gdp->lastError == 5))
$this->lastError = 'La imágen proporcionada está corrupta.';
elseif($this->gdp->lastError == 6)
$this->lastError = 'No fué posible crear el directorio para guardar la fotografía. Contáctese con su Administrador.';
elseif($this->gdp->lastError == 7)
$this->lastError = 'Fué imposible guardar la imágen. Contáctese con su Administrador.';
else
$this->lastError = 'Hubo un error al intentar guardar la imágen. Contáctese con su Administrador.';
}else
echo 'Imágen guardada: '.$outpath;
No te guarda un cuadrado de 700x700 sino que establece el ancho y alto máximo manteniendo las proporciones.
Si el directorio de la fotografía a guardar no existe la creará, si no deseas que la haga entonces ponle false después del valor de la altura máxima así:
<?php
if(!$this->gdp->resize(
$_POST['files']['photo']['tmp_name'],
'/var/www/uploads/galerias/'.($outpath = md5(microtime()).'.jpg'),
700,
700,
false
) and ($this->gdp->lastError)){
...
Además está asegurado para que nadie pueda subirte una shell o algún archivo malicioso, en otras palabras es seguro.
Yo en lo personal prefiero redimensionar con GD en ves de Imagick porque la calidad de redimensionado con imágenes HD queda mejor y para el trabajo que estoy haciendo es indispensable.
Saludos
