Envío de imágenes y datos con AS3
En el anterior post, en el apartado El envÃo de la postal, comentaba que parte del desarrollo consistÃa en enviar una imagen y distintas variables de Flash al servidor, pero que en AS3 no habÃa una forma sencilla de hacer un envÃo multipart y habÃamos recurrido a la potente librerÃa as3httpclientlib para conseguirlo.
A pesar de que dicha librerÃa funciona perfectamente, lo hace todo mediante sockets, cosa que añade un grado (o varios, según el caso) de dificultad. Como para el proyecto de IKEA no Ãbamos sobrados de tiempo, no le di más vueltas y la utilicé, pero me quedó la espinita de si no habÃa maneras más sencillas de hacerlo, y desde entonces he estado mirando todo lo relacionado con el tema de envÃos desde Flash. Este artÃculo recoge y explica distintas soluciones que he ido encontrando.
Empezaremos con el caso más sencillo, que es enviar una imagen desde Flash al servidor.
Enviar una imagen con AS3
En AS3 contamos con la clase URLRequest, que combinándola con otros métodos para hacer envÃos, permite mandar datos como texto, como variables o como binario. Asà pues, se puede pasar cualquier archivo como binario, pero para ello primero hay que codificarlo. En el caso de un jpg o un png, podemos utilizar la librerÃa de Adobe as3corelib, que cuenta con las clases JPGEncoder y PNGEncoder, y a partir de un BitmapData (el formato interno de Flash para almacenar datos de una imagen) te genera un ByteArray con la información.
Como ejemplo vamos a crear una imagen a partir de un movieclip que tenemos en el escenario y a enviarla a un php para que la muestre:
Nota: para que funcione el ejemplo, tanto el swf como el php se deben encontrar en el mismo dominio.
El código del ejemplo está comentado aunque es bastante sencillito, y la única tarea realmente dura la hace la clase JPGEncoder. Vamos a echar un vistazo a las partes relevantes:
Se toma un "pantallazo" dibujando el movieclip en un bitmapData
-
var bmpData:BitmapData = new BitmapData(foto_mc.width, foto_mc.height);
-
bmpData.draw(foto_mc);
Se crea un objeto JPGEncoder. El parámetro indica la calidad de la imagen (sobre 100). Se codifica el bitmapData y se asigna a un byteArray.
-
var jpg_codificado:JPGEncoder = new JPGEncoder(99);
-
var byteArray:ByteArray = jpg_codificado.encode(bmpData);
El tipo de cabecera indica que se trata de un archivo binario
-
var cabecera:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");
Se crea un objeto URLRequest que contiene toda la información referente al envÃo. El parámetro data es que el que contiene la foto codificada, y el parámetro vFoto el nombre que le queramos asignar (no es obligatorio).
-
var urlFoto:URLRequest = new URLRequest();
-
urlFoto.requestHeaders.push(cabecera);
-
urlFoto.method = URLRequestMethod.POST;
-
urlFoto.data = byteArray;
-
urlFoto.url = _ruta + "?vFoto=" + _nombre_foto;
En este ejemplo se manda abrir el php en una ventana en blanco, pero lo normal serÃa utilizar un objeto URLLoader para enviar la información y procesar el resultado.
-
navigateToURL(urlFoto, "_blank");
Por último, el php se encarga de recibir la imagen y mostrarla por pantalla.
Nota: como son operaciones que mucha gente busca, en el php he incluido una rutina para guardar el archivo en el servidor y otra que da la opción de descargar el fichero al disco duro.
Limitaciones de este método
Para cosas muy sencillas el ejemplo anterior es perfecto, pero normalmente, cuando se envÃa un archivo se suele acompañar también de variables que contienen información. Al asignar a la propiedad data el byteArray, perdemos todas las opciones de adjuntar un objeto con dicha información.
Un "truquillo" serÃa enviar la foto mediante POST y aprovechar la url para pasar variables por GET, igual que hemos hecho con el nombre del archivo. Por ejemplo:
-
urlFoto.url = "ruta/form.php?vFoto=avatar.jpg&nombre=llops&edad=28";
De todas formas, no es el sistema más limpio, y mejor usarlo como un recurso puntual para pasar pocos parámetros (aunque no tiene nada que ver con el mito de los 256 caracteres).
Lo ideal es poder hacer un envÃo multipart, igual que se hace con los formularios html o como lo hace la propia clase de AS3 FileReference. Y buscando buscando, di con una clase que sirve perfectamente para el propósito...
Enviando una imagen y datos mediante la clase UploadPostHelper
La clase UploadPostHelper te permite pasar un nombre de archivo, un ByteArray y un Object y devuelve otro ByteArray con todo el contenido codificado que podemos enviar como data.
El uso sigue siendo muy sencillo: la mayorÃa de pasos del ejemplo anterior son los mismos, y UploadPostHelper hace todo el trabajo sucio de forma transparente:
-
var urlFicha:URLRequest = new URLRequest();
-
urlFicha.contentType = 'multipart/form-data; boundary=' + UploadPostHelper.getBoundary();
-
urlFicha.requestHeaders.push( new URLRequestHeader( 'Cache-Control', 'no-cache' ) );
-
urlFicha.method = URLRequestMethod.POST;
-
urlFicha.data = UploadPostHelper.getPostData(_nombre_foto, byteArray, datos);
-
urlFicha.url = _ruta;
En la segunda linea vemos que se establece el contentType como multipart. El boundary es un string que se genera en cada envÃo aleatoriamente y sirve para delimitar las diferentes partes del envÃo. En la cuarta linea es donde se llama al método getPostData, que nos devuelve un array con todos los datos pasados.
Se manda y... ya tenemos nuestro envÃo multipart. ¿Fácil, no?
Mandando varios archivos
Y aunque el método anterior sirve para el 90% de los casos, para rizar el rizo, ya sólo falta poder enviar varios archivos a la vez, cosa que no hace UploadPostHelper, pero sà la librerÃa basada en sockets (as3httpclientlib).
Como no vi nada similar pensé en modificar la clase UploadPostHelper, ya que el trabajo duro estaba hecho, y lo único que falta es permitir añadir nuevas partes, pero para mi sorpresa, mientras me documentaba, he encontrado a alguien que ha escrito una clase con el mismo objetivo hace sólo dos dÃas :)
El post en cuestión es este: http://blog.inspirit.ru/?p=139 y el ejemplo es bastante claro, asà que no redundaré para no hacer esto más largo.
Resumiendo
A medida que las capacidades de Flash Player crecen, cada vez es más corriente generar imágenes en el mismo player, y también aumenta la necesidad de poder exportarlas. Pero el tema no se reduce sólo a jpgs, sino también a otro tipo de archivos como pdf, zip o mp3.
Gracias a la potencia de AS3 y al esfuerzo de muchas personas que crean todo tipo de librerÃas y utilidades, llevar a cabo esta tarea se convierte en un paseo, pero detrás hay un trabajo realmente complejo (sólo hay que echar un vistazo a dichas clases).
Con este artÃculo espero haber allanado un poco el camino por si alguna vez te tienes que enfrentar con el tema.
10 comentarios
#1 Juan
Este post lo voy a consultar más de una vez... ¿He dicho alguna vez que eres una máquina?? ;D
Jan 19, 2009
#2 ErneX
Excelente post, lo de hacer un POST a un target que sea una URL que contiene variables es realmente útil y creo que es suficiente para los mayorÃa de los casos en los que sea necesario pasar variables junto con la imagen.
Pero de igual forma espero que integren en Flash soporte multipart (sin librerÃas externas ni virguerÃas mediante sockets) en una futura versión.
Jan 19, 2009
#3 Angel E. Anton
Interesante!
En este post también hablan del tema:
http://labs.findsubstance.com/2008/04/03/as3-upload-encode-images/
saludos.
Jan 19, 2009
#4 Ditmar
Me encanto gracias por compartir tus experiencias 100 Puntos ^^
Feb 9, 2009
#5 kassel
Gracias, me sirvio de muxo este post, y el ejemplo, es muy clara la metodologia y la libreria, si os sirve use Matrix para recortar la imagen y PNGencoder para que fuera transparente.
;)
Mar 5, 2009
#6 Pablo
He probado este código y funciona bastante bien, pero en Firefox si dices de "guardar imagen como" te lo hace con la extensión form.php, mientras que en IExplorer te lo hace con la extensión form.jpg, Hay alguna manera de solucionar esto?. Gracias.
Apr 15, 2009
#7 FCO
Excelente informacion solo que necesito enviar la imagen al servidor desde un .exe generado por flash sabrias como hacerlo ? Gracias
Apr 17, 2009
#8 xleon
Esas clases del "findsubstance" me han salvado la vida en varias ocasiones. Me refiero al UploadPostHelper.
Aunque otra buena manera de hacer esto es remoting
Apr 28, 2009
#9 Siroko
AMF to the power!!!
May 18, 2009
#10 Jose
Me has salvado la vida!!!! no encontraba forma de mandar imagen y datos!! mil gracias
Mar 2, 2010
¡Deja un comentario!