Archivo

Entradas Etiquetadas ‘modificar’

Jugando con ImageMagick (IV): Automatizando procesos, creando animaciones

Martes, 14 de Septiembre de 2010 Gaspar Fernández 3 comentarios

El cuarto post de la serie, anteriormente hablábamos de:

  1. Dimensiones, Captura, Color y Efectos
  2. Color (continuación) y Rotación
  3. Jugando con ImageMagick (III): Colecciones, texto, y unión de efectos

Ya que estamos hartos de ver lo que es capaz de hacer ImageMagick, ahora mezclemos esto con la potencia de la consola, y tendremos una de las herramientas más potentes jamás inventadas en cuanto a imagen digital se refiere.

Modificando imágenes en un directorio

Aunque podremos hacer cualquier tipo de modificación, tal y como hemos visto anteriormente, haremos un ejemplo en el que redimensionaremos todos los archivos de un directorio al 50% (muy útil si preparamos en un directorio muchos archivos directamente de una cámara digital para subir a Internet):

$ mogrify -resize 50% directorio/*

Con mogrify podemos hacer lo mismo que con convert, sólo que el fichero de origen y de destino es el mismo.

Aunque… ¿y si queremos guardar los archivos originales? Tendremos que hacer un pequeño script para convertir los archivos de un directorio y guardarlos en otro direcorio diferente; pero… y si son muchos ? Tenemos algunas posibilidades:

$ for f in test/*.jpg; do convert -monitor -resize 50% $f “test2/”${f##*/}; done

Si tenemos todos los archivos en el directorio test, queremos redimensionar al 50% y guardarlos en test2/ con el mismo nombre que tienen. ${f##*/} elimina el directorio del nombre del archivo, es lo mismo que la orden basename. Y con el parámetro -monitor veremos más o menos lo que está haciendo convert en cada momento.

Aunque, tal vez queramos un indicador de progreso para saber más o menos cuánto queda y cuántos archivos llevamos, lo podemos hacer con bc y Xdialog:

1
2
3
4
5
6
7
8
9
archivos=`ls test/*.jpg`;
total=`echo $archivos | wc -w`;
hecho=0;
for f in $archivos;
do
convert -resize 50% $f "test2/"${f##*/};
let hecho=$hecho+1;
echo "scale=0;$hecho*100/$total"|bc;
done | Xdialog --gauge "Progreso..." 10 100 0

En este ejemplo, separamos en variables los archivos a tratar y contamos el total de archivos a procesar. La variable hecho contará cuántos archivos ha convertido hasta el momento.

Luego en el bucle principal convertiremos los archivos e iremos incrementando la variable hecho en 1. Más adelante, con la ayuda de bc calculamos el porcentaje hecho. El bucle lo pasamos con una pipe a Xdialog, con su opción de gauge con lo que iremos indicando el proceso a medida que se vayan convirtiendo archivos.

Añadiendo un texto a todas las imágenes

Podemos, además, añadir un texto a todas las imágenes con un formato determinado para incluir el nombre de fichero, ancho, alto, la etiqueta de fichero, etc:

$ mogrify -gravity South -pointsize 20 -fill black -annotate ‘%f %b bytes” *

Con lo que anotaremos dentro de la imagen en color negro el nombre del archivo y el tamaño en bytes. Para esto tenemos algunas palabras clave como %f y %b en este enlace: Imagemagick.org (Identify -format).

hamburguesonAunque tal vez queramos poner un texto diferente a cada foto. Imaginemos que tenemos muchos ficheros jpg y muchos ficheros txt. Los ficheros txt tienen el mismo nombre que los jpg y sólo varía la extensión; y queremos plasmar el texto de los txt en los ficheros jpg:

1
2
3
4
5
6
7
8
9
10
11
for f in *.jpg;
do
if [ -r ${f%.*}.txt ];
then
txt=`cat ${f%.*}.txt`;
else
txt="Mis guisos 2010";
fi;
echo $txt en $f;
mogrify -gravity North -pointsize 15 -fill white -annotate 0x0+10+10 "$txt" $f;
done

Esta vez, si encontramos el fichero de texto con el mismo nombre que la imagen, solo que con extension txt escribiremos ese texto en la parte superior de la imagen; pero si no, escribiremos “Mis guisos 2010″ y así recorriendo todos los archivos jpg del directorio.

Una animación sencilla

destinVamos a crear una transición entre dos imágenes. Y para el ejemplo, hemos utilizado estas dos imágenes:

$ convert -size 720×576 xc:black -gravity Center -fill white -pointsize 250 -font impact -draw ‘text 0 0 A’ a.jpg

$ convert -size 720×576 xc:black -gravity Center -fill white -pointsize 250 -font impact -draw ‘text 0 0 B’ b.jpg

Para realizar el fundido hacemos lo siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
n_imgs=30; # Número de imágenes
s=`echo "scale=2;100/$n_imgs" | bc` # Porcentaje de inremento de cada paso.
o=0;   # Visibilidad de la imagen B
d=100; # Visibilidad de la imagen A
f=0;   # Fotograma actual
while (( $f < 20 ));
do
convert -compose blend -set "option:compose:args" $o,$d a.jpg b.jpg -composite dest/anim_$f.jpg;
o=`echo "scale=2;$o+$s" | bc`;
d=`echo "scale=2;$d-$s" | bc`;
f=$(($f+1));
echo "Frame: $f O=$o D=$d";
done

Con esto se creará la secuencia de $n_imgs (que al principio le damos valor 30) imágenes en el directorio dest/; todas empezando por anim_.

Si queremos crear un gif animado con esto, podemos hacer lo siguiente:

$ convert dest/anim_{0..29}.jpg trans.gif

Nos ponemos serios con PHP: Empezamos con un CRUD (la esencia no es exclusiva de PHP)

Viernes, 16 de Julio de 2010 Gaspar Fernández Sin comentarios

crudHace años tuve entre manos un gran proyecto web, en el que invertí 8 meses de mi vida y funcionó bastante bien durante un tiempo. En su desarrollo recuerdo que tuve que desarrollar cerca 50 formularios diferentes, comprobar los valores de cada uno de los campos, hacer lecturas y escrituras en base de datos con los datos obtenidos, y opcionalmente realizar alguna tarea extra una vez enviado y validado el formulario. Además, tenía que ser capaz de listar la información, modificarla y eliminarla. Por aquel entonces, aunque había partes en común y aproveché para realizar código, no lo hice de la forma más efectiva; podría haber ahorrado muchísimo trabajo.
En los últimos años, para mis proyectos web decidí fabricarme una biblioteca para hacer este tipo de tareas de forma más rápida (con menos esfuerzo, y al fin y al cabo de forma más depurada y segura). Para eso me fabriqué una biblioteca CRUD.

Es cierto que perdemos eficiencia, es más rápida por lo general una herramienta específica, que haga justo lo que se le pide en un momento dado, que una herramienta configurable y flexible (tendremos muchas más sentencias de control y a veces se ejecutarán procesos innecesarios), pero por otro lado hay que tener en cuenta que no podemos echar un mes en un proyecto que generalmente requiere unos días, y por otra parte, seguro seguro que tenemos que hacer modificaciones antes de entregarlo, y éstas no deben llevarnos otro mes más. En definitiva, nos compensa perder algo de eficiencia en favor de un tiempo de desarrollo más corto y generar un código más fácilmente mantenible.

Lo importante de un CRUD, es la posibilidad de Crear, Ver, Actualizar, Borrar (y listar información), si lo pensamos es simple, lo ideal sería tener una clase (o una función) que simplemente llamándola nos hiciera esta complicada tarea; aunque también es verdad, si lo pensamos un poco más, que podemos complicar todo esto de mil formas, y todo lo que queramos. Además, tenemos que crear una herramienta que sea lo más flexible posible para todo tipo de bases de datos y tablas, y además, sería interesante manejar los errores que puedan surgir en el proceso, para poder generar una salida acorde.

Aunque podemos encontrar bibliotecas por Internet que hacen esta tarea, yo siempre prefiero una solución DIY (Do it yourself) (Hazlo tú mismo), de esta forma, el código será 100% mío y yo controlaré el proceso por completo, además de que como materia de aprendizaje es bastante efectivo. Dejo por aquí algunas instrucciones para empezar a fabricarnos un CRUD un tanto sencillo (y que a medida que vayamos haciendo proyectos podemos ir completándolo con las necesidades que nos vayan surgiendo):

  • Listar información de base de datos: Debemos tener la posibilidad de elegir los campos a listar
  • Crear entrada: Debemos tener la posibilidad de introducir campos que concuerden con entradas en una base de datos, y también la posibilidad de generar datos automáticamente (fecha de introducción, identificadores únicos, etc):
    • Necesitaremos un generador de formularios y la posibilidad de elegir el mejor tipo de campo para cada campo de la tabla que vamos a modificar
    • Debemos tener la posibilidad de verificar, vía servidor (PHP) o cliente (Javascript), mejor hacerlo de las dos formas, que los datos estén bien formados (números máximos de caracteres, formato de introducción (por ejemplo, de una fecha, un teléfono, una dirección e-mail…)
    • Inserción en tabla, y muestra de la salida, para que el usuario vea si todo ha ido bien o mal. Sería conveniente también, que esto fuera una redirección, para que, si se refresca la página, no se reenvíen los formularios.
  • Modificar entrada:
    • Podemos aprovechar mucho código de la creación de entrada (muestra de formulario, verificación…)
    • Debemos modificar la tabla de datos, a lo mejor actualizar fechas de modificación, logs, etc
  • Eliminar entrada:
    • Idealmente, debemos presentar un diálogo tipo: “¿Está seguro?” para confirmar que no se hace por accidente, tal vez los datos no siempre interese eliminarlos, sólo hacer una marca de que no se visualicen.
  • Ver información:
    • Necesitamos hacer un sistema de visualización flexible, automático y tener la posibilidad de seleccionar los campos a mostrar (los identificadores únicos, fechas internas, IDs, no le suelen interesar al usuario), por otra parte, a veces para visualizar un dato es necesario hacer varias consultas a base de datos y tenemos que estar preparados.

Pero como dije antes, esto lo podemos complicar hasta la saciedad, aumentando el número de campos que podemos introducir (por ejemplo inserción de ficheros, Javascripts para introducir la fecha de forma fácil, o inclusión de áreas de texto HTML (como TinyMCE).

En cuanto al listado podemos implementar paginación automática (para el caso de que haya muchos elementos a listar) y ordenación de los elementos por columna (tal vez por nombre, por fecha, etc)

Por otra parte, tenemos que tener muy en cuenta el diseño, éste suele ser diferente para cada página (quitando esas páginas que parece que están hechas todas con el mismo molde), así que tenemos que hacer que nuestra salida en (x)HTML sea lo más flexible posible, que nos deje introducir código adicional, cambiar las imágenes utilizadas (iconos de insertar, eliminar…)

Y como colofón, podemos implementar soporte para relaciones, puede que echemos unos días desarrollando nuestro CRUD, pero  nos va a ahorrar mucho tiempo de desarrollo si lo utilizamos en nuestros proyectos.

La web a mi gusto: Descargar contenidos de Moodle rápidamente

Viernes, 12 de Febrero de 2010 Gaspar Fernández Sin comentarios

Quiero continuar con una serie de posts que llevarán una temática parecida: muchas páginas web funcionan de una forma fija, pero a mí me incomoda bastante esa forma de funcionar, pero como necesito cubrir mis necesidades, intento que funcionen como yo quiero.
Tras esa gran descripción, quiero introducir mi problema:
Moodle es un sistema ampliamente aceptado como solución web académica, tiene muchas opciones y está muy bien, personalmente, en la Universidad, los profesores cuelgan apuntes, ejercicios y más material a la web, lo malo es que cuando llego a una página, me gusta descargar a mi disco duro todos los contenidos (pdfs, documentos, etc), y para ello invierto mucho tiempo.
Para ello viene bien una extensión para Firefox: Chickenfoot, también podemos utilizar Greasemonkey (también hay extensiones para IE y Safari).

Sin más preámbulos, el script utilizado para que Moodle descargue los contenidos más rápido es el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var alltags = new Array();

function detecta_pdf(cont)
{
  var url_match = /https?:\/\/([-\w\.]+)+(:\d+)?(\/([\w/_\.]*(\?\S+)?)?)?/;
  var contenido=cont.match(url_match);
  document.location=contenido[0];
}

function pdfplay(que)
{
  var cont=que.innerHTML;
  que.innerHTML='';
  detecta_pdf(cont);  
}

function CogeElementoPorClase(tipo, clase, quehacer)
{
  var alltags=document.getElementsByTagName(tipo);

  for (i=0; i<alltags.length; i++)
  {
    if (alltags[i].className==clase)
    {
    quehacer(alltags[i]);
    }
  }
}

CogeElementoPorClase('div', 'resourcepdf', pdfplay);

La función CogeElementoPorClase() es la misma que utilicé en este post anterior para modificar la web de mi proveedor de hosting.

Tras ello debemos crear un trigger, es decir será el evento con el que se disparará automáticamente el script que acabamos de hacer; por ejemplo, para la Universidad de Málaga podemos decir que el script se dispare cuando la página a la que accedemos sea: http://*.cv.uma.es/mod/resource/view.php?id=*.

En principio el script fue pensado para los PDFs (el acrobat reader tarda bastante en abrirse cuando tienes que abrir más de 10 PDFs), pero puede servir para cualquier contenido. Por otra parte, aunque no está muy optimizado (la necesidad me llevó a hacer el script rápidamente) espero que os sea útil.

Visita otras webs de la red