La verdad es que Bash no es el mejor lenguaje de programación para hacer operaciones matemáticas complejas. En este artículo me voy a centrar en las operaciones matemáticas más sencillas y un par de trucos para exprimirlas un poco más. Si has llegado aquí por casualidad buscando aprender a hacer operaciones más complejas, busca información sobre bc... o estate atento y sigue a Linux Center en las redes sociales, que pronto escribiré sobre bc.
De momento, haré un script con las operaciones básicas:
#!/bin/bash
let operador1=5
let operador2=3
let suma=$operador1+$operador2
let resta=$operador1-$operador2
let multiplicacion=$operador1*$operador2
let division=$operador1/$operador2
let resto=$operador1%$operador2
echo "El resultado de la suma es "$suma
echo "El resultado de la resta es "$resta
echo "El resultado de la multiplicación es "$multiplicacion
echo "El resultado de la división es "$division
echo "El resto de la división es "$resto
Que, al ejecutarlo, me da el siguiente resultado:
El resultado de la suma es 8
El resultado de la resta es 2
El resultado de la multiplicación es 15
El resultado de la división es 1
El resto de la división es 2
Este último operador, el módulo o resto de la división, que, como vemos, no es nada preciso, ya que redondea a un único dígito, siendo el resultado un decimal periódico puro. Sin embargo, puede dar mucho juego:
* Delimitar el rago de aleatoriedad de un número
* Hallar todos los divisores de un número
Trabajar con funciones ahorra bastante tiempo y esfuerzo al incluir en las funciones tareas repetitivas, además de hacer scripts mucho más modulares y manejables, que nos facilita el mantenimiento y evolución de los scripts.
Ya hemos visto qué son las funciones en shell script, qué son los parámetros, tanto en shell script como en las funciones, cómo enviar parámetros a funciones y cómo recibir como variable el resultado de una función.
Ahora vamos a ver un sencillo truco para poder trabajar con funciones u otras porciones de código. Hagamos una función:
function enficheroexterno()
{
echo "Soy una función que está en distinto fichero que el script"
}
Y la guardo en un fichero que se llama funcionexterna (no hace falta que le pongamos extensión, aunque podemos hacerlo).
Y un script:
#!/bin/bash
. funcionexterna
enficheroexterno
Y cuando ejecuto el script, me da el siguiente resultado:
Soy una función que está en distinto fichero que el script
Para incluir la función de un fichero externo, únicamente he puesto un punto antes del nombre del fichero. De esa manera, incluye el texto del fichero en nuestro script.
Las máscaras son imágenes, generalmente en blanco y negro, o escala de grises en el que, al aplicarla a la composición de una imagen a través de dos o más imágenes superpuestas, uno de los dos colores deja ver totalmente la imagen que se encuentra en un segundo plano mientras que la región de la máscara coloreados con el otro color sean opacos y por lo tanto, se vea la imagen superior.
Dicho de otra manera: una máscara lo que hace es que unas partes de una imagen sean opacas y otras transparentes. En las zonas opacas se verá la imagen superior y en las zonas transparentes se verá la imagen inferior.
Y cuando hay más colores que el blanco y el negro, los tonos medios serán más o menos traslúcidos dependiendo si se acercan al color transparente o al color opaco.
Cuando componemos una imagen con composite, el orden de las imágenes es de arriba a abajo, es decir, la primera imagen que le indiquemos será la superior y la segunda imagen,será la capa inferior.
Y cuando usemos una máscara, esta deberá ser la última imagen indicada.
Respecto al color opaco y transparente, el blanco será el color opaco y el negro, el color tranparente.
Como una imagen vale más que mil palabras, vamos a ver cuatro imágenes. Que, por una sencilla regla de tres, valdrá más que cuatro mil palabras:
Hacemos dos imágenes planas para que se vea claro, una roja y otra azul:
convert -size 300x150 xc:red rojo.png
convert -size 300x150 xc:blue azul.png
Y una imagen blanca y negra que será la que usemos como máscara:
convert -size 150x150 xc:white xc:black +append mascara.png
Y ahora vamos a comprobar cómo trabaja composite con máscaras poniendo en primer plano la imagen roja, en segundo plano la azul y usando la máscara:composite rojo.png azul.png mascara.png imagenconmascara.png
A veces nos puede interesar generar una imagen promediada de dos imágenes. Las utilidades son muchas: bien porque queramos hacer una transición en un vídeo, bien porque queramos aplicar un filtro a una imagen y generar el promedio con la imagen original o bien porque queramos hacer un montaje con dos imágenes... Las limitaciones aquí, como en cualquier otro campo, son casi exclusivamente las que la imaginación que el autor tiene.
Para generar una imagen con el promedio de otras dos o más imágenes tenemos el parámetro -average. Digo que se pueden unir dos o más imágenes, pero cuidado con el abuso que unir muchas imágenes que puede generar un pastiche sin sentido... o un maravilloso caos. La instrucción sería:
convert imagen1.png imagen2.png [... imagenN.png ] -average imagenpromediada.png
Veamos varios ejemplos:
Tomaremos como referencia una de las torres que hay a la entrada por Isabel la Católica del Parque Grande José Antonio Labordeta de Zaragoza:
Y le vamos a aplicar un efecto. Por ejemplo, sombrearlo con -shade:convert torre_entrada_parque_grande.jpg -shade 15x45 torre_sombreada.jpg
Los perfiles son los mismos, pero los colores no lo son, así que nos vendrá bien para ver cómo trabaja -average:
convert torre_entrada_parque_grande.jpg torre_sombreada.jpg -average torre_promediada.jpg
Al promediar con una gran parte gris, desatura los colores, pero realza algunas zonas sombreadas.
Podemos hacer un lienzo sólido de un color y luego promediarlo con la imagen original
convert -size 500x375 xc:red lienzorojo.jpg
convert torre_entrada_parque_grande.jpg lienzorojo.jpg -average torreenrojecida.jpg
O promediando el rojo y la sombra:
convert torre_sombreada.jpg lienzorojo.jpg -average sombraenrojecida.jpg
Podemos generar una imagen con el promedio de dos imágenes distintas. Promediaremos esa torre con el Auditorio de Zaragoza:
convert torre_entrada_parque_grande.jpg auditorio.jpg -average auditorio_torre_promedio.jpg
Y como habíamos dicho antes, -average no sólo une dos imágenes, sino que puede unir más. Añadámosle estas columnas del Parque de Bomberos 3 de Zaragoza:convert auditorio.jpg torre_entrada_parque_grande.jpg columnas_bomberos.jpg -average pastiche.jpg
Y podríamos seguir añadiendo imágenes hasta el infinito, pero este efecto queda más limpio cuando las imágenes son más uniformes. Veamos el promedio de un detalle de la Pasarela del Voluntariado y un anochecer con el sol rielando en una acequia en Pastriz:convert anochecer_acequia.jpg detalle_pasarela_del_voluntariado.jpg -average anochecer_voluntariado.jpg
En ImageMagick podemos unir imágenes de muchas maneras. La más sencilla es juntarlas de forma horizontal o vertical con append.
Creamos dos imágenes, una azul y otra amarilla para usarlas como ejemplo:
convert -size 200x200 xc:Yellow amarillo.jpg
convert -size 200x200 xc:Blue azul.jpg
Para hacer una unión horizontal le indicaremos a convert primero el listado de imágenes que queramos concatenar y que las una horizontalmente con +append. Por último, el fichero destino:
convert amarillo.jpg azul.jpg +append amarilloazulhorizontal.jpg
Para hacer una unión horizontal le indicaremos a convert primero el listado de imágenes que queramos concatenar y que las una horizontalmente con -append. Por último, el fichero destino:
convert amarillo.jpg azul.jpg -append amarilloazulvertical.jpg
Para voltear una imagen en ImageMagick tenemos dos parámetros que lo hacen sin tener que aplicarles valores ni tener que calcular nada: son los parámetros flip y flop.
Vamos a coger una imagen de un cielo:
Para hacer un espejo horizontal de una imagen, usaremos el parámetro -flip:
convert cielo.jpg -flip cieloespejovertical.jpg
Para hacer un espejo horizontal de una imagen, usaremos el parámetro -flip:
convert cielo.jpg -flop cieloespejohorizontal.jpg
Hemos estado haciendo fotos y resulta que algunas de las fotos que hemos hecho sin darnos cuenta las hemos hecho con la cámara en vertical o en horizontal.
Pues, tranquilos, que esto tiene una solución fácil con ImageMagick. Gracias al parámetro -auto-orient
Veamos una foto que he hecho con la cámara en posición vertical:
Para verla bien, podemos girar la cabeza o la pantalla 90 grados, pero es más interesante si a quien mostramos esa foto la puede ver con la orientación correcta. Para ello, podemos girarla, pero, ¿qué pasa si no sabemos si está una imagen está orientada correctamente (por ejemplo, cuando hacemos un script que procesa miles de imágenes automáticamente o si no recibimos en un script una imagen que no hemos visto)?
La solución la tenemos con el parámetro -auto-orient:
convert parque_roma.jpg -auto-orient parque_roma_bien_orientada.jpg
Solucionado.
ImageMagick no es un único progrma, sino un conjunto de comandos complementarios, pero cada uno con unas funcionalidades distintas. En esta ocasión veremos convert y mogrify, dos comandos que realizan modificaciones sobre ficheros de imágenes, pero con una diferencia fundamental: convert genera un nuevo fichero con las modificaciones mientras que mogrify aplica las modificaciones sobre el fichero origen.
Con mogify ahorramos espacio en disco ya que no generamos nuevos ficheros, pero sus cambios son irreversibles.
Con convert mantenemos la imagen original intacta, pero, a cambio, consumimos espacio en disco con cada nuevo fichero. Y cuando generamos vídeos u otros procesos en lotes grandes, a veces corremos el riesgo de llenar el disco duro del ordenador, máxime si hacemos vídeos con ratios de 60 fotogramas por segundo y en 4k. (Cada fotograma en png puede pesar 7/8 Mb x 60 fotogramas por segundo, podemos estar generando entre 400 y 500 Mb por cada segundo de vídeo. ¡Más de 20 Gb por minuto! Y si a esto le añadimos los ficheros auxiliares que podamos usar para generar el vídeo, como cartelas, fotogramas para superponer, subtítulos, degradados... tenemos que trabajar con cuidado. iremos viendo cómo optimizar el trabajo.
Dado que la principal diferencia entre convert y mogrify es que con convert genera un nuevo fichero y que mogrify no lo genera, a la hora de invocarlos, con convert deberemos especificar el nombre del nuevo fichero y con mogrify no hace falta, ya que sobreescribe el fichero de origen.
Veamos el uso más habitual de estos comandos:
convert imagenoriginal.png -parametro valor imagendestino,png
mogrify -parametro valor imagenoriginal.png
Y ahora, un ejemplo real sobre el fichero torres.jpg:
convert torres.jpg -negate torresnegadas.jpg
Y seguimos teniendo la imagen original:
ls
torres.jpg torresnegadas.jpg
Ahora, probemos con mogrify:mogrify -negate torres.jpg
Seguimos teniendo dos ficheros:ls
torres.jpg torresnegadas.jpg
Pero ambos son iguales:
Como es obvio, si en convert ponemos primero el fichero de destino antes que el de origen, no podrá leer el fichero original y por lo tanto, no podrá procesar las modificaciones:
convert alapiz.png -charcoal 1 torres.jpg
convert.im6: unable to open image `alapiz.png': No existe el archivo o el directorio @ error/blob.c/OpenBlob/2638.
convert.im6: unable to open file `alapiz.png' @ error/png.c/ReadPNGImage/3667.
convert.im6: no images defined `torres.jpg' @ error/convert.c/ConvertImageCommand/3044.
Por lo que tenemos que escribir bien el orden:convert torres.jpg -charcoal 1 alapiz.jpg
Con mogrify también es importante el orden, si escribimos el fichero antes de las modificaciones, no las aplica, ya que no sabe qué modificaciones aplicar al fichero:
mogrify torresnegadas.jpg -charcoal 1
Sin embargo, si escribimos las modificaciones antes del fichero, las aplica:
mogrify -charcoal 1 torresnegadas.jpg
Convert puede generar ficheros desde 0, mogrify, no. Como vimos en el artículo sobre la generación de lienzos con ImageMagick, con el modificador xc de convert e indicando el tamaño, podemos generar lienzos:convert -size 500x250 xc:red imagenroja.jpg
Pero con mogrify no:
convert -size 500x250 xc:red imagenroja.jpg
mogrify.im6: no encode delegate for this image format 'blue' @ error/constitute.c/WriteImage/1209.
mogrify.im6: unable to open image `imagenazul.jpg': No existe el archivo o el directorio @ error/blob.c/OpenBlob/2638.
Con convert podemos crear una imagen con un texto con la siguiente instrucción:convert -size 500x250 -gravity Center -background blue -font FreeMono-Negrita label:"Linux Center" cartela_Linux_Center.jpg
Y con mogrify, básicamente igual que cuando generamos un lienzo: :
mogrify -size 500x250 -gravity Center -background green -font FreeMono-Negrita label:"Linux Center" cartela_Linux_Center_verde.jpg
mogrify.im6: no encode delegate for this image format 'Linux Center' @ error/constitute.c/WriteImage/1209.
mogrify.im6: unable to open image `cartela_Linux_Center_verde.jpg': No existe el archivo o el directorio @ error/blob.c/OpenBlob/2638.
Así que, si no hay imagen previa, no queda otra opción que usar convert. Por lo demás, la diferencia es si queremos crear nuevo fichero o no.
ImageMagick es una suite de edición de imágenes en modo consola. Es decir, es un conjunto de comandos para trabajar con imágenes, con una serie de comandos que cada uno realiza una serie de procesos para cubrir todo el abanico de necesidades que un usuario pueda tener para cualquier actividad gráfica, tanto con mapa de bits como con vectores.
ImageMagick tiene una serie de características que le convierten en una herramienta muy útil para cualquier diseñador gráfico, fotógrafo o simplemente aficionados a la imagen, pero también para el trabajo con vídeo, ya que, en esencia, un vídeo no es más que una sucesión de imágenes.
Nota: cuando digo que IM trabaja con más de 200 formatos, más de 60 modos de composición o más de 20 espacios de color, no digo cifras concretas ya que podría cambiar de una versión a otra. Para más información de tu versión, escribe:convert -list format
convert -list colorspace
convert -list compose
Como hemos visto antes, ImageMagick no es un único programa, sino que es una suite formada por varios comandos que cada uno nos ofrece unas posibilidades distintas:
Animate: muestra una secuencia de imágenes con la carencia que deseemos entre imagen e imagen, así como los efectos que queramos que muestre sin que afecte a la imagen. Ofrece la posibilidad de previsualizar secuencias sin tener que aplicar los cambios a los ficheros.
Uso básico:
animate *.png
Display: muestra una imagen, así como los efectos que queramos que muestre sin que afecte a la imagen. Ofrece la posibilidad de previsualizar imágenes sin tener que aplicar los cambios a los ficheros.
Uso básico:
display imagen.png
Composite: superpone imágenes una encima de otra. Permite usar máscaras con las que definir la opacidad.
Uso básico:composite primerplano.png fondo.png imagencompuesta.png
Conjure: ejecuta scripts en msl (Magick Scripting Language), el lenguaje de scripts multiplataforma de ImageMagick.
Uso básico:
conjure script.msl
Convert: crea un nuevo fichero a partir de las modificaciones indicadas en los parámetros. Puede generar imágenes desde 0, como lienzos, imágenes con texto... o modificar imágenes sobre las que le idicamos las modificaciones a realizar.
Uso básico:
convert origen.png -parametro valor destino.png
Display: muestra una imagen. Le podemos indicar parámetros de modificación de la imagen para que muestre una previsualización de una imagen sin tener que generar un fichero nuevo con los cambios ni aplicarlos sobre esa imagen.
Uso básico:
display imagen.png
Identify: Muestra información sobre una imagen, como el tamaño, el nombre, el formato... podemos indicarle que nos de únicamente algún dato concreto, como el tamaño de una imagen, por ejemplo, para usar esos datos en nuestros scrpts.
Uso básico:
identify imagen.png
Import: Captura pantallazos, tanto de la pantalla completa como de una única ventana o de una porcion de la pantalla. También puede capturar una serie pantallazos, le podemos indicar el tiempo entre captura y captura.
Uso básico:
import pantallazo.png
Mogrify: Modifica un fichero de imagen sin generar un nuevo fichero, es decir, aplica los cambios sobre el mismo fichero de origen.
Uso básico:
mogrify imagen.png -parametro valor
Montage: Crea un mosaico con las imágenes que le indiquemos, que puede ser una a una o una secuencia tipo *.png. Permite definir el espacio entre imágenes, el número de filas, de columnas...
Uso básico:
montage *.png mosaico.png
Ya sabemos algunas formas de recortar una imagen con ImageMagick con el parámetro -crop:
Ajustar una imagen a un determinado tamaño
Cortar horizontal y verticalmente una imagen
Cortar horizontal o verticalmente una imagen
Pero, ¿y si queremos hacer más grande el lienzo? Para eso tenemos el parámetro -extent. Su uso básico es:
convert $origen -extent $anchoX$alto $destino
Con esta instrucción definimos el tamaño del fichero destino, sea este mayor o menor que el de la imagen origen.
Veamos una imagen:
Y queremos quedarnos únicamente con el escudo. Haremos un recorte de 200x150 pixeles. convert farola.jpg -extent 200x150 recorte.jpg
Ooooops... Queríamos un león y sólo se le ve un trozo de las garras. Esto ha pasado porque, al no definir la gravedad, ha tomado como referencia el punto 0x0. Así que, como lo que queríamos era la parte central de la imagen, lo definiremos con -gravity center:convert farola.jpg -gravity center -extent 200x200 leon.jpg
Como hemos visto, -extent permite cambiar el tamaño del lienzo, por lo que también podemos hacer el lienzo más grande. Vamos verlo:
convert leon.jpg -gravity center -extent 300x300 leonenmarcado.jpg
Ahora tenemos el león centrado en un lienzo blanco de 300x300 pixeles.
Por defecto, ImageMagick hace blanco el color del fondo, pero esto podemos cambiarlo. El parámetro es -background $color.
Vamos a hacer otro lienzo de 300x300 píxeles, pero esta vez que sea negro:
convert leon.jpg -gravity center -background black -extent 300x300 leonenmarcadoennegro.jpg
Si en lugar de utilizar un color determinado lo que quisiéramos es un fondo transparente, por ejemplo para superponer a otra imagen, lo que haríamos es definir el color de fondo como "transparent"convert leon.jpg -background Transparent -gravity center -extent 300x300 leonsobretransparente.png
Nótese aquí que he estado utilizando todas las imágenes en formato jpg menos la última, que he puesto leonsobretransparente.png, ya que el formato png admite transparencias mientras que el jpg no admite transparencia.