Como crear Thumbnails con PHP

En mi ultimo post hice un «tutorial» de como crear una galería de imágenes en PHP. Para mostrar la galería simplemente había aplicado CSS para establecer el tamaño de las imágenes y que así luciese como una galería pero obviamente si las imágenes fuesen muy pesadas o hubiese muchas la galería tardaría en cargarse.

Aquí explicare las sencillas funciones que he creado con PHP para crear thumbnails de las imágenes y aumentar así la velocidad de con la que se cargaría nuestra galería.

He optado por separar el código en 3 funciones para encapsular un poco los procesos y facilitar así futuras modificaciones, porque hay varias formas para crear thumbnails con PHP o con lo que sea dependiendo de si queremos recortar la imagen, escalarla, o cualquier convinación que se nos ocurra. Vamos con la función central que será la que creara los thumbnails.


/**
 * Crea un thumbail de una imagen con el ancho y el alto pasados como parámetros. Si se pone el
 * ancho o el alto a 0, este se calculara para que la imagen conserve las proporciones originales.
 * 
 * @param type $nombreImagen Nombre completo de la imagen incluida la ruta y la extension.
 * @param type $nombreThumbnail Nombre completo para el thumbnail incluida la ruta y la extension.
 * @param type $nuevoAncho Ancho para el thumbnail.
 * @param type $nuevoAlto Alto para el thumbnail.
 */

function crearThumbnail($nombreImagen, $nombreThumbnail, $nuevoAncho, $nuevoAlto){
    
    // Obtiene las dimensiones de la imagen.
    list($ancho, $alto) = getimagesize($nombreImagen);

    // Establece el alto para el thumbnail si solo se paso el ancho.
    if ($nuevoAlto == 0 && $nuevoAncho != 0){
        $factorReduccion = $ancho / $nuevoAncho;
        $nuevoAlto = $alto / $factorReduccion;
    }
    
    // Establece el ancho para el thumbnail si solo se paso el alto.
    if ($nuevoAlto != 0 && $nuevoAncho == 0){
        $factorReduccion = $alto / $nuevoAlto;
        $nuevoAncho = $ancho / $factorReduccion;
    }
             
    // Abre la imagen original.
    list($imagen, $tipo) = abrirImagen($nombreImagen);
    
    // Crea la nueva imagen (el thumbnail).
    $thumbnail = imagecreatetruecolor($nuevoAncho, $nuevoAlto);  
    imagecopyresampled($thumbnail , $imagen, 0, 0, 0, 0, $nuevoAncho, $nuevoAlto, $ancho, $alto);
    
    // Guarda la imagen.
    guardarImagen($thumbnail, $nombreThumbnail, $tipo);
}

El código esta comentado de arriba a abajo, por lo que hay poco más que comentar. Lo único decir que con esta sencilla función englobamos dos de las tres opciones que hay para crear thumbnails de las imágenes:

  • Crear la imagen con el ancho y alto elegidos. Tiene el problema de que la imagen probablemente quede distorsionada y su ventaja es que por ejemplo cara crear una galería nos permite que se vean todas las imágenes del mismo tamaño.

  • También es posible crear una imagen respetando las proporciones originales, si le pasamos por ejemplo solo el ancho que queremos y ponemos 0 en el alto.

La opción restante es:

  • Que la imagen resultante sea un trozo de la imagen original, es decir, cortar un trozo de la imagen. Que seria muy sencillo de hacer bastaría con pasar a la función imagecopyresampled() en lugar del tamaño de la imagen el tamaño del thumbnail y ya tendríamos un thumbnail que seria la esquina superior izquierda de la imagen original y jugando con las coordenadas de la imagen original podríamos obtener el trozo de la imagen original que nos pareciese.

    
    imagecopyresampled($thumbnail , $imagen, esquinaSupIzqThumb, esquinaSupDrchThumb, esquinaSupIzqImg, esquinaSupDrchImg, $nuevoAncho, $nuevoAlto, $ancho, $alto);
    

    A mi esta opción no me gusta mucho pues si la imagen es un poco grande puede que el thumbnail no sea nada representativo. Por ejemplo este es el resultado con la imagen que se crearon los anteriores, thumbnails.

Además de estas opciones hay la opción por ejemplo de crear thumbnails con el ancho y el alto que queramos pero que mantenga las proporciones originales lo que puede ser sin duda interesante, y lo mejor es que es así de fácil de hacer:


/**
 * Crea un thumbail de un imagen con el ancho y el alto pasados como parametros, 
 * pero manteniendo las proporciones originales añadiendo bordes a la imagen.
 * 
 * @param type $nombreImagen Nombre completo de la imagen incluida la ruta y la extension.
 * @param type $nombreThumbnail Nombre completo para el thumbnail incluida la ruta y la extension.
 * @param type $nuevoAncho Ancho para el thumbnail.
 * @param type $nuevoAlto Alto para el thumbnail.
 */

function crearThumbnail2($nombreImagen, $nombreThumbnail, $nuevoAncho, $nuevoAlto){
    
    // Obtiene las dimensiones de la imagen.
    list($ancho, $alto) = getimagesize($nombreImagen);
    
    // Comprueba que medida es menor para ponerle luego bordes.
    if ($ancho > $alto){
        $anchoImagen = $nuevoAncho;
        $factorReduccion = $ancho / $nuevoAncho;
        $altoImagen = $alto / $factorReduccion;
    }
    else{
        $altoImagen = $nuevoAlto;
        $factorReduccion = $alto / $nuevoAlto;
        $anchoImagen = $ancho / $factorReduccion;
    }
     
    // Abre la imagen original.
    list($imagen, $tipo)= abrirImagen($nombreImagen);
    
    // Crea la nueva imagen (el thumbnail).
    $thumbnail = imagecreatetruecolor($nuevoAncho, $nuevoAlto);  
    imagecopyresampled($thumbnail , $imagen, ($nuevoAncho-$anchoImagen)/2, ($nuevoAlto-$altoImagen)/2, 0, 0, $anchoImagen, $altoImagen, $ancho, $alto);
    
    // Guarda la imagen.
    guardarImagen($thumbnail, $nombreThumbnail, $tipo);
}

El resultado seria este:

Bueno, la verdad puede ser un poco lioso de entender porque hay que manejar 3 tipos de ancho y alto, pero viendo el código es más sencillo.

Después de haber escrito este tema, se me vino otra opción a la cabeza en la que no había pensado y que puede que sea la mejor, asique aquí os la añado supercomentada porque esta es un poco más compleja:


/**
 * Crea un thumbail de un imagen con el ancho y el alto pasados como parametros, 
 * recortando en caso de ser necesario la dimension mas grande por ambos lados.
 * 
 * @param type $nombreImagen Nombre completo de la imagen incluida la ruta y la extension.
 * @param type $nombreThumbnail Nombre completo para el thumbnail incluida la ruta y la extension.
 * @param type $nuevoAncho Ancho para el thumbnail.
 * @param type $nuevoAlto Alto para el thumbnail.
 */

function crearThumbnailRecortado($nombreImagen, $nombreThumbnail, $nuevoAncho, $nuevoAlto){
    
    // Obtiene las dimensiones de la imagen.
    list($ancho, $alto) = getimagesize($nombreImagen);
        
    // Si la division del ancho de la imagen entre el ancho del thumbnail es mayor
    // que el alto de la imagen entre el alto del thumbnail entoces igulamos el 
    // alto de la imagen  con el alto del thumbnail y calculamos cual deberia ser
    // el ancho para la imagen (Seria mayor que el ancho del thumbnail). 
    // Si la relacion entre los altos fuese mayor entonces el altoImagen seria
    // mayor que el alto del thumbnail.
    if ($ancho/$nuevoAncho > $alto/$nuevoAlto){
        $altoImagen = $nuevoAlto;
        $factorReduccion = $alto / $nuevoAlto;
        $anchoImagen = $ancho / $factorReduccion;      
    }
    else{
        $anchoImagen = $nuevoAncho;
        $factorReduccion = $ancho / $nuevoAncho;
        $altoImagen = $alto / $factorReduccion;
    }
     
    // Abre la imagen original.
    list($imagen, $tipo)= abrirImagen($nombreImagen);
    
    // Crea la nueva imagen (el thumbnail).
    $thumbnail = imagecreatetruecolor($nuevoAncho, $nuevoAlto);  
    
    // Si la relacion entre los anchos es mayor que la relacion entre los altos
    // entonces el ancho de la imagen que se esta creando sera mayor que el del
    // thumbnail porlo que se centrara para que se corte por la derecha y por la 
    // izquierda. Si el alto fuese mayor lo mismo se cortaria la imagen por arriba
    // y por abajo.
    if ($ancho/$nuevoAncho > $alto/$nuevoAlto){
        imagecopyresampled($thumbnail , $imagen, ($nuevoAncho-$anchoImagen)/2, 0, 0, 0, $anchoImagen, $altoImagen, $ancho, $alto);
    }  else {
        imagecopyresampled($thumbnail , $imagen, 0, ($nuevoAlto-$altoImagen)/2, 0, 0, $anchoImagen, $altoImagen, $ancho, $alto);
    }
    
    // Guarda la imagen.
    guardarImagen($thumbnail, $nombreThumbnail, $tipo);
}

Y el resultado seria este:

Finalmente,como se puede ver tanto en esta función modificada como en la original se llama a las funciones abrirImagen($nombreImagen) y guardarImagen($thumbnail, $nombreThumbnail, $tipo) que se encargan de abrir la imagen y de guardarla como su nombre indica.


/**
 * Abre la imagen con el nombre pasado como parametro y devuelve un array con la imagen y el tipo de imagen.
 * 
 * @param type $nombre Nombre completo de la imagen incluida la ruta y la extension.
 * @return Devuelve la imagen abierta.
 */

function abrirImagen($nombre){
    $info = getimagesize($nombre);
    switch ($info["mime"]){
        case "image/jpeg":
            $imagen = imagecreatefromjpeg($nombre);
            break;
        case "image/gif":
            $imagen = imagecreatefromgif($nombre);
            break;
        case "image/png":
            $imagen = imagecreatefrompng($nombre);
            break;
        default :
            echo "Error: No es un tipo de imagen permitido.";
    }
    $resultado[0]= $imagen;
    $resultado[1]= $info["mime"];
    return $resultado;
}

/**
 * Guarda la imagen con el nombre pasado como parametro.
 * 
 * @param type $imagen La imagen que se quiere guardar
 * @param type $nombre Nombre completo de la imagen incluida la ruta y la extension.
 * @param type $tipo Formato en el que se guardara la imagen.
 */

function guardarImagen($imagen, $nombre, $tipo){

    switch ($tipo){
        case "image/jpeg":
            imagejpeg($imagen, $nombre, 100); // El 100 es la calidade de la imagen (entre 1 y 100. Con 100 sin compresion ni perdida de calidad.).
            break;
        case "image/gif":
            imagegif($imagen, $nombre);
            break;
        case "image/png":
            imagepng($imagen, $nombre, 9); // El 9 es grado de compresion de la imagen (entre 0 y 9. Con 9 maxima compresion pero igual calidad.).
            break;
        default :
            echo "Error: Tipo de imagen no permitido.";
    }
}   

En la función abrirImagen() comentar que se ha usado la función getimagesize() que puede resultar extraño porque no hace falta saber el tamaño para abrir la imagen pero es que esta función devuelve un array con información de la imagen y es por tanto el medio con el que contamos para poder saber el tipo de imagen mediante [‘mime’] y también decir que como resultado de la función abrirImagen() se devuelve un array con la imagen y con el tipo de esta para luego poder guardar la imagen con el mismo tipo aunque no seria necesario guardar las imágenes con el mismo tipo.

Y para terminar puedes descargarte el código aquí.

4 Comments

  1. gmendezm 6 abril, 2013 Reply
  2. Anonymous 20 abril, 2013 Reply
  3. Robert Niño 10 noviembre, 2014 Reply
  4. Robert Niño 10 noviembre, 2014 Reply

Leave a Reply