Archivo de la etiqueta: as3

Fotomatón, o haciendo fotos instantáneas online

La idea es sencilla, conectas con la webcam de tus usuarios, les haces una foto y la envías a una galería donde se pueden ver los caretos de tus visitantes. La implementación es casi tan sencilla como la teoría y el resultado es increíble y original.

El sistema es el mismo que utilizaba BloggerSnap, un servicio que tuvo un increíble éxito en su lanzamiento y que parece cerrado desde abril. Hace un año estaba por encima del puesto 40.000 en Alexa, seguramente estuvo incluso más alto. Imagino que sería muy complicado mantener el coste del ancho de banda con tanta popularidad. Hace un par de años estuvimos a punto de lanzar un servicio similar y lo desestimamos ya que no veíamos la manera de monetizarlo mientras que, a poco que tuviese éxito, los gastos se dispararían.

En un escenario normal dependerías de software que el usuario tendría que instalar para que se hiciese la foto y posteriormente te la enviase, con lo cual no conseguirías el objetivo de la instantaneidad, pero existe una solución que permite hacerlo todo mediante una aplicación online: Flash, en nuestro caso Flex 😛 .

La potencia de la plataforma Flash en el tratamiento de audio y vídeo va mucho más allá de lo que pueda parecer y permite crear aplicaciones multimedia avanzadas con participación del usuario de manera bastante rápida. Si además dispones de dinero suficiente, puedes combinarlo con Flash Media Server y los límites los pondrá tu imaginación. Otro día crearemos un videochat 😉 .

La clave es el acceso a la cámara y al micrófono del equipo que permite la plataforma Flash previa autorización del usuario, obviamente. Si lo autorizas, el player conectará con tu webcam y comenzará a mostrar el vídeo de la misma y, si la aplicación lo requiere, enviarlo a otros usuarios. Lo mismo se puede hacer con el audio.

En el taller de hoy haremos una pequeña aplicación para crear una galería de fotos instantáneas en web/blog. Los usuarios que lo deseen pueden hacerse la foto con su propia webcam y ésta quedará alojada en la galería. Simple pero llamativo.

La aplicación constará de dos partes:

  • Zona de capturas: una aplicación desarrollada en Flex que permitirá a los usuarios hacerse fotos sin más necesidad que tener una webcam.
  • Galería: una sencilla página html donde se listan todas las fotos que se han hecho los usuarios.

Capturando imágenes

Aunque pueda parecer algo muy complicado veremos a continuación que la facilidad de conectar con la webcam en Flex es impresionante.

Nuestra aplicación consta de dos únicos componentes, una imagen y un botón. La imagen nos aportará simplemente algo de estilo y el botón lo utilizaremos de disparador de nuestra cámara de fotos online.

Hay tres tareas bien diferenciadas:

  • Conectar con la webcam.
  • Capturar la foto.
  • Enviarla a nuestro servidor.

Conectar con la webcam

Con este sencillo código estaremos visualizando en nuestra aplicación la webcam que el usuario tenga conectada a su equipo.

private function insertWebcamVideo():void{
	var videoHolder:UIComponent = new UIComponent();
	if(Camera.names.length>0){
	   camera = Camera.getCamera();
	   if(camera==null || camera.width==-1 || camera.height==-1 || camera.fps==-1){
	   		Alert.show("Lo sentimos, no tienes cámara", "Error", 4, null, null, iconoAlerta);
	   		captura.enabled=false;
	   		camera=null;
	   }else{
		   camera.addEventListener(StatusEvent.STATUS, cerrar);
		   video = new Video(camera.width, camera.height);
		   video.attachCamera(camera);
		   videoHolder.addChild(video);
		   videoHolder.width=video.width;
		   videoHolder.height=video.height;
		   videoHolder.visible=true;
		   videoHolder.y=0;
		   caja.addChildAt(videoHolder, 0);
		   caja.removeChild(fotillo);
	   }
	}else{
   		Alert.show("Lo sentimos, no tienes cámara", "Error", 4, null, null, iconoAlerta);
   		captura.enabled=false;
	}
	//Security.showSettings(SecurityPanel.CAMERA);
}

Tan fácil como comprobar primero si tiene webcam (sino, obviamente, no puede hacerse fotos 😛 ) y posteriormente añadirla a un componente de vídeo que habremos incorporado a un UIComponent para mostrarlo en la aplicación. En este momento ya tenemos la cámara del usuario en vivo en la aplicación.

Capturar la foto

Teniendo el flujo de vídeo en la aplicación, queremos que cuando el usuario presione el botón «Capturar» se le haga la foto.

private function getSnapshot():void{
	var snapshot:BitmapData = new BitmapData(video.width, video.height, true);
	var m : Matrix = new Matrix();
	snapshot.draw(video, m);
	var jpegEnc:JPGEncoder=new JPGEncoder(75);
	var jpegDat:ByteArray = jpegEnc.encode(snapshot);
	var img_src:String = base64Encode(jpegDat);

	if(img_src.length>1600){
		//imagen correctamente capturada
	}else{
		Alert.show("La imagen capturada parece estar vacía", "Error", 4, null, null, iconoAlerta);
	}
}

Con este otro código conseguimos este efecto. Se obtiene una captura bit a bit del objeto de vídeo y se comprime en JPEG para enviarla al servidor. ¡Ya tenemos la foto hecha!

Enviar la foto

Utilizaremos un HTTPService para enviar por POST la foto que hemos realizado y que guardaremos en una base de datos. Añadimos a la función anterior el código para enviar la foto.

private function getSnapshot():void{
	var snapshot:BitmapData = new BitmapData(video.width, video.height, true);
	var m : Matrix = new Matrix();
	snapshot.draw(video, m);
	var jpegEnc:JPGEncoder=new JPGEncoder(75);
	var jpegDat:ByteArray = jpegEnc.encode(snapshot);
	var img_src:String = base64Encode(jpegDat);

	if(img_src.length>1600){
		var temp:Object=new Object();
		temp.imagen=img_src;
		httpService.send(temp);
		cargandoWindow = ventanaEspera(PopUpManager.createPopUp(this as DisplayObject, ventanaEspera, true));
	}else{
		Alert.show("La imagen capturada parece estar vacía", "Error", 4, null, null, iconoAlerta);
	}
}

<mx:httpservice id="httpService" showbusycursor="false" useproxy="false" method="POST" resultformat="text" url="upload.php" result="onResult()"
fault="onHTTPFault(event)" />

Ya está. El script upload.php de tu servidor recibirá por POST la variable «imagen» con el contenido de tu foto. Sólo habrá que guardarla en un archivo y habrás terminado la parta más ¿complicada? del proyecto.

if($_POST['imagen'] & strlen($_POST['imagen'])!=0 & strlen($_POST['imagen'])>1600){
        $bmd=base64_decode($_POST['imagen']);
        $im = fopen("fotos/foto.jpg",'w');
        fwrite($im,$bmd);
        fclose($im);
}

Antes de guardar la imagen en disco podrías añadir un registro a una base de datos que te permita generar después la galería. Esa parte queda a tu elección.

Generando la galería

Esta es la parte fácil, simplemente creas un script PHP (o en el lenguaje que prefieras) que liste las fotos que has ido guardando en la base de datos paginando como creas oportuno. Creo que sobran más comentarios para algo tan fácil.

Conclusiones

Hoy hemos visto cómo de una manera extremadamente rápida y sencilla se puede conectar con la webcam (y el micrófono) de los usuarios. Sólo hemos visto como hacer una fotografía instantánea de lo que se está viendo a través de la cámara, pero el sistema abre un inmenso mundo de posibilidades.

Descárgate aquí el código del proyecto.

Generador de códigos de barras en AS3

Hoy vamos a ver un ejemplo sobre cómo generar códigos de barras al vuelo utilizando ActionScript3. Un código de barras es la representación mediante líneas paralelas de distinto grosor de un código numérico o alfanumérico. Esta representación lineal los hace de fácil interpretación para un lector láser. No creo que se necesiten más explicaciones, todo el mundo sabe lo que es un código de barras.

Los códigos de barras lineales pueden ser de distintos tipos, en el ejemplo de hoy generaremos EAN y C128. EAN es el más utilizado a nivel mundial y el utilizado en España, así que será el que nos ocupe hoy. Mi trabajo está basado en la clase para generar códigos C128 de Friedrich Dimmel (lo siento, no localizo el link original). La clase que genera el código EAN no es ni más ni menos que la reescritura en AS3 de la que trae phpBarcode  y adaptada para generar la secuencia de líneas que se dibujan bajo la lógica de Friedrich Dimmel en vez de generar una imagen con GD como hace la clase original. Como casi siempre, este pequeño desarrollo lo hice hace un par de años para un sistema de control de stocks, no me critiquéis mucho el código :P.
swfobject.embedSWF(«/wp-content/uploads/2008/10/codigosdebarras1.swf», «codigosdebarras», «470», «350», «9.0.000»);

Flash del generador

Un código EAN son 13 dígitos, 12 de información (código de país, empresa y producto) y un dígito de control que ayuda a verificar que la decodificación posterior es correcta.
Para crear la imagen de nuestro código simplemente debemos llamar a la clase generadora  con los parámetros:

  • Código: la cadena que queremos convertir a código de barras.
  • Alto de la imagen generada.
  • Tipo de código (EAN o C128).
  • Mostrar el texto del código (opcional).
  • Color de fondo (opcional).

Por ejemplo:

BarcodeGenerator.generateBarcode("3456789012345", 50, "EAN");

Como hemos visto, el último dígito es de control, con lo que con introducir los 12 dígitos con valor será suficiente, la clase generará el treceavo automáticamente. No voy a explicar detalladamente como generar los códigos EAN, hay suficiente literatura acerca del algoritmo googleando un poco y para ver el resultado lo mejor es que examinéis el código fuente que os dejo más abajo. Creo que lo más curioso e importante es ver cómo generamos la imagen una vez tenemos generado el código de líneas.

public static function generateBarcode(code:String="0", height:Number=60, tipo:String="EAN", showText:Boolean=true, backgroundColor:uint=0xffffff):Canvas {
    var can:Canvas = new Canvas();
    can.horizontalScrollPolicy = "off";
    can.verticalScrollPolicy = "off";
    can.height = height;
    can.setStyle("backgroundColor", backgroundColor);
    var sBarcode:Shape;
    var rect:Rectangle;
    var bd:BitmapData;
    var img:Image;
    var bitmap:Bitmap;
    if(tipo=="EAN"){
      var barcode:BarcodeEAN = new BarcodeEAN();
      barcode.code = code;
      barcode.barHeight = height;
      if(showText) {
        barcode.barHeight -= 15;
      }
      var k:Object=barcode.barcode_encode_ean(code);
      if(!k.bars) return new Canvas();
      var bars:String=k.bars;
      var text:String=k.text;
      sBarcode = barcode.generateBarcode();
      rect = new Rectangle(0, 0, (sBarcode.width / 2) + 1, barcode.barHeight);
      bd = getBitmapData(sBarcode, rect);
      img = new Image();
      bitmap = new Bitmap(bd);
      img.source = bitmap;
      can.addChild(img);
      var chars:Array=text.split(" ");
      var n:String;
      var v:String;
      var total_y:Number=40;
      for(n in chars){
        v=chars[n];
        if (StringUtil.trim(v)){
          var inf:Array=v.split(":");
          var fontsize:Number=inf[1]/1.8;
          var fontheight:Number=30;
          var label:Label = new Label();
          label.text = inf[2];
          label.x = Number(inf[0])-2;
          label.y = fontheight;
          label.setStyle("fontSize", 9);
          label.setStyle("paddingBottom", 0);
          label.setStyle("paddingLeft", 0);
          label.setStyle("paddingRight", 0);
          label.setStyle("paddingTop", 0);
          can.addChild(label);
        }
      }
    }
    return can;
}

En realidad es tan sencillo como crear una imagen a partir de lo que nos devuelve la clase generadora EAN (un objeto de tipo Shape). Finalmente si queremos imprimir el código en la propia imagen tendremos que poner cada letra en el sitio que le toca, no van en cualquier lado.

¿Qué tal si hacemos el proceso contrario con un lector casero?

Os dejo el código fuente del proyecto.

Actualización del cliente IRC online flash, versión 1.0

Hace unos meses anunciábamos el lanzamiento de un cliente IRC realizado en Flash (Flex para ser más exactos) en colaboración con Irc-Hispano. Bien, pues no nos hemos quedado ahí. Durante los últimos meses hemos estado haciendo ajustes y mejoras en la aplicación. Se han solucionado algunos errores que fueron apareciendo y añadido algunas funcionalidades nuevas y llamativas.

El sistema lleva ahora mismo cuatro meses online. En julio hubo 4.500 usuarios únicos diarios de media mientras que en agosto se sobrepasaron los 5.000. Ahora mismo estamos por encima de esa cifra, creo que es un dato más que excelente y más si se compara con los que había antes de su implantación.

Coincidiendo con esta actualización hemos decidido etiquetarla como v.1.0 pues ya es completa, funcional y estable. Hasta ahora estábamos en R.C., hasta tres R.C. pasaron por las manos de los usuarios.

Han sido muchos meses de duro trabajo, no sólo de desarrollo puro y duro, sino además de documentación y planificación. EL RFC del protocolo del IRC ha sido nuestra principal compañía durante mucho tiempo.

Irc Online con fotos

Pero sin duda lo más revolucionario que se ha hecho es permitir a los usuarios poner fotos instantáneas al más puro estilo Messenger. Desde ahora los usuarios ya no tienen que salir del IRC para mostrarse fotos entre ellos. Las fotos, para respetar la intimidad y privacidad de los usuarios, son independientes entre distintas conversaciones, puedes mostrar tu foto a un usuario y no a los demás e incluso tener cada usuario con una foto distinta. Nunca entendimos que a nadie se le haya ocurrido antes permitir a los usuarios verse, a fin de cuentas todos sabemos que es la finalidad de un chat. ¿Qué será lo siguiente? ¿Quizás vídeo? 😉 .

El único inconveniente que tiene el sistema de fotos online es que, por el momento,  solamente lo pueden utilizar aquellos usuarios del webchat y, aunque cada día son más, no cabe duda que el grueso de la gente que chatea utiliza software especializado como mirc y el IRcap.

¿Alguien se atreve con un plugin para mirc para las fotos instantáneas?

Insertar imágenes en RichTextEditor de Flex

Esta semana, a raíz de un mensaje en la lista de correo de Made in Flex, recordé una de las primeras aplicaciones que hice en Flex hace ya dos años con lo cual me lancé a recuperar aquél código, limpiarlo de cosas supérfluas y publicarlo. Os dejo también el enlace a un post mio en la lista Flexcoders donde explicaba como hacerlo, de hecho ha sido mucha la gente que, a partir de ese post, me ha escrito preguntando detalles.

Para los puristas, os aviso de antemano que puede haber cosas que no funcionen bien, código extraño y mil historias más, es un código que tiene dos años, si hacéis cuentas veréis que justo estos días Flex2 cumple dos años. Sí, lo comencé con las primeras betas de aquella versión. Lo único que he hecho ha sido crearlo en Flex3 y dejar la aplicación limpia para que se vea el funcionamiento. Si me váis a dejar un comentario diciendo que tal o cual cosa no funciona bien, podéis ahorrárosla.

Como una imagen vale más que mil palabras, aquí tienes el ejemplo y el código fuente de todo el proyecto.

Todos a los que en algún momento se nos ocurrió utilizar Flex para crear un gestor de contenidos nos hemos dado con un grave problema en la frente: el componente ideal para escribir y actualizar contenidos, RichTextEditor, NO permite, por defecto, insertar imágenes, con lo cual pierde prácticamente su utilidad. Escarbando en la ayuda, sin embargo, te das cuenta de que entre los tag HTML soportados por el componente Textarea se encuentra <IMG>, con lo que, a priori, nada impediría insertar una imagen. En efecto así es y en eso se basa todo este artículo/proyecto. Un detalle importante es que la utilización de imágenes no está bien conseguida en el propio Flash Player, con lo que si comenzamos a añadir y quitar imágenes llegará un momento en el que todo el Textarea será inestable y hará cosas extrañas.

El proyecto se basa en dos componentes, nuestro editor de texto y un explorador de archivos. Desde el editor tendremos un botón Insertar imagen que abrirá un explorador al más puro estilo del escritorio del sistema operativo donde nos mostrará los archivos que tenemos en el servidor, pudiendo subir y eliminar. La lógica del explorador con el servidor la he eliminado al máximo, dejando sólamente unos XML estáticos que listan las carpetas e imágenes disponibles. Para hacerlo bien haríais un script con salida similar a esta pero que liste lo que en realidad hubiese en una ruta de tu servidor.

Nuestro editor de texto

Intentaré explicar como hice todo el proceso, pero fue hace bastante tiempo así que es posible que se me olvide algún detalle.

La idea era hacer un editor avanzado, con las caracteristicas que le faltaban al RichTextEditor original:

  • Insertar imágenes.
  • Posibilidad de añadir datos tabulados (que no tablas como tales).
  • Cambiar el color de fondo del editor para, por ejemplo, crear texto en color blanco.
  • Eliminar todo el texto (e imágenes).
  • Editor avanzado de links.
  • Botón guardar texto (lo insertaría en tu base de datos)

Partimos para ello de un RichTextEditor al que le quitamos el botón predefinido de Añadir link y añadimos nuestros nuevos botones. Siguiendo el código entenderás lo que hacen, por lo que nos centraremos en el de imágenes que es el objeto del artículo. Primero os explico en qué consiste el botón de tabular datos. Es muy sencillo. Si quisiésemos, en el RichTextEditor, crear una tabla de valores con el tabulador, no podríamos, ya que al presionar tabulador saldría el foco del Textarea de escribir  y se iría, por defecto, al selector de fuente. Para solucionarlo añadimos un botón que lo único que hace es añadir un carácter de tabulación (t) en el texto, con lo que comprobaréis que ya puedes tabular datos perfectamente. Muy útil el truco.

Pasemos pues al botón de insertar imágenes. El botón, tal y como expliqué anteriormente, abre el popup del explorador de archivos, con lo que esta parte la veremos en la siguiente sección. Cuando en el explorador seleccionamos la imagen a insertar se devuelve el control al editor y es éste el que añade la imagen. Para añadir la imagen inserta en la posición del cursor el tag <IMG> con los parámetros necesarios. Aparentemente no tiene más truco, pero al empezar a probar cosas nos damos cuenta que sí que lo tiene.

Para empezar, si guardamos el htmltext de este RichTextEditor en la base de datos y posteriormente intentamos recuperarlo recibiremos un desagradable error de validación XML. Quiero aclarar antes de nada, que este error me ocurría en aquél entonces, quizás, ojalá, las ultimas versiones de Flex lo hayan solucionado, te ahorraría muchos problemas. La causa del error de validación era que internamente, aunque tu añadieses un tag <img … /> (o <img…></img>) válido, el editor te devolvía siempre <img .. > , es decir, el XML sin cerrar, con lo cual al cargarlo de nuevo saltaba error de validación. Para solucionar este problema creamos un método desProcesaTexto que lo que hace es convertir todos los tags <img..> no válidos a tag válidos, con lo que tenemos el primer problema resuelto. Utilizando expresiones regulares será extremadamente sencillo.

var pattern:RegExp = /<IMG([^>]*)>/gi;
texto=texto.replace(pattern, "<IMG $1 ></IMG>");

Segundo problema. Una vez insertamos una imagen, ¿cómo podemos quitarla o modificarla? Aquí viene parte del truco. La idea, básicamente, es añadir a cada imagen un link de manera que al hacer click en ella se nos abra un popup que nos permita eliminar la imagen o modificar sus atributos. Esto genera otro inconveniente. Cuando queremos recuperar el contenido del Textarea para guardarlo en la base de datos debemos eliminar estos links falsos añadidos para la interfaz de usuario, pero que no queremos que salgan cuando se muestre el texto. Por contra, cuando cargamos un texto desde la base de datos debemos procesar los atributos de imágenes para añadirles este link y podamos operar con ellos.

var temp:XML=XML("<texto>"+texto+"</texto>");
var allTags: XMLList;
var item:XML;
var tempitem:XML;allTags= temp..IMG;
for each(item in allTags) {
    var xlcParent:XMLListCollection = new XMLListCollection(item.parent().parent().children());
    tempitem=XML(xlcParent.toXMLString());
    xlcParent.setItemAt(item, 0);
}

Como se aprecia en el código, bucamos todos los tags <IMG> y, asumiendo que todos tendrán un tag <A> anterior, reemplazamos el nodo <A> completo por el <IMG> y todo solucionado, más sencillo de lo que parece una vez se entiende el procedimiento.

Para contemplar estas peculiaridades cada vez que asignamos el texto al componente o cada vez que lo recuperamos, tenemos los siguientes métodos:

public function getHtmlText():String{
    return desProcesaTexto(this.htmlText);
}

public function setHtmlText(texto:String):void{
    this.htmlText=procesaTexto(texto);
}

No hay mucho más que explicar. Como peculiaridad, veremos como procesaríamos los tags <IMG> cuando cargamos un texto nuevo en el componente. La idea, básicamente, es añadir el link que nos permita modificarla, pero este link necesita conocer los datos de la imagen (src, width, height..).

allTags= temp..IMG;
for each(item in allTags) {
    var xlcParent:XMLListCollection = new XMLListCollection(item.parent().children());
    var iIndex:int = xlcParent.getItemIndex(item);    idlink=Math.round((Math.random()*100000)*(Math.random()*100000));
    nuevoNodo="<A href="event:IMAGEN##||##"+item.@ID+"##||##"+item.@SRC+"##||##"+item.@WIDTH +
    "##||##"+item.@HEIGHT+"##||##"+item.@VSPACE+"##||##"+item.@HSPACE+"##||##"+item.@ALIGN +
    "##||##"+idlink.toString()+"" ID=""+idlink.toString()+"">"+xlcParent.toXMLString()+"</A>";

    xlcParent.setItemAt(XML(nuevoNodo), iIndex);
}

Sencillo.

El explorador de archivos

El explorador de archivos es un componente bastante resultón que, si lo trabajas un poco, te puede solucionar muchas tareas. Igual que el Explorador de Archivos de Windows, tienes a la izquierda un árbol de directorios y a la derecha los archivos de la carpeta seleccionada y sus detalles. Arriba tenemos botones para subir archivos nuevos y crear nuevas carpetas (la lógica de estos botones es cosa tuya) y, sobre todo, un combo para cambiar el modo de ver los archivos de manera que puedes ver la lista de los mismos o las miniaturas. Si, si listas imágenes verás un thumbnail de las mismas, perfecto para nuestro editor. No voy a enrollarme mucho más con el funcionamiento ya que en el código fuente tienes todo lo necesario. El evento interesante es el doble click sobre un archivo, que devuelve el control a una nueva ventana donde puede configurar los parametros de la imagen a insertar. Con el ejemplo lo entenderas.

En tu editor deberás crear los métodos adecuados en el servidor para listar las carpetas y archivos de tu directorio de uploads si quieres que todo sea dinámico y el usuario pueda organizarse por su cuenta los archivos.

Tal como había comentado, no he sido tan explícito como en otras ocasiones. Si tienes algún problema no dudéis en dejar un comentario e intentaré solucionarlo a la mayor brevedad posible.

Aquí tienes el ejemplo y el código fuente de todo el proyecto.

Cliente IRC online en Flex en colaboración con Irc-Hispano

Ayer lunes entró en producción uno de nuestros proyectos más ambiciosos junto a Irc-Hispano, la red de chat más grande e importante del mundo hispanohablante. Se puede acceder a nuestra aplicación desde aquí.

Cliente IRC Flash

Hacía muchos años que queríamos algo así pero no existía la tecnología necesaria. Los que usamos Internet desde hace muchos años, en mi caso desde 1994, sabemos que antes de que existiese el Messenger ya estaba el IRC, el chat de toda la vida. El problema era que se necesitaban programas concretos para utilizarlo (Mirc) y después había que saber configurarlo y tener unas nociones básicas (servidores, nicks, canales, kick, ban, join…). Muy complicado para el usuario no experto. Así apareció a finales de los 90 la probablemente mayor utilidad de los applets de Java: el cliente IRC online. Ahora los usuarios ya no necesitaban conocimientos ni instalarse nada, simplemente accedían a la web, ponian su nick, el canal donde querían chatear, y a «relacionarse». Incluso aparecieron clientes IRC en HTML, muy útiles pero sin las opciones de usabilidad de las otras.

La idea era muy buena, pero nadie había contado con los problemas asociados: necesidad de la máquina virtual de Java, lentitud, pesadez, etc. Los usuarios no tenían más que problemas.

Corría entonces el año 2002 cuando se nos ocurre hacer lo mismo pero en Flash, una tecnología presente en la mayoría de navegadores y con una implantación mucho mayor que la de Java. Nos pusimos a investigar y nos llevamos una gran decepción, no había forma de comunicarse con un servidor IRC estandar, en aquél momento Flash sólo disponía de xmlsocket, que permitía conectarse a hosts remotos pero siguiendo unas especificaciones especiales.

Todo estaba perdido hasta 2006. En junio de este año Adobe (que ya había absorvido a Macromedia) lanzaba Flex2 y junto a él la versión 9 de Flash Player con la funcionalidad más esperada por nosotros: la posibilidad de crear sockets binarios. Con esto ya se podían hacer en Flash clientes pop/smtp, ftp y, por supuesto, IRC. Esto marcó un antes y un después y nos pusimos de inmediato a planificar nuestro sueño. Tardamos más de seis meses en meternos de lleno en el proyecto puesto que ya estábamos trabajando en otros.

Desde el primer día tuvimos que comenzar a pelearnos con el RFC del protocolo IRC, fundamental para conocer el funcionamiento del sistema ya la sintaxis de todos los mensajes de ida y vuelta con el servidor. Una vez tuvimos el núcleo básico fue relativamente sencillo construir toda la interfaz de usuario sobre él, creando los comandos y acciones así como los eventos de respuesta. El primer problema era que había muchas opciones distintas, así que fuimos fijando prioridades y trabajando sobre ellas.

Cuando teníamos una versión básica pero funcional y debido a las políticas de seguridad de la máquina virtual Flash, nos pusimos en contacto con Irc-Hispano y desde el primer momento les encantó la idea, los planes y nuestro prototipo, con lo que fue sencillo llegar a un acuerdo que beneficiase a ámbas partes. Mientras nosotros desarrollábamos, la gente de Irc-Hispano se ocupaba del testing.

Hablando ya técnicamente, y aunque esté mal que yo lo diga, se ha hecho un trabajo impresionante exprimiendo toda la potencia de Flex. Hemos conseguido integrar bastantes cosas que a simple vista son casi imposibles de utilizar en Flex, como los smileys en un área de texto, o los colores de fondo. Documentándonos por aquí y por allí y viendo lo que habían conseguido otros conseguimos adaptar ciertos sistemas a nuestras necesidades quedando el conjunto francamente bien.

Desde el primer momento tuvimos claro que la única forma de conseguir sacar una aplicación de este tipo era usando técnicas de desarrollo ágiles, y así lo hicimos, preparando periódicamente versiones funcionales de lo que hubiese y poniéndola a disposición de los usuarios para que nos aportasen el feedback necesario, no solo de errores sino también de usabilidad y funcionalidad en general. La experiencia ha sido perfecta y todo el equipo ha salido beneficiado de este modo de trabajo, ya que se elimina automáticamente el estrés del miedo a los cambios cuando el producto está ya terminado.

Y así llegamos hasta hoy en que se lanza públicamente. Se han hecho muchas más funcionalidades de las previstas inicialmente y seguramente se irán haciendo muchas más a medida que se vaya utilizando. Por nuestra parte ha sido un esfuerzo enorme en horas de trabajo y quebraderos de cabeza para hacer y solucionar problemas sin respuesta aparente, pero el resultado ha valido la pena.

A partir de ahora esperamos ir corrigiendo bugs y añadiendo mejoras, ideas no nos faltan y seguramente habrá muchas sorpresas ;). Algún día también refactorizaremos :P.

Domina rápidamente Adobe Air

Leo en el blog de Mario Casario esta entrada donde anuncia la disponibilidad gratuita y bajo licencia Creative Commons de la guía Adobe AIR 1 for JavaScript Developer en formato PDF.

Para los que no lo sepáis, Air es la tecnología de Adobe para desarrollar rápidamente aplicaciones de escritorio utilizando otras tecnologías ya existentes: HTML, Javascript y Flash. Así de sencillo, aplicando lo que ya sabes puedes generar aplicaciones de escritorio multiplataforma (Windows y Mac ahora mismo, Linux en camino).

Air está de moda y más desde la compra de Twhirl por parte de Seesmic, de hecho Twitter es de lo más utilizado para crear aplicaciones Air.

Con Air puedes crear rápidamente pequeñas aplicaciones con acceso al sistema de archivos local, bases de datos locales (SQLlite), arrastrar y soltar… todo lo que necesitas para crear tus aplicaciones.

Os aseguro que es increíble lo que se puede hacer con poquísimas líneas de código.

Precargar CSS con la aplicación Flex

A la hora de crear una aplicación Flex con temas (skins) intercambiables o personalizables, uno de los problemas principales con el que nos encontramos es la precarga del mismo. En general tendríamos por un lado nuestro swf de la aplicación y por el otro el del css que estamos cargando. Asumiendo que cargásemos el tema en el evento creationComplete con

 StyleManager.loadStyleDeclarations("micss.swf", true )

tendríamos un problema de sincronización. Los usuarios no verían el look&feel de nuestra aplicación hasta que se hubiese cargado el swf del tema, mientras tanto se vería el tema por defecto, lo que ofrece una imagen bastante pésima de la aplicación.

Para solucionarlo recurrimos a precargar el tema junto a la aplicación, de manera que cuando lancemos el evento creationComplete, el swf está ya en la caché del navegador y casi instantáneamente se aplica sin que el usuario note apenas retardo.

Para hacer la precarga personalizada de la aplicación deberemos extender el componente DownloadProgressBar. Además de para nuestro propósito de cargar el css, podemos también aprovechar para traducir los textos de la percarga, de manera que aparezcan en castellano, un detalle para los usuarios.

Os dejo el código de ejemplo.

Lo primero será decirle a nuestra aplicación que utilice nuestra precarga personalizada y cargar nuestro swf de estilos. Recuerda que cuando se ejecute el evento creationComplete, este swf estará ya en caché del navegador, no se cargará de nuevo desde el servidor.

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
creationComplete="StyleManager.loadStyleDeclarations("micss.swf", true )"
preloader="com.xplota.mainloader.AppProgressBar">

Ahora veremos rápidamente como personalizamos el componente.

package com.xplota.mainloader{
	import mx.preloaders.*;
	import flash.events.ProgressEvent;
	import flash.text.TextFormat;
	import mx.controls.Image;
	import flash.display.Sprite;
	import flash.events.Event;
	import mx.events.FlexEvent;
	import mx.events.RSLEvent;
	import flash.display.Loader;
	import flash.net.URLRequest;
	public class AppProgressBar extends DownloadProgressBar{
	 	private var loader:Loader;
	 	private var _preloader:Sprite;
		public function AppProgressBar() {
	 		super();
	 		//Configuramos las etiquetas
	 		downloadingLabel="Cargando..."
	 		initializingLabel="Iniciando..."
	 		// Set the minimum display time to 2 seconds
	 		MINIMUM_DISPLAY_TIME=2000;
	 	}

		// Override to return true so progress bar appears during initialization.
	 	override protected function showDisplayForInit(elapsedTime:int, count:int):Boolean {
	 		return true;
	 	}

		// Override to return true so progress bar appears during download.
	 	override protected function showDisplayForDownloading(elapsedTime:int, event:ProgressEvent):Boolean {
	 		return true;
	 	}

	 	//cambiamos el color de fuente de la precarga
		 override protected function get labelFormat():TextFormat{
	 		var tf:TextFormat=new TextFormat();
	 		tf.color=0xFFFFFF;
	 		tf.font = "Verdana";
	 		tf.size = 10;
	 		return tf;
	 	}

		override protected function createChildren(): void {
	 		super.createChildren();
	 	}

		 //una vez ha cargado la aplicacion cargamos el tema usando la misma precarga
	 	override protected function completeHandler(event:Event):void{
	 		this.label="Cargando tema...";
	 		loader=new Loader();
	 		loader.load(new URLRequest("css/obsidian.swf"));
			loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressHandler);
	 		loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteHandler);
	 	}

		private function loaderCompleteHandler(event:Event):void{
	 		_preloader.addEventListener(FlexEvent.INIT_PROGRESS, initProgressHandler);
	 		dispatchEvent( new Event( Event.COMPLETE ) );
	 	}

		override public function set preloader( preloader:Sprite ):void{
	 		_preloader=preloader;
	 		preloader.addEventListener(ProgressEvent.PROGRESS, progressHandler);
	 		preloader.addEventListener(Event.COMPLETE, completeHandler);
	 		preloader.addEventListener(RSLEvent.RSL_PROGRESS, rslProgressHandler);
	 		preloader.addEventListener(RSLEvent.RSL_COMPLETE, rslCompleteHandler);
	 		preloader.addEventListener(RSLEvent.RSL_ERROR, rslErrorHandler);
	 	}
	}
}

En el constructor de la clase configuramos las etiquetas en nuestro idioma. Aprovechamos para sobreescirbir el método labelFormat de manera que podamos modificar la fuente de las etiquetas para acomodar la precarga a nuestro diseño.

Lo importante llega al sobreescribir el método set preloader. Lo principal es capturar el evento Event.COMPLETE, que se disparará cuando termine la precarga y antes de que se inicie la aplicación. Cuando se dispare este evento lanzaremos la carga de nuestro CSS pasando al mismo preloader el progreso de carga de los estilos, de manera que reaprovechamos la misma precarga. Cuando termine de cargar el CSS será cuando lancemos manualmente el evento Event.COMPLETE del componente, lo cual iniciará la aplicación teniendo ya nuestros estilos en caché.

Este método no sirve sólo para cargar los estilos, podemos precargar cualquier archivo que necesitemos. Nosotros lo hemos utilizado para cargar, además de los estilos, un archivo de configuración XML. Puedes, además, ir cambiando la etiqueta de carga: cargando configuración, cargando tema, etc.

Recuerda que para jugar a extender componentes lo más sencillo siempre es ver como está construído el original. Haciendo ctrl+click en el código sobre un tipo se nos abrirá automáticamente el código fuente del mismo, pudiendo explorar los métodos que tienes disponibles, los que puedes sobreescribir y el funcionamiento completo.

Ajax vs. Flex

O Flex vs. Ajax. O Silverlight. O JavaFX. Menudo debate. A muchos no les gustará y sé que generará mucha controversia. Yo hablaré de Flex pues es el que conozco, pero podríais hacer la misma comparación con los otros dos.

Para el que a estas alturas no lo sepa, FLEX es la tecnología Flash orientada a programadores. Tradicionalmente Flash ha sido una herramienta de animación y diseño, la que conoces de toda la vida. Después de un primer intento más o menos fallido con Flex1 y 1.5, Adobe, tras adquirir Macromedia, decidió reorientar el rumbo, construyendo algo auténticamente revolucionario con Flex2. Las secuelas, además de Flex3, han sido AIR (para aplicaciones de escritorio) y próximamente Thermo (diseño de R.I.A.). Con Flex2 han conseguido crear una herramienta para la construcción de interfaces de usuario en Flash.

No cabe duda que las R.I.A. están de moda. Da igual la tecnología utilizada, cada día aumentan las aplicaciones online. Desde sistemas operativos online hasta aplicaciones de edición de fotografías o vídeos pasando por aplicaciones corporativas de gestión de cualquier tipo.

Pero ¿qué es mejor para construirlas? La respuesta es sencilla: depende de para qué. No me sirven argumentos sobre plugins (¿Javascript funciona en Lynx?) o software libre vs. privativo (¿acaso al usuario habitual le importa o sabe lo que es?) o SEO (¿Javascript es search engine friendly?). Hablemos mejor de utilidad y de conveniencia para el desarrollador y el usuario.

Lo primero que deberíamos preguntarnos es

¿Qué voy a hacer?

No es lo mismo hacer una web o una aplicación que va a utilizar mucha gente que hacer una aplicación de gestión para una empresa de seguros o un banco. ¿Alguien se imagina a una aseguradora haciendo su software de gestión en Javascript? Pero sí en Flex como de hecho están haciendo ya. Por otro lado a nadie se le ocurriría hacer una web en Flex, no tiene sentido, no es su cometido. Pero sí que harías una aplicación como la de Flickr para editar fotografías online o la de Youtube para hacer montajes de vídeo. O pequeños módulos concretos que no podrías hacer de otro modo o que te costaría demasiado, o widgets varios como está haciendo mucha gente utilizando feeds, mapas, etc. Este creo que sería el punto clave diferenciador. Con Ajax hacemos complementos para aplicaciones web o pequeñas aplicaciones, con Flex hacemos aplicaciones completas. Lógicamente estoy generalizando y cada uno puede pensar y hacer lo que quiera, hay aplicaciones completas realizadas 100% en Javascript, no hay ningun inconveniente, para ejemplo EyeOS. ¿Por qué opino esto entonces? Sencillo, por una simple cuestión de ingeniería del software y productividad. Flex es un lenguaje orientado a objetos 100% y con todas las ventajas que aporta. Crear interfaces de usuario con Flex es impresionantemente sencillo. ¿Alguien puede decir lo mismo de Javascript? Que se puede hacer es indudable, pero a costa de convertir la aplicación en una auténtica telaraña de Javascript‘s. ¿Qué ocurrirá cuando otro programador deba tomar esa aplicación y modificarla? Cualquiera que haya hecho lo más mínimo en Ajax sabe que es una locura. No hay un patrón MVC y la interacción con la interfaz de usuario (html) es harto difícil, innerHTML está muy bien y es muy rápido, pero siendo puristas deberíamos utilizar DOM, a medio plazo lo agradeceremos, y sino intenta modificar atributos de código insertado con innerHTML :P.

Mejor aún, encontremos un responsable de proyectos, director técnico o el cargo que se os ocurra que se comprometa a realizar un proyecto medianamente importante en Ajax. Si conoce Flex verá las similitudes con Java, de hecho se hizo con Java en mente. Si no lo conoce pensará directamente en Java, difícilmente se le ocurriría pensar en Ajax, su cuello es el que está en juego en definitiva.

¿Para qué hemos utilizado nosotros Flex?

Hemos hecho widgets de distintos tipos, paneles de control y gestión, aplicaciones de audio/vídeo multiusuario (chat, audio-chat y vídeo-chat). Ahora mismo trabajamos en un cliente IRC en colaboración con una de las principales redes de IRC.

En backoffices y otros paneles administrativos hemos comprobado que para el usuario la comprensión y utilización de la aplicación es muy superior a interfaces html puesto que son más parecidas a una aplicación de escritorio tradicional y tienen más interactividad, algo que el usuario agradece.

En artículos posteriores os expondré algunos ejemplos de cosas que hemos ido haciendo a lo largo de los dos últimos años, aunque también veremos cosas en Ajax, no son tecnologías excluyentes.

Añadir que Flex ya es de código abierto, el SDK es libre y hay un excelente plugin para Eclipse. Lo único que es de pago es el Flex Builder de Adobe, la aplicación oficial, pero puedes hacer tus aplicaciones con el plugin de Eclipse del mismo modo.

Por cierto, Adobe no me paga nada por este post :P.

Calendario Multirango en Flex2

Hace algo más de un año trabajábamos en un proyecto que consistía en una aplicación de gestión de reservas para una cadena de hoteles. Una de las opciones necesarias era el mantenimiento de las temporadas de cada hotel, es decir, las tarifas. Aunque pueda parecer algo sencillo y sin importancia, en realidad dista bastante del clásico alta/media/baja. De hecho ni siquiera es algo que permanezca inalterado a lo largo del año, sino que, en función de la demanda y disponibilidad de habitaciones, el propio hotel va modificando las temporadas en función de sus necesidades. La gestión de temporadas se realiza manualmente día a día y para cada uno de los hoteles de la cadena y cambia cada año. Necesitábamos, por tanto, desarrollar un sistema que permitiese administrar las temporadas de manera rápida y sencilla.

La solución que se nos ocurrió fue crear un calendario anual completo, doce DateChooser, uno por cada mes del año, y permitir al administrador configurar en un solo paso el año entero de temporadas. Simplemente seleccionando la temporada que se va a configurar y haciendo click en los días de cada DateChooser se van marcando de un color distinto para cada temporada. Como podéis ver en el ejemplo, es muy sencillo cambiar de temporada los días, seleccionamos otra tarifa y hacemos click en el día que queremos modificar. Es casi tan sencillo cambiar un día como un mes completo.

El problema llegó con el DateChooser puesto que, por defecto, sólo permite seleccionar un día o rango de días, pero siempre marcándolos en el mismo color. Nosotros necesitábamos que de un vistazo el administrador supiese la configuración de las temporadas de su hotel, necesitábamos un código de colores para los fondos de los días, en los números sería poco visual. La solución parte de un componente desarrollado para Flex1.5 hace bastante y que su autor no llegó a portar a Flex2, algo que hicimos nosotros con algunas modificaciones.

Extendiendo el DateChooser

El efecto que queríamos conseguir era colorear el fondo cada día del calendario en función de la tarifa adjudicada, de manera que con un rápido vistazo se tenía claro qué es cada uno.

Lo primero que necesitábamos en nuestro caso particular era ocultar las flechas de navegación de meses, puesto que sólo íbamos a utilizar un mes de cada DateChooser dejando la navegación por años. Por defecto no hay forma de hacerlo ya que estos botones se han definido en mx_internal, así que hemos de recurrir a:

this.mx_internal::fwdMonthButton.visible=false;
this.mx_internal::backMonthButton.visible=false;

En nuestro componente está por defecto, vosotros tendríais que eliminar esas líneas o, mejor, crear un método publico que permita quitarlos.

A continuación definimos el método que haremos público para colorear los días. Como véis en el código, los parámetros son un array con los días a marcar y el color de fondo que le vamos a dar. Tuvimos que implementar un callLater ya que nuestra aplicación, al iniciarse, carga del servidor las temporadas del año en curso y configura los distintos DateChooser, pero nos dimos cuenta que esto se producía antes de que el componente estuviese disponible, con lo cual si intentábamos colorear los días saltaban excepciones de componente no disponible.

Finalmente la función highlight busca los días que se le pasan en el array y configura el color de fondo de cada uno. Dentro del DateChooser, los días son instancias de TextField, pero de nuevo no son accesibles, tenemos que acudir de nuevo a mx_internal. El código es muy explicativo.

public function highlightDays(dayArray:Array, highColor:Number=0xff9900):void{
	var o:CalendarioMultipleColor = this;
	callLater(highlight,[dayArray, highColor]);
}
private function highlight(dayArray:Array, highColor:Number):void {
	if (!dayArray is Array) return;
	if (isNaN(highColor)) highColor = 0xff9900;
	// row 0 of the dateGrid is used for the display of day names
	var startRow:Number = 1;
	// calculate the column where the first day of the month is placed
	var startCol:Number = getOffsetOfMonth(this.displayedYear, this.displayedMonth);
	// how many days do we have this month?
	var lastDay:Number = getNumberOfDaysInMonth(this.displayedYear, this.displayedMonth);
	for (var i:Number = 0; i < dayArray.length; i++) {
		var day:Number = dayArray[i];
		 // only numbers allowed
		if (isNaN(day)) continue;
		if (day < 1) continue;
		if (day > lastDay) continue;
		// calculate row and column of the day
		var row:Number = Math.floor((day-1 + startCol) / 7) + 1;
		var col:Number = (day-1 + startCol) % 7;
		//finally we set background color
		this.mx_internal::dateGrid.mx_internal::dayBlocksArray[col][row].background=true;
		this.mx_internal::dateGrid.mx_internal::dayBlocksArray[col][row].backgroundColor=highColor;
	}
}

Aquí os dejo el ejemplo y código fuente, ya sabéis, botón derecho y View Source.