sábado, 22 de diciembre de 2012

Reducir una imágen con PHP y GD

Reducir una imagen con PHP y GD

Este simple script permite procesar una imagen, pudiendo ser usado tanto al subir la imagen para guardar una version reducida de esta, o para emitir una version ajustada a la medida solicitada leyendo desde una imagen mas grande.

Se requiere que la instalación de PHP tenga incorporada la librería GD.

 Efecto Image Zoom:  Una variante de este código podría usarse para hacer "Zoom" en una imagen muy alta resolución, programando adecuadamente el vector de desplazamiento sobre la imagen original y trayendo solo un área específica, esta técnica combinada con Ajax realiza el efecto de Zoom

Ejemplo de uso:

  1. // IMAGEN ORIGINAL..EN ALTA RESOLUCION.
    $fullName = '/anypath/image.jpg';

    // OBTENER INFORMACION DE LA IMAGEN ORIGINAL.
  2. list($ow, $oh, $xmime) = getimagesize($fullName);
  3. $imageSize = filesize($fullName);
  4. $mime = '';
  5. if($xmime == 2) $mime = 'image/jpg';
  6. if($xmime == 3) $mime = 'image/png';

  7. // LEER LA IMAGEN ORIGINAL
  8. $f = fopen($fullName,"r");
  9. $imageData = fread($f, $imageSize);
  10. fclose($f);

  11. // HACER EL RESIZE A 160 x 120 px, con 70% de compresion JPEG    
  12. $r = new ImageResizer();
  13. $newImage = $r->resize($imageData, 160, 120, 70, 'jpg', $ow, $oh);

    // EMITIR LA IMAGEN
  14. header('Content-type: '.$mime);
  15. echo $newImage;


Si el ejemplo anterior estuviese alojado en una pagina PHP llamada:

http://miservidor/imagen.php

podríamos visualizar la imagen en una pagina HTML asi:

<html>
   <img src='http://miservidor/imagen.php'>
</html>

Está demás decir que se pudiera programar el script para recibir argumentos y asi emitir la imagen en un formato especifico:

<html>
   <img src='http://miservidor/imagen.php?w=320&h=200&c=50'>
</html>

El script podria recibir los argumentos pasados aqui y asi emitir la imagen en esa dimensión solicitada.


Por qué "a veces" es incorrecto hacer:  "<img src='...' width=160 height=120  >" ?

Respuesta:  Porque "a veces" la imagen original pesa 4 megas y no vas a querer tener en un website una imagen de 160x120 pixels que pese 4 megas, debido a que aunque estes solicitando esas medidas en tiempo de browsing (es decir al momento de presentarla) esa imagen pesara 4 megas, tardara en bajar al browser para finalmente ser presentada en una medida muy pequeña, aparte de quedar horrible por la fragmentación del pixelado, va a pesar mucho.

Código fuente:

  1. <?php
  2. /**
  3.  * ImageResizer
  4.  *      a helper class to handle image resize.
  5.  *
  6.  *      example usage:
  7.  *             
  8.  *  $fullName = '/anypath/image.jpg';
  9.  *      list($ow, $oh, $xmime) = getimagesize($fullName);
  10.  *      $imageSize = filesize($fullName);
  11.  *      $mime = '';
  12.  *      if($xmime == 2) $mime = 'image/jpg';
  13.  *  if($xmime == 3) $mime = 'image/png';
  14.  *       
  15.  *      $f = fopen($fullName,"r");
  16.  *      $imageData = fread($f, $imageSize);
  17.  *      fclose($f);
  18.  *     
  19.  *      $r = new ImageResizer();
  20.  *      $newImage = $r->resize($imageData, 160, 120, 70, 'jpg', $ow, $oh);
  21.  *      header('Content-type: '.$mime);
  22.  *      echo $newImage;
  23.  *
  24.  *
  25.  * @author Christian Salazar <christiansalazarh@gmail.com>
  26.  * @license NEW BSD.
  27.  */
  28. class ImageResizer {
  29.         /**
  30.          * resize
  31.          *      resizes an image making it to fit into a rectangle
  32.          *
  33.          * @param mixed $image  Binary raw image data.
  34.          * @param mixed $dw     destination viewport width
  35.          * @param mixed $dh     destination viewport height
  36.          * @param mixed $q      quality for jpg or png: 1 to 100.
  37.          * @param mixed $imgtype desired output image type 'jpg' or 'png'
  38.          * @param mixed $ow     original image width
  39.          * @param mixed $oh     original image height
  40.          * @return new image. you can echo it or use GD functions to handle it.
  41.          */
  42.         public function resize($image, $dw, $dh, $q, $imgtype, $ow, $oh){
  43.                 $im = imagecreatetruecolor($dw, $dh);
  44.                 $im_src = imagecreatefromstring($image);
  45.                 $_w = 0;
  46.                 $_h = 0;
  47.                 $this->_scaleVector($dw, $dh, 0.95, $ow, $oh, $_w, $_h);
  48.                 // displacement vector, this vector center the image.
  49.                 $dx = ($dw - $_w)/2;
  50.                 $dy = ($dh - $_h)/2;
  51.                 $fillcolor = imagecolorallocate($im,255,255,255);
  52.                 //$xcolor = imagecolorallocate($im, 200,200,200);
  53.                 imagefilledrectangle($im, 0,0,$dw, $dh, $fillcolor);
  54.                 //imagefilledrectangle($im, $dx,$dy, $dx + $_w, $dy + $_h, $xcolor);
  55.                 imagecopyresampled(
  56.                                 $im, $im_src,
  57.                                 $dx, $dy, 0, 0,
  58.                                 $_w, $_h,
  59.                                 $ow, $oh
  60.                 );
  61.                 if($imgtype == 'png')
  62.                         return imagepng($im, null, $q);
  63.                 return imagejpeg($im, null, $q);
  64.         }
  65.         /**
  66.          * _scaleVector
  67.          *     
  68.          *
  69.          * @param mixed $dw             |       destination viewport:
  70.          * @param mixed $dh             |               d = {w, h}
  71.          * @param mixed $delta          |       delta: is a fixture measurement. max 1.
  72.          * @param mixed $ow             |       original viewport to be scaled into "d":
  73.          * @param mixed $oh             |               o = {w, h}
  74.          * @param mixed $out_w         
  75.          * @param mixed $out_h
  76.          * @access private
  77.          * @author Christian Salazar H. <christiansalazarh@gmail.com>  
  78.          * @return void
  79.          */
  80.         private function _scaleVector($dw, $dh, $delta, $ow, $oh, &$out_w, &$out_h){
  81.                 $dR = $dw / $dh;
  82.                 if($dR >= 1){
  83.                         $out_w = $delta * $dw;
  84.                         $out_h = ($out_w * $oh) / $ow;
  85.                 }else{
  86.                         $out_h = $delta * $dh;
  87.                         $out_w = ($out_h * $ow) / $oh;
  88.                 }
  89.         }
  90. }

4 comentarios:

  1. Excelente amigo muy bueno.

    ResponderEliminar
  2. El script está genial, yo el unico problema qué le veo es qué este script deveria de guardar las imagenes y remplazarlas por las antiguas, para mi esto seria genial. un saludo!

    ResponderEliminar
    Respuestas
    1. hola, eso no es responsabilidad de este componente. la responsabilidad es de convertir la imagen, no de aplicar una logica de negocios, eso se le delega a otro componente.

      Eliminar
    2. cuando leiste la imagen y la reduces al porcentaje indicado, simplemente con la funciòn de escribir archivo - nombre se puede "pisar" el file original con el nuevo tamaño, o podès darle un nuevo nombre con un còdigo que te indique que el archivo ya està procesado y puede borrar el original luego

      Eliminar