Comunidad de diseño web y desarrollo en internet

Redimensionar imágenes en PHP con clases abstractas

Las clases abstractas en la programación orientada a objetos son clases de las que no se pueden crear instancias/objetos directamente de ella.

¿Para qué defino una clase como abstracta si no puedo crear objeto de ella?


Si puedes crear instancias pero solo de clases que hereden dicha clase (que no sean abstractas por supuesto). El objetivo principal de la herencia es mejorar la clase heredada. Así que sabiendo esto, las clases abstractas en su más pura esencia son clases mejorables!

Una clase abstracta puede tener métodos y propiedades como cualquier otra clase.

¿Cuando debo definir una clase abstracta?


Cuando puedas crear diferentes clases que tengan propiedades y métodos comunes, y aún sabiendo que en el futuro que puedes crear más clases del mismo tipo.

En la clase abstracta se definirían las propiedades y métodos comunes, para que las clases que la hereden no tengan la necesidad implementar esos métodos o definir las propiedades.


Métodos Abstractos


Así como hay clases abstractas, también hay métodos abstractos. Estos métodos no son implementados en su definición, pero obliga a las clases que hereden el método a implementarlo.

Un método abstracto se puede definir en casi cualquier clase, no necesariamente debe ser una clase abstracta. Un ejemplo en las que no se deberían definir métodos abstractos serian en las clases finales, pues no se podrían implementar.

Las clases finales: son las clases engreídas en la POO su lema principal: ¡Nadie me puede mejorar!. Es decir, que no se pueden heredar. Entonces se podría decir que son las opuestas a las clases abstractas que son la de baja autoestima su lema: "Soy inútil sola, mejorame por favor ".

Redimensionar imágenes en PHP usando clase abstracta


Definimos una clase abstracta llamada ImageBase. Todas las clases que hereden esta clase tendrán:
  • Las propiedades width y height, con sus respectivos setters y getters.
  • Además de dos metodos comunes los cuales son: gdFromFile y gdToFile.
  • Obliga a la clase que le herede a implementar el metodo save


Código :

abstract class ImageBase
{
    protected $width;
    protected $height;

    public function setWidth($w)
    {
        // gd solo maneja enteros, ergo obligamos que ancho sea entero. 
        $w = (int) $w;
        // ancho debe ser mayor que 0
        if ($w > 0)    $this->width = $w;
    }

    public function getWidth()
    {
        return $this->width;
    }

    public function setHeight($h)
    {
        // gd solo maneja enteros, ergo obligamos que alto sea entero
        $h = (int) $h;
        // alto debe ser mayor que 0
        if ($h > 0)    $this->height = $h;
    }

    public function getHeight()
    {
        return $this->height;
    }

    /**
     * Genera una imagen gd del archivo con nombre $filename 
     * Retorna FALSE si ocurrior algun error, por ejemplo: el tipo no es soportado
     *
     * @param string $filename nombre del archivo
     * @param int $type Tipo de imagen para saber que funcion usar
     * @return resource Una imagen gd. 
     */
    protected function gdFromFile($filename, $type)
    {
        $gd = false;
        switch ($type)
        {
            case IMAGETYPE_PNG:
                $gd = imagecreatefrompng($filename);
                break;
            case IMAGETYPE_JPEG:
                $gd = imagecreatefromjpeg($filename);
                break;
            case IMAGETYPE_GIF:
                $gd = imagecreatefromgif($filename);
                break;
        }
        return $gd;
    }

    /**
     * Guarda una imagen gd en el archivo de nombre $filename
     * 
     * @param resource $gd La imagen a guardar
     * @param string $filename nombre del archivo
     * @param int $type Tipo de imagen para saber que funcion usar
     * @return bool TRUE en caso de exito, FALSE en caso contrario
     * 
     */
    protected function gdToFile($gd, $filename, $type)
    {
        $success = false;
        // si $filename es nulo las funciones posteriores imprimiran en la salida directamente
        // aqui tratamos de evitar eso
        $filename = (string) $filename;
        if (trim($filename) != "")
        {
            // no tiene sentido verificar si el archivo existe, pues si no existe se creara
            // las siguientes funciones retornan false si ocurrio algun error, true en caso de exito
            switch ($type)
            {
                case IMAGETYPE_PNG:
                    $success = imagepng($gd, $filename);
                    break;
                case IMAGETYPE_GIF:
                    $success = imagegif($gd, $filename);
                    break;
                case IMAGETYPE_JPEG:
                    $success = imagejpeg($gd, $filename);
                    break;
            }
        }
        return $success;
    }

    // Obligamos a que las clases que hereden esta clase implementen este método
    /**
     * La intencion de este metodo es que guarde la imagen creada en un archivo 
     *
     * @param string $filename Nombre del archivo
     * @return bool TRUE en caso de exito, FALSE en caso contrario
     */
    abstract public function save($filename);
}


Creamos ImageResize que hereda ImageBase.

Código :

class ImageResize extends ImageBase
{

   private $src;
   private $origWidth;
   private $origHeight;
   private $origType;
   private $hasError = false;

   public function __construct($src)
   {
      $this->setSrc($src);
   }

   private function setSrc($src)
   {
      if (is_file($src))
      {
         // getimagesize retorna un arreglo si tuvo exito con la informacion de la imagen
         // false en caso contrario
         $info = getimagesize($src);
         if ($info !== FALSE)
         {
            $this->src = $src;
            $this->origWidth = $info[0]; // ancho de la imagen
            $this->origHeight = $info[1]; // alto de la imagen
            $this->origType = $info[2]; // constante de php que tiene el tipo de imagen, un entero

            // por defecto usaremos las dimensiones de la imagen original
            $this->resize($this->origHeight, $this->origHeight);
         }
         else
         {
            $this->throwError("$src is not an image file", E_USER_ERROR);
         }
      }
      else
      {
         $this->throwError("$src is not file valid", E_USER_ERROR);
      }
   }

   /**
    * Asigna los valores a los que se redimensionara la imagen
    *
    * @param int $w ancho
    * @param int $h alto
    */

   public function resize($w, $h)
   {
      if ($w < 1)   $this->throwError("Ancho debe ser mayor que 0", E_USER_NOTICE);
      if ($h < 1)   $this->throwError("Alto debe ser mayor que 0", E_USER_NOTICE);
      $this->setWidth($w);
      $this->setHeight($h);
   }

   /**
    * Redimensiona la imagen con el ancho y alto asignado en resize
    * y la guarda en el archivo de nombre $filename
    *
    * @param string $filename nombre del archivo
    * @return bool TRUE en caso de exito, FALSE si algo salio mal
    */

   public function save($filename)
   {
      $success= false;
      // obtenemos la imagen en gd del archivo
      $orig = $this->gdFromFile($this->src, $this->origType);
      if ($gd !== FALSE) // si lo obtuvimos
      {
         // creamos una imagen vacia con ancho y alto, servira de contenedor
         $base       = imagecreatetruecolor($this->width, $this->height);

         // aqui redimensionamos la imagen
         // la imagen redimensionada queda en $base, esta funcion retorna TRUE si tuvo exito, FALSE en caso contrario
         $resized   = imagecopyresampled($base, $orig, 0, 0, 0, 0, $this->width, $this->height, $this->origWidth, $this->origHeight);
         if ($resized) // pudimos redimensionar
         {
            // guardamos gd en el archivo $filename
            if (!$this->gdToFile($base, $filename, $this->origType))
            {
               $this->throwError("Archivo no generado", E_USER_WARNING);
            }
            else
            {
               // todo salio bien
               $success = true;
               // liberamos los recursos gd
               imagedestroy($base);
               imagedestroy($orig);
            }
         }
      }
      else
      {
         $this->throwError("Gd no fue generado.", E_USER_WARNING);
      }
      return $success;
   }

   private function throwError($msg, $level)
   {
      trigger_error($msg, $level);
   }
}
?>


Uso de ImageResize


Código :

<?php
$src = "archivo.jpg";
$dest = "archivo150x150.jpg";
$resize = new ImageResize($src);
$resize->resize(150,150);
if (!@$resize->save($dest))
{
   echo "Archivo no fue generado. Error: " . error_get_last();
}
else 
{
   echo "Archivo $dest generado.";
}
?>


¿Que otra clase pudiera heredar ImageBase?



¿Que tantas clases puede crear con la libreria gd de php?
  • Captcha: una clase que genere captcha.
  • Gráficos: una clase que genere gráficos.
  • Thumbs: si no te gusta ImageResize, mejorala o crea tu propia clase.


¿Se te ocurre una otra? Comenta aquí.

Nota: la implementación de ambas clases se pueden mejorar. La única intención de estas implementaciones es mostrar un ejemplo real de como se deben usar y lo útil que son las clases abstractas.

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate