Linux Center Valencia - Elementos filtrados por fecha: Noviembre 2018

Hace muchos años, la programación multihilo solo servía para darnos a los usuarios la sensación de multitarea y que el ordenador pudiera respondeer cuando interactuábamos con él. Normalmente sólo teníamos un único núcleo de CPU y solo podía ejecutar una cosa en un momento del tiempo determinado. Aunque el sistema operativo se encargaba de ir cambiando las tareas que iba ejecutando varias veces por segundo, y por eso podíamos estar viendo una página web y al mismo tiempo chateando con otro programa, copiando un archivo, etc. Esta multitarea también nos ayudaba mucho cuando una aplicación estaba esperando un dato del disco o de un dispositivo (ratón, teclado, red...), ya que estos dispositivos son mucho más lentos que la CPU del ordenador. Es decir, mientras la CPU puede procesar millones de operaciones por segundo, pedir un dato a un disco duro, puede tardar lo mismo que tardarían varios miles de operaciones, y si el dato viene de Internet, puede tardar mucho más. Así que los sistemas operativos multitarea, suspenden la ejecución de dicha aplicación hasta que el dato esté listo, y así aprovechan los ciclos de procesador que podían haberse perdido para hacer cosas más productivas como la descompresión de fotogramas de un vídeo de gatitos.

Eso sí, si en una CPU monohilo ejecutamos dos tareas que requieren CPU de forma intensiva como la compresión de vídeo, renderizado 3D o aplicación de filtros sobre imágenes, nos daremos cuenta de que el tiempo total de la ejecución de las tres tareas es aproximadamente el mismo que ejecutar una tarea detrás de otra.

Pero en los tiempos que corren, es muy común encontrar procesadores con varios núcleos, incluso con varios hilos por núcleo. Al tener varios núcleos, podremos ejecutar varios programas y normalmente el sistema operativo se encarga de colocarlos en uno u otro núcleo, de forma que, ya que nuestro procesador puede ejecutar varias cosas a la vez, aprovechemos esa potencia para terminar las tareas antes.
Aunque ahora el problema suele ser que las aplicaciones no están pensadas para ejecutarse en varios hilos. Bueno, actualmente muchas aplicaciones pueden aprovechar la potencia de los procesadores modernos, como compresores de vídeo, software de minería de criptomonedas, tratamiento de imágenes etc. Pero, muchos programas comunes de búsqueda de datos en ficheros, compresión/descompresión, y muchos de nuestros scripts en Bash o Python no están preparados. 


Ejecución de tareas en paralelo en Bash

Cuando, en Bash queremos ejecutar dos tareas a la vez, siempre podemos ejecutarlo con un & al final, volveremos a nuestro shell para ejecutar más cosas mientras el programa inicial se está ejecutando:

$ programa &
19238
$ … ejecuto más cosas …


O también podemos ejecutarlo normalmente, pulsar Control+Z (^Z). El programa se detendrá, si escribimos en la consola "fg" el programa seguirá en primer plano (foreground), pero si ponemos "bg" el programa seguirá en segundo plano (background), y mientras éste está corriendo, podremos ejecutar más cosas:

$ programa
…
^Z
[1]+ Stopped   programa
… ejecuto más cosas …
$ fg
programa
… programa sigue ejecutándose …
^Z
[1]+ Stopped    programa
$ bg
[1]+ programa &
… puedo ejecutar lo que quiera …


GNU Parallel

Con esto puede ser suficiente para muchos de nosotros pero, ¿y si queremos utilizar más hilos? Es un poco pesado ejecutar varios programas con sus argumentos y una & al final. ¿O queremos que los argumentos vayan cambiando según la ejecución? ¿O incluso queremos ejecutar cientos de tareas pero que se vayan repartiendo la CPU de 2 en 2, de 4 en 4 o más dependiendo del número de núcleos que tengamos? Para eso, y mucho más, tenemos la utilidad GNU Parallel.
Un ejemplo típico es crear un programa que calcule dígitos del número PI con un hilo de CPU, es muy fácil con bc:

#!/bin/bash
echo "scale=4000; a(1)*4" | bc -l

Lo salvamos como pi.sh y le damos permiso de ejecución con:

$ chmod +x pi.sh


Este programa, ejecutado en mi ordenador tarda unos 11 segundos en terminar. Suponiendo que nuestro equipo tenga 2 núcleos, podemos hacer:

$ time ./pi.sh & time ./pi.sh


Veremos que tarda también 11 segundos (más o menos). Esto lo podemos hacer con GNU Parallel de esta forma:

$ time seq 2 | parallel -n0 ./pi.sh

Donde se ejecutará el comando pi.sh dos veces y de forma simultánea. Pero, aunque esta orden pueda parecer complicada, podemos jugar un poco con ella, para ejecutar pi 4 veces de forma simultánea:

$ time seq 4 | parallel -n0 ./pi.sh

Si nuestra CPU tiene 4 núcleos, seguirá tardando 11 segundos, en realizar cuatro tareas, pero si nuestra CPU tiene 2 núcleos, tardará más de 22 segundos. Ya que las tareas utilizan mucho la CPU y es un trabajo extra para el sistema operativo intercalarlas para que se ejecuten a la vez. Pero, imaginémonos que queremos ejecutar 4 veces pi, pero que se repartan de 2 en 2, para ello podemos hacer:

$ time seq 4 | parallel -n0 -j2 ./pi.sh

Si queremos, podemos ejecutar un gestor de tareas o el comando "top" con el que veremos qué tareas están en ejecución cada vez.


Varias tareas con argumentos

Ahora vamos a modificar pi.sh así:

#!/bin/bash
DECIMALES=$1
echo "scale=$1; a(1)*4" | bc -l

De modo que tengamos que introducir el número de dígitos que queremos de Pi. Así ejecutaremos pi.sh de forma concurrente pero con parámetros diferentes en cada ejecución. Podemos jacer lo siguiente:

$ time echo "1000 2000 3000 4000" | tr ' ' '\n' | parallel ./pi.sh

O si queremos que solo haya dos ejecuciones de pi.sh simultáneas:

$ time echo "1000 2000 3000 4000" | tr ' ' '\n' | parallel -j2 ./pi.sh

Nota: El uso de tr es porque parallel necesita que los argumentos vayan uno por línea. Si los argumentos los tenemos en un archivo y uno por línea podríamos hacer:

$ cat argumentos | parallel -j2 ./pi.sh


Combinaciones de argumentos

Con GNU Parallel podemos incluso combinar argumentos. En este ejemplo, cambiamos de base varios números binarios a base 10

$ parallel echo -n {1}{2}{3}{4} = \;'echo "ibase=2;{1}{2}{3}{4}" | bc' ::: 0 1 ::: 0 1 ::: 0 1 ::: 0 1
0000 =0
0001 =1
0010 =2
0011 =3
0100 =4
0101 =5
0110 =6
0111 =7
1000 =8
1001 =9
1010 =10
1011 =11
1100 =12
1101 =13
1110 =14
1111 =15

Y como vemos, GNU Parallel, además de proporcionarnos una forma sencilla de ejecutar programas simultáneamente, nos proporciona también una forma de combinar argumentos y generar resultados muy potente. Utilizando {1}, {2},...{n} dependiendo del número de argumento que estemos tratando

Convirtiendo masivamente archivos de JPG a PNG

Uno de mis usos preferidos, es la conversión automática de archivos, o tratamiento de imágenes con ImageMagick. Además, podemos automatizar esta conversión para realizarla en cientos de archivos y despreocuparnos del ordenador ya que él se encarga de hacer el trabajo. Una tarea muy sencilla es convertir un archivo de JPG a PNG con convert. Pero, ¿si tenemos una carpeta llena de archivos? Podemos ejecutar convert en todos ellos, y hacerlo uno detrás de otro, pero podríamos hacerlo, por ejemplo de 2 en 2 o de 4 en 4 dependiendo dee nuestra CPU, incluso podríamos subir a 3 o 5 porque la conversión de archivos implica lecturas y escrituras y es tiempo que podemos estar procesando datos (los archivos convertidos entrarán en el directorio convertidas):

$ find -maxdepth 1 -name*.jpg’ | parallel --progress -j3 convert -verbose {} convertidas/{/.}.png

Fijaos cómo en el segundo argumento le quito la extensión para llamarla png. Podría variar el número del argumento -j según mis preferencias. Además, he introducido --progress que nos indicará el progreso de la tarea.
Como último ejemplo, nos basaremos en el anterior. Pero esta vez, utilizaremos zenity para presentar una barra de progreso de manera gráfica. ¡Porque, que sea terminal no significa que no sea visual!

$ find -maxdepth 1 -name*.jpg’ | parallel --bar convert {} convertidas/{/.}.png 2> >(zenity --progress --auto-kill)

¡Espero que les haya resultado útil!

Normalmente tenemos en ejecución decenas de servicios, y todos deben estar en ejecución en todo momento. Puede que si somos usuarios de escritorio y tenemos un problema, lo detectemos al momento y reiniciemos el ordenador, o incluso investiguemos qué se ha detenido, lo reiniciamos y continuamos trabajando.

Aunque, si tenemos un VPS, una Raspberry PI o un NAS con un pequeño servidor, o cualquier sistema que tenga que estar todo el día encendido de forma independiente ejecutando un sistema GNU/Linux tenemos que tener en mente que los servicios fallan en algún momento. Ya sea por ejecutar una versión experimental, descubrir un bug, o simplemente quedarte sin memoria o disco. La clave es tener previsto que esos servicios pueden sufrir un problema. En el caso de tener un VPS con una web o un blog, significaría dejar a los usuarios sin poder acceder si por ejemplo se cae el servidor web o el servidor de aplicación. O en el caso de una Raspberry implicaría conectarnos o conectar monitor y teclado para reiniciar el servicio a mano, cuando debería ser algo que funcione de manera independiente.

Y como actualmente muchas distribuciones incluyen Systemd, vamos a hacerlo utilizando este sistema.

NOTA: En este tutorial, estoy utilizando sudo para ejecutar acciones con privilegios de root, pero puede que tu sistema no tenga sudo configurado. Así que tendrás que alcanzar el usuario root para ejecutar los comandos.

Listar nuestros servicios

Para ello, tenemos que tener claro cómo se llama el servicio. En Systemd todos acaban con ".service", algunos ejemplos de servicios pueden ser: apache, nginx (servidores web), sshd (servidor ssh), ufw (firewall), etc.

Podemos obtener un listado de los servicios de nuestro sistema así

sudo systemctl list-units --type=service

Vamos a probar, por ejemplo con el servicio apache2.service, es un servidor web y será muy fácil hacer pruebas con él.

Simulando fallos en el servicio

Es posible que este servicio falle. Y es algo que pasa en servidores del mundo real. Puede ser por algún fallo que se haya descubierto y haya sido explotado por un atacante, falta de recursos en el servidor, o incluso un fallo en un módulo, pero no podemos renunciar a ofrecer el servicio a nuestros usuarios. Así que, vamos a matar el proceso, para que éste finalice repentinamente sin contar con systemd:

sudo killall -9 apache2

Lo ejecutamos varias veces, hasta que nos aseguremos de que el proceso está realmente muerto. Si queremos, podemos intentar acceder al servidor web, y asegurarnos de que no responde.

Editando el servicio

Ahora, vamos a editar el archivo de descripción del servicio. Lo bueno de systemd es que no tenemos que editar el archivo original que describe el servicio, en mi caso /lib/systemd/system/apache2.service. Editar el archivo original implica que si actualizamos el sistema, una actualización puede deshacer nuestros cambios y nos obligaría a revisarlos cada vez que actualicemos. En su lugar podemos editar el archivo /etc/systemd/system/apache2.service o, en versiones más modernas de systemd, podemos ejecutar:

sudo systemctl edit apache2.service
 


Esto directamente nos mostrará un editor de texto (vi, nano, etc) con un fichero en blanco desde el que podemos introducir modificaciones al fichero original. Los cambios introducidos aquí se sumarán al fichero original y systemd lo interpretará como un archivo que contiene todas las directivas conjuntas. El comando, crea un directorio llamado /etc/systemd/system/apache2.service.d/ y dentro de ese directorio creará el archivo override.conf.

En dicho editor introduciremos lo siguiente:

 
[Service]
Restart=always
 

Con esto indicaremos a systemd que debe reiniciar el servicio siempre que se pare. Guardamos el fichero y ejecutaremos ahora:

sudo systemctl daemon-reload
sudo systemctl daemon-reload

Con este comando indicaremos a systemd que debe leer de nuevo todos los ficheros de configuración de los servicios. Ya podemos reiniciar el servicio (porque lo dejamos parado antes):

sudo systemctl restart apache2.service

o

sudo service apache2 restart

Este segundo es el antiguo método, aunque systemd lo mantiene. Para comprobar que realmente funciona este método, podemos esperarnos un minuto y pedir el estado del proceso apache2, para ello ejecutamos:

sudo systemctl status apache2.service

Y veremos algo parecido a esto:

● apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: ena
Drop-In: /lib/systemd/system/apache2.service.d
└─apache2-systemd.conf
/etc/systemd/system/apache2.service.d
└─override.conf
Active: active (running) since Sun 2018-11-18 14:15:51 CET; 1min 19s ago
Process: 13229 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS
Main PID: 13245 (apache2)
Tasks: 55 (limit: 4915)
CGroup: /system.slice/apache2.service
├─13245 /usr/sbin/apache2 -k start
├─13248 /usr/sbin/apache2 -k start
└─13249 /usr/sbin/apache2 -k start

En la línea que comienza por Active, veremos cuánto tiempo lleva el proceso arrancado, en este caso 1 minuto y 19 segundos. Ahora, si matamos el proceso apache2 y pedimos el estado del proceso de nuevo, ahora veremos que el proceso sigue activo, pero se habrá iniciado hace unos segundos nada más. También veremos que los PID de los procesos son diferentes, y veremos una líneas indicando este reinicio.

Ver el log del proceso

Si queremos ver el log del proceso para saber el momento en el que se ha reiniciado, o ver directamente si se ha producido este reinicio y diagnosticarlo, porque lo ideal es que esto nunca suceda, podemos ejecutar:

sudo journalctl -u apache2.service

Ganando algo más de control

Ya hemos conseguido que los procesos se reinicien automáticamente, ahora vamos a afinar un poco esta configuración. Puede que nuestro servicio necesite unos segundos antes de levantarse, para lo que podremos editar el archivo de descripción del servicio e introducir:

RestartSec=2s

Y así esperaremos 2 segundos antes de reiniciarlo.

Incluso podemos limitar el número de veces que se reiniciará dentro de un intervalo de tiempo, por ejemplo, le podemos decir que si en un intervalo de 10 segundos, el servicio se reinicia 3 veces, no intentemos reiniciarlo más. Imaginemos que el equipo se queda sin disco, y vamos a tener a systemd reiniciando constantemente un servicio, ocupando CPU y memoria y puede que impidiendo la administración remota. Lo podemos hacer introduciendo estas líneas en la descripción del servicio:

StartLimitBurst=3
StartLimitIntervalSec=10

Y por supuesto, podemos probarlo matando el servicio varias veces. Incluso systemd nos indicará en el estado que ha superado el límite de reinicios y por eso el servicio se ha detenido.

Otra buena idea es, por ejemplo, enviar un correo electrónico al administrador en caso de reinicio de determinados servicios. Para ello, en esta misma descripción podemos incluir:

ExecStartPre=/usr/local/bin/correo_error_admin.pl

Luego, podemos crear el script que envía el correo, por ejemplo en Perl, introduciendo lo siguiente en el script /usr/local/bin/correo_error_admin.pl :

#!/usr/bin/perl
use strict;
use warnings;
# first, create your message
use Email::MIME;
my $message = Email::MIME->create(  
  header_str => [
    From    => <a href="mailto:Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.'">Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.'</a>,
    To      => <a href="mailto:Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.'">Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.'</a>,
    Subject => 'Error en tu servidor',
  ],
  attributes => {
    encoding => 'quoted-printable',
    charset  => 'ISO-8859-1',
  },
  body_str => "Lo siento, tu servidor se ha reiniciado\n",
);
# send the message
use Email::Sender::Simple qw(sendmail);
sendmail($message);

En este script podemos incluir cualquier acción que nos interese automatizar cuando se inicie el servicio. Incluso podemos utilizar ExecStartPost= para ejecutar una acción cuando el servicio se haya iniciado y de la misma manera ExecStopPre= y ExecStopPost= para ejecutar acciones cuando paremos el servicio (pero no cuando el servicio se detenga o muera).

¡Espero que les haya sido útil!

 

Foto: unsplash-logoAles Nesetril

Publicado en Configuraciones
Jueves, 15 Noviembre 2018 22:26

LaTeX para escritores - Ejemplos simples

En mi último artículo hice una breve introducción a LaTeX para escritores que ahora voy a ilustar con ejemplos para aquellos que quieran ver el resultado antes de copiar y pegar el código LaTeX.

Portada de un libro:

Se define el título, el autor, la fecha... en el preámbulo y se invoca en el cuerpo del documento con \maketitle:

\documentclass[a5paper,12pt]{book}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\title{Fuenteovejuna}
\author{Lope de Vega}
\date{1614}
\begin{document}
\maketitle
\end{document}



Resultado:

portada.png

Otra opción de hacer una portada es con {titlepage} que nos ofrece mayor versatilidad a la hora de cambiar el tamaño de las letras, incluso la alineación de los textos:


\documentclass[a5paper,12pt]{book}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\begin{document}

\begin{titlepage}
\begin{center}
\begin{Huge}
Fuenteovejuna \\
\end{Huge}
\begin{large}
Lope de Vega \\
\end{large}
\end{center}
\begin{flushright}
\begin{small}
1614
\end{small}
\end{flushright}
\end{titlepage}
\end{document}


Cuyo resultado sería:

fuenteovejuna-opciondos.png

 

 

Resumen de artículos

Como ya comentaba en el anterior artículo sobre LaTeX, el resumen no vale para libros, sí para artículos o proyectos:

 

\documentclass[a5paper,12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}

\begin{document}
\begin{abstract}
Breve introducción a LaTeX para escritores en el que se ven las principales instrucciones de LaTeX para editar libros y poder exportarlos a otros formatos.
\end{abstract}
\end{document}



Genera:


abstract.png

Capítulos

\documentclass[a5paper,12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}

\begin{document}
    \section{''El mundo ordinario''}
    En el que se presentan los personajes y su entorno
    \section{''Llamada a la aventura''}
    El protagonista debe actuar en algo
    \section{''Rechazo de la llamada''}
    El protagonista prefiere mantenerse en su mundo ordinario
    \section{''Travesía del umbral''}
    Comienza la aventura
\end{document}



Que genera esto:

capitulos1.png

Una de las ventajas de LaTeX es que añadir un nuevo capítulo no necesita una nueva numeración. Los numera automáticamente.

\documentclass[a5paper,12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}

\begin{document}
\section{''El mundo ordinario''}
En el que se presentan los personajes y su entorno
\section{''Llamada a la aventura''}
El protagonista debe actuar en algo
\section{''Rechazo de la llamada''}
El protagonista prefiere mantenerse en su mundo ordinario
\section{''Encuentro con el mentor''}
Alguien influye en el protagonista para que acepte el reto
\section{''Travesía del umbral''}
Comienza la aventura
\end{document}



Como vemos, numera sin tener que añadir nada más que el nuevo capítulo:

capitulos2.png

Encabezamiento y pie de página



Vamos a poner en las páginas impares "Aprendiendo LaTeX" "Linux Center"
y en las páginas pares "Linux Center" "Aprendiendo LaTeX"
En todas, en el pie, el número de página:

[code]

\documentclass[a5paper,12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[RO,LE]{Aprendiendo \LaTeX}
\fancyhead[LO,RE]{Linux Center}
\fancyfoot[FO,FE]{\thepage}
\begin{document}

\section{Cabecera y pie de página}
\end{document}

[/code]

Que nos daría un resultado como:

cabeceraypie.pngAlineación de los textos

[code]

\documentclass[a5paper,12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[RO,LE]{Aprendiendo \LaTeX}
\fancyhead[LO,RE]{Linux Center}
\fancyfoot[FO,FE]{\thepage}
\begin{document}

\section*{Alineación}
\begin{center}
Este texto está centrado
\end{center}
\begin{flushleft}
Este texto está alineado a la izquierda
\end{flushleft}
\begin{flushright}
Este texto está alineado a la derecha
\end{flushright}
\end{document}

[/code]

alineacion.png
Anotaciones a pie de página

[code]

\documentclass[a5paper,12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[RO,LE]{Aprendiendo \LaTeX}
\fancyhead[LO,RE]{Linux Center}
\fancyfoot[FO,FE]{\thepage}
\begin{document}

\section*{Anotaciones a pie de página}
Fernando Lázaro Carreter \footnote{Zaragoza, 13 de abril de 1923 – Madrid, 4 de marzo de 2004} escribió <>.
\end{document}

[/code]



anotaciones.png


Varias columnas


Se indica en el preámbulo:

\usepackage{multicol}
\setlength\columnseprule{0.5pt}

 

Y en el cuerpo:

 

\begin{multicols}{3}
Texto
\end{multicols}

 

Aprovecho para explicar otro concepto: colocar un texto en apaisado, aquí me viene bien para no cortar los versos en las columnas.

Forma parte del paquete lscape, por lo que tendremos que añadir en el preámbulo:

\usepackage{lscape}

Y en el cuerpo delimitaremos con:

\begin{landscape}

\end{landscape}

 

Nos quedaría un código así:

[code]

\documentclass[a4paper,12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[RO,LE]{Aprendiendo \LaTeX}
\fancyhead[LO,RE]{Linux Center}
\fancyfoot[FO,FE]{\thepage}
\usepackage{lscape}

\usepackage{multicol}
\setlength\columnseprule{0.5pt}

\begin{document}
\begin{landscape}
\section*{Varias columnas}

\begin{multicols}{2}
\begin{verse}
\begin{center}
Luis de Góngora
\end{center}
Anacreonte español, no hay quien os tope,
que no diga con mucha cortesía,
que ya que vuestros pies son de elegía,
que vuestras suavidades son de arrope.

¿No imitaréis al terenciano Lope,
que al de Belerofonte cada día
sobre zuecos de cómica poesía
se calza espuelas, y le da un galope?

Con cuidado especial vuestros antojos
dicen que quieren traducir al griego,
no habiéndolo mirado vuestros ojos.

Prestádselos un rato a mi ojo ciego,
porque a luz saque ciertos versos flojos,
y entenderéis cualquier gregüesco luego.
\end{verse}
\columnbreak

\begin{center}
Francisco de Quevedo
\end{center}
\begin{verse}
Érase un hombre a una nariz pegado,
érase una nariz superlativa,
érase una alquitara medio viva,
érase un peje espada mal barbado;

Era un reloj de sol mal encarado.
érase un elefante boca arriba,
érase una nariz sayón y escriba,
un Ovidio Nasón mal narigado.

Érase el espolón de una galera,
érase una pirámide de Egito,
las doce tribus de narices era;

Érase un naricísimo infinito,
frisón archinariz, caratulera,
sabañón garrafal morado y frito.
\end{verse}
\end{multicols}

\end{landscape}
\end{document}

[/code]

 

 

Y el resultado sería:

 

doscolumnas.png

Si lo queremos ver mejor:

 



Publicado en Multiplataforma
Miércoles, 14 Noviembre 2018 23:09

Introducción a LaTeX para escritores

Con motivo del NaNoWriMo mucha gente está en este momento en plena ebullición creativa y escritora y por eso quiero explicar unas nociones de LaTeX orientado a escritores, ya que cuando un texto está escrito, reescrito, corregido ortotipográficamente, reescrito, revisado por otras personas, reescrito, corregido el estilo, reescrito... y reescrito unas cuantas veces más, el siguiente paso es compartirlo con más gente, bien mandando el manuscrito a otras personas para que lo lean, enviarlo a editoriales o autopublicarlo.

Y aquí es cuando llega el primer problema, ¿en qué formato mandarlo y cómo editarlo?

El mundo editorial es amplísimo y cada editorial selecciona los formatos de recepción de manuscritos que desea, por lo que lo mejor es maquetar el libro de tal manera que el cambio entre formatos sea lo más sencillo posible.

Y si amplio es el mundo editorial, mucho más amplio es el mercado, por lo que aquí no hay duda alguna: hay que publicar y compartir los contenidos en formatos que pueda leer el mayor número de personas: mobi, epub, pdf, ps, html...

Para poder convertir un texto a distintos formatos de una manera sencilla, rápida y con garantías de que en la transformación de formato no va a haber una transformación de la maquetación, lo mejor es editarlo en LaTeX o en html y luego exportarlo a otros formatos.

En este artículo hablaré de LaTeX para escritores y en otro artículo haré lo mismo con html. Y ustedes elijan en qué formato maquetar sus textos.

 

¿Qué es LaTeX?


LaTeX es un sistema de composición de textos que se basa en instrucciones independientes del texto, es decir, por un lado escribimos el texto y por otro le damos el formato.

De hecho, yo siempre lo hago así, tanto con LaTeX como con html. Primero escribo el texto y luego le doy formato.



¿En qué programa se edita LaTeX?



Otra ventaja de usar LaTeX es que podemos usar cualquier editor de texto:

  • vi
  • GNU Emacs
  • nano
  • gedit
  • Geany

 

¿Cómo se transforma un texto editado en LaTeX a otros formatos?


Es necesario un compilador de LaTeX, en GNU/Linux tenemos TexLive, que se puede instalar en modo básico:

sudo apt-get install texlive-base

o la versión completa:

sudo apt-get install texlive-full

Nunca he usado la versión básica por lo que me centraré en la completa. LaTeX es software libre y hay versiones para otros sistemas operativos. Una búsqueda en Google devolverá qué programas se pueden usar en otros sistemas distintos a GNU/Linux.


Exportar a pdf, html, epub u otros formatos


Desde la consola:
pdflatex fichero.tex

O también podemos usar un programa mucho más genérico: pandoc

pandoc -s original.tex -o fichero.extension

Pandoc es como convert, simplemente indicándole la extensión del fichero de salida le da ese formato.

Instrucciones de LaTeX

Visto cómo crear el entorno de trabajo para editar con LaTeX, pasemos a lo divertido: maquetar un texto.

Para ello, abrimos nuestro editor de texto favorito con el texto a maquetar, a poder ser en texto plano, y vamos a darle formato.

Veamos un ejemplo muy sencillo de uso:

Abrimos vi, o cualquier otro editor de textos, y escribimos:

\documentclass{article}
\begin{document}
¡Hola, mundo!

Este es mi primer texto con \LaTeX{}.

Estoy feliz^2: feliz por usar \LaTeX{} y feliz por compartirlo con ustedes.

Pero no sé si esta frase se verá bien. Estoy usando tildes y eso me puede hacer la puñeta.
\end{document}

Guardamos como holamundo.tex, o el_nombre_que_queramos.tex, y ejecutamos:

pdflatex holamundo.tex

Y nos saldrá esto:

primeraprueba.png

No se ve bien, así que vamos a mejorarlo:

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}

\begin{document}
¡Hola, mundo!

Este es mi primer texto con \LaTeX{}.
\pre
Estoy feliz^2:\newline
\textrm{feliz por usar \LaTeX{}} \newline
\textrm{y feliz por compartirlo con ustedes.}\newline
\pre
\textrm{Pero no sé si esta frase se verá bien. Estoy usando tildes y eso me puede hacer la puñeta.}
\end{document}

Ahora nos mostrará el texto bien formateado:

 

 

El ejemplo anterior era muy sencillo, pero vemos dos partes diferenciadas, primero le decimos que el tipo de documento es un artículo y luego trabajamos con el texto.

En LaTeX estas partes se conocen como preámbulo y documento.

El tamaño importa. Siempre, pero más en el preámbulo.

En LaTeX primero de todo hay que indicar el tipo de documento. Esto se hace con
\documentclass{tipo_de_documento}

Fundamentalmente hay tres tipos de clases de documentos:
article: artículos, textos cortos
report: se suele usar para proyectos
book: libros

Aunque hay más tipos, como letter para cartas, pero una carta bien se podría maquetar como "article".

Aquí le podemos indicar formato de la página. Bien si queremos un formato estándar como pueda ser DIN A4, DIN A5... o si queremos un tamaño especial y el tamaño de la letra. Es muy importante si vamos a maquetar un libro, elegir bien el tamaño del soporte sobre el que queremos que se lea el texto. Y que el tamaño de la letra sea el adecuado.

Luego según qué formato, el usuario podrá ampliar o reducir el tamaño de la letra o cambiar el tamaño del documento, pero eso es cuestión del usuario.

Veamos distintas formas de seleccionar el tamaño del documento.

Formato estándar:
 \documentclass[a4paper,10pt]{article}

En el tamaño del papel le podemos indicar:
a4paper
a4paper
...

Si tiene una o dos caras:
oneside
twoside

En el preámbulo también podemos añadir paquetes adicionales. Por ejemplo, si escribimos en español, podemos indicar que añada paquetes con eñes, tildes, diéresis...:

\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}

Interlineado

Se define con:
\renewcommand{\baselinestretch}{factor_de_interlineado}
Donde podemos indicar un número decimal como factor de interlineado.

De esta forma no tendremos que editar a mano cada vez que queramos que se muestre una tilde ni que nos pase como en el primer ejemplo.

Dando formato al texto

Una vez definido el preámbulo, pasamos a la edición del texto, que será lo que compilará LaTeX al transformar el fichero .tex a excepción de los comentarios, que son notas que nos podemos dejar para indicar si tenemos que revisar algo, si le dejamos apuntado algo a otra persona con la que estamos editando el texto o cualquier anotación que no queramos que se muestre en el documento final.

Comentarios

% Esto es un comentario, ya que va con un signo de porcentaje delante

Comienzo y fin de documento

\begin{document}

Este es el texto del documento. Todo lo que vaya después del end no será procesado. Pero lo que esté entre begin y end, sí será procesado.

\end{document}

Título

\title{Aquí escribo mi título}

Autor

\author{Nombre del autor}

Fecha de edición

\date{Fecha de edición}

Resumen del artículo o proyecto


El bloque abstract sólo funciona en report y article, no en book.

Esto vale:
\begin{abstract}
Breve introducción a LaTeX para escritores en el que se ven las principales instrucciones de LaTeX para editar libros y poder exportarlos a otros formatos.
\end{abstract}

Esto no vale:
\begin{abstract}
Este es el resumen del libro en el que unos personajes están en un lugar y les ocurren cosas.
\end{abstract}


Títulos y subtítulos

Cualquier libro puede tener capítulos, secciones, subsecciones, subsecciones de las subsecciones, párrafos, subpárrafos... Veamos sus instrucciones

\chapter{Título del capítulo}
\section{Título de la sección}
\subsection{Título de la subsección}
\subsubsection{Título de la subsección de la subsección}
\paragraph{Título del párrafo}
\subparagraph{Título del subpárrafo}

Estas instrucciones numeran automáticamente las secciones, subsecciones, los capítulos... por lo que no hace falta indicar la numeración y añadir una nueva instrucción supone que se renumeran automáticamente.

Si queremos que algún apartado no esté numerado se le indica al compilador con un asterisco entre la instrucción y el corchete de apertura del título:
\chapter*{Título no numerado de un capítulo}


Cabecera de las páginas


Se define con \pagestyle y puede tener los siguientes valores:
empty: vacía, no tiene ni cabecera ni pie de página
plain: cabecera vacía, numeración de página al pie.
headings: cabecera con el título de los capítulos y las secciones
myheadings: texto definido por el usuario

Si se usa
\pagestyle{myheadings}
Se define el texto a mostrar con:
\markboth{Texto alineado a la izquierda}{Texto alineado a la derecha}

Numeración de las páginas

Se definen con:
\pagenumbering{formato_de_numeración}
Que suelen tener los siguientes valores:
arabic -> numeración árabe del 0 al 9
Roman -> numeración romana en mayúsculas. Si se quiere en minúsculas, es roman
Alph -> numeración alfabética de la A a la Z mayúsculas. Si se quiere en minúsculas, es alph

Formato de las letras

Se puede cambiar el formato de tipo de letra con:
\textrm{Texto en letra redonda}
\textit{Texto en cursiva}
\texttt{Texto con tipografía de máquina de escribir}
\textbf{Texto en negrita}

Tamaño de las letras


Los tamaños de las letras también se puede modificar, dejo la lista por orden de la más pequeña a la más grande. Nótese que tanto la instrucción como el texto va entre llaves:
{\tiny Texto}
{\scriptsize Texto}
{\footnotesize Texto}
{\small Texto}
{\large Texto}
{\Large Texto}
{\LARGE Texto}
{\huge Texto}
{\Huge Texto}

Alineación del texto

\begin{center}
Este texto está centrado
\end{center}
\begin{flushleft}
Este texto está alineado a la izquierda
\end{flushleft}
\begin{flushright}
Este texto está alineado a la derecha
\end{flushright}

Poemas

Para maquetar poemas en LaTeX está el bloque "verse" que acota el comienzo y el final del poema. Los versos se separan con \\

\begin{verse}
\begin{center}
Escritura
\end{center}
Mi psicólogo mide doce centimientros\\
y vive en un estuche \\
terapias de papel y tinta \\
si la vida es pasajera mis palabras infinitas \\
abro el bloc pronto por la mañana \\
cuando la pizarra de la menta \\
aun no ha sido emborronada \\
por los sucesos de la jornada \\
\begin{flushright}
Xhelazz
\end{flushright}
\end{verse}

Nos daría un resultado así:

xhelazz.png

 

Acotaciones al pie de página

\footnote{Esto es una nota al pie de página}

piedepagina.png

Salto de párrafo

Para hacer un salto de párrafo tenemos dos opciones:
Dejar una línea en blanco entre párrafo y párrafo
Usar la instrucción \par

Sangría

Por defecto LaTeX sangra la primera línea de un párrafo. Para evitarlo:
\noindent

Salto de línea

\newline


Caracteres especiales

Aquí no voy a poner más que unos pocos caracteres especiales que puedan usarse de forma más o menos habitual por parte de escritores, que es el público objetivo de este artículo, aunque LaTeX permita trabajar con fórmulas matemáticas, no las veremos aquí.

^ Superíndice. Por ejemplo: E=mc^2
_ Subíndice. Por ejemplo: H_2O

Tildes y eñes

Aunque añadiendo los paquetes:
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
no necesitaríamos indicar a LaTeX que una letra lleva tilde o es eñe, dejo aquí los códigos por si alguien los necesitase o no pudiese usar paquetes adicionales:

\’a -> á
\’e -> é
\’i -> í
\’o -> ó
\’u -> ú

\’A -> Á
\’E -> É
\’I -> Í
\’O -> Ó
\’U -> Ú
 ̃
\~n -> ñ
\~N -> Ñ

Comillas españolas


Para escribir comillas españolas o latinas, se escribe menor que menor que, el texto a entrecomillar, mayor que mayor que y LaTeX lo transforma a las dobles comillas españolas:

<<Este texto está entre comillas españolas>>

Resultado:

comilla.png

 

Libros con varias columnas


Aunque esto es más habitual en periódicos o revistas, también podemos querer maquetar nuestro libro en varias columnas. Para eso usaremos el paqute multicol y definiremos la separación entre las columnas con columnseprule, después en el texto indicaremos el número de columnas:

\usepackage{multicol}
\setlength\columnseprule{0.5pt}
\begin{document}

\begin{multicols}{3}
\blindtext
\end{multicols}

Bloque de bibliografía

\begin{thebibliography}{00}
\bibitem{1}
Primera referencia
\bibitem{2}
Segunda referencia
\bibitem{3}
Tercera referencia
\end{thebibliography}

 

 

Publicado en Multiplataforma
Miércoles, 14 Noviembre 2018 02:06

Consejos para manejar texto directamente en Bash

Bash nos permite hacer millones de cosas. Es más, como nos permite hacer llamadas a otros programas, colocando las entradas y salidas adecuadas podremos producir cualquier resultado. Nos viene muy bien poder encadenar varios comandos, como en este tutorial en el que la salida de echo la pasamos como entrada de tr. Pero en este tutorial quiero hablar de operaciones que podemos hacer directamente en Bash, sin ningún programa extra o dependencia. Además, su realización será mucho más rápida ya que no tenemos que cargar en memoria un programa. Esto nos resultará de gran ayuda si utilizamos sistemas empotrados como Raspberry PI, o cualquier dispositivo con chips o almacenamiento reducidos. 


Eso sí, para muchos ejemplos necesitaremos Bash 4.x (aunque ya tiene unos años, la versión salió en 2009)
¡Manos a la obra!


1 - Reemplazar subcadenas

Aunque existen herramientas como sed o awk que, no estoy diciendo que no las usemos, porque son herramientas muy potentes. Cuando se trata de hacer un simple reemplazo de un texto por otro dentro de un texto más grande. O lo que es lo mismo, reemplazar subcadenas dentro de una cadena, podemos hacer lo siguiente:

 
texto="Los mejores tutoriales sobre Windows en WindowsCenter"
echo ${texto//Windows/Linux}
 

La clave está en tener el texto en una variable y luego hacer

 
echo ${VARIABLE//Cadena a buscar/Cadena que reemplaza}
 

O también podemos hacer lo siguiente:

 
texto="No hables de Linux en LinuxCenter"
echo ${texto/Linux/Windows}
 

Fijaos que ahora solo hay una barra (/) en lugar de dos. Con las sustituciones podemos hacer muchas cosas, incluso utilizar expresiones regulares.

2 – Contar caracteres de una cadena

Es muy común hacer lo siguiente:

 
texto="cadena de caracteres muy muy larga"
echo $texto | wc -m
 

Pero podemos hacerlo sin llamar a wc (cuidado, también podemos utilizar -c, pero tendremos problemas con caracteres especiales) de la siguiente manera:

 

 
texto="cadena de caracteres muy muy larga"
echo ${#texto}
 

Una nota, si comparáis los dos resultados, saldrán distintos, el primer método tendrá un carácter más. Eso es porque contamos el "intro" o mejor dicho, el retorno de carro, cuando utilizamos la primera forma. También podríamos hacerlo así:

 
texto="cadena de caracteres muy muy larga"
echo -n $texto | wc -m
 

 

3 – Recortar cadenas

 

¿Qué ocurre si queremos sacar una subcadena dentro del texto? Por ejemplo, tenemos esta cadena de texto:"Los mejores tutoriales sobre Linux en LinuxCenter"
Y queremos extraer 10 letras desde el carácter número 12, podemos hacer:

 
texto="Los mejores tutoriales sobre Linux en LinuxCenter"
echo ${texto:12:10}
 

O si queremos sacar desde el carácter 37 hasta el final, podemos hacer:

 
texto="Los mejores tutoriales sobre Linux en LinuxCenter"
echo ${texto:37}
 

 

4 - Saber si una subcadena existe

 

Si tengo este texto: "Esto es un pequeño tutorial de Linux en el que hablo de Bash."
Y quiero saber si una subcadena está presente, puedo hacer lo siguiente:

 
texto="Esto es un pequeño tutorial de Linux en el que hablo de Bash."
if [[ "$texto" == *"Windows"* ]]; then    
  echo "ESTÁ"; 
else
  echo "NO ESTÁ"; 
fi
 

 

5 - Extraer la ruta de un archivo

 

Si tenemos un nombre de archivo con la ruta completa y queremos extraer el directorio donde está localizado el fichero podemos hacer lo siguiente:

 

 
fichero="/usr/share/icons/hicolor/64x64/mimetypes/libreoffice-oasis-data.png"
echo "${fichero%/*}"
 


En este caso obtendremos: /usr/share/icons/hicolor/64x64/mimetypes/ . En teoría estamos eliminando de la cadena desde el final hasta la última / y devolvemos lo que nos queda. Al final obtenemos lo mismo que haciendo:

 

 
dirname /usr/share/icons/hicolor/64x64/mimetypes/libreoffice-oasis-data.png
 

 

6 – Extraer el archivo sin la ruta

 

Ahora si lo que queremos es sacar el nombre de archivo libreoffice-oasis-data.png sin la ruta, igual que hacemos con el comando basename. Podemos hacer:

 
fichero="/usr/share/icons/hicolor/64x64/mimetypes/libreoffice-oasis-data.png"
echo "${fichero##*/}"
 


En este caso, eliminamos todos los caracteres desde el principio hasta la última / que encontramos.

 

7 – Extraer el nombre de archivo sin la extensión

 

De la misma forma que hicimos para sacar la ruta del archivo, vamos a extraer la extensión de un archivo, de la siguiente manera:

 
fichero="/home/usuario/backups/2018_11_13.tar.gz"
echo "${fichero%%.*}"
 

 

8 – Sacar solo la extensión del archivo

 

Ahora queremos quedarnos con la extensión, para ello, propongo dos casos. En el primero, sacaremos todo lo que hay detrás del primer punto del archivo:

 
fichero="/home/usuario/backups/2018_11_13.tar.gz"
echo ${fichero##*.}
 


Aunque también puede ser que solo necesitemos la última extensión (desde el último punto hasta el final):

 
fichero="/home/usuario/backups/2018_11_13.tar.gz"
echo ${fichero#*.}
 

 

9 - Conocer la posición de una palabra dentro de una cadena

Queremos saber en qué letra se encuentra la palabra Linux dentro de la frase "Esto es un pequeño tutorial de Linux en el que hablo de Bash." así que hacemos lo siguiente:

 
texto="Esto es un pequeño tutorial de Linux en el que hablo de Bash."
tmp="${texto%%Linux*}"
echo ${#tmp}
 


Si os fijáis, es parecido a lo que hacíamos para extraer el nombre de archivo (solo que ahora en lugar de un punto, buscamos la palabra Linux, y luego contamos las letras de la cadena temporal generada. Incluso la palabra a buscar puede ser otra variable. Eso sí, tendremos un problema cuando la palabra no exista, que nos devolverá la posición del final de la cadena, entonces podemos hacer lo siguiente:

 
busca="Linux"texto="Esto es un pequeño tutorial de Linux en el que hablo de Bash."
tmp="${texto%%$busca*}"
[[ "$texto" = "$tmp" ]] && echo -1 || echo ${#tmp}
 

Con lo que si el texto no se encuentra, devuelve -1

Bonus

Por último, quiero dejaros para copiar y pegar todo esto en forma de funciones para poder incorporar fácilmente a vuestros scripts estas utilidades:

#!/bin/bash
function replace()
{
    local text="$1"
    local busc="$2"
    local repl="$3"
    echo ${text//$busc/$repl}
}
function replace_once()
{
    local text="$1"
    local busc="$2"
    local repl="$3"
    echo ${text/$busc/$repl}
}
function longitud()
{
    local text="$1"
    echo ${#text}
}
function recorta()
{
    local text="$1"
    local desde=$2
    local hasta=$3
    [ -z $hasta ] && echo ${text:$desde} || echo ${text:$desde:$hasta}
}
function encuentra()
{
    local text="$1"
    local subt="$2"
    [[ "$texto" == *"Windows"* ]] && true || false
}
function ruta_archivo()
{
    local fich="$1"
    echo "${fich%/*}"
}
function base_archivo()
{
    local fich="$1"
    echo "${fich##*/}"
}
function extension_archivo()
{
    local fich="$1"
    echo ${fich##*.}
}
function extension_archivo2()
{
    local fich="$1"
    echo ${fich#*.}
}
function posicion_cadena()
{
    local text="$1"
    local subc="$2"
    tmp="${text%%$subc*}"
    [[ "$texto" = "$tmp" ]] && echo -1 || echo ${#tmp}
}

Ahora Probamos las funciones

replace "I love Windows, forever Windows" "Windows" "Linux"replace "I love Windows, forever Windows" "Windows" "Linux"
replace_once "I love Windows. Windows never closes unexpectedly" "Windows" "Linux"
longitud "Esta es una cadena muy larga que no se cuantas letras contiene"
recorta "Desde que uso GNU/Linux soy más feliz" 14 9
recorta "Desde que uso GNU/Linux soy más feliz" 24
if encuentra "$(uname)" "Linux"; then echo "Buen sistema el tuyo!"; fi
ruta_archivo "/home/usuario/proyectos/github/tutoriales/cadenas_bash.txt"
base_archivo "/home/usuario/proyectos/github/tutoriales/cadenas_bash.txt"
extension_archivo "/home/usuario/proyectos/github/tutoriales/cadenas_bash.tar.bz2"
extension_archivo2 "/home/usuario/proyectos/github/tutoriales/cadenas_bash.tar.bz2"
posicion_cadena "No sé dónde está Linux en todo este texto" "Linux"
¡Espero que les haya sido útil!
Publicado en Programación

En Kdenlive 17 han cambiado la ubicación de algunas funciones en los menús. Y algunas han desaparecido, como la de invertir los clips. Por extrapolación de cómo se hace en otros programas he deducido la solución que os comparto:

Sobre el clip que se desea invertir, botón derecho / Agregar efecto / Moviemiento / Velocidad. Y le damos una velocidad negativa al clip.
Si queremos un vídeo que siga el orden normal y otro que vaya hacia atrás, lo que podemos hacer es sobre el fichero en la carpeta del proyecto: botón derecho / Trabajos del clip / Duplicar el clip con cambio de velocidad. Y le damos una velocidad negativa al clip.

Publicado en Multimedia
Sábado, 10 Noviembre 2018 22:46

Imágenes rotadas en ImageMagick

Para girar o rotar una imagen con ImageMagick tenemos el parámetro -rotate que debe ir seguido por los grados de rotación a girar la imagen.

Veamos un ejemplo. Primero, creamos una imagen:

 

convert -size 250x250 xc:Blue cuadroazul.png



cuadroazul.png
Y una vez que tenemos la imagen, lo podemos rotar:

convert cuadroazul.png -rotate 45 cuadroazul-rotado.png


cuadroazul-rotado.png

Al rotar una imagen nos podemos encontrar con dos problemas, pero para ambos problemas hay solución:
que nos podemos encontrar que el color de fondo no nos guste, que se soluciona con -background
que el resultado sea una imagen con un tamaño que nos descuadre el resto de la composición, que se soluciona con -extent

Veamos los dos con ejemplos. Primero, el color de fondo:

convert cuadroazul.png -background Red -rotate 45 cuadroazul-rotado-confondorojo.png
cuadroazul-rotado-confondorojo.png

Y segundo, el tamaño de la imagen, que pasa de 250x250 píxeles a 356 × 356 píxeles. Para mantenerlo en 250x250 podemos recortar con -extent 250x250:

convert cuadroazul.png -background Red -rotate 45 -extent 250x250 cuadroazul-rotado-confondorojo-ajustado.png
cuadroazul-rotado-confondorojo-ajustado.png
Pero aquí nos coge como punto de gravedad el punto 0,0. Si queremos centrarlo, deberemos indicarlo con el parámetro -gravity Center:

convert cuadroazul.png -background Red -rotate 45 -gravity Center -extent 250x250 cuadroazul-rotado-confondorojo-ajustado-centrado.png
cuadroazul-rotado-confondorojo-ajustado-centrado.png

Visto esto, ya somos capaces de imitar con ImageMagick a Kazimir Malévich y hacer nuestra versión de Cuadro blanco sobre fondo blanco con un:

convert -size 500x500 xc:GhostWhite -background NavajoWhite -rotate 45 -gravity NorthEast -extent 1000x1000 cuadroblancosobrefondoblanco-imagemagick.png


cuadroblancosobrefondoblanco-imagemagick.png



Publicado en Multimedia

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
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í