En ImageMagick podemos usar once puntos de referencia a la hora de alinear elementos, hacer recortes, ajustar o cualquier otra acción que implique el uso de unas coordenadas. Estos son:
None -> Sin punto de gravedad. Toma como referencia orientativa la esquina superior izquierda a la hora de hacer un mapa de bits, pero como los dibujos vectoriales no tienen punto de gravedad es mejor usar esta opción cuando vamos a hacer una imagen vectorial.
Center-> El centro. El punto resultante de calcular $anchura/2 x $altura/2
East-> Centro derecha. El punto resultante de calcular $anchura x $altura/2
Forget -> No hace uso del parámetro gravity, por lo que toma como referencia 0x0.
NorthEast -> Esquina superior derecha. El punto $anchura x 0
North -> Centro superior. El punto $anchura/2 x 0
NorthWest -> Esquina superior izquierda. El punto 0 x 0
SouthEast -> Esquina inferior derecha. El punto $anchura x $altura
South -> Centro inferior. El punto $anchura/2 x $altura
SouthWest -> Esquina inferir izquierda. El punto $anchura x 0
West -> Centro izquiera. El punto $altura/2 x 0
Para listar los puntos de gravedad, como con cualquier otro listado en ImageMagick, podemos usar el parámetro -list. En este caso:
convert -list gravity
None
Center
East
Forget
NorthEast
North
NorthWest
SouthEast
South
SouthWest
West
Vamos a ver un script que nos muestre cómo queda un cuadro pequeño sobre otro más grande, para que se vea bien, montado con composite e indicándole las distintas posibilidades de punto de gravedad de ImageMagick:
#!/bin/bash
convert -size 500x500 xc:red fondorojo.png
convert -size 50x50 xc:black cuadronegro.png
for i in $(convert -list gravity)
do
composite cuadronegro.png -gravity $i fondorojo.png $i.png
done
Que nos genera:
None.png
Center.png
East.png
Forget.png
NorthEast.png
North.png
NorthWest.png
SouthEast.png
South.png
SouthWest.png
West.png
Para superponer una imagen sobre otra en ImageMagick tenemos el comando composite que, en su uso más básico se utiliza:
composite $imagensuperior $imageninferior $imagendestino
Veamos una prueba sencilla:convert -size 50x50 xc:blue cuadroazul.png
convert -size 100x50 xc:red fondorojo.png
Con estos comandos hemos creado dos imágenes: una, llamada fondorojo.png que 100x50 pixeles y otra de mitad de tamaño, 50x50 llamada cuadroazul.png. Y para superponerlas, escribiremos:composite cuadroazul.png fondorojo.png montajeazulsobrerojo.png
Ya hemos visto cómo dividir horizontal y verticalmente en partes iguales una imagen, pero, ¿y si queremos hacer la dividisión únicamente en un eje?
Se lo indicaremos a crop con el porcentaje seguido de x100% si queremos que los cortes sean verticales o con 100%x seguido del porcentaje si queremos que la división sea horizontal. Así:
convert $origen -crop 50%x100% $corteshorizontales
convert $origen -crop 100%x50% $cortesverticales
Veamos un ejemplo: supongamos que queremos desordenar aleatoriamente una imagen en 10 franjas verticales.
Para pasar de:
A esto (o parecido, porque al ser aleatorio, cada vez que ejecutemos el script nos generará una imagen distinta):
Veamos el script:
#!/bin/bash
convert $ordendeimagenes +append $destino
origen="guarderia_calle_Reino.jpg"
destino="guarderia_desordenada.jpg"
ordendeimagenes=""
convert $origen -crop 10%x100% temporales%d.jpg
numerosaleatorios=$(shuf -i 0-9)
for i in $(seq 1 10)
do
posicion=$(echo $numerosaleatorios | cut -d " " -f $i)
ordendeimagenes="temporales"$posicion".jpg "$ordendeimagenes
done
Como siempre, vamos a ver paso a paso qué hemos hecho en este script:
#!/bin/bash -> Para indicar el shell que queremos usar
Después, las variables que vamos a utilizar. No me cansaré de repetir que ser ordenados ayuda a mantener y mejorar nuestros scripts, así como que otras personas puedan adaptarlos a sus necesidades. convert $origen -crop 10%x100% temporales%d.jpg -> dividimos en recortes iguales de un tamaño del 10% horizontalmente y un 100% vertical de la imagen original
numerosaleatorios=$(shuf -i 0-9) -> Creamos una variable que contenga una serie de números del 0 al 9 (indicamos el rango con -i 0-9) ordenados aleatoriamente (shuf desordena)
Después recorremos esa variable con un for que irá del 1 al 10 ya que cut empieza a contar desde el 1, mientras que las imágenes creadas con -crop empiezan en 0.
Con posicion=$(echo $numerosaleatorios | cut -d " " -f $i) recortamos el listado anterior indicando que las partes a recortar están separadas con un espacio en blanco (indicado con -d " ") y que cada vez que pasa por el for muestre la columna correspondiente (indicado con -f $i) recordando que cut comienza a contar por 1.
Concatenamos los nombres de los ficheros a unir con ordendeimagenes="temporales"$posicion".jpg "$ordendeimagenes. Lo que hacemos es añadir a una cadena de texto que hemos inicializado al comienzo como una cadena vacía (ordendeimagenes="") los ficheros con el patrón fijo que hemos indicado al hacer el recorte ("temporales"), la posición de la imagen que hemos extraido de la cadena aleatoria ($posicion) y la extensión seguida de un espacio (".jpg ") para que entre los nombres de los ficheros haya un espacio en blanco que permita que al unirlos después, lo entienda como ficheros distintos.
Y, por último, concatenamos esos ficheros horizontalmente con +append. (Para concatenarlos verticalmente sería con -append).
A todos nos encantan las pantallas gigantes en los conciertos, en escaparates, en espectáculos y eventos de todo tipo... en general, en cualquier sitio donde vemos pantallas, nos quedamos mirándolas (por eso las ponen). Y si además, las imágenes cambian si interactuamos con la pantalla o con el entorno, nos gustan más todavía (por ejemplo, imágenes procesadas sobre la marcha con ImageMagick). Y cuanto más grandess sean, mejor. Tanto es así, que muchas veces se utilizan varias pantallas para mostar una imagen.
Y si somos nosotros los que programamos la interacción con los usuarios, lo último que queremos es que se vea mal o que se descuadre la imagen al mostrarse en las pantallas. Así que vamos a ver cómo dividir una imagen para mostrar cada una de las partes en una pantalla distinta.
Usaremos una imagen cualquiera:
Y supongamos que queremos dividirla en cuatro imágenes iguales para cuatro pantallas distintas. ¿Cómo lo haremos? Cortando por la mitad horizontalmente y por la mitad verticalmente. Es decir, al 50% horizontalmente y al 50% verticalmente. Esto es muy importante, porque instintivamente podemos pensar en divididir al 25%. Pero esto nos haría cuatro cortes (100/25=4) horizontales y otros tantos cortes verticales, por lo que nos dejaría una imagen dividida en 16 partes (4x4 cortes).
Vamos a comprobarlo:
convert fuente_plaza_Emperador_Carlos.jpg -crop 50% fuente_plaza_Emperador_Carlos%d.jpg
Explicación:
convert -> el comando de ImageMagick con el que trabajamos.
fuente_plaza_Emperador_Carlos.jpg -> El nombre de la imagen con la que vamos a trabajar. En este caso, como es una fuente que está en la Plaza del Emperador Carlos, la he llamado así. Si fuera una foto de mi prima bailando una jota, se llamaría mi_prima_bailando_una_jota.jpg. Pero no es el caso.
-crop 50% -> Le indicamos a convert que corte por la mitad horizontalmente y por la mitad verticalmente. Podemos usar también -crop 50%x50% pero como el valor es el mismo para el corte horizontal y el vertical, nos podemos ahorrar unos caracteres indicando sólo una vez el porcentaje.
fuente_plaza_Emperador_Carlos%d.jpg -> Cómo queremos que se llamen los ficheros generados. Le indicamos tres patrones:
Veamos el resultado:
fuente_plaza_Emperador_Carlos0.jpg:
fuente_plaza_Emperador_Carlos1.jpg:
fuente_plaza_Emperador_Carlos2.jpg
fuente_plaza_Emperador_Carlos3.jpg
Y, ya que estamos troceando imágenes, vamos a ver cómo quedaría si hubiera tenido la tentación de escribir 25%:
convert fuente_plaza_Emperador_Carlos.jpg -crop 25% fuente_plaza_Emperador_Carlos%d.jpg
fuente_plaza_Emperador_Carlos0.jpg:
fuente_plaza_Emperador_Carlos1.jpg:
fuente_plaza_Emperador_Carlos2.jpg:
fuente_plaza_Emperador_Carlos3.jpg:
fuente_plaza_Emperador_Carlos4.jpg: fuente_plaza_Emperador_Carlos5.jpg: fuente_plaza_Emperador_Carlos6.jpg: fuente_plaza_Emperador_Carlos7.jpg: fuente_plaza_Emperador_Carlos8.jpg: fuente_plaza_Emperador_Carlos9.jpg: fuente_plaza_Emperador_Carlos10.jpg: fuente_plaza_Emperador_Carlos11.jpg: fuente_plaza_Emperador_Carlos12.jpg: fuente_plaza_Emperador_Carlos13.jpg: fuente_plaza_Emperador_Carlos14.jpg: fuente_plaza_Emperador_Carlos15.jpg:
¿Necesitas saber el tamaño de una imagen para poder trabajar con ella, ajustarla a un tamaño determinado, ampliarla, reducirla o recortarla? ImageMagick te lo dice con el comando identify y el parámetro -format. Para saber el tamaño, trabajaremos con dos modificadores:
identify -format %w -> Nos inidca la anchura
identify -format %h -> Nos indica la altura
identify -format %w imagen.png
identify -format %h imagen.png
Devuelve la anchura y la altura respectivamente, de la imagen contenida en imagen.png
Si queremos sacarle más partido y pasarle esos valores a una variable numérica:
let anchura=$(identify -format %w imagen.png)
let altura=$(identify -format %h imagen.png)
Con esto, ya podremos operar con los valores de las variables $anchura y $altura.
Cada vez las cámaras fotografían con mayor resolución, incluso con resoluciones mayores a las pantallas en las que vemos esa imagen. Y esto nos da mucho juego para poder manipular las imágenes haciendo recortes que nos permitan, entre otras cosas:
Veamos esta fotografía de la escultura de Miguel Servet en la antigua facultad de medicina de Zaragoza:
Si queremos mostrar únicamente la escultura, sobra imagen por todos los lados. Avuelapluma y sin ajustar demasiado (estamos hablando de ImageMagick, no de armonía, ni de composición), pienso que podemos quitar 1/7 por arriba y por abajo y alrededor de 1/5 a izquierda y derecha, así que, como ya sabemos cómo preguntarle a ImageMagick el tamaño de las imágenes, voy a hacer esos recortes:
#!/bin/bash
origen="servet.jpg"
destino="servet_recortado.jpg"
let anchura=$(identify -format %w $origen)
let altura=$(identify -format %h $origen)
let anchurarecorte=$anchura/5
let alturarecorte=$altura/7
let nuevaanchura=$anchurarecorte*3
let nuevaaltura=$alturarecorte*5
recorte=$nuevaanchura"x"$nuevaaltura"+"$anchurarecorte"+"$alturarecorte
convert $origen -crop $recorte $destino
Veamos lo que he hecho en este script:
Primero, indicarle que estamos escribiendo un script en Bash con #!/bin/bash
E indicarle cual es la imagen que vamos a procesar y cómo queremos que se guarde la imagen modificada, Aunque esta sea una operación sencilla, siempre viene bien ser ordenados y definir primero las variables con las que vamos a trabajar y acostumbrarnos a nombrar con variables. Poco a poco iremos haciendo más complejos los scripts y cuando empecemos a hacer animaciones con ImageMagick viene muy bien ser estructurados.
El siguiente paso ha sido preguntarle a ImageMagick la altura y la anchura de la imagen para poder calcular dos cosas: Las partes a recortar, tanto horizontal como verticalmente (ese 1/7 y 1/5 que hemos dicho antes) y el tamaño de la imagen resultante. En este caso, como le quitábamos 1/7 por arriba y por abajo serían 7-1-1=5 -> 5/7 de la imagen y como le recortamos 1/5 a izquierda y otro 1/5 a la derecha, nos quedaría 5-1-1=3 -> 3/5 partes de la imagen.
Una variable que contiene primero la anchura expresada en anchuraxaltura y después el recorte que le hacemos por arriba y por la izquiera expresado en +recortehorizontal+recortevertical.
Cuando tenemos todos los valores calculados, ejecutamos la instrucción diciéndole a convert que recorte con -crop y cómo queremos que sea el recorte.
Al final, la imagen resultante ha quedado así:
ImageMagick cuenta con una serie de colores predefinidos a los que podemos llamar por su nombre en lugar de por su código hexadecimal. Es más cómodo invocarlos por su nombre, aunque es más preciso hacerlo por su código. Así que cada uno que elija lo que más le interese, aunque en este artículo nos vamos a centrar en los colores preestablecidos y cómo sacarle partido a este listado.
Para poder listar en ImageMagick está el parámetro -list.
convert -list $listaamostrar
Nos mostrará la lista que le pidamos. En este caso, le pediremos que liste los colores:
convert -list color
Y nos mostrará el listado de colores. En mi caso:
$ convert -list color | wc -l$ convert -list color | wc -l
683
Me dice que tengo 683 colores predefinidos. Con wc -l le he pedido que me diga únicamente las líneas del listado, no el listado en sí, y así sé el número de colores que tengo.
Si quiero saber los distintos colores predefinidos basados en un determinado color, lo que puedo hacer es redirigir la salida del listado a un grep e indicarle el patrón. Veamos cómo listar las tonalidades de rojo que tengo:
convert -list color | grep Redconvert -list color | grep Red
DarkRed srgb(139,0,0) SVG X11
IndianRed srgb(205,92,92) SVG X11 XPM
IndianRed1 srgb(255,106,106) X11
IndianRed2 srgb(238,99,99) X11
IndianRed3 srgb(205,85,85) X11
IndianRed4 srgb(139,58,58) X11
MediumVioletRed srgb(199,21,133) SVG X11 XPM
OrangeRed srgb(255,69,0) SVG X11 XPM
OrangeRed1 srgb(255,69,0) X11
OrangeRed2 srgb(238,64,0) X11
OrangeRed3 srgb(205,55,0) X11
OrangeRed4 srgb(139,37,0) X11
PaleVioletRed srgb(219,112,147) SVG X11 XPM
PaleVioletRed1 srgb(255,130,171) X11
PaleVioletRed2 srgb(238,121,159) X11
PaleVioletRed3 srgb(205,104,137) X11
PaleVioletRed4 srgb(139,71,93) X11
VioletRed srgb(208,32,144) X11 XPM
VioletRed1 srgb(255,62,150) X11
VioletRed2 srgb(238,58,140) X11
VioletRed3 srgb(205,50,120) X11
VioletRed4 srgb(139,34,82) X11
Pero vemos que esto es un listado con tres columnas y que me da más información que la que voy a usar a la hora de invocar un color, ya que para esto, utilizaré únicamente el nombre. Así que limpiaré el listado y me quedaré con la primera columna que es la que me interesa:
convert -list color | grep Red | cut -f 1 -d " "
DarkRed
IndianRed
IndianRed1
IndianRed2
IndianRed3
IndianRed4
MediumVioletRed
OrangeRed
OrangeRed1
OrangeRed2
OrangeRed3
OrangeRed4
PaleVioletRed
PaleVioletRed1
PaleVioletRed2
PaleVioletRed3
PaleVioletRed4
VioletRed
VioletRed1
VioletRed2
VioletRed3
VioletRed4
Así ya podemos ver el listado limpio y podemos trabajar con esos valores
En muchas ocasiones nos interesa utilizar distintos tonos de un color, por ejemplo, para dar ir cambiando la tonalidad de una imagen. Para ello, una vez que tenemos el listado limpio, únicamente tenemos que recorrerlo con un for:
function hazlienzosdecolor()
{
for i in $(convert -list color | grep Red | cut -f 1 -d " ")
do
#Instrucciones
done
}
Supongamos que queremos hacer una serie de lienzos de un tamaño determinado basados en un color que le pasemos como parámetro. Podríamos hacer un script como este:
#!/bin/bash
tamlienzo="200x100"
let numlienzo=0
function hazlienzosdecolor()
{
if [ $1 ] && [ "$(convert -list color | grep $1 | cut -f 1 -d " ")" ]
then
for i in $(convert -list color | grep $1 | cut -f 1 -d " ")
do
destino="lienzo"$1$numlienzo".png"
convert -size $tamlienzo xc:$i $destino
let numlienzo++
done
fi
}
hazlienzosdecolor $1
Y al ejecutarlo, genera:
./hazlienzosdecolor Orange
Qué hemos hecho en este script:
Primero indicamos las variables, de esta forma, si queremos modificarlas en cualquier momento, las tenemos localizadas a simple vista
Después le decimos que si al ejecutarse el script recibe un parámetro ([ $1 ]), y además (&&) este es un color válido ([ "$(convert -list color | grep $1 | cut -f 1 -d " ")" ]) ejecute estas órdenes:
for i in $(convert -list color | grep $1 | cut -f 1 -d " ")-> Recorre el listado de los colores que contengan el valor indicado en el primer parámetro y únicamente el primer campo del listado
destino="lienzo"$1$numlienzo".png" -> Da valor a la variable destino con una cadena de texto, en este caso el patrón "lienzo", luego el nombre el color que ha indicado el usuario, el número que corresponde a ese lienzo y la extensión ".png"
convert -size $tamlienzo xc:$i $destino -> Genera el lienzo
let numlienzo++ -> Suma uno a la variable numlienzo para que el siguiente lienzo a crear tenga el próximo número correlativo.
Seleccionar un color de forma aleatoria
Para seleccionar un color aleatorio, no le indicaremos un patrón (quitamos el grep $1) y lo que tenemos que indicarle al listado generado es que lo desordene y muestre sólo un color, que se lo indicaremos con shuf -n 1:convert -list color | cut -f 1 -d " " | shuf -n 1
Y si lo queremos usar en un script para que una variable recoja ese color aleatorio, podemos hacer:
#!/bin/bash
function coloraleatorio()
{
color=$(convert -list color | cut -f 1 -d " " | shuf -n 1)
echo $color
}
color=$(coloraleatorio)
echo $color
Puede parecer excesivo hacer una función para algo tan sencillo, pero cuando estás generando muchos colores aleatorios al cabo del día, se agradece tener funciones creadas ;)