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!

03.05.2009: Archiv (vorkompiliert) SWFParser-0.1.1 183 KBjar
03.05.2009: Archiv (nur Sources) SWFParser-0.1.1-src 47 KBtar.bz2

21.07.2008: Archiv (vorkompiliert, inkl. Sources) SWFParser-0.1 275 KBjar
21.07.2008: Archiv (nur Sources) SWFParser-0.1-src 35 KBtar.bz2

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.