lunes, 12 de agosto de 2013

Tratamiento de imágenes con CodeIgniter.

En mi artículo “Reglas propias para validación de formularios con CodeIgniter”, te comenté cómo adicionar reglas y mensajes propios al FormValidation de Codeigniter. Además usé como ejemplo la validación de la carga de archivos, llamando con un callback una función de validación, que a su vez utilizaba la biblioteca upload de Codeigniter para cargar (o intentar hacerlo) un fichero. Especificamos requisitos como el tipo permitido (allowed_types) y el tamaño en bytes (max_size) y si es una imagen el ancho y alto (max_width y max_height).

En este artículo te hablaré sobre el uso de otra biblioteca de CodeIgniter, la image_lib, que te permite formatear las imágenes según tus necesidades, con un código como el siguiente:

$this->load->library('image_lib');

$config_img = array();

$config_img['image_library'] = 'gd2';

$config_img['source_image'] = './uploads/path/my_image.jpg;

$config_img['create_thumb'] = FALSE;

$config_img['maintain_ratio'] = FALSE;

$config_img['width'] = 250;

$config_img['height'] = 250;

$this->image_lib->initialize($config_img);

$this->image_lib->resize();

En este ejemplo cargas la biblioteca antes mencionada, especificas la imagen a transformar, y le das el nuevo ancho y alto, pasas los parámetros con initialize y llamas la función de cambiar el tamaño. Si pones create_thumb en TRUE creará una nueva imagen llamada my_image_thumb.jpg con el nuevo tamaño, sino transformará la imagen original. El maintain_ratio permite transformar la imagen manteniendo la razón de aspecto ancho/alto, en este caso aplica el width especificado y calcula internamente el height manteniendo las proporciones de la imagen.


Con eso es suficiente para ajustar las imágenes a los tamaños deseados sin tener que obligar a los usuarios del sitio a que la ajusten antes de subirla.

Esta funcionalidad también es útil para crear thumbs de las imágenes y conservar ambas versiones, la grande y la chiquita, así puedes mostrar en tu sitio las vistas previas o thumbs con un menor tamaño, lo cual es muy conveniente porque el navegador en el cliente no tiene que tardarse ajustando la imagen a los parámetros width y height del tag <img…>, sino que escribes un <img> sin width ni height. Entonces, al dar clic en la imagen para aumentar pues muestras la imagen original, con algún efecto o en otra página, como más te guste. Lo mismo es útil para descargar imágenes.

Bien, si tienes un sitio en el que es común subir imágenes desde diferentes vistas, y estas imágenes tienen requerimientos diferentes, por ejemplo, en una página los usuarios suben fotos de 40X40 para su perfil, y en otra pueden subir fotos de sus vacaciones con un tamaño mayor, y en otra… pues se hace necesario unificar el código relacionado con el tratamiento de estas imágenes para su reutilización.

Ante un caso similar, hice una biblioteca como interfaz entre mi aplicación y la biblioteca image_lib. Recuerda que una biblioteca y un helper de CodeIgniter son similares, con la diferencia de que la biblioteca se programa orientada a objetos (con clases) y el helper es una colección de funciones. Por lo que para hacer una interfaz con una biblioteca es mejor programarla orientada a objetos, y para esto tienes dos opciones, crear una biblioteca que incluye a la otra, o crear una biblioteca que reimplemente funciones de la otra, y este caso se llamaría My_image_lib. Yo opté por la primera variante pues no me interesaba reimplementar nada sino llamar a las funciones de image_lib.

Primero, creé la clase image_manager que puse en un fichero image_manager.php en la carpeta libraries de CodeIgniter. En el constructor de esta clase cargué la biblioteca (load->library('image_lib')), y puse tres funciones por el momento, upload, resize y delete.

La función delete llama a unlink($image) para borrar una imagen del directorio de uploads (el borrado de la tabla en la base de datos la hago en el modelo correspondiente).

La función resize básicamente hace el código que te puse más arriba, especificando como argumentos de la función los parámetros $filename, $thumb_width, $thumb_height y $maintain_ratio.

La función upload hace lo que puse dentro de la función valid_file en el artículo “Reglas propias para validación de formularios con CodeIgniter”, sólo que aquí recibe los argumentos $user_filename, $upload_path, $thumb_width = 0, $thumb_height = 0 y $create_thumb, para especificar el nombre del componente visual de tipo file (se usa dentro de upload->do_upload($user_filename)) y la carpeta donde se va a subir la imagen en el servidor. Si $thumb_width y $thumb_height son distintos de cero asumo que se quiere cambiar el tamaño de la imagen que se está subiendo, así que internamente llamo a resize con estos últimos tres parámetros; sino, la dejo como viene. No obstante hago una restricción de una tamaño máximo de la imagen para no colgar el servidor.

En esta función upload en lugar de devolver TRUE o FALSE devuelvo un mensaje de error, vacío si se subió la imagen, sino devuelvo el valor de $this->upload->display_errors().

¿Cómo se utilizaría estos en los controladores? Mi función de validar quedaría ahora así:

function valid_image()
{
$this->load->library('image_manager');
$filename = $_FILES['userfile']['name'];
if (!$filename)
{
$this->form_validation->set_message('valid_image',
'La foto es obligatoria…');
return FALSE;
//si no es obligatorio subir una imagen simplemente se retorna TRUE
}
else
{
$error_message = $this->image_manager->upload('userfile',
'./uploads/users/', 40, 40, FALSE);
if ($error_message == '')
return TRUE;
else
{
$this->form_validation->set_message('valid_image',
$error_message);
return FALSE;
}
}
}

Y en la función que recibe los posts de la vista adicionas la regla callback_valid_image.

Un detalle final: en las vistas de inserción pones sencillamente un input de tipo file para subir la imagen, pero en las vistas de modificación de los datos deberías permitir sustituir la imagen, o eliminarla si no es obligatoria, así que te recomiendo diseñar visualmente componentes que le permitan al usuario (puede ser con checkboxes, etc) cambiar la imagen o eliminarla.

En este caso en el controlador debes revisar todas las variantes, y si se cambió la foto o se pidió eliminarla, hacer las correspondientes actualizaciones en la base de datos y en el sistema de ficheros del servidor. Para esto te recomiendo hacer una función privada aparte en el mismo controlador, se puede llamar input_image, que se encargue de todas estas verificaciones y devuelva el nombre definitivo de la imagen, ya sea el de la misma imagen que había antes, o una nueva, o vacío si se eliminó. Este nombre es el que se pasará al update a la BD.

De esta forma la función que recibe el post quedaría aproximadamente así:

function insert()
{
$this->form_validation->set_rules('name', 'Nombre', 'required');

$this->form_validation->set_rules('userfile', 'Foto',
'callback_valid_image');

if ($this->form_validation->run() == FALSE)
$this->form_insert();
else
{
$name = $this->input->post('name');

$image_name = $this->input_image();

$this->users_model->insert($name, …, $image_name);
}
}

La función de actualizar quedaría muy parecida, quizás debas pasarle a input_image algún parámetro que indique que se está haciendo una actualización en vez de una inserción, para así preguntar por los respectivos componentes visuales.


En conclusión, hemos visto que la biblioteca image_lib de Codeigniter puede resultar muy útil para ajustar nuestras imágenes a los tamaños requeridos o crear versiones de diferentes tamaños y thumbs. Combinada con la biblioteca upload y el FormValidation, permite hacer un correcto manejo y validación de las imágenes subidas a nuestro servidor, lo cual nos permitirá mantener la integridad de nuestro sitio y los servicios que estemos prestando.


¿Te ha gustado este Post? Compártelo con tus amigos.

1 comentario:

IconIconIcon