Uno de los primeros artículos que escribí en Linux Center sobre ImageMagick versaba sobre cómo generar lienzos simples en ImageMagick.

Ahora, después de haber publicado unos cuantos artículos más sobre ImageMagick me parece un buen momento para hacer una recopilación de las distintas formas de hacer un lienzo y cómo aplicarle efectos para poder generar multitud de imágenes distintas como fondo de escritorio, fondos para escribir textos en redes sociales y llamar así más la atención de los destinatarios, imágenes para WhatsAPP / Telegram... y de paso, ver también cómo construir instrucciones complejas en ImageMagick.

A modo de recordatorio

Lienzos simples

Para generar imágenes con ImageMagick el comando a usar es convert, al cual le tenemos que indicar el tamaño de la imagen con -size, el color a usar con xc: y el nombre de la imagen a generar.

La estructura más sencilla para generar una imagen con ImageMagick sería algo así:

convert -size 500x100 xc:Black franjanegra.png

franjanegra.png

Podríamos combinar en la misma instrucción varias veces el parámetro xc: con atención a que si no añadimos más parámetros, convert generará tantos ficheros como imágenes generadas con xc:

convert -size 500x100 xc:Black xc:Red xc:Blue franjanegra.png

Generará tres ficheros:

franjanegra-0.png

franjanegra-0.png

franjanegra-1.png

franjanegra-2.png

franjanegra-2.png

 

Si queremos que esos lienzos formen parte de un único fichero unido verticalmente necesitamos usar el parámetro append. Con -append la unión será vertical y con +append la unión será horzontal.

convert -size 500x100 xc:Black xc:Red xc:Blue -append tresfranjas.png


tresfranjas.png

Como hemos visto hasta aquí, si únicamente utilizamos un -size, todas las piezas medirán lo mismo. Veamos cómo hacer una imagen con piezas de distintos tamaños. Y de paso, veamos cómo concatenar imágenes en formato horizontal (con +append):

convert -size 100x500 xc:Black -size 200x500 xc:Red -size 300x500 xc:Blue +append tresfranjasverticales.png

tresfranjasverticales.png

Marcos

A los lienzos generados se les puede añadir nuevos parámetros. Por ejemplo -border que añade un borde al lienzo del color indicado con -bordercolor:

convert -size 300x300 xc:Red -bordercolor Black -border 100x100 negroborderojo.png

 

Gradientes de color

Los gradientes de color o degradados básicos que se pueden hacer en ImageMagick son lineales o radiales, con los parámetros gradient: y radial-gradient: en lugar de xc:

convert -size 500x500 gradient:Red-Blue degradadorojoazul.png

degradadorojoazul.png

convert -size 500x500 radial-gradient:Red-Blue degradadoradialrojoazul.png


degradadoradialrojoazul.png

Aplicando nuevos parámetros a las lienzos


Una vez visto este recordatorio, aquí empezamos con la elaboración de instrucciones complejas en ImageMagick.

Uniendo xc: y gradient:


Los degradados lineales realizados con gradient no permiten grandes posibildades de adaptación, pero podemos unir parámetros, como xc: y gradient: para poder hacer imágenes en el que haya partes sin degradados:

convert -size 500x100 xc:Red -size 500x300 gradient:Red-Blue -size 500x100 xc:Blue -append unionxcgradient.png
unionxcgradient.png

Uniendo xc:, gradient: y rotate

Vamos a rizar un poco más el rizo y vamos a unir un parámetro más, el parámetro rotate para girar la imagen y que el degradado tenga formato horizontal:

convert -size 500x100 xc:Red -size 500x300 gradient:Red-Blue -size 500x100 xc:Blue -append -rotate 90 unionxcgradientgirado.png

unionxcgradientgirado.png

Varios gradientes en una imagen


Podemos encadenar distintos gradientes y lienzos lisos, tantos como queramos, aquí uniremos dos degradados con un lienzo liso a modo de ejemplo:

convert -size 500x200 gradient:Red-Blue -size 500x100 xc:Blue -size 500x200 gradient:Blue-Red -append doblegradiente.png

doblegradiente.png

Difuminados


A los lienzos creados, podemos aplicarles un difuminado posterior para que haga el efecto de degradado

convert -size 500x250 xc:Blue xc:Red -append -blur 0x250 difuminadoblur.png

difuminadoblur.png

Y aquí viene un punto muy importante que quiero remarcar:

ImageMagick procesa los parámetros de izquierda a derecha, así que para que pueda generarse el difuminado en la unión de los dos lienzos es necesario que el parámetro -append esté antes del parámetro -blur.

Gradientes lineales y radiales.

A convert se le puede indicar que haga degradados en direcciones concretas. Tanto lineales como radiales. Veamos esta última opción con distintos grados aplicados como valor al parámetro -radial-blur ya que es más sencillo ver el resultado en una imagen que leer su descripción:

convert -size 500x250 xc:Blue xc:Red -append -radial-blur 45 difuminadoradialblur-45.png

 

 

 

 

convert -size 500x250 xc:Blue xc:Red -append -radial-blur 90 difuminadoradialblur-90.png




difuminadoradialblur-90.png

convert -size 500x250 xc:Blue xc:Red -append -radial-blur 135 difuminadoradialblur-135.png



difuminadoradialblur-135.png

convert -size 500x250 xc:Blue xc:Red -append -radial-blur 180 difuminadoradialblur-180.png

difuminadoradialblur-180.png

convert -size 500x250 xc:Blue xc:Red -append -radial-blur 225 difuminadoradialblur-225.png

difuminadoradialblur-225.png

convert -size 500x250 xc:Blue xc:Red -append -radial-blur 270 difuminadoradialblur-270.png

difuminadoradialblur-270.png

convert -size 500x250 xc:Blue xc:Red -append -radial-blur 315 difuminadoradialblur-315.png

difuminadoradialblur-315.png

convert -size 500x250 xc:Blue xc:Red -append -radial-blur 360 difuminadoradialblur-360.png



difuminadoradialblur-360.png

Vista la evolución de -radial-blur, veamos lo mismo con -motion-blur, que cuenta con tres parámetros: $radioX$sigma+$ángulo

convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+45 difuminadomotionblur-45.png


difuminadomotionblur-45.png

convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+90 difuminadomotionblur-90.png


difuminadomotionblur-90.png

convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+135 difuminadomotionblur-135.png


difuminadomotionblur-135.png

convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+180 difuminadomotionblur-180.png


difuminadomotionblur-180.png

convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+225 difuminadomotionblur-225.png


difuminadomotionblur-225.png

convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+270 difuminadomotionblur-270.png


difuminadomotionblur-270.png

convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+315 difuminadomotionblur-315.png


difuminadomotionblur-315.png

convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+360 difuminadomotionblur-360.png



difuminadomotionblur-360.png
Sobre todo quiero que se note cómo afecta a la imagen un -motion-blur con un ángulo de 180 ó 360 grados en una imagen con dos franjas horizontales. Y ahora veamos cómo afecta el valor del ángulo tanto en -radial-blur como -motion-blur en una imagen con predominancia de un color y una forma que la cruce. Por ejemplo, una cruz de San Jorge:

convert -size 400x400 xc:White -background Red -splice 100x100+200+200 sanjorge.png

sanjorge.png

 

Y ahora vamos a hacer una evolución de un -motion-blur y un -radial-blur para ver cómo afecta cuando la imagen muestra una forma de cruz:

Veamos la diferencia entre -motion-blur 90 y -motion-blur 180

 

Y entre -motion-blur 45 y -motion-blur 135

 

 

Y en cuanto a -radial-blur, veamos como afecta con 90 y múltiplos de 90: 180, 270 y 360:

sanjorge-radial-blur-90.pngsanjorge-radial-blur-360.pngsanjorge-radial-blur-270.pngsanjorge-radial-blur-180.png

 

Y sin embargo, cómo afecta cuando no son mútliplos de 90:

-radial-blur 45

sanjorge-radial-blur-45.png

-radial-blur 135

sanjorge-radial-blur-135.png

-radial-blur 225

sanjorge-radial-blur-225.png

-radial-blur 315

sanjorge-radial-blur-315.png

 

Dispersiones

Otra forma de modificar las imágenes y hacer menos nítidos los bordes es mediantes las dispersiones con el parámetro -spread:

convert -size 500x250 xc:Red xc:Blue -append -spread 5 rojoazul-spread5.png



rojoazul-spread5.png
A mayor valor en el parámetro spread, mayor será la dispersión entre píxeles:

[code]convert -size 500x250 xc:Red xc:Blue -append -spread 50 rojoazul-spread50.png[/code]
rojoazul-spread50.png

Incluso se puede aplicar un valor mayor al tamaño en píxeles de la altura de la imagen dando un efecto de caos total:

convet -size 500x250 xc:Red xc:Blue -append -spread 1000 rojoazul-spread1000.png

 

Dispersión y difuminado

En una imagen en el que no están definidas las líneas, sí que afecta el -motion-blur con 180 y 360:

[code]convert -size 500x250 xc:Red xc:Blue -append -spread 1000 -motion-blur 0x100+180 rojoazul-spread1000-motion-blur180.png[/code]

rojoazul-spread1000-motion-blur180.png
convert -size 500x250 xc:Red xc:Blue -append -spread 1000 -motion-blur 0x100+360 rojoazul-spread1000-motion-blur360.png


rojoazul-spread1000-motion-blur360.png

Del mismo modo, al aplicarle un difuminado radial de 90 o múltiplo, el resultado también es completamente distinto:

convert -size 500x250 xc:Red xc:Blue -append -spread 1000 -radial-blur 90 rojoazul-spread1000-radial-blur90.png


rojoazul-spread1000-radial-blur90.png
convert -size 500x250 xc:Red xc:Blue -append -spread 1000 -radial-blur 360 rojoazul-spread1000-radial-blur360.png



rojoazul-spread1000-radial-blur360.png
De nuevo, nótese que el orden de los parámetros es muy importante a la hora de generar la imagen final. Veamos qué pasa si primero aplicamos el parámetro -motion-blur y luego el parámetro -spread:

convert -size 500x250 xc:Red xc:Blue -append -radial-blur 360 -spread 1000 rojoazul-radial-blur360-spread1000.png


rojoazul-radial-blur360-spread1000.png

¿Por qué aquí no ha dispersado los píxeles?
Básicamente porque no había diferencia entre unos píxeles y otros, por lo que, aunque los disperse, no había variaciones de color:

[code]convert -size 500x250 xc:Red xc:Blue -append -radial-blur 360 rojoazul-radial-blur360-sin-spread.png[/code]

rojoazul-radial-blur360-sin-spread.png
Publicado en Multimedia

En el anterior artículo contaba cómo pasar cadenas de texto a mayúsculas, a minúsculas o todas en minúsculas excepto la primera letra, que esa sí que pasaría, en caso de que no lo estuviera, a mayúsculas (por ejemplo para escribir nombres propios).

Aquí dejo otra pildorita sobre tr, cómo eliminar los espacios en blanco de una variable:

#!/bin/bash
variable="Esto es una cadena de texto con espacios en blanco"
sinespacios=$(echo "$variable" | tr -d '[[:space:]]')
echo $sinespacios

Al ejecutar este script, la salida será:

Estoesunacadenadetextoconespaciosenblanco

 

 

Publicado en Programación

Para transformar caracteres, bien para borrarlos o bien para modificarlos en GNU/Linux tenemos el comando tr, que cuenta con una serie de filtros para procesar en bloque cadenas de texto. En este artículo veremos dos de ellos: [:lower:] y [:upper:]

Transformar todos los caracteres a minúsculas

En la consola:

variable="LINUXCENTER"; echo $variable | tr '[:upper:]' '[:lower:]'

que devuelve:

linuxcenter

Todos los carecteres que recibe tr en mayúsculas ('[:upper:]') a mayúsculas ('[:lower:]')

En un script:

variable="LINUXCENTER"
minusculas=$(echo $variable | tr '[:upper:]' '[:lower:]')

Transformar todos los caracteres a mayúsculas

En consola:

variable="linuxcenter"; echo $variable | tr '[:lower:]' '[:upper:]'

Que devuelve:
LINUXCENTER

Ya que todos los caracteres que recibe tr en minúsculas ('[:lower:]') lo transforma en mayúsculas ([:upper:])

En un script:

variable="linuxcenter"
mayusculas=$(echo $variable | tr '[:lower:]' '[:upper:]')

Convertir la primera letra en mayúscula y el resto en minúsculas

En consola:

variable="linuxcenter"; echo -n ${variable:0:1} | tr '[:lower:]' '[:upper:]'; echo ${variable:1} | tr '[:upper:]' '[:lower:]'

Que devuelve:
Linuxcenter

Veamos qué hace esta línea:

variable="linuxcenter"; -> Le damos un valor cualquiera a una variable.
echo -n ${variable:0:1} | tr '[:lower:]' '[:upper:]'; -> -n indica a echo que no envíe el salto de línea al final de la cadena que va a mostrar. ${variable:0:1} indica que extraiga desde la posición 0 un caracter y que lo pase a tr. Si está en minúscula, pasará el caracter a mayúscula.
echo ${variable:1} | tr '[:upper:]' '[:lower:]' -> ${variable:1} extrae la subcadena contenida en la variable $variable que va desde la posición 1 hasta el final.

Y en un script:

variable="linuxcenter"
conmayuscula=$(echo -n ${variable:0:1} | tr '[:lower:]' '[:upper:]'; echo ${variable:1} | tr '[:upper:]' '[:lower:]')
Publicado en Programación

En ImageMagick podemos seleccionar colores de varias maneras, principalmente mediante el nombre predefinido del color o mediante un código hexadecimal.

Ya hemos visto en otros artículos que para trabajar con los colores predefinidos por ImageMagick podemos listarlos con:

convert -list color

Y usar esos colores. Es una forma muy útil y práctica de trabajar, pero esto nos limita a unos cuantos colores, unos setecientos según la versión, podemos saber la cantidad con:

convert -list color | wc -l

Y además no nos permite trabajar con transparencias. 
Por lo tanto, el trabajo con código hexadecimal, aunque nos obligue a un pequeño mayor esfuerzo a la hora de programar, nos ofrece una mayor cantidad de colores. Con los nombres de los colores predefinidos tenemos algo menos de 700 colores frente a los 255 * 255 * 255 colores con los que podemos trabajar si usamos códigos hexadecimales. Y si usamos el canal alpha para las transparencias, el número pasa a ser de  255 * 255 * 255 * 255 = 4.228,250.625 colores posibles.

Podemos escribir a mano el código:

convert -size 500x200 xc:#11223344 imagen.png

imagen.png

O podemos generar ese código aleatoriamente.
Para ello nos ayudaremos de shuf para generar un número aleatorio y bc para convertir de decimal a hexadecimal.

Y veamos una función que nos genere aleatoriamente un código hexadecimal de color en nuestros scripts. Pero que, además de dar la posibilidad de generar aleatoriamente un color aleatorio que le podamos indicar que tenga una tonalidad rojiza, verdosa o azulada, o bien que tenga menos coloración de uno de esos canales, que el color sea claro u oscuro y que tenga o no transparencia. Para ello uso una serie de parámetros en la función:

t T -t -T -> Se añade un canal Alfa de transparencia

d D -d -D o O -o -O -> oscuro o dark, el color generado será oscuro, entre 0 y 85 (255 / 3)

 l L -l -L c C -c -C -> claro o light, el color será claro, entre 170 ( 255 / 3 * 2 ) y 255

gb GB -gb -GB bg BG -bg -BG -> Mayor cantidad de verde y azul que de rojo

rb RB -rb -RB br BR -br -BR -> Mayor cantidad de rojo y azul que de verde

rg RG -rg -RG gr GR -gr -GR -> Mayor cantidad de rojo y verde que de azul

b B -b -B -> Color azulado

g G -g -G -> Color verdoso

r R -r -R -> Color rojizo

 

Con esas premisas, aquí dejo la función en un script de ejemplo:

#!/bin/bash

function devuelvecolor()
{

    if [ $1 = "r" ] || [ $1 = "R" ] || [ $1 = "-r" ] || [ $1 = "-R" ]
    then
        let decimalrojo=$(shuf -i 128-255 -n 1)
        let decimalverde=$(shuf -i 0-127 -n 1)
        let decimalazul=$(shuf -i 0-127 -n 1)
    elif [ $1 = "g" ] || [ $1 = "G" ] || [ $1 = "-g" ] || [ $1 = "-G" ]
    then
        let decimalrojo=$(shuf -i 0-127 -n 1)
        let decimalverde=$(shuf -i 128-255 -n 1)
        let decimalazul=$(shuf -i 0-127 -n 1)
    elif [ $1 = "b" ] || [ $1 = "B" ] || [ $1 = "-b" ] || [ $1 = "-B" ]
    then
        let decimalrojo=$(shuf -i 0-127 -n 1)
        let decimalverde=$(shuf -i 0-127 -n 1)
        let decimalazul=$(shuf -i 128-255 -n 1)
    elif [ $1 = "rg" ] || [ $1 = "RG" ] || [ $1 = "-rg" ] || [ $1 = "-RG" ] || [ $1 = "gr" ] || [ $1 = "GR" ] || [ $1 = "-gr" ] || [ $1 = "-GR" ]
    then
        let decimalrojo=$(shuf -i 128-255 -n 1)
        let decimalverde=$(shuf -i 128-255 -n 1)
        let decimalazul=$(shuf -i 0-127 -n 1)
    elif [ $1 = "rb" ] || [ $1 = "RB" ] || [ $1 = "-rb" ] || [ $1 = "-RB" ] || [ $1 = "br" ] || [ $1 = "BR" ] || [ $1 = "-br" ] || [ $1 = "-BR" ]
    then
        let decimalrojo=$(shuf -i 128-255 -n 1)
        let decimalverde=$(shuf -i 0-127 -n 1)
        let decimalazul=$(shuf -i 128-255 -n 1)
    elif [ $1 = "gb" ] || [ $1 = "GB" ] || [ $1 = "-gb" ] || [ $1 = "-GB" ] || [ $1 = "bg" ] || [ $1 = "BG" ] || [ $1 = "-bg" ] || [ $1 = "-BG" ]
    then
        let decimalrojo=$(shuf -i 0-127 -n 1)
        let decimalverde=$(shuf -i 128-255 -n 1)
        let decimalazul=$(shuf -i 128-255 -n 1)
    elif [ $1 = "l" ] || [ $1 = "L" ] || [ $1 = "-l" ] || [ $1 = "-L" ] || [ $1 = "c" ] || [ $1 = "C" ] || [ $1 = "-c" ] || [ $1 = "-C" ]
    then
        let decimalrojo=$(shuf -i 170-255 -n 1)
        let decimalverde=$(shuf -i 170-255 -n 1)
        let decimalazul=$(shuf -i 170-255 -n 1)
    elif [ $1 = "d" ] || [ $1 = "D" ] || [ $1 = "-d" ] || [ $1 = "-D" ] || [ $1 = "o" ] || [ $1 = "O" ] || [ $1 = "-o" ] || [ $1 = "-O" ]
    then
        let decimalrojo=$(shuf -i 0-85 -n 1)
        let decimalverde=$(shuf -i 0-85 -n 1)
        let decimalazul=$(shuf -i 0-85 -n 1)
    else
        let decimalrojo=$(shuf -i 0-255 -n 1)
        let decimalverde=$(shuf -i 0-100 -n 1)
        let decimalazul=$(shuf -i 0-255 -n 1)
    fi

    if [ "$2" ]
    then
        if [ $1 = "t" ] || [ $1 = "T" ] || [ $2 = "t" ] || [ $2 = "T" ] || [ $1 = "-t" ] || [ $1 = "-T" ] || [ $2 = "-t" ] || [ $2 = "-T" ]
        then
             let decimaltransparencia=$(shuf -i 30-125 -n 1)
            hexadecimaltransparencia=$(echo "ibase=10;obase=16;$decimaltransparencia" | bc)
            if [ `expr length $hexadecimaltransparencia` -lt 2 ]
            then
                hexadecimaltransparencia="0"$hexadecimaltransparencia
            fi
        fi
    fi


    hexadecimalrojo=$(echo "ibase=10;obase=16;$decimalrojo" | bc)
    if [ `expr length $hexadecimalrojo` -lt 2 ]
    then
        hexadecimalrojo="0"$hexadecimalrojo
    fi
    hexadecimalverde=$(echo "ibase=10;obase=16;$decimalverde" | bc)
    if [ `expr length $hexadecimalverde` -lt 2 ]
    then
        hexadecimalverde="0"$hexadecimalverde
    fi
    hexadecimalazul=$(echo "ibase=10;obase=16;$decimalazul" | bc)
    if [ `expr length $hexadecimalazul` -lt 2 ]
    then
        hexadecimalazul="0"$hexadecimalazul
    fi



    echo "#"$hexadecimalrojo$hexadecimalverde$hexadecimalazul$hexadecimaltransparencia

}

devuelvecolor R t

Publicado en Multimedia

Como ya vimos en otro artículo, si queremos operar matemáticamente en Bash más allá de las operaciones básicas necesitamos ayudarnos de bc.

Una de las funcionalidades que nos ofrece bc es cambiar entre sistemas de numeración. Por ejemplo, para pasar de decimal a hexadecimal lo podemos hacer con:

decimal=100

hexadecimal=$(echo "ibase=10;obase=16;$decimal" | bc)

Sin embargo, para pasar de hexadecimal a decimal, no hace falta indicar la base de salida (obase), nos valdría con:

hexadecimal=AA

decimal=$(echo "ibase=16; $hexadecimal" | bc)

Publicado en Programación

Aquí traigo un truco sencillo que uso mucho y que puede ser de gran interés para otras personas que automaticen muchos procesos y quieren que parezca que no está todo automatizado. Para simular que algo está hecho a mano, pero realmente está automatizado es necesaria siempre una dosis de aleatoriedad.

Y una forma interesante de aleatorizar los procesos automáticos es seleccionar de forma aleatoria las funciones que realizan tareas.

Para ello necesitamos tener las funciones almacenadas en un fichero distinto al script que las ejecuta e invocarla a través de:

. $bibliotecafunciones
Y seleccionar la función a usar con:

funcionausar=$(grep function $bibliotecafunciones | cut -d " " -f 2 | shuf -n1 | sed 's/()//')

Con esto lo que hacemos es meter en la variable funcionausar el resultado de grep function $bibliotecafunciones | cut -d " " -f 2 | shuf -n1 | sed 's/()//'.

Veamos qué hace cada parte de esta línea:

grep function $bibliotecafunciones -> Busca la cadena de texto function en el fichero cuyo nombre está almacenado en la variable $bibliotecafunciones

cut -d " " -f 2 -> Extrae la segunda columna (-f 2) de la cadena que ha recibido siendo los separadores entre columnas el espacio en blanco (-d " ")

shuf -n1 -> Ordena aleatoriamente lo que ha recibido y extrae la primera línea

sed 's/()//' -> Cambia la cadena de texto () por otra cadena vacía, ya que entre las barras no hay nada (//).

Y ahora vamos a ver un ejemplo que no hace nada, pero ilustra lo que estoy comentando:

 

#!/bin/bash

# Recibe en bibliotecafunciones dónde se encuentras las funciones

bibliotecafunciones="lib/bibliotecafunciones.sh"

# Incluye el código del fichero almacenado en $bibliotecafunciones en este script

. $bibliotecafunciones

# Iniciarlizar las variables que usaremos como parámetros para la función seleccionada

let parametro1=1

let parametro2=2

let parametro3=3

 

# Selecciona aleatoriamente la función a usar

funcionausar=$(grep function $bibliotecafunciones | cut -d " " -f 2 | shuf -n1 | sed 's/()//')

# Uso de la función

resultadodelafuncion=$(eval $funcionausar $parametro1 $parametro2 $parametro3)

Y ahora vamos a ver la biblioteca:

function funcionuno()
{
    # Función que hace unas cosas
}

function funciondos()
{
    # Función que hace otras cosas
}

function funcionuno()
{
    # Función que hace cosas distinas
}

function funcionuno()
{
    # Función que hace algo... o no
}

Publicado en Programación

Hemos hecho un vídeo que no tiene sonido a partir de imágenes generadas con ImageMagick, o a partir de una única imagen, o hemos concatenado vídeos con ffmpeg o... sea como sea, resulta que tenemos un vídeo sin audio.

Y queremos que tenga audio para que sea más agradable su visionado.

Pero hay veces que nos ha salido un vídeo más largo, otras veces más pequeño... generalmente, al montar un vídeo no sabemos antes de empezar la duración exacta de dicho vídeo. Y si lo hemos hecho automáticamente con scripts, menos. Así que queremos vacilar de ser hackers de ImageMagick, deberemos de buscar, de forma automática, una canción que dure exactamente lo mismo que el vídeo.
Y aquí viene de nuevo vinfo.sh a ayudarnos. Y youtube-dl también puede ayudarnos mucho, ya que podemos buscar canciones con licencia creative commons en YouTube y descargarlas en un directorio. Y usarlas justo en el momento que coincida su duración con la duración del vídeo que acabamos de hacer.

¿Vemos cómo?

Aquí está el código, bastante autodescriptivo si has leído los anteriores artículos. Pero con una salvedad: si los nombres de las canciones, o de cualquier otro fichero puede que contenga espacios vacíos, deberemos cambiar el separador de campo.

#!/bin/bash
 
# Script que recibe un vídeo como parámetro
# calcula su duración y busca en un directorio
# una canción que coincida en duración 
# y lo anexa. 
# Para mantener el nombre original el script
# creará una copia temporal que luego borrará. 
# Para poder enlazar la canción y referenciar 
# al autor, acabará el script escribiendo 
# el nombre del fichero de la canción. 
 
directoriocanciones="instrumentales"
 
# Cambia el separador de campo
IFS='
'
 
# Extrae el nombre del fichero 
# y la extensión del fichero pasado como parámetro
sinextension=${1%.*}
extension=${1##*.}
 
# Calcula la duración del audio del fichero pasado como argumento
duracion=$(./vinfo.sh duration $1)
duracionneta=${duracion:0:8}
 
echo "La duracion del video es "$duracion
 
# Crea el fichero temporal y borra el antiguo
 
nuevofichero=$sinextension"-temp."$extension
 
echo "El nuevo fichero será: "$nuevofichero
 
# Busca una canción en el directorio de canciones
# que tenga la misma duración que el vídeo
 
for i in $(ls $directoriocanciones)
do
    duracioncancion=$(./vinfo.sh duration "$directoriocanciones/$i")
    duracionnetacancion=${duracioncancion:0:8}
        echo "duracion video: "$duracionneta
        echo "duracion cancion: "$duracionnetacancion
        echo "cancion: "$i
 
    if [ "$duracionneta" = "$duracionnetacancion" ]
    then
 
        ffmpeg -i $1 -i "$directoriocanciones/$i" -c:v copy -c:a copy $nuevofichero
        rm $1
        mv $nuevofichero $1
        rm $nuevofichero
        echo $i
        break
    fi
done
Publicado en Multimedia

Cuando recorremos un directorio con ficheros cuyo nombre puede que contenga espacios en blanco (algo muy habitual si descargamos vídeos con youtube-dl), no funciona el típico:

#!/bin/bash

directorio="midirectorio"

for i in $(ls $directorio)
do
    echo $i
done

 

Ni siquiera serviría entrecomillar el $i, ya que no le llegaría el nombre del fichero al recortarse en el for.

La solución es cambiar antes de hacer el for el separador de campo con:

IFS='
'

Quedando el script así:

#!/bin/bash


directorio="midirectorio"
IFS='
'

for i in $(ls $directorio)
do
    echo $i
done

 

Guardad este artículo en favoritos. Es una de esas piedras en las que todos tropezamos una y otra vez. A menos yo. Pero ya tengo la chuleta y así ya no tendré que mirar una y otra vez scripts antiguos.

 

 

Publicado en Programación

En GNU/Linux tenemos dos comandos que suelen ir de la mano que permiten extraer los primeros y últimos elementos de un listado.

Su uso más habitual es extraer las primeras líneas de un fichero con head o las últimas con tail.

Veamos un ejemplo sencillo sobre un fichero de texto con "Un soneto me manda hacer Violante" de Lope de Vega:

head violante.txt

Un soneto me manda hacer Violante
que en mi vida me he visto en tanto aprieto;
catorce versos dicen que es soneto;
burla burlando van los tres delante.

Yo pensé que no hallara consonante,
y estoy a la mitad de otro cuarteto;
mas si me veo en el primer terceto,
no hay cosa en los cuartetos que me espante.

tail violante.txt
mas si me veo en el primer terceto,
no hay cosa en los cuartetos que me espante.

Por el primer terceto voy entrando,
y parece que entré con pie derecho,
pues fin con este verso le voy dando.

Ya estoy en el segundo, y aun sospecho
que voy los trece versos acabando;
contad si son catorce, y está hecho.

Por defecto y sin pasarle ningún argumento más que el fichero a listar, tanto tail como head muestran diez líneas. Head las diez primeras líneas, tail las diez últimas líneas.

Pero podemos cambiar el número de líneas a mostrar con -n $numerodelineas

Veamos el primer cuarteto:

head -4 violante.txt
Un soneto me manda hacer Violante
que en mi vida me he visto en tanto aprieto;
catorce versos dicen que es soneto;
burla burlando van los tres delante.

Y el último terceto:

tail -n 3 violante.txt
Ya estoy en el segundo, y aun sospecho
que voy los trece versos acabando;
contad si son catorce, y está hecho.

Otra posibilidad que le podemos decir a tail es que muestre desde una determinada línea hasta el final.

tail -n+13 violante.txt
pues fin con este verso le voy dando.

Ya estoy en el segundo, y aun sospecho
que voy los trece versos acabando;
contad si son catorce, y está hecho.

Y si en lugar de mostrar las primeras y las últimas líneas lo que queremos es mostrar líneas centrales, lo que vamos a indicarles es que trabajen juntos: head, muestra las X primeras líneas y se las das a tail, para que seleccione las Y últimas líneas que les pases. Algo así:

head -n 13 violante.txt | tail -n 8
Yo pensé que no hallara consonante,
y estoy a la mitad de otro cuarteto;
mas si me veo en el primer terceto,
no hay cosa en los cuartetos que me espante.

Por el primer terceto voy entrando,
y parece que entré con pie derecho,
pues fin con este verso le voy dando.

Extraer únicamente los x primeros o últimos caracteres

Ambos comandos tienen una opción, -c que le indican que, en lugar de trabajar con líneas trabajen con caracteres:

head -c 30 violante.txt
Un soneto me manda hacer Viola

tail -c 30 violante.txt
i son catorce, y está hecho.

Hacer que tail y head muestren el nombre del fichero

Para hacer que tail y head muestren el nombre del fichero, se lo indicaremos con -v:

tail -n+13 -v violante.txt
==> violante.txt <==
pues fin con este verso le voy dando.

Ya estoy en el segundo, y aun sospecho
que voy los trece versos acabando;
contad si son catorce, y está hecho.

Sin embargo, si lo que queremos es que no muestre el nombre del fichero, lo indicaremos con -q:

tail -n+13 -q violante.txt
pues fin con este verso le voy dando.

Ya estoy en el segundo, y aun sospecho
que voy los trece versos acabando;
contad si son catorce, y está hecho.

Esto es básicamente lo que ha estado haciendo hasta ahora, pero ¿qué pasaría si queremos mostrar extractos de varios ficheros?

Cómo mostrar extractos de varios ficheros

Le podemos indicar a head o a tail que muestren extractos de multiples ficheros, y aquí si que viene bien que indique el nombre del fichero. Quizá no en este ejemplo, ya que el nombre del fichero es la primera línea sin espacios, pero en otras ocasiones, sí.

head -v lope/*
==> lope/albaniayaceaquifabiosuspira.txt <==
Albania yace aquí, Fabio suspira,
matóla un parto sin sazón, dejando
la envidia alegre, y al Amor llorando;
pues ya cualquiera fuerza le retira.

El Tajo crece por mostrar su ira
y corre, de la Muerte murmurando;
párase el sol, el túmulo mirando,
temiendo en sí, lo que en Albania mira.


==> lope/amormilanoshaquemehasjurado.txt <==
Amor, mil años ha que me has jurado
pagarme aquella deuda en plazos breves;
mira que nunca pagas lo que debes,
que esto sólo no tienes de hombre honrado.

Muchas veces, Amor, me has engañado
con firmas falsas y esperanzas leves;
a estelionatos con mi fe te atreves,
jurando darme lo que tienes dado.


==> lope/laclaraluzenlasestrellaspuesta.txt <==
La clara luz en las estrellas puesta
del fogoso León por alta parte
bañaba el sol, cuando Acidalia y Marte
en Chipre estaban una ardiente siesta.

La diosa por hacerle gusto y fiesta
la túnica y el velo deja aparte,
sus armas toma y de la selva parte,
del yelmo y plumas y el arnés compuesta.


==> lope/violante.txt <==
Un soneto me manda hacer Violante
que en mi vida me he visto en tanto aprieto;
catorce versos dicen que es soneto;
burla burlando van los tres delante.

Yo pensé que no hallara consonante,
y estoy a la mitad de otro cuarteto;
mas si me veo en el primer terceto,
no hay cosa en los cuartetos que me espante.


==> lope/yanoquieromasbienquesoloamaros.txt <==
Ya no quiero más bien que sólo amaros
ni más vida, Lucinda, que ofreceros
la que me dais, cuando merezco veros,
ni ver más luz que vuestros ojos claros.

Para vivir me basta desearos,
para ser venturoso conoceros,
para admirar el mundo engrandeceros
y para ser Eróstrato abrasaros.

 

O le podemos decir que no muestre el nombre del fichero ni que separe las líneas de los distintos ficheros con -q. Veamos el último terceto de cada uno de estos sonetos sin nombre:
tail -q -n 3 lope/*
Venganza fue para que ejemplo quede
que quien fue basilisco en dar veneno,
muriese como víbora en el parto.
Mas, ¿cómo pagarás, Amor, si has hecho
pleito de acreedores por mil años
y, en buscando tu hacienda, estás desnudo?
Venus le respondió: «Cuando te atrevas
verás cuanto mejor te vence armada
la que desnuda te venció primero».
Ya estoy en el segundo, y aun sospecho
que voy los trece versos acabando;
contad si son catorce, y está hecho.
Que entre tales riquezas y tesoros
mis lágrimas, mis versos, mis suspiros
de olvido y tiempo vivirán seguros.

Un poco lioso todo, pero para eso hemos elegido un autor barroco ;)

 

Más usos de tail y head

Mostrar el primer y último fichero de un directorio

Estos dos comandos nos permiten saber, por ejemplo, cuál es el primer y último fichero de un directorio:

ls lope/ | head -n 1
albaniayaceaquifabiosuspira.txt

ls lope/ | tail -n 1
yanoquieromasbienquesoloamaros.txt

Esto viene muy bien cuando numeramos los ficheros y queremos saber cuál es el último.

Supongamos que tenemos un directorio que se llame "fotogramas" con un número de fotogramas que desconocemos y queremos saber cuál es el último. Le podemos indicar en un script que lo extraiga y lo guarde en una variable:

ultimofotograma=$(ls $directoriofotogramas | tail -n 1)

Extraer colores consecutivos para hacer un degradado

Dentro de un bucle for, podemos ir cambiando el valor de head manteniendo tail constante a -n 1 y lo que harán será ir extrayendo uno a uno los elementos que le indiquemos.

Veamos un ejemplo:

#!/bin/bash

colores=""

for i in $(seq 1 5)
do
    color=$(convert -list color | grep LightBlue | cut -d " " -f 1 | head -n $i | tail -n 1)
    colores=$colores"xc:"$color" "
done

convert -size 500x100 $colores -append -motion-blur 0x100+90 celeste.png

Con este script generamos una imagen como esta:

celeste.png

Porque head y tail no sólo sirven para trabajar con ficheros de texto. También ayudan a hacer degradados ;)

 

Publicado en Programación

En GNU/Linux tenemos dos comandos que suelen ir de la mano que permiten extraer los primeros y últimos elementos de un listado.

Su uso más habitual es extraer las primeras líneas de un fichero con head o las últimas con tail.

Veamos un ejemplo sencillo sobre un fichero de texto con "Un soneto me manda hacer Violante" de Lope de Vega:

head violante.txt

Un soneto me manda hacer Violante
que en mi vida me he visto en tanto aprieto;
catorce versos dicen que es soneto;
burla burlando van los tres delante.

Yo pensé que no hallara consonante,
y estoy a la mitad de otro cuarteto;
mas si me veo en el primer terceto,
no hay cosa en los cuartetos que me espante.

tail violante.txt
mas si me veo en el primer terceto,
no hay cosa en los cuartetos que me espante.

Por el primer terceto voy entrando,
y parece que entré con pie derecho,
pues fin con este verso le voy dando.

Ya estoy en el segundo, y aun sospecho
que voy los trece versos acabando;
contad si son catorce, y está hecho.

Por defecto y sin pasarle ningún argumento más que el fichero a listar, tanto tail como head muestran diez líneas. Head las diez primeras líneas, tail las diez últimas líneas.

Pero podemos cambiar el número de líneas a mostrar con -n $numerodelineas

Veamos el primer cuarteto:

head -4 violante.txt
Un soneto me manda hacer Violante
que en mi vida me he visto en tanto aprieto;
catorce versos dicen que es soneto;
burla burlando van los tres delante.

Y el último terceto:

tail -n 3 violante.txt
Ya estoy en el segundo, y aun sospecho
que voy los trece versos acabando;
contad si son catorce, y está hecho.

Otra posibilidad que le podemos decir a tail es que muestre desde una determinada línea hasta el final.

tail -n+13 violante.txt
pues fin con este verso le voy dando.

Ya estoy en el segundo, y aun sospecho
que voy los trece versos acabando;
contad si son catorce, y está hecho.

Y si en lugar de mostrar las primeras y las últimas líneas lo que queremos es mostrar líneas centrales, lo que vamos a indicarles es que trabajen juntos: head, muestra las X primeras líneas y se las das a tail, para que seleccione las Y últimas líneas que les pases. Algo así:

head -n 13 violante.txt | tail -n 8
Yo pensé que no hallara consonante,
y estoy a la mitad de otro cuarteto;
mas si me veo en el primer terceto,
no hay cosa en los cuartetos que me espante.

Por el primer terceto voy entrando,
y parece que entré con pie derecho,
pues fin con este verso le voy dando.

Extraer únicamente los x primeros o últimos caracteres

Ambos comandos tienen una opción, -c que le indican que, en lugar de trabajar con líneas trabajen con caracteres:

head -c 30 violante.txt
Un soneto me manda hacer Viola

tail -c 30 violante.txt
i son catorce, y está hecho.

Hacer que tail y head muestren el nombre del fichero

Para hacer que tail y head muestren el nombre del fichero, se lo indicaremos con -v:

tail -n+13 -v violante.txt
==> violante.txt <==
pues fin con este verso le voy dando.

Ya estoy en el segundo, y aun sospecho
que voy los trece versos acabando;
contad si son catorce, y está hecho.

Sin embargo, si lo que queremos es que no muestre el nombre del fichero, lo indicaremos con -q:

tail -n+13 -q violante.txt
pues fin con este verso le voy dando.

Ya estoy en el segundo, y aun sospecho
que voy los trece versos acabando;
contad si son catorce, y está hecho.

Esto es básicamente lo que ha estado haciendo hasta ahora, pero ¿qué pasaría si queremos mostrar extractos de varios ficheros?

Cómo mostrar extractos de varios ficheros

Le podemos indicar a head o a tail que muestren extractos de multiples ficheros, y aquí si que viene bien que indique el nombre del fichero. Quizá no en este ejemplo, ya que el nombre del fichero es la primera línea sin espacios, pero en otras ocasiones, sí.

head -v lope/*
==> lope/albaniayaceaquifabiosuspira.txt <==
Albania yace aquí, Fabio suspira,
matóla un parto sin sazón, dejando
la envidia alegre, y al Amor llorando;
pues ya cualquiera fuerza le retira.

El Tajo crece por mostrar su ira
y corre, de la Muerte murmurando;
párase el sol, el túmulo mirando,
temiendo en sí, lo que en Albania mira.


==> lope/amormilanoshaquemehasjurado.txt <==
Amor, mil años ha que me has jurado
pagarme aquella deuda en plazos breves;
mira que nunca pagas lo que debes,
que esto sólo no tienes de hombre honrado.

Muchas veces, Amor, me has engañado
con firmas falsas y esperanzas leves;
a estelionatos con mi fe te atreves,
jurando darme lo que tienes dado.


==> lope/laclaraluzenlasestrellaspuesta.txt <==
La clara luz en las estrellas puesta
del fogoso León por alta parte
bañaba el sol, cuando Acidalia y Marte
en Chipre estaban una ardiente siesta.

La diosa por hacerle gusto y fiesta
la túnica y el velo deja aparte,
sus armas toma y de la selva parte,
del yelmo y plumas y el arnés compuesta.


==> lope/violante.txt <==
Un soneto me manda hacer Violante
que en mi vida me he visto en tanto aprieto;
catorce versos dicen que es soneto;
burla burlando van los tres delante.

Yo pensé que no hallara consonante,
y estoy a la mitad de otro cuarteto;
mas si me veo en el primer terceto,
no hay cosa en los cuartetos que me espante.


==> lope/yanoquieromasbienquesoloamaros.txt <==
Ya no quiero más bien que sólo amaros
ni más vida, Lucinda, que ofreceros
la que me dais, cuando merezco veros,
ni ver más luz que vuestros ojos claros.

Para vivir me basta desearos,
para ser venturoso conoceros,
para admirar el mundo engrandeceros
y para ser Eróstrato abrasaros.

 

O le podemos decir que no muestre el nombre del fichero ni que separe las líneas de los distintos ficheros con -q. Veamos el último terceto de cada uno de estos sonetos sin nombre:
tail -q -n 3 lope/*
Venganza fue para que ejemplo quede
que quien fue basilisco en dar veneno,
muriese como víbora en el parto.
Mas, ¿cómo pagarás, Amor, si has hecho
pleito de acreedores por mil años
y, en buscando tu hacienda, estás desnudo?
Venus le respondió: «Cuando te atrevas
verás cuanto mejor te vence armada
la que desnuda te venció primero».
Ya estoy en el segundo, y aun sospecho
que voy los trece versos acabando;
contad si son catorce, y está hecho.
Que entre tales riquezas y tesoros
mis lágrimas, mis versos, mis suspiros
de olvido y tiempo vivirán seguros.

Un poco lioso todo, pero para eso hemos elegido un autor barroco ;)

 

Más usos de tail y head

Mostrar el primer y último fichero de un directorio

Estos dos comandos nos permiten saber, por ejemplo, cuál es el primer y último fichero de un directorio:

ls lope/ | head -n 1
albaniayaceaquifabiosuspira.txt

ls lope/ | tail -n 1
yanoquieromasbienquesoloamaros.txt

Esto viene muy bien cuando numeramos los ficheros y queremos saber cuál es el último.

Supongamos que tenemos un directorio que se llame "fotogramas" con un número de fotogramas que desconocemos y queremos saber cuál es el último. Le podemos indicar en un script que lo extraiga y lo guarde en una variable:

ultimofotograma=$(ls $directoriofotogramas | tail -n 1)

Extraer colores consecutivos para hacer un degradado

Dentro de un bucle for, podemos ir cambiando el valor de head manteniendo tail constante a -n 1 y lo que harán será ir extrayendo uno a uno los elementos que le indiquemos.

Veamos un ejemplo:

#!/bin/bash

colores=""

for i in $(seq 1 5)
do
    color=$(convert -list color | grep LightBlue | cut -d " " -f 1 | head -n $i | tail -n 1)
    colores=$colores"xc:"$color" "
done

convert -size 500x100 $colores -append -motion-blur 0x100+90 celeste.png

Con este script generamos una imagen como esta:

celeste.png

Porque head y tail no sólo sirven para trabajar con ficheros de texto. También ayudan a hacer degradados ;)

 

Publicado en Programación
Página 1 de 3

¡Atención! Este sitio usa cookies y tecnologías similares.

Si no cambia la configuración de su navegador, usted acepta su uso. Saber más

Acepto

Vea nuestra política de cookies y enlaces de interés aquí