Cómo Firmar Tus Fotos
Este artículo fue publicado en The Flight of the Platypus, la versión en inglés de El Cantar de la Lluvia, en junio del 2006. Fue el segundo artículo que publiqué ahí. La verdad no tengo claro por qué no lo publiqué también aquí. Más vale tarde que nunca, entonces!
* * *
He estado postenado fotos cada vez más grandes en mi otro blog, El Cantar de la Lluvia, y quería incorporarles aunque sea un poco de información de autor. No me refiero a nada exagerado como Digimarc, ni una filigrana de cuadro completo. Quería una forma fácil y automatizada de colocarle una frase a lo largo del borde derecho, rotado en 90º, y ojalá con una herramienta lo suicientemente astuta como para detectar si la imagen es vertical u horizontal.
Probé varios programas para OS X, algunos gratis, algunos demos, y terminé detestándolos. Decidí crear mi propia herramienta. Al fin y al cabo, tengo a mi disposición una librería de manipulación de imágenes libre y fácil de usar (el cual, agregaré de manera poco humilde, escribí yo) llamado PNGwriter.

Escribí PNGwriter para que programadores amateur pudieran acceder a directamente a los pixeles de una imagen, sin tener que mamarse el trabajo de aprender a usar una biblioteca de imágenes primaria.
Mis objetivos para este proyecto fueron los siguientes.
Después de algunas horas de escribir código compuesto, en su mayor parte de, de errores y traspiés (hace un año que no programo) logré producir algo que cumplía con los requerimientos mencionados. Descubrí que la idea de proveer el "copyright string" al momento de ejecutar el programa como opción de línea de comando no era tan buena idea, ya que es difícil lograr que el shell se comporte bien con caracteres especiales, espacios, etc. Finalmente opté por un procedimiento alternativo.
El programa, que decidí llamar watermarker, toma tres argumentos; ni más ni menos. Aquí hay un ejemplo del uso del programa.
Los nombres de archivo son arbitrarios y los archivos pueden estar en cualquier ubicación. El único requerimiento es que la imagen sea un PNG de 24 bits por pixel (muy importante), que el archivo copyrightstring.txt contenga el string relevante en formato UTF-8 (o en ASCII normal, dado que los caracteres ASCII normales en codificación UTF-8 son simplemente caracteres normales ASCII) y que watermarker.config contenga la siguiente información.
A modo de ejemplo, mi configuración se ve así:
Éste es el código fuente del programa. Lo estoy distribuyendo como código libre. Lo único que requiero es que si lo modificas y publicas, deberás atribuirlo correctamente ("Basado en watermarker, por Paul Blackburn"). Y si lo usas, deja un comentario y cuéntame cómo te fue.
(Nota: si encuentras '>' o '<' en lo que sigue, reemplázalos por '>' y '<'. Son algunos que se me escaparon al convertir el código C++ a HTML, y tratar de lidiar con la imbecilidad con patas que es el editor online de Blogger.com).
(Nota 2: Dado que el editor online de Blogger.com fue programado por una manada de chimpancés ebrios, cada vez que edito este artículo se come cualquier parte del código que esté entre <>. Ergo al código siguiente le faltan #includes y partes varias. Para evitar confusiones, puedes bajar un .zip del archivo original aquí.)
Finalmente, si quieres que el programa procese todas las imágenes en un directorio, quizás te sirva este shellscript.


Y así es como se firman las fotos, cuando todos los programas disponibles son una caca.
* * *
He estado postenado fotos cada vez más grandes en mi otro blog, El Cantar de la Lluvia, y quería incorporarles aunque sea un poco de información de autor. No me refiero a nada exagerado como Digimarc, ni una filigrana de cuadro completo. Quería una forma fácil y automatizada de colocarle una frase a lo largo del borde derecho, rotado en 90º, y ojalá con una herramienta lo suicientemente astuta como para detectar si la imagen es vertical u horizontal.
Probé varios programas para OS X, algunos gratis, algunos demos, y terminé detestándolos. Decidí crear mi propia herramienta. Al fin y al cabo, tengo a mi disposición una librería de manipulación de imágenes libre y fácil de usar (el cual, agregaré de manera poco humilde, escribí yo) llamado PNGwriter.

Escribí PNGwriter para que programadores amateur pudieran acceder a directamente a los pixeles de una imagen, sin tener que mamarse el trabajo de aprender a usar una biblioteca de imágenes primaria.
Mis objetivos para este proyecto fueron los siguientes.
- Crear un programa que tomara las fotos de 630 pixeles de lado exportados desde iPhoto, una vez que haya hecho la selección de imágenes para el artículo, y que les agregue una frase.
- La frase deberá ser fácilmente modificable, nada de dejarlo grabado en el programa mismo.
- El programa deberá aceptar strings en formato UTF-8 (mi amor por la codificación de texto UTF-8 no tiene límites).
- El string debería ir a lo largo del borde derecho de la imagen y rotado en 90º con el fin de ser discreto.
- El string debería ser escrito automáticamente con negro sobre fondos claros y con blanco sobre fondos oscuros.
- El string posiblemente irá combinado con el fondo, con un efecto artificial de transparencia.
- El programa deberá ser fácilmente ejecutado desde un shell script, con opciones de línea de comando, para que el proceso pueda ser automatizado.
- El programa deberá agregar el string "-wmk" al nombre de los archivos procesados, y el original no se tocará.
- Creo que esta lista es lo suficientemente larga.
Después de algunas horas de escribir código compuesto, en su mayor parte de, de errores y traspiés (hace un año que no programo) logré producir algo que cumplía con los requerimientos mencionados. Descubrí que la idea de proveer el "copyright string" al momento de ejecutar el programa como opción de línea de comando no era tan buena idea, ya que es difícil lograr que el shell se comporte bien con caracteres especiales, espacios, etc. Finalmente opté por un procedimiento alternativo.
El programa, que decidí llamar watermarker, toma tres argumentos; ni más ni menos. Aquí hay un ejemplo del uso del programa.
./watermarker watermarker.config copyrightstring.txt IMG00001.png
Los nombres de archivo son arbitrarios y los archivos pueden estar en cualquier ubicación. El único requerimiento es que la imagen sea un PNG de 24 bits por pixel (muy importante), que el archivo copyrightstring.txt contenga el string relevante en formato UTF-8 (o en ASCII normal, dado que los caracteres ASCII normales en codificación UTF-8 son simplemente caracteres normales ASCII) y que watermarker.config contenga la siguiente información.
- Desplazamiento horizontal (X-offset), en pixeles, de la esquina inferior derecha del string vertical a ser dibujado, contando a partir del lado derecho de la imagen.
- Desplazamiento vertical (Y-offset), en pixeles, de la esquina inferior derecha del texto a ser dibujado, contando a partir del extremo inferior de la imagen.
- Tamaño del font.
- Coeficiente de transparencia artificial. Valor decimal entre 0.0 y 1.0. 1.0 es 100% opaco.
- Un archivo TrueType (.ttf) válido.
A modo de ejemplo, mi configuración se ve así:
2
2
9
0.6
VeraBD.ttf
2
9
0.6
VeraBD.ttf
Éste es el código fuente del programa. Lo estoy distribuyendo como código libre. Lo único que requiero es que si lo modificas y publicas, deberás atribuirlo correctamente ("Basado en watermarker, por Paul Blackburn"). Y si lo usas, deja un comentario y cuéntame cómo te fue.
(Nota: si encuentras '>' o '<' en lo que sigue, reemplázalos por '>' y '<'. Son algunos que se me escaparon al convertir el código C++ a HTML, y tratar de lidiar con la imbecilidad con patas que es el editor online de Blogger.com).
(Nota 2: Dado que el editor online de Blogger.com fue programado por una manada de chimpancés ebrios, cada vez que edito este artículo se come cualquier parte del código que esté entre <>. Ergo al código siguiente le faltan #includes y partes varias. Para evitar confusiones, puedes bajar un .zip del archivo original aquí.)
#include
#include
#include
#include
#include
using namespace std;
int main(int argc, char * argv[])
{
if(argc != 4)
{
std::cout << "Wrong number of args (" << argc - 1 << "). Usage: ";
std::cout << "watermarker " ;
std::cout << "\n" ;
std::cout << "UTF8 string file should be a plain text or";
std::cout << "UTF8-formatted text file containing the copyright string";
std::cout << "to be used. \nConfig file should be a text file containing,";
std::cout << "on separate lines, \n";
std::cout << " pos_x;\n pos_y\n font_size\n blend coef.\n";
std::cout << " fontfile\n";
exit(1);
}
// Get copyright string into a binary array.
char * copyrightfile = argv[2];
char * copyright;
long size;
ifstream file (copyrightfile, ios::in|ios::binary|ios::ate);
if (! file.is_open())
{
std::cout << "Error opening UTF8 text file."; exit (1);
}
size = file.tellg();
file.seekg (0, ios::beg);
copyright = new char [size];
file.read (copyright, size);
file.close();
// Load configuration parameters.
std::ifstream params (argv[1]);
if (! params.is_open())
{
std::cout << "Error opening config file"; exit (1);
}
string filename(argv[3]);
string fontfile;
int pos_x;
int pos_y ;
int font_size;
double angle;
double blend;
params << pos_x;
params << pos_y;
params << font_size;
params << blend;
params << fontfile;
params.close();
// Create PNGwriter instance
pngwriter image(1,1,0,"caca.png");
image.readfromfile(filename.c_str());
char * fn;
fn = new char[1024];
strcpy( fn, fontfile.c_str());
double average;
int minx, miny, maxx, maxy;
average= 0.0;
angle = 1.57079633;
minx = image.getwidth() - pos_x;
maxx = image.getwidth();
maxy = pos_y + image.get_text_width_utf8(fn, font_size, copyright);
miny = pos_y;
// Calculate the average intensity of the image
// behind the text.
for(int xx=minx; xx <=maxx; xx++)
{
for(int yy=miny; yy <=maxy; yy++)
{
average = average + image.dread(xx,yy);
}
}
average = average/( (double)( (maxx-minx)*(maxy-miny) ));
std::cout << "Average image intensity in text area: " << average;
std::cout << ", Number of pixels taken: " << (maxx-minx)*(maxy-miny);
std::cout << ", text will be";
// Plot the text on the image.
if(average>0.5)
{
std::cout << " black." << std::endl;
image.plot_text_utf8_blend( fn, font_size,
image.getwidth() - pos_x, pos_y, angle,
copyright,
blend,
0.0, 0.0, 0.0);
}
else
{
std::cout << " white." <<std::endl;
image.plot_text_utf8_blend( fn, font_size,
image.getwidth() - pos_x, pos_y, angle,
copyright,
blend,
1.0, 1.0, 1.0);
}
// Rename the file, add -wmk to the basename.
char * newfilename;
char fl[1024];
strcpy(fl, filename.c_str());
newfilename = strtok (fl, "." );
strcat(newfilename, "-wmk.png" );
image.pngwriter_rename(newfilename);
image.settext(filename.c_str(), "Paul Blackburn",
"Copyright 2006, 2007, 2008, 2009 Paul Blackburn, paulwb AT gmail.com, All Rights Reserved.",
"Watermaked with PNGwriter plus a small program called watermarker.");
// Write the PNG image to disk.
image.close();
delete [] fn;
return 0;
}
#!/bin/bash
for caca in *.jpg
do
base=`basename $caca .jpg`
png=${base}.png
convert -depth 24 $caca $png
./watermarker watermarker.config copyrightstring.txt $png
convert -depth 8 ${base}-wmk.png ${base}-wmk.jpg
echo "Finished " ${base}-wmk.jpg
done
Aquí hay dos imágenes que he firmado. El programa eligió blanco para la primera imagen, y negro para la segunda.for caca in *.jpg
do
base=`basename $caca .jpg`
png=${base}.png
convert -depth 24 $caca $png
./watermarker watermarker.config copyrightstring.txt $png
convert -depth 8 ${base}-wmk.png ${base}-wmk.jpg
echo "Finished " ${base}-wmk.jpg
done


Y así es como se firman las fotos, cuando todos los programas disponibles son una caca.


PNGwriter
Dando Jugo En La Parva
La Ruta Del Cóndor, Invierno '09
Al Cerro Renca Con Alvaro
Al Valle Las Arenas Con Camilo
De Albuquerque A Santiago, Invierno '09
Retrospectiva Fotográfica 2008
Las Lagunas Del Santuario 3: Montañas y Sorojchi
Rally Dakar Argentina-Chile '09
De Valparaíso A Ritoque
A Lagunillas Con Camilo
Solito A La Laguna Piuquenes
Al Embalse El Yeso Con Rodrigo
A La Yesera Con Alvaro
De Albuquerque A Santiago, Verano '09
Y Ahora, Al Norte!
Cómo Firmar Tus Fotos
Jemez National Forest
Hacia Las Sangre de Cristo
Valles Caldera
Los Álamos, NM
La Vuelta A Los Yunai Esteits
Cajón del Maipo Nevado
Santiago En HDR
Cerro Pochoco
Cerro Renca
Cabezón
Del Río Puerco a Río Rancho
Vuelta Jémez
San Lorenzo Canyon
Sandía Peak, Madrid, Cerrillos
Lagunillas '08
Tranque Las Cenizas y La Invernada
San Francisco de Mostazal y Alrededores
Reñaca Beach y el J Cruz
Tranque La Luz y Playa Las Docas
La Ruta del Cóndor
Valle Nevado y Laguna Piuquenes
Valle de las Arenas 2
De La Parva a Piedra Numerada
Valle De Las Arenas
Las Lagunas del Santuario 2: Laguna Los Ángeles
Carreras En Leyda 4
El Tabo Y La Central Hidroeléctrica El Sauce
Explorando Los Cerros De Lampa
A Baños De Colina Por El Otro Camino
Las Minas De La Cuesta La Dormida
Las Lagunas del Santuario
Segunda Caravana De Protesta Por Un Tag Justo
Caravana De Protesta Contra El Tag
Enduro En Lagunillas
Embalse El Yeso Y Termas Del Plomo
Paseo A Peñuelas
Cerro Chena
Carreras en Leyda 3
Lagunillas 2
Baños de Colina 2
Carretera Austral: Índice Visual
La Pequeña Gigante y Termas Del Plomo 2
De Vuelta En Dos Ruedas
Carreras en Leyda 2
Quantum Optics III En Pucón
Meseta En Chicureo
Chanta, Picante, Roto: Recoge Tu Botella De Cerveza Y Lárgate A Tu Casa
Aviones y Cerros
Camino Cortado
Lubricación De La Suspensión Trasera Y Ajuste De Válvulas #2
Paseo A Lagunillas
Laguna Verde 2
Antipaseo A Aculeo
Ahora Sí, Cerro El Roble
Baños De Colina
Algunos Caminan Sobre La Nieve
Carreras 400 cc En Leyda
La Serena, Parte 3: La Vuelta A Santiago
Casi Cerro El Roble
A Curacaví Con ARV
Un Toro, Dos Vacas, Un Zorro
La Serena, Parte 2B: Valle Del Elqui
Escape A Cuesta La Dormida
Ajuste De Válvulas
La Serena, Parte 2A: Coquimbo Y La Recova
Barro Y Pinos
La Serena Parte 1
Enchúlame El Tubo De Escape
Paseo A Laguna Verde
Paseo a la Mina
Termas El Plomo
Acampando en Colliguay
Paseo a Portillo
Paseo a Olmué y Con Con
Siete Tazas
Mirando cómo se va el día que me trajo hasta aquí
Motos de Buenos Aires
Paseo a Talca con el Grupo Adach
Torres y Cerros
Las Trancas 05
Maria Pinto, Melipilla, Aculeo
El Carburador y Yo




1 Comments:
Fabuloso =D
Post a Comment
<< Home