domingo, 10 de agosto de 2014

Tip: Cómo agregar texto a una imagen con ImageMagick

Hola!

    Necesito agregar la fecha a una imagen. Algún día les contaré qué estoy haciendo :P



    Tengo esta imagen, saca de The Humble Yogini - Observations from the realm of Samsara:








Y con este comando, ¡pasen y vean! , le agregamos tóscamente la fecha:
 /usr/bin/convert \
        Computer_color_spectrum.jpg \
        -pointsize 38 -font URW-Bookman-L-Light \
        -annotate +80+100 "$(date --rfc-3339=date)"  \
         /tmp/colores.gif
 


Y quedó así:



         Tada!





Saludos!
 -- Diego.



sábado, 9 de agosto de 2014

Cómo sacar algunos sigils ($@%&), parte 4

Esto es... no sé qué es. Es una chanchada. Es otro forma de sacar sigils. No creo que deba usarse, pero acá está:

Cuando uno usa objetos en perl (sean hechos con Moo(se) o de cualquier otra forma) (pero hay que usar Moo(se) :) ), hace algo así:

use MiClase;
my $objeto = MiClase->new();

Y después usamos los atributos y métodos de $objeto. Supongamos que sirve para guardar frases célebres:

use Quote;
my $q = Quote->new();
$q->set_phrase("Un problema imaginario es la raíz de
                               todo pensamiento negativo");

print "La frase es: " . $q->get_phrase . "\n";

Con esto podemos tener (instanciar) un montón de objetos "Quote".

my $q = Quote->new();
my $otra_q = Quote->new()
my $otro = Quote->new()
Pero también podríamos evitar los sigils, no instanciando (creando) un objeto, sino usando la clase. Esto es horrible, y no debe hacerse, pero WTH, lo hago igual :)

 use Quote;
Quote->set_phrase("Un problema imaginario es la raíz de
                                    todo pensamiento negativo
");
print Quote->get_phrase() . "\n";
 Este es el código de Quote.pm

package Quote;

use strict;

our $self;

# Cuando se llama a la clase directamente, el primer argumento
# es justamente el nombre de la clase. No nos interesa.
sub set_phrase {
  my $class = shift;
  my $phrase = shift;
  $self->{phrase} = $phrase;
}

sub get_phrase {
  my $class = shift;
  return $self->{phrase};
}

1;
Sinceramente, no sé cuán horrible es esto. Qué efectos secundarios tendrá. Le encontré por lo menos una, que es que la clase/objeto es global. Osea, si le ponés un valor a la frase, lo va a tener dentro de toda sub. Supongo que hay alguna forma de cambiarlo. Les dejo un gato:






domingo, 3 de agosto de 2014

Pequeño ejemplo de crear archivos ical con Perl

¡Hola de nuevo!

    Estuve trabajando en un programa que en una parte guarda eventos en un archivo ical. Me costó un poco encontrar un buen módulo. El mejor y más sencillo es Tie::iCal, aunque verán que tiene un bug al final.

sub guardar_evento {
    # segundos: tiempo que falta para el final del evento
    # contenido: la descripción del evento (ej "Reunión con Pepe")
    my ($segundos, $contenido) = @_;
    my %my_events;
    my $calfile = "/.mycalendar.ics";
    tie %my_events, 'Tie::iCal', $calfile or die "Failed to tie file!\n";

    # Summary no puede tener enter, así que lo cambio por \n
    $contenido =~ s/\n/\\n/gs;



    # Cada evento es una entrada, y c/u tiene un UID
    my $uid = time();
    $my_events{$uid} = [
    'VEVENT',
             {
              'SUMMARY' => $contenido,
              'DTSTART' => secs_to_ical_date(0),
              'DTEND'   => secs_to_ical_date($segundos),
             }
    ];
    untie %my_events;
}



# Esta func agrega $secs segundos a la fecha/hora actual
# y lo devuevle en el formato para iCal
sub secs_to_ical_date {
    my ($secs) = @_;


  
    # Usamos Time::Piece, que viene con Perl y nos lo hace más facil
    my $now = mk_time_piece_now();
    $now += $secs;
    my $date = $now->strftime( "%Y%m%d" )  . "T" .
               $now->strftime( "%H%M00" ) . "Z";
    return $date;
}

sub mk_time_piece_now {
      # Esto pasa porque el objeto Time::Piece que resulta de

      # localtime tiene mal el timezone. Así que lo hago string,
      # y lo vuelvo a hacer objeto. Grrrr.
      my $now        = localtime;
      my $now_string = $now->strftime("%d-%m-%Y %H:%M");
         $now        = Time::Piece->strptime($now_string, 

                                            "%d-%m-%Y %H:%M");
      return $now;
}



Pero resulta que el archivo iCal queda mal hecho, así que este pedazo de código lo arregla. Reporté el bug acá.

open( my $ical, "<", ".mycalendar.ics") or die $!;

my $head = "";
foreach my $n (1, 2, 3) {
     my $temp = <$ical>;
     $head = $head . $temp;
}


my $body = "";
while ( <$ical> ) {
    next if ( /BEGIN:VCALENDAR/ );
    next if ( /VERSION:/ );
    next if ( /PRODID:/ );
    next if ( /END:VCALENDAR/ );
    $body = $body . $_;
}

my $foot = "END:VCALENDAR\n";


# Y escribirlo a un archivo.
use File::Slurp;
write_file( ".mycalendar_fixed.ics", $head . $body . $foot );



Dos bugs. No está nada bien :(

Les dejo un conejo.



Saludos!
-- Diego



Slides sobre Moose, la implementación moderna de OO de perl

estoy con fiaca de escribir :P

Diapositivas, o tutorial con pocas letras sobre el sistema de OO de perl (el nuevo), con todos los roles, mixins y magia que hay en el mundo de la programación OO.


Les dejo un camello:


Algo más quería postear, pero no me acuerdo...


viernes, 11 de julio de 2014

Como pasar un color a transparente en una imagen

Acabo de sorpenderme de los sencillo que es esto. Había abierto el gimp, pero ImageMagick la rompe.

convert image.png -transparent <color> nueva_img.png
donde <color> es un color, justamente. Yo lo probré con white, y funcionó.


sábado, 14 de junio de 2014

Cómo ver algunos partidos sin flash

Nota posteriror: Estoy funciona, salvo que por lo menos en mi caso, la conexión a el sitio web que da el streaming de video se vuelve *muy* lenta cuando hay un partido, así que no lo puedo ver. Sin embargo, queda acá por si alguien quiere mirar otros programas, o tiene una mejor conexión .

----

Hola,

    Ayer estuve viendo cómo ver los partidos del mundial por canal 7 (y mirá que no dije ATC) sin usar el navegador. En linux, el plugin de flash funciona lento, así que quería verlo con un programa específico para mirar videos, como mplayer o vlc.

    Resulta que para usan un protocolo llamado "HDS". Les contaría de qué se trata, pero no tengo ganas. En definitiva, hay que usar el script AdobeHDS.php que se puede bajar acá. El script necesita la URL del archivo "manifest", que es el que describe de dónde bajar el stream de video, y el contenido del encabezado "Referrer" del pedido HTTP.

    Para encontrar la URL y el valor del encabezado, yo usé firefox, así: 
  • Abrir el sitio web donde está la señal del canal para ver.
  • Abrir la pantalla de información sobre el tráfico de red, yendo a Tools -> Web Developer -> Network, o apretando Ctrl + Shift + Q.
  • En el navegador, poner a ejecutar el stream de video.
  • Hacer click con el botón derecho sobre la línea del archivo "manifest". Elegir "Copy URL". En la imagen, la línea correspondiente.



  • Hacer click con el mouse sobre esa misma línea. Aparecerá un panel a la derecha:



  • Buscar en ese panel, bajo el título "Request headers", la línea que dice "Referrer", y copiar la URL que le corresponde.
  • Ejecutar AdobeHDS:php con los dos parámetros tal que guarde el video en un archivo:
 php AdobeHDS.php --manifest URL_del_manifest --referrer URL_de_Referrer --outfile partido.flv 
  • En otra terminal, ejecutar mplayer o el visor de videos que uno quiera.

Eso es todo. Tiene, sin embargo, algunas contras.

Primero, hay que elegir a mano la calidad. Si se elige una más alta de la se puede, el video se va a cortar, porque mplayer va a llegar al fin del archivo. Osea, mplayer le va a "ganar" a AdobeHDS.php. Con volver a ejecutar todo es suficiente, pero bien puede pasar.

El protocolo HDS está pensado para enviar video en tiempo real, evitando el buffering. Esta solución lo usa (el cache de mplayer), así que el video tiene una demora de unos segundos. Osea, que puede pasar que el vecino grite "¡Gol!" y el video empiece a mostrar la jugada. A mi me parece muy conveniente, así puedo distraerme de partidos aburridos y alguien me avisa cuando está por pasar algo interesante. Pero seguramente sea una contra para mucha gente.

Saludos
 -- Diego.



lunes, 26 de mayo de 2014

Cómo sacar algunos sigils ($@%&), parte 3

Algunas ideas que se me ocurrieron a partir de las dos entradas anteriores:

  • Podemos hacer que al declarar las variables en BEGIN, ya que estamos, le agreguemos un default.

BEGIN {
        var "espia" => "James Bond";
        var "jefe"    => "M5";
        var "familia_que_ignora_la_verdad"  => "No tiene";
}
Solo hay que cambiar un poco el corazón de todo esto:
# Esta es la subrutina que genera las demas.
sub var ($;$) {
        say "Creando $_[0]... Hecho!" if $debug;
        my $p = "main"; # El namespace esta fijo en "main". TODO.

        # Si la sub que queremos que exista se llamara "espia" esto de abajo
        # sería: *main::espia = sub ...
        # El segundo argumento, si hay, es el default de la "variable" / sub.
        no strict 'refs';
        *{"${p}::${_[0]}"} = sub (;$) :lvalue {
                state $internal = "**internal**";
                if ( $_[0] ) { $internal = $_[0]; }
                return $internal;
        };
        &{"${p}::${_[0]}"} = "$_[1]" if $_[1];
        use strict;
}


  • También podríamos poner otras opciones en las definiciones:

BEGIN {
        var "nombre" => "NN", validate => { $_[0] !~ /admin|root/i };
        var "jefe"    => "M5",     validate => { $_[0] != nombre };
        var "edad" => 1, max => 18;
}
  • También podríamos poner otros nombres en vez de var, con otros restrains:

BEGIN {
        var "nombre" => "NN", validate => { $_[0] !~ /admin|root/i };
        bool "es_jefe"    => "true",     validate => { ... };
        int "edad" => 1, max => 18;
}
 Ya estoy delirando, porque para eso debe haber varios módulos hechos por gente que sabe más que yo :) Pero este, "casero", tiene muy pocas líneas de código.

Saludos!
 -- Diego.