Jan 18, 2009

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:

This movie requires Flash Player 9

Descargar ejemplo

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

[as3]var bmpData:BitmapData = new BitmapData(foto_mc.width, foto_mc.height);
bmpData.draw(foto_mc);[/as3]

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.
[as3]var jpg_codificado:JPGEncoder = new JPGEncoder(99);
var byteArray:ByteArray = jpg_codificado.encode(bmpData);
[/as3]
El tipo de cabecera indica que se trata de un archivo binario
[as3]var cabecera:URLRequestHeader = new URLRequestHeader(“Content-type”, “application/octet-stream”);
[/as3]
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).
[as3]
var urlFoto:URLRequest = new URLRequest();
urlFoto.requestHeaders.push(cabecera);
urlFoto.method = URLRequestMethod.POST;
urlFoto.data = byteArray;
urlFoto.url = _ruta + “?vFoto=” + _nombre_foto;
[/as3]
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.
[as3]
navigateToURL(urlFoto, “_blank”);
[/as3]
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:
[as3]urlFoto.url = “ruta/form.php?vFoto=avatar.jpg&nombre=llops&edad=28”;[/as3]
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.

This movie requires Flash Player 9

Descargar ejemplo

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:
[as3]
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;
[/as3]
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.

Información del artículo

Post publicado el 18 de January de 2009 a las 22:26 por llops

Categorias: Artículos

Etiquetas: , , , , , , , , , , ,

Comparte

19 comentarios

  • Este post lo voy a consultar más de una vez… ¿He dicho alguna vez que eres una máquina?? ;D

  • 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.

  • Interesante!
    En este post también hablan del tema:
    http://labs.findsubstance.com/2008/04/03/as3-upload-encode-images/

    saludos.

  • Ditmar

    Me encanto gracias por compartir tus experiencias 100 Puntos ^^

  • 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.
    ;)

  • 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.

  • FCO

    Excelente informacion solo que necesito enviar la imagen al servidor desde un .exe generado por flash sabrias como hacerlo ? Gracias

  • 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

  • Siroko

    AMF to the power!!!

  • Jose

    Me has salvado la vida!!!! no encontraba forma de mandar imagen y datos!! mil gracias

  • muy muy bueno.. te felicito..

  • Arturo

    A mí me da error. Al parecer sobrepasa el límite de datos del post:

    ………..

    ±ØüŸŒÀ<] ”ªNXHsJ+šœeW–«¡R6NK–¦¯EÈqYfA“ñ'qÖÃ<4Âáq« Z!ˆ•”Ÿ,å|Ô½´%v¢ù¡¢Õ¿Õb×ïñ_ÀxÚ;èpåÕþO&Ö*‡ÍǯoóþE|†6–çßåµ¾OäCþmËŸö+÷ÿ�†ý

    … postDataSizeLimitMessage …

    òòåRÕ"î P†o)sçÃãŸÓúWØ`f½ÓóÌΗÄ|;û~þų/ÇŸ…ºÏ‹ü{ð/áÆ¿ã MKG—Tñä>´Ñ¾!I¥Ïrº{Â<u ]XÄ·wV

    ………

    He probado de distintas maneras pero no he logrado solucionarlo :(
    A ver si alguien puede echarme una mano. Gracias.

  • Hola,

    no sé si abuso al hacerte esta pregunta, pero no veo otra salida…

    Tengo un formulario en as3 que me funciona perfectamente cuando exporto la película en mi escritorio y mi servidor envia mail cuando pruebo el archivo SEND.php, pero cuando subo el flash dentro de un html al servidor el formulario no hace nada. Tienes idea de porqué puede ser?

    gracias!

  • Manel

    Hola a todos, me ha parecido muy bueno el POST, sólo una petición, alguien puede mostrar como seria la parte de servidor en C#?
    No consigo traducirlo y me seria de gran ayuda.

    Muchas gracias

  • Marisol

    Hola, tengo una duda si alguien me pudiera ayudar se los agradecería mucho.
    formo una imagen con varios movieClips para que el usuario pueda guardarla en su máquina o imprimirla, hasta aquí todo el proceso va bien, pero requiero mostrar esa misma imagen que generé un una pestaña nueva del navegador, sólo la imagen. Se puede hacer esto directamente desde Flash o necesito crear una rutina en PHP para que la muestre como en este ejemplo?
    De antemano gracias!

  • Sólo con flash no podrás, tienes que utilizar php (u otro lenguaje) para poder recibir la imagen y mostrarla por pantalla.

    Saludos!

  • Marisol

    Mi equipo no quiere que para mostrar esa imagen se dependa del servidor, ya que consumiría recursos, hay alguna otra forma de hacer esto, tal vez con JavaScript? Cómo podría hacerlo? Muchas gracias!

  • Cesar Azuero

    Muchísimas gracias, me has sacado de una aprieto.

  • Ale

    Hola, probé la clase UploadPostHelper, y cuando compilo localmente me funciona perfecto. Pero al subir este swf al servidor, no logro hacer que funcione, porque puede ser este error?