21.07.2008, 17:58
SWF Parser
Nachdem Adobe die (bis auf
Nellymoser- und
Speex-Audiokomprimierung
und VP6(-Alpha)/VP7-Video-Codecs von On2) vollständige
Spezifikation
(PDF, 943KB) für Shockwave Flash-Dateien bis inklusive der neusten Version 10 veröffentlicht
hatte, stand einem Parser nichts mehr im Wege.
Vorweg ein kurzes Lob für den Detailreichtum, mit dem diese Spezifikation den Entwickler an
die Hand nimmt und die Implementierung vereinfacht; sie ist wirklich lesenswert.
In den Bereichen ActionScript-Tags und Sound-Formate ist die Version noch unvollständig.
Anregungen, Kritik oder Fehler des Programms bitte an dev ## karlchenofhell %% org
(Ersetze
## durch @ und %% durch .).
Der SWF-Parser ist seit Version 0.1 Bestandteil des Suchframeworks Paxle.
Benutzer von Maven können das Paket über
Paxles Maven Repository einbinden:
org.karlchenofhell
swf
0.1.1
]]>
Die Benutzung dieser Software unterliegt den Bestimmungen der
Common Public License 1.0!
Changelog
* 04.05.2009:
- added support for MP3- and AdPCM-frames in sound-streaming tags
- added switch "-sound" to dump the sounds found in the SWF into files
(for streamed sound, only MP3 is supported up to now, otherwise the headers get mixed up)
* 03.05.2009:
- added support for MP3-frames in DefineSound-tags
* 03.05.2009:
- release 0.1.1
- ImageViewer: speeded up displaying of lossless images
- added support for SWF10:
- tags: DefineBitsJPEG4, DefineFont4
- new sound-formats
- prepared for GIF89a- and PNG-data in DefineBitsJPEG[234]-tags (which is allowed but seldomly used)
- minor corrections on tag-loading code
* 21.07.2008:
- release 0.1
Der Parser enthält einige ursprünglich nur zum Testen erstellte Funktionen, die sich dennoch
auch im Alltagsbetrieb mit Flashdateien als nützlich erwiesen haben:
-
Extraktion der Header-Informationen (SWF-Version, Größe entpackter Daten, Größe des Fensters
in 1/20 Pixeln (sog. Twips), Anzahl Frames und Framerate)
- (De-)Komprimierung von SWF-Dateien (nützlich für Fehlersuche in Rohdaten)
- Auflistung aller enthaltenen Tags inklusive Metadaten
- Extraktion des in Flashdateien enthaltenen Texts
- Extraktion der in Flashdateien enthaltenen Sounds
-
Ein Swing-Bildbetrachter für die enthaltenen Bilddaten (sowohl JPEG/JFIF- als auch verlustfrei
Komprimierte)
24.07.2008, 02:56
Aussichten
Shape Viewer
Momentan befindet sich ein Shape Viewer aufgesetzt auf den Image Viewer in Arbeit.
Da Java die Funktionalität der SWF-Shapes von Haus aus nicht vollständig unterstützt und mir
eine gewisse Erfahrung in Graphikprogrammierung fehlt, geht die Arbeit nur schleppend voran.
Als Beispiel seien hier Gradienten
genannt; zwar existiert mit dem
GradientPaint
eine Implementierung für lineare Gradienten, aber Funktionen für bspw. radiale sowie auch Gradienten
mit mehreren Farben fehlen. Das Apache Batik-Projekt
bietet allerdings mit dem
MultipleGradientPaint
für beide Fälle eine (fast alleinstehende) Lösung an, allerdings widerstrebt es mir, für Beispielcode
auf externe Bibliotheken zurückzugreifen. Ein weiteres Beispiel sind die Enden gezeichneter Linien,
welche im SWF-Format unterschiedlich sein können, je nachdem ob es sich um einen Linienbeginn oder ein
-ende handelt. Javas
BasicStroke bietet
aber leider nur eine Methode für beide Enden einer Linie an.
Deshalb wird der Shape Viewer wohl später als separates Programm (bzw. Teil dessen) veröffentlicht
werden, falls ich bis dahin noch keine Lust gehabt haben sollte, mich mit dem Thema näher
auseinanderzusetzen und eigene Versionen der benötigten Funktionen zu bauen.
Sound- und Videounterstützung
Die Sound- und Video-Tags der SWF-Dateien können mit Hilfe des SWF Parsers zwar erkannt und deren Daten
auch extrahiert werden, allerdings fehlt noch Unterstützung für Nellymoser ASAO- und Speex-Formate, in
denen beide Tagklassen ihren Inhalt speichern. Bis auf Weiteres besteht auch keine nähere Planung zur
Erweiterung des Parsers um diese Funktionen.
Action-Tags und ActionScript
Auch mit der Actions-Unterstützung habe ich mich erst rudimentär beschäftigt, allerdings ist der
vollständige Support aller bis dato definierten SWF Action-Tags geplant, ebenso wie ein Interpreter,
der die dekodierten Instruktion in einer Testumgebung ausführt. Die Dokumentation von Adobe gibt dazu
zum Glück genug her, sodass ich zuversichtlich bin, diesen Punkt mit genügend Zeit in Angriff nehmen zu können.
Stoff für Entwicklungen bieten die drei SWF Action-Tags zur Genüge, so können nicht nur die in der
typischen SWF-Struktur defifinierten Actions interpretiert werden, sondern es existiert mit dem
DoABC
-Tag auch noch eine weitere Stelle, an der gearbeitet werden kann: Unterstützung des
Bytecodes der ActionScript 3.0 Virtual-Machine und
damit die teilweise Implementierung derselben. Dies wird aber - wenn überhaupt - außerhalb des Rahmens des Parsers
geschehen.
24.07.2008, 20:28
Ein Wort zum Image Viewer
Als die Arbeit für den Image Viewer begann, der sowohl die im SWF-eigenen qualitätsverlustfreien Format
als auch die im JPEG-/JFIF-Format gespeicherten Bilder anzeigen können sollte (und inzwischen auch kann),
hatte ich noch keinerlei Bedenken ob der in der Java-Klassenbibliothek mitgelieferten Routinen zum
JPEG-Parsing. Das sollte sich allerdings spätestens dann ändern, als JFIF-Daten in
Images umgewandelt werden
sollten. Das Parsen mit Hilfe der
Toolkit-Klasse war extrem
langsam, deshalb stieg ich schnell auf die
Klassen der
Java2D-API um, die mit den diversen Plugins
für die unterschiedlichen Bildformate nicht nur flexibel sondern im Vergleich auch sehr schnell ist.
Allerdings hat sowohl der sun.awt.image.JPEGImageDecoder
(JPEG-Backend für
Toolkit.createImage()
) als auch der
com.sun.imageio.plugins.jpeg.JPEGImageReader
Probleme beim Einlesen von JFIFs bei denen
die Quantization- und
Huffman-Tables den eigentlichen Bilddaten
vorangestellt sind. Interessanterweise besteht das Problem nicht beim eigentlichen Interpretieren der
Table- bzw. Bilddaten, sondern bei der Behandlung der Abfolge der Daten im Strom. Das Problem sollte
also eigentlich recht unproblematisch und einfach zu beheben sein; in Version 1.6.0 der Java-Umgebung
von Sun ist davon allerdings noch keine Spur zu finden.
Wie dem auch sei, die Lösung ist recht trivial: Der komplette Datenstrom wird erst einem
JPEG-ImageReader
übergeben, die Tables via getStreamMetadata()
ausgelesen und mit etwas
DOM-Handling
in einen
JPEGImageReadParam
verwandelt. Nun muss (aufgrund eines weiteren Fehlers in Suns eigener JPEG-ImageReader-Implementation)
der Quellstream
neu gesetzt
werden, um die ImageReader-internen Variablen (vor allem die Image-Index-Tabelle) zurückzusetzen und
dann ist es endlich möglich, an der Stelle, an der das Auslesen der Tabellen beendet wurde, das Einlesen
des eigentlichen Bildes unter Zuhilfenahme ebendieser Tabellen
fortzusetzen.
Doch Obacht: diese Methode des Einlesens eines Bildes funktioniert nur, wenn die Tabellen auch wirklich
als Erstes in der Datei definiert werden, ansonsten schlägt diese Methode fehl und es sollte stattdessen
eher die "normale"
Methode
ohne zusätzliche Tabellenbehandlung verwendet werden. Festgestellt werden kann dies durch Überprüfung
auf den DQT
-Marker direkt nach
SOI
am Beginn des Stroms.
Eine Implementierung der oben beschriebenen Logik kann in den statischen Methoden
toImage(byte, DefineBitsJPEG2, Component)
und extractReadParamTables(IIOMetadata)
der Klasse org.karlchenofhell.swf.ImageViewer
gefunden werden.