Ein großartiges Beispiel von Thibault Imbert zeigt, wie man mit ActionScript 3 unter Nutzung der JPEG-Encoder-Klasse (von Tinic Uro) JPEG-Grafiken in Flash erzeugen kann. Auf eine .flv-Datei angewendet kann man dadurch „Schnappschüsse“ aus dem laufenden Video als Grafikdatei abspeichern.
Link: Live JPEG Encoder 0.3 Sources (Thibault Imbert)
Link: More fun with image formats in AS3 (JPEG-Encoder Klasse von Tinic Uro)
Ich habe den Originalcode von Thibault Imbert etwas ausgedünnt und auf das wesentliche reduziert, damit die Vorgehensweise deutlicher zu erkennen ist. Erläuterungen gibt es weiter unten im Text. Das erstellte Beispiel gibt’s hier: Beispiel anschauen. Einfach auf „Vorschaubild“ klicken, dann wird ein JPEG generiert und in der rechten Hälfte angezeigt. Mit einem Klick auf „Download“ wird die Datei heruntergeladen.
1. Vorgehensweise
Die grundsätzliche Vorgehensweise besteht darin, ein BitmapData-Objekt mit dem JPEG-Encoder in einen binären Datenstrom zu wandeln. Danach zeigt das Beispiel von Thibault Imbert, wie die binären Daten an eine PHP-Datei geschickt werden. Das PHP-File kann das Bild nun entweder auf dem Server abspeichern oder dem Anwender direkt als Download anbieten.
2. Das JPEG erstellen und anzeigen
Zuerst wird die JPEG-Encoder Klasse mit import encoding.JPEGEncoder importiert.
Die Loader-Klasse kann SWF-Dateien, JPG-,PNG- oder GIF-Bilder laden. Zuerst wird deshalb einer neuer Loader erstellt, in den später das JPEG zum Anschauen geladen wird. Dieser Loader wird in der rechten Bildhälfte platziert.
[as]
var vorschau:Loader = new Loader();
vorschau.x = 480;
[/as]
Mit var myJPEGData:ByteArray wird ein neues Objekt vom Typ ByteArray geschaffen. Die ByteArray-Klasse ist unter flash.utils.ByteArray zu finden. Sie dient dazu binäre Daten zu verarbeiten. Dieses Objekt wird später die JPEG-Daten enthalten.
Nun folgt die Funktion createJPEG():
[as]
function createJPEG ( evt:MouseEvent ):void
{
// neues Bitmap-Objekt
var myBmd:BitmapData = new BitmapData ( myVideo.width, myVideo.height );
// Bitmap vom Video erstellen
myBmd.draw ( myVideo );
// neues JPEP-Objekt (Angabe in Klasmmern ist die Qualitaet)
var myEnc:JPEGEncoder = new JPEGEncoder(20);
// neues ByteArray (binäre Daten)
myJPEGData = myEnc.encode (myBmd);
// loadBytes() lädt binäre Daten aus einem ByteArray
vorschau.loadBytes (myJPEGData);
// vorschau auf der Bühne platzieren
addChild (vorschau);
// Save-Button anzeigen
buttonSave.visible = true;
}
[/as]
Zuerst wird ein „Snapshot“ des Videos in einem BitmapData-Objekt abgespeichert. Danach kommt der JPEG-Encoder zum Einsatz: Über den Zahlenwert in Klammern wird die Qualität bzw. die Kompression festgelegt. Anschließend wird das JPEG mit der Methode encode() in das ByteArray abgelegt.
Der zu Beginn erstellte Loader kann nun mit der Methode loadBytes den JPEG-Datenstrom einlesen. Somit wird eine Vorschau des JPEGs auf der Bühne erstellt.
3. Das JPEG-File versenden
Das Anzeigen auf der Bühne ist nun erledigt. Jetzt geht es darum, dass das File serverseitig abgespeichert bzw. ein Download gestartet wird. Hier die Funktion save zum Abspeichern/Versenden des JPGs:
[as]
function save(evt:MouseEvent) {
// neue URL-Anfrage festlegen
var myRequest:URLRequest = new URLRequest („save-to-disk.php?name=meinBild.jpg“);
// Content-type (application/octet-stream) header festlegen und hinzufügen
var header:URLRequestHeader = new URLRequestHeader („Content-type“, „application/octet-stream“);
myRequest.requestHeaders.push (header);
// über POST versenden
myRequest.method = URLRequestMethod.POST;
// JPEG-Daten mit der URL-Anfrage verknüpfen
myRequest.data = myJPEGData;
// URLLoader mit der URL-Anfrage verknüpfen und danach laden
myURLLoader.load (myRequest);
navigateToURL (myRequest, „_blank“);
}
[/as]
Die save-Funktion funktioniert folgendermaßen: Zuerst wird eine URL festgelegt, die aufgerufen werden soll. In diesem Fall die PHP-Datei, die den Download des JPEGs beim User initiert (Alternativ kann man diese Zeile auch mit save-to-server.php ersetzen, um das JPEG serverseitig abzuspeichern).
Nun wird der MIME-Type festgelegt. Anschließend wird als Methode des HTTP-Protokolls zum Versenden der Daten „POST“ gewählt (Die Daten werden also an den Header angehängt). Danach wird das JPEG als Daten an die Anfrage gehängt. Zuletzt wird die PHP-Seite aufgerufen.
Hinweis: Das ganze funktioniert natürlich nur auf einem Server (Ansonsten erscheint nur der Quellcode der PHP-Datei).
Download: Quelldateien als ZIP
PS: Es gibt übrigens auch eine PNG-Encoder Klasse: PNG Encoder in AS3
Hallo,
ist der Quellcode noch aktuell – bei CS3 bekomme ich einige Warnings und das Video (Preview) funkioniert nicht !
Bis jetzt konnte ich den Fehler nicht lokalisieren :-(
Hi,
Hab das selbe Problem wie im vorigen post beschrieben. Bekomme beim Speichern den Hinweis, dass das fla in Flash 8 oder niedriger erstelt wurde und konvertiert wird, oder ich soll speichern unter auswählen. Versuch ich als Flash 8 zu speichern geht (logischerweise) AS 3.0 verloren. So oder so funktioniert dann die Darstellung des Videos nicht. Mach ich etwas falsch, oder ist das ein bug?
Danke im Vorhinein,
Wolfgang
Das Problem ist, dass dieses Beispiel mit der Flash 9 Alphaversion erstellt wurde, die die Dateien noch im Flash 8 Format abgespeichert hat …
Wenn ich Zeit habe, werde mal eine aktuelle Version dieses Beispiels erstellen.
das wäre echt eine große Hilfe, vielen Dank schon mal im Vorhinein!
Der “Live JPEG Encoder” von ByteArray wurde mittlerweile upgedatet:
„We now have a 0.4 version which gives better performance and simpler code.“
ByteArray
Danke fuer das tolle Beispiel. Leider funktioniert das nach nach dem Export der Beispieldateien bei mir nicht mehr. Haettest Du ev. nochmal die komplette Source von dem Webcam-Snapshot Beispiel? Vielen Dank!
funktioniert so nicht mehr in fp10
wenn sich jemand wundert.
mehr dazu hier: http://actionscript-blog.imaginationdev.com/5/save-jpg-jpeg-png-bmp-image-action-script-3/
anstatt navigate to url:
private function createJPG(m:Sprite, q:Number, name:String):void
{
serverUniqueFileName = name+new Date().getTime()+".jpg";
trace(serverUniqueFileName);
var jpgSource:BitmapData = new BitmapData (m.width, m.height);
jpgSource.draw(m);
var jpgEncoder:JPGEncoder = new JPGEncoder(q);
var jpgStream:ByteArray = jpgEncoder.encode(jpgSource);
var header:URLRequestHeader = new URLRequestHeader ("Content-type", "application/octet-stream");
var jpgURLRequest:URLRequest = new URLRequest (host+"php/download.php?name=" + serverUniqueFileName);
jpgURLRequest.requestHeaders.push(header);
jpgURLRequest.method = URLRequestMethod.POST;
jpgURLRequest.data = jpgStream;
var jpgURLLoader:URLLoader = new URLLoader();
jpgURLLoader.dataFormat = URLLoaderDataFormat.VARIABLES; jpgURLLoader.addEventListener(Event.COMPLETE, imageUrlLoaderComplete ); jpgURLLoader.addEventListener(IOErrorEvent.IO_ERROR, sendIOError);
jpgURLLoader.load( jpgURLRequest );
}
private function imageUrlLoaderComplete(e:Event):void
{
if (e.target.data.write == "yes") //FileReference.download()
}
private function sendIOError(event:Event):void
{
trace("Error occured");
}
funktioniert so nicht mehr in fp10
http://actionscript-blog.imaginationdev.com/5/save-jpg-jpeg-png-bmp-image-action-script-3/
anstatt
navigatetourl:
var jpgURLLoader:URLLoader = new URLLoader();
jpgURLLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
jpgURLLoader.addEventListener(Event.COMPLETE, imageUrlLoaderComplete );
jpgURLLoader.addEventListener(IOErrorEvent.IO_ERROR, sendIOError);
jpgURLLoader.load( jpgURLRequest );
}
private function imageUrlLoaderComplete(e:Event):void
{
if (e.target.data.write == "yes") FileReference_download();
}