Aus Flash & Flex generierte PDFs

Oft ist es doch so, dass innerhalb einer Flash oder Flex Applikation PDFs zum download angeboten werden sollen. Sind diese fest auf dem Server hinterlegt, ist dies kein Problem. Einen Link darauf setzen und das Problem ist gelöst. Doch was nun, wenn die Inhalte aus dem SWF dazu dienen sollen, das PDF zu erzeugen. Dann wird es schon interessanter.

Ohne eine serverseitige Programmierung geht hier nichts. Zum Beispiel Java oder PHP müssen zur Hilfe genommen werden. Ärgerlich und vor allem umständlich wenn es darum geht, das PDF und die auf dem Screen enthaltenen Inhalte zu synchronisieren. Es muss hier nun überlegt werden, welche Informationen sende ich wie an den Server, um das Ergebnis zu reproduzieren, welches clientseitig eigentlich schon da ist. Wie gesagt sehr umständlich.

Thibault Imbert hat hier einen Ansatz geschaffen, der es Flash und Flex Entwicklern ermöglicht, PDFs clientseitig zu generieren. Nur ein kleines PHP Script ist noch nötig, um das PDF fertig zu stellen. Dieses ist im Package schon enthalten und fertig zum nutzen. AlivePDF heißt dieses Package und ist, was die Entwicklergemeinde freut, open source. Und die Handhabung des ganzen ist denkbar einfach.

var pdf:PDF = new PDF(orientation:String, unit:String, pageSize:Object=null, rotation:int=0);

Mit dieser Zeile ist das Grundgerüst der PDF schon erstellt, wobei orientation Hoch- oder Querformat definiert, unit das Maß in dem das PDF angelegt wird (Pixel, mm, ..), pageSize definiert die Seitengrößen (A4, A3, usw.) und letztlich rotation die Drehung der Inhalte als letzten Parameter. Für die ersten drei gibt es Klassen mit statischen Variablen zur Definition. Interessant ist hier die Size-Klasse, die sich recht leicht um weitere Seitengrößen erweitern lässt.

pdf.setDisplayMode (zoom:String = "FullWidth", layout:String = "SinglePage", mode:String = "UseNone");

Hiermit lässt sich definieren wie die Seite selbst dargestellt werden soll. Mit zoom zum Beispiel ist die Vergößerung der Anzeige definiert oder mit layout das Layout des Dokumentes selbst. Einfache Seite, eine Spalte oder zwei Spalten links sind mögliche Parameter.

pdf.addPage(page:Page = null);

Hiermit wird eine Seite im PDF hinzugefügt, der dann schlussendlich die Inhalte hinzugefügt werden. Als Parameter ist es möglich ein Page-Objekt mitzugeben, welches wiederum andere Größen- und Formatausrichtungen haben kann, als das PDF selbst. Damit können im PDF auch unterschiedliche Seitengrößen erzeugt werden, je nach dem was gerade benötigt wird.

Nun ist die erste Seite erzeugt und lässt sich mit Inhalten befüllen. Dabei gibt es Funktionen zur allgemeinen Seitendefinition (z.B. setRightMargin) oder eben um Inhalte einzufügen. Dabei können Grafikobjekte wie Kreise, Flächen oder Pfade erzeugt werden, wobei hier die sehr große Ähnlichkeit zu den Graphics-Funktionen den Workflow von vorne herein einfach gestalten. Aber auch Texte oder Bilder können eingefügt werden. Aber auf all diese Funktionen nun einzugehen, würde jeden Rahmen sprengen.

Um nun aus dem PDF-Objekt ein richtiges PDF zu machen, wird nun das create.php aus dem Package benötigt. An diese sendet man den erzeugten ByteCode und das php-File sagt dem ByteStream: „Du bist ein PDF und jetzt kann man dich runterladen.“ Das war es auch schon. Wie gesagt sehr einfach gehalten.

Um es kurz zusammen zu fassen, es gibt eine unglaubliche Masse an Funktionen und Einstellungsmöglichkeiten, dabei handelt es sich bei der aktuellen Version von AlivePDF um eine Alpha-Version und bisher ist mir noch kein Fehler untergekommen. Also hat Thibault ganze Arbeit geleistet! Vieles ist noch immer etwas experimentell, da die Dokumentation noch nicht sehr weit gediehen ist, aber bei einer Alpha Version ist dies glaub zu verkraften. Insgesamt also schon jetzt ein sehr gelungenes Werk.

Noch ein paar Links zum Thema:
www.alivepdf.org
Dokumentation
Download

Und drei kleine Videotutorials:
Getting Started
Flex & AlivePDF
Introduction on Adobe TV

Google Analytics für Flash und Flex

Google Analytics ist ein mächtiges Tool um das Nutzerverhalten innerhalb einer Seite zu untersuchen. Wo klickt der User, welche Themen sind besonders interessant und wie kann die Seite für den Nutzer optimiert werden? Dies sind nur ein paar Punkte bei denen Google Analytics hilfreich zur Seite steht.

Bei Flash und Flex Anwendungen war hier bisher Schluss. Die Seite wird aufgerufen, das SWF geladen und dies war der letzte Aufruf des Trackers, wenn der User sich ab nun innerhalb der SWF bewegt. Ein Zustand der jeden Marketingmenschen zur Verzweiflung treibt.

public var gaTracker:GATracker;

Der hier aufgeführte GATracker ist der Kern des com.google.analytics – Packages. Es enthält alle notwendigen Klassen um Google Analytics auf einer Flash oder Flex Anwendung anzusprechen. Dazu wird wie oben beschrieben eine Variable der GATracker erstellt. Über diese läuft dann die gesamte Kommunikation.
Nur wird bei applicationComplete (Flex) oder eben im Konstruktor (Flash) die oben beschriebene Variable instanziiert. Dazu müssen verschiedene Parameter mitgegeben werden damit die Kommunikation zu Google Analytics auch so funktioniert wie es soll. Wenn die Flash oder Flex Anwendung und auf dem MVC-Model basiert, bietet es sich zu dem an, die Tracker Variable im Model anzulegen. So lässt sie sich von überall nutzen.

Um nun aber auf die Parameter der Instanziierung einzugehen:

gaTracker = new GATracker(this, 'XX-XXXXXXX-X', TrackerMode.AS3, true);

Dies beschreebt die Instanziierung der GATrackers via ActionScript. Wobei ‚this‘ das parent DisplayObject darstellt. Ich denke dass es sinnvoll ist, mit this auf root der SWF zu verweisen. Als nächstes kommt der Google Analytics-Account. Diese ID einfach hier als String eintragen. Nun wird es interessanter. Der dritte Parameter beschreibt den TrackerMode ausgehened von der App. Dabei gibt es zwei Modi: TrackerMode.AS3 oder TrackerMode.BRIDGE. Dabei lässt es sich recht einfach unterscheiden, welchen Modus man verwenden soll. Der BRIDGE Modus wird genutzt, wenn in der HTML-Seite, in welche das SWF eingebettet wird, bereits ein Google Analytics-Tracker vorhanden ist. Dieser Tracker wird im BRIDGE-Modus über External-Interface angesprochen und dann auch für die Kommunikation zu Google Analytics genutzt. Der AS3-Modus wird hingegen genutzt, wenn kein Tracker in der HTML-Seite vorhanden ist. Der letzte Parameter sagt aus, ob der Tracker im Debug-Modus laufen soll oder nicht. Dies ist besonders interessant während der Entwicklung um zu überwachen welche Informationen gesendet werden.

Für die Flex-MXML Syntax gibt es einen eigenen Tag zum implementieren:

Hier verhalten sich die Attribute wie oben beschrieben, nur eben das es keinen Verweis auf das DisplayObject gibt, da der Tag sowieso schon in einem liegt. Hinzu kommt aber eine ID um den Tracker aufrufen zu können.

Wie wird nun die Userinteraktion an Google Analytics übertragen? Um es vorweg zu sagen, man kann als Entwickler definieren was alles getrackt werden soll und wie es ankommt. So ließe sich zum Beispiel vom MouseClick bis hin zur kleinsten Mausbewegung alles mittracken. Das dies (meist) nicht sinnvoll ist, ist klar aber es zeigt auf, welche Möglichkeiten es gibt.

Es gibt zwei Aufrufe zum senden von Informationen. trackPageview und trackEvent. Mit dem ersten wird GoogleAnalytics eine Information übermittelt, entsprechend dazu, wenn der User auf eine andere Seite navigieren würde:

gaTracker.trackPageview("/aFakePage");

Dabei wird die „neue“ Verzeichnisstruktur in der sich der User befindet, an Google übermittelt. Eben so als hätte sich die URL verändert.
Die zweite Möglichkeit dient dazu interne Events der RIA zu übermitteln, die nicht von der Usernavigation ausgehen.

gaTracker.trackEvent('category', 'action', 'label', [value:optional]);

Hier entspricht die „category“ der Gruppe zu der der Event zugeordnet werden soll und die „action“ ist inhaltlich an die „categorie“ gebunden. Das heißt, wenn es sich um Events handelt, die beispielsweise von einer Videosteuerung ausgehen, ist es sinnvoll die „category“ ‚video‘ zu nennen und the „actions“ wären zum Beispiel „play“, „pause“ und so weiter. Das „label“ bietet die Möglichkeit weitere Informationen zum category-action-Paar zu übermitteln, ebenso wie über „value„, wobei es sich hier um einen positiven Integer handeln muss.

Insgesamt eine sehr einfache Variante, um aus einem SWF heraus zu Google Analytics zu kommunizieren. Letztendlich würden sorgar zwei Zeile Code ausreichen, um den Datenaustausch zu erstellen. Das Package gibt es im übrigen zum Download bei GoogleCode.

Links:
http://code.google.com/p/gaforflash/
http://www.insideria.com/2009/02/using-google-analytics-within.html

Flash und Flex debuggen mit dem De MonsterDebugger

Der De MonsterDebugger ist ein Open Source Projekt des Design Studios De Monsters.

Der Debugger ist in Flex realisiert und wird AIR Applikation verwendet. Diese stellt alle Objekte einer laufenden Flash, Flex oder AIR Applikation in einer übersichtlichen Baumstruktur dar, vergleichbar mit dem Debugger des Flex Builders / Flash Builders.

Der Vorteil zum Flex Debugger ist allerdingst, dass Properties der Instanzen direkt geändert werden können und diese Änderungen Live in der Applikation sichtbar sind (bekannt aus der Firefox Erweiterung FireBug). Außerdem werden alle Funktionen angezeigt und diese können zur Laufzeit ausgeführt werden.
Der Debugger enthält eine eigene trace Funktion die nicht nur Strings ausgeben kann sondern Objekte als Baumstruktur aufschlüsselt, also eine wesentlich übersichtlichere Darstellung als wenn man sich ein Objekt mit ObjectUtil.toString() ausgeben lässt.

Ein Großer Nachteil ist, dass nur Properties und Funktionen die auf public gesetzt sind angezeigt und werden können. Der Debugger verwendet intern die Funktion describeType(myObject) : XML die eine XML Struktur über das Object zurückgibt. Hier werden allerdings nur alle Properties und Funktionen die public sind ausgegeben.
Der Debugger unterstützt auch keine Breakpoints wie ein klassischer Debugger, dafür bietet er einen guten Einblick in die aktuell dargestellten und geladenen Objekte.

Anwendung

Um den Debugger nutzen zu können muss zuerst die entsprechende AIR Anwendung installiert werden. Daraus kann über File->Export Client Class die Client Klasse exportiert werden, die dann in das Flash / Flex Projekt eingebunden werden muss.

Beispiel Flash

package {
	import flash.display.Sprite;
	import nl.demonsters.debugger.MonsterDebugger;

	public class Main extends Sprite {

		// Variable to hold the debugger
		private var debugger:MonsterDebugger;

		public function Main() {

			// Init the debugger
			debugger = new MonsterDebugger(this);

			// Send a simple trace
			MonsterDebugger.trace(this, "Hello World!")
		}
	}
}

Beispiel Flex

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="init()">
	<mx:Script>
		<![CDATA[

		// Import the debugger
		import nl.demonsters.debugger.MonsterDebugger;

		// Variable to hold the debugger
		private var debugger:MonsterDebugger;

		private function onInit():void
		{
			// Init the debugger
			debugger = new MonsterDebugger(this);

			// Send a simple trace
			MonsterDebugger.trace(this, "Hello World!");
		}
		]]>
	</mx:Script>
</mx:Application>

Fazit

Der De MonsterDebugger ersetzt nicht den Debugger des Flex Builders, aber gerade um komplexere Objekte zu tracen ist er gut geeignet. Der größte Vorteil ist, dass sich Anwendungen in ihrer wirklichen Umgebung (also im Netz, oder als AIR Anwendung) einfach und komfortabel Inspizieren lassen.

Weitere Informationen und Download unter http://www.demonsterdebugger.com/

Text Layout Framework für Flash, Flex und AIR

Das neue Text Layout Framework für den Adobe® Flash® Player 10 and Adobe AIR® 1.5 ist als Beta Version bei Adobe Labs verfügbar. Das Framework setzt auf die neue Text-Engine des Flash Player 10 auf und kann ab Flash CS4 und dem Flex SDK 3.2 benutzt werden. In der nächsten Version von Flex (Codename „Gumbo“) ist das Framework bereits integriert.

Features

Die wichtigesten Features sind:

  • Verschiedene Textrichtungen: links-rechts, rechts-links sowie vertikal
  • über 30 verschiedene Schriftsysteme unter anderen Arabisch, Hebräisch, Chinesisch, Japansich, Koreanisch, Thailändisch, Laotisch und die wichtigesten Systeme von Indien.
  • Verschiedene text styling Optionen wie Ligaturen, Kerning, Leading, Hoch- und Tiefgestellter Text ect.
  • Mehrspaltigkeit
  • Verknüpfte Text Container
  • Tabulatoren
  • Inline Bilder die sich wie Buchstaben im Textfluss verhalten.

Architektur

Der interne Aufbau des Text Layout Frameworks lehnt sich an das Model-View-Controller (MVC) Entwurfsmuster an.

Im Model wird ein abstrakter TextFlow definiert der den Text selbst enthält. Der Text über eine an XHTML angelehnte Struktur hierarchisch gegliedert. Als Basis dient immer eine Instanz der TextFlow Klasse, diese kann direkt einen Absatz (p) enthalten oder einen Container (div). Das DivElement kann wiederum ein DivElement oder einen Absatz enthalten. Der Absatz kann eine SpanElement (Span), eine Grafik (Graphic), ein Link (Link) oder ein TCYElement enthalten. Ein TCYElement repräsentiert kurze Textabschnitte die sowohl horizontal als auch vertikal ausgerichtete Texte enthalten können. Das TCYElement kann ein oder mehrere Span Elemente enthalten.
Außerdem gehört eine Konvertierungsklasse zum Model die Text importieren und wieder exportieren kann.

Im View wird der Text mit Hilfe der neuen Text-Engine des Flash Player 10 gerendert und angezeigt. Für das rendern gibt es zwei Ansätze, einen einfacheren für statischen Text und einen aufwendigeren für dynamischen Text der auch bearbeitet werden kann (siehe Beispiel).

Der Controller des Text Layout Frameworks enthält Klassen um Interaktionen des Benutzers mit dem Text und dessen Formatierung zu realisieren.

Beispiel für das Einbinden von des Text Layout Frameworks in Flex:

<mx:Script>
<![CDATA[
import flashx.textLayout.edit.UndoManager;
import flashx.textLayout.edit.EditManager;
import flashx.textLayout.container.DisplayObjectContainerController;
import flashx.textLayout.container.IContainerController;
import flashx.textLayout.conversion.TextFilter;
import flashx.textLayout.elements.TextFlow;

// container to hold the text
private var _container:Sprite = null;

private function init() : void {

// create a sprite to hold the TextLines
_container = new Sprite();
textContainer.rawChildren.addChild(_container);

// The text to display in the textContainer
var markup:String = ‚<TextFlow xmlns=“http://ns.adobe.com/textLayout/2008″><p><span>Hello,</span> <span     fontWeight=“bold“>World</span></p></TextFlow>‘;

// import the text into a new textFlow
var myFlow:TextFlow = TextFilter.importToFlow(markup, TextFilter.TEXT_LAYOUT_FORMAT);
// create a controller instace
var contr:IContainerController = new DisplayObjectContainerController(_container, textContainer.width,     textContainer.height);
// associate the controller with the flowComposer property of the text flow
myFlow.flowComposer.addController(contr);

// create a new instace of the EditManager and assign it with the interactionManager of the flow
myFlow.interactionManager = new EditManager(new UndoManager());

// update the display list
myFlow.flowComposer.updateAllContainers();
}

]]>
</mx:Script>

<mx:Canvas id=“textContainer“ width=“100″ height=“50″ backgroundColor=“0xFFFFFF“ top=“20″ left=“20″/>

Das war ein kurzer Einblick in das neue Text Layout Framework. Weitere Informationen gibt’s bei Adobe unter http://labs.adobe.com/technologies/textlayout/#fma

Reduzieren der Dateigröße eines Flex-SWFs

Flex-SWFs wachsen gerade bei komplexen Anwendungen oft zu relative großen Dateien an. Größen über 2 MegaByte sind keine Seltenheit. Daraus resultieren größere Ladezeiten für den User und die Gefahr, dass dieser, wenn diese Zeit zu lang wird, den Download abbricht und die Seite und deren Inhalt nie ansehen wird. Jedoch gibt es einige Einstellungen für den Compiler und Möglichkeiten der geladenen Asstes zu reduzieren.

Fangen wir zunächst mit den Compilereinstellungen an:

mxmlc -optimize=true MyApp.mxml
Dieser Ausdruck weist den Compiler an die Dateigröße zu optimieren, indem redundanter Bytecode entfernt wird.

mxmlc -debug=false MyApp.mxml
Durch diese Einstellung werden alle Zeilennummern oder Navigationsinformationen aus dem SWF entfernt, die eigentlich nur während der Entwicklung notwendig sind. Auch dieser Schritt reduziert die Dateigröße um einen großen Schritt.

mxmlc -strict=true MyApp.mxml
Hier verifiziert der Compiler alle Definitionen und Packages innerhalb der import-Statements. Werden Klassen nicht benötigt wirft der Compiler einen Fehler und die Klassen können entfernt werden. Des weiteren wird somit während des compilierens eine Typprüfung durchgeführt, was die Dateigröße wiederum etwas reduziert.

mxmlc -link-report=true MyApp.mxml
Diese Einstellung erstellt eine Zusammenfassung im XML-Format welche Verlinkungen verwendet werden. Somit lässt sich untersuchen welche Verknüpfungen vorhanden sind und daraus schließen ob diese auch wirklich benötigt werden. Während der Codeentwicklung ist es üblich Referenzen auf Klassen zu erstellen, die dann später doch nicht verwendet werden. Diese können mit dieser Zusammenfassung erkannt und entfernt werden.

Auch im Code lassen sich Vorkehrungen treffen um die Dateigröße zu reduzieren. Eine davon ist die Typprüfung mit der getQualifiedClassName() Methode. Prüft man zu Laufzeit ab ob ein Child zum Beispiel ein Button ist wird dies mit einen is-Vergleich durchgeführt.
var isAButton:Boolean = child is mx.controls.Button;
Durch diese Anweisung wird der Compiler dazu gebracht die Buttonklasse in das SWF zu integrieren, auch wenn diese gar nicht benötigt wird. Mit der getQualifiedClassName()-Methode lässt sich der selbe Vergleich bewerkstelligen, ohne jedoch die Vergleichsklasse zu laden.
Die Methode liefert einen String zurück, welche mit dem Namen einer Klasse verglichen werden kann.
var className:String = getQualifiedClassName(child);
var isAButton:Boolean = className == "mx.controls::Button";

Des weiteren muss man überlegen ob wirklich alle Assets von Anfang an in die Anwendung geladen werden müssen, oder nicht doch zur Laufzeit hinzugefügt werden. Dies lässt dich über die Modularisierung des Projektes, run-time stylesheets, RSLs oder eben über das Laden der Assets zur Laufzeit und nicht über das Einbetten dieser, bewerkstelligen. Jedoch ist hier zu überlegen, ob wirklich immer eine Ersparnis vorliegt, denn letztendlich müssen die Daten sowieso geladen werden, die Frage ist wann. Auf jeden Fall ist mit dieser Methode das SWF kleiner und wird schneller geladen.

Ein großer Teil der Größe einer Anwendung sind immer die verwendeten Schriften. Ein komplett eingebetteter Zeichensatz kann mehrere tausend Zeichen enthalten, auch solche die garantiert nie verwendet werden. Entwickler die aus der Flash-Ecke kommen, kennen die Möglichkeit die eingebetteten Zeichen zu reduzieren. Genau dies lässt sich auch im CSS der Applikation umsetzen. Hier wird über den @font-face die Schrift eingebettet. Über das Attribut unicodeRange lässt sich nun bestimmen welche Zeichen der Schriftart zur Anwendung hinzugefügt werden.
@font-face {
src:url("../assets/MyriadWebPro.ttf");
fontFamily: myFontFamily;
unicodeRange:
U+0041-U+005A, /* Upper-Case [A..Z] */
U+0061-U+007A, /* Lower-Case a-z */
U+0030-U+0039, /* Numbers [0..9] */
U+002E-U+002E; /* Period [.] */
}

Ein weiterer Punkt wo die eingebetteten Zeichen bestimmt werden können ist die flex-config.xml, mittels dem <language-range> Tag.
<language-range>
<lang>Latin I</lang>
<range>U+0020,U+00A1-U+00FF,U+2000-U+206F,U+20A0-U+20CF,U+2100-U+2183</range>
</language-range>

Durch diese Einstellungen lässt sich doch einiges an der Dateigröße des SWF machen und letztendlich viele der unnötig geladenen Daten herausfiltern.

Flash Player 10 Content in Flash CS3 erstellen

Flash 10 bietet eine enorme Fülle an neuen Möglichkeiten und auch das Script hat eine Erweiterung erfahren. Da schon die Sprachreferenz für ActionScript 3 / Flash 10 herausgegeben wurde, sowie der Flash Plaer 10 bereits zum Download bereit steht, wäre es natürlich interessant die Möglichkeiten, ins besondere die der neuen AS-Klassen, zu testen.

Es gibt eine, wenn auch etwas umständlichere Möglichkeit, Flash 10 Content in Flash CS3 zu erstellen. Dazu legt man zunächst ein AS3/FL9-Dokument an und verbindet dieses mit der AS-Programmierung. In dieser Programmierung wird nun eine Versionsabfrage für den Player implemetiert:

var resultString:String = String(Capabilities.version);

Das Ergebnis aus dieser Abfrage kann nun für eine Unterscheidung zwischen den einzelnen Versionen genutzt werden. Um nun ein Ergenbis zu sehen, nutzen wir einen Befehl der nur in Flash 10 nutzbar ist: die 3D Rotation. Dazu erstellen wir einen Movieclip den wir um die x-Achse rotieren und schreiben den Film heraus.

Um nun einen echten Flash 10 Content zu bekommen öffnen wir das erstellte SWF-File in einem HexCode-Editor. Hier ersetzten wir das 4 Paar (09 bei Flash 9 Content durch ‚0A‘. Dies zeigt dem Player nun an, dass Version das SWF-File von der Version 10 ist. Öffnen wir nun das SWF in einem Flash 10 Player sehen wir den rotierten MovieClip, ansonsten nur den planen MovieClip.

Sollten bei Ihnen schon der Player 10 installiert sein, sehen Sie hier eine rotierte Fläche. Bei den Versionen unter 10 ist eine plane Ebene zu sehen:

Flash 10 Content in Flash CS3

Download des aktuellen Players unter: adobe.com

LocalConnection

In manchen Fällen ist es nötig dass zwei getrennte SWF-Container mit einander kommunizieren können, um zum Beispiel einen Datenaustausch oder eine Steuerung des einen SWFs durch das andere zu gewährleisten.

Für diese Kommunikation gibt es verschiedene Möglichkeiten und auch Schnittstellen. Eine wäre die Kommunikation mittels JavaScript falls die SWFs in der selben HTML-Seite liegen. Jedoch birgt dies Probleme: Die Kommunikation entfällt falls JavaScript deaktiviert ist und ist dies ein kleines Sicherheitsrisiko da dem User ein Zugang zur SWF-Datei geboten wird. Hier kann der User die Daten manipulieren.

Interessanter für eine Schnittstelle ist die LocalConnection. Sie bietet alle erforderlichen Funktionen und Eigenschaften um die Kommunikation zu erstellen. Mit ihr wird ein eindeutiger Kommunikationskanal geschaffen, worüber Funktionen mit Parameterübergabe in der anderen SWF aufgerufen werden kann.

Der Datenaustausch ist bei der LocalConnection auch nicht darauf beschränkt, dass beide SWFs in einem Container liegen. Vielmehr können mit ihr alle SWFs die auf einem Client laufen miteinander Daten austauschen, also kann zum Beispiel eine AIR-Applikation mit einem SWF in einer HTML-Seite kommunizieren. Auch der Datenaustausch zwischen Flash und Flex ist möglich, da beide die entsprechende Klasse bereitstellen.

Der Aufbau einer LocalConnection ist relativ einfach und innerhalb weniger Zeilen Code realisierbar:

Sender SWF

private var _localConnect:LocalConnection = new LocalConnection();
private function initConnection() : void{

_localConnect.addEventListener(StatusEvent.STATUS, onStatusHandler);
}
private function onStatusHandler(event:StatusEvent):void {
switch (event.level) {
case "status":
trace("LocalConnection.send() succeeded");
break;
case "error":
trace("LocalConnection.send() failed");
break;
}
}
private function aButtonClicked(event:MouseEvent) : void{
_localConnect:LocalConnection.send('connectionName', 'calledFunction', param:Type);
}

Empfänger SWF

private var _receiveConnect:LocalConnection = new LocalConnection();
private function initConnection() : void{
_receiveConnect.client = this;
try {
_receiveConnect.connect('connectionName');
}
catch (error:ArgumentError) {
trace("Can't connect.");
}
}
public function calledFunction (param:Type) : void {
// do something
}

Mit diesen beiden Codeschnipseln lässt sich die Kommuniktion aufbauen und problemlos Daten senden. Die Kommunikation erfolgt, wie man im Beispiel sieht immer nur in eine Richtung. Für die Rückkommunikation ist eine weitere LocalConnection erforderlich. Jedoch ist eine Kommunikation zwischen ActionScript 3 SWFs in Richtung ActionScript 1 und 2 SWFs, sowie in entgegengesetzter Richtung, möglich.

Mit der LocalConnection ist also eine einfach erstellte Schnittstelle, die eine problemlose Kommunikation ermöglicht, vorhanden. Sie kann vielfältig genutzt werden und bietet viele Vorteile gegenüber einer Kommunikation mit zum Beispiel ExternalInterface zwischen SWFs.

Flash Matrix

Die Matrix Klasse ist eine Transformationsmatrix. Sie legt fest, wie ein Punkt innerhalb des Koordinatensystems einem anderen Koordinatenraum zugeordnet ist. Mit Hilfe dieser Matrix ist es möglich, Objekte zu verschieben, skalieren, drehen und zu scheren beziehungsweise zu neigen. Dabei handelt es sich um affine Transformationen, was bedeutet, dass gerade und somit parallele Linien erhalten bleiben.

Über die transform() Methode lassen sich somit DisplayObjects mit den oben beschriebenen Eigenschaften modifizieren. Aber auch der BitmapData.draw() Methode enthält als Parameter eine Matrix, welche dann bestimmt, wie das neue BitmapData-Objekt gezeichnet wird. Ein weiteres Anwendungsgebiet der Matrix ist die Bestimmung der Fülleigenschaften von display.Graphics (BitmapFill, GradientFill, GradientStyle). Hier lässt sich mit der Matrix die Art der Füllung mit bestimmen.

Die Flash-Matrix ist grundsätzlich gesehen eine 3×3-Matrix:

Flash 3x3 Matrix

Für die oben beschriebenen Transformationen werden jedoch nur die oberen beiden Zeilen verwendet. Die Werte u = 0, v = 0 und w = 1 verhalten sich neutral. Diese untere Zeile wird nicht verwendet, da Flash nur im 2D-Raum operiert und die oben beschiebenen Werte werden somit vorausgesetzt. Dies bedeutet die Flash-Matrix sieht eigentlich so aus:

Flash 2x3 Matrix

Für die Verschiebung werden die tx und ty Eigenschaften verändert:

Flash Matrix Verschiebung

Für die Skalierung werden die Eigenschaften a (sx) und d (sy) verändert:

Flash Matrix Neigung

Bei der Rotation werden die vier Werte a, b, c und d verändert mit der folgenden Werteberechnung:
a -> cos(alpha)
b -> -sin(alpha)
c -> sin(alpha)
d -> cos(alpha)

Flash Matrix Rotation

Das Scheren, beziehungsweisen Neigen lässt sich mit den Eigenschaften b und c definieren:
b -> tan(neigungx)
c -> tan(neigungy)

Flash Matrix Neigung

Anwendungsbeispiel:

Anwendung findet die Matrix zum Beispiel beim „kopieren“ von Bildteilen. Nimmt man ein Bitmap als Ausgangsgrafik und will einen bestimmten Bereichen davon in ein anderes BitmapData-Objekt zeichnen, ist eine Matrix unerlässlich. Zunächst wird ein leeres BitmapData-Objekt erstellt, mit der Größe der zu kopierenden Fläche. Des Weiteren wird ein Rectangle-Objekt benötigt mit ebenfalls der selben Größe. In der nun zu erstellenden Matrix werden die tx und ty Eigenschaften auf den negativen Wert der Koordinaten des Punktes gesetzt, der die linke obere Ecke des zu kopierenden Bereiches darstellt. Mit dem folgenden Script wird nun der gewünschte Bereich in das neue BitmapData-Objekt gezeichnet:

clipBitmapData.draw(originalBitmapData, transformMatrix, null, null, clipRectangle);

Dieses Objekt kann nun als eigenständiges Objekt in Flash weiter verwendet werden.

Mehr zum Thema: Matrix in den LiveDocs

Ein kleiner Nachtrag:

Gelegentlich kann es vorkommen, dass man eine Matrix hat (zum Beispiel die TransformMatrix eines Objektes) und möchte daraus wiederum den Drehungwinkel berechnen. Und wie oben zu sehen ist, geht eine Rotation in der Matrix über die 4 Parameter a, b, c und d. Also nicht ganz einfach, wenn man die Berechnung von Hand bewerkstelligen will. Aber hier hat Adobe im fl.motion-Package ein kleine Helferklasse drin, die eben solche Probleme löst. So liefert die Funktion getRotation(m:Matrix) den gesuchten Rotationswinkel in Grad zurück. Aauch die anderen Transformationen können so ausgelesen werden.

Mehr dazu unter: MatrixTransformer

Video Snapshot in Flash

Wie schon ein paar mal berichtet, bietet Flash mit den Bitmap- und BitmapData-Klassen sehr viele Möglichkeiten im Umgang mit Grafiken. Diese können in vielen erdenklichen Weisen modifiziert und verändert werden. Die Möglichkeiten dieser beiden Klassen sind damit aber noch nicht ausgeschöpft.

Vielmehr lassen sich mit diesen auch Snapshots von Videos erstellen. Dazu wird zunächst eine Videokomponente erstellt in der ein Video abgespielt wird. Wird nun der Event zum Erstellen eines Snapshots ausgelöst, wird zunächst ein BitmapData-Objekt in der Größe des Videoobjektes erstellt. In dieses wird dann das Video über die draw-Methode gezeichnet. Damit ist der größte Aufwand vollzogen. Das BitmpData-Objekt kann nun über addChild einem anderen Objekt zugewiesen werden.

Vielmehr als die oben beschriebenen Schritte sind nicht nötig um Snapshots von Videos zu erstellen. Obwohl es nur ein sehr kurzes Beispiel ist, lässt sich abschätzen, wie vielseitig anwendbar dieser Ablauf ist. So lassen sich nicht nur Videos capturen, sondern auch andere, auf der Bühne befindliche Szenerien „fotografieren“. Denkbar wäre auch, ein 3D-Model über Papervision3D einzubinden und zu animieren, um so ein virtuelles Fotoshooting zu inszinieren.

Über eine Kombination mit weiteren Funktionen von Flash lassen sich die erstellten Bilder auch nachbearbeiten. Auch eine Kombination mit PHP ist möglich, welches ein JPG aus den Bitmap-Daten generiert, was wiederum heruntergeladen werden kann.

Beispiele:
campaigns.mykindaplace.com/superman
www.fullofpotential.ca

Flash: ExternalInterface

ExternalInterface bietet dem Entwickler von Flash eine Schnittstelle zwischen ActionScript und dem Container der den Flash-Player enthält. Im besonderen können hiermit JavaScript-Funktionen in HTML-Seiten aufgerufen werden.

ExternlInterface bietet nicht nur einen Aufruf von Funktionen außerhalb von Flash, sondern hiermit können auch Rückgabewerte zurück an Flash geliefert werden. Auch der Weg vom Flash-Player-Container zu ActionScript ist möglich. Das heißt, bestimmte Funktionen können in ActionScript zum Beispiel mittels JavaScript aufgerufen wegen mit Parameter-Übergabe. Die zwei hierfür verwendeten Methoden sind die addCallback- und call-Methoden. Die addCallBack-Methode ermöglicht den Aufruf von AS-Funktionen von außen, call den Weg anders herum.

Die Parameter von ExternalInterface.addCallBack sind erstens der Name mit dem die Funktion von außen aufgerufen werden kann, zweitens das Objekt auf das sich die Methode bezieht und drittens die Methode die zur weiteren Verarbeitung aufgerufen wird. Die Verknüpfung erfolgt wie das Beispiel von Adobe zeigt:

<script>
function callExternalInterface() {
thisMovie("externalInterfaceExample").goHome();
}
function thisMovie(movieName) {
if (navigator.appName.indexOf("Microsoft") != -1) {
return window[movieName]
}
else {
return document[movieName]
}
}
</script>

Hier müssen das id-Attribut (Object-Tag) und das name-Attribut (Embed-Tag) den Wert “externalInterfaceExample“ haben.

Mit ExternalInterface.call können wie gesagt Funktionen aufgerufen werden. Call hat zwei Parameter. Zum Einen dem Funktionsnamen und zum Anderen einen optionalen Parameter. Auch kann mit der call-Methode ein Rückgabewert abgefangen und weiterverarbeitet werden.

Diese beiden Methoden bieten ein die Möglichkeit einer einfachen Implementierung einer Schnittstelle in Flash, die sich vorwiegend für die Kommunikation mit JavaScript, aber auch anderen Sprachen wie C, anbietet. Die Anwendungsgebiete hierfür sind sehr zahlreich und reichen vom einfachen Auslesen der Browserinnengröße bis zur Verwendung einer Flash-Navigation in Web 2.0 Seiten.