Der zeroseven SOUND VISUALIZER

Der Visualizer ist aus der einfachen Idee entstanden, Sounds mittels Flash zu visualisieren. Begonnen hat es mit einfachen Ausgaben des Spektrums eines Sounds mit Hilfe der computeSpectrum() Methode des SoundMixers. Immer weitere Versuche, was mit dem entstehenden ByteArray machbar ist, entstanden.

In Gesprächen entwickelte sich dann die Idee, eine Plattform zu schaffen, welche Sounds eines Users analysiert, visualisiert und später dann ein Bild zum Download der aktuellen Visualisierung anbietet. Ein einfacher Screenshot wäre hier möglich gewesen und die Bilder jpg- oder png-kodiert zum download anzubieten. Aber solche Bilder sind sehr klein und können dann z.B. nicht als Plakat gedruckt werden. Also suchte ich nach einer anderen Lösung. SVG wäre eine Variante gewesen. Dazu hatte ich auch schon die Grundzüge eines Exporters geschrieben, der die XML-Struktur aus Graphics-Elementen in ActionScript bilden kann. Hiermit wäre zumindest die freie Skalierbarkeit des Plakates gewährleistet. Etwa zu dieser Zeit bin ich dann auf die Bibliothek AlivePDF von Thibault Imbert gestoßen und hab auch hier erste Versuche betrieben (siehe labs-Eintrag dazu). Und nach ein paar Tests war klar, das ist der Weg, den ich für den Visualizer gehen muss.

Aber der SVG Exporter war nicht ganz gestorben. Das Logging-Tool das im Hintergrund mitläuft ist noch immer Teil der Anwendung. Einfach gesagt, merkt sich dass Tool die Spezifikationen aller Elemente. Dieses Log nutze ich jetzt beim PDF-Export zum Erstellen der Elemente des PDFs.

Anfangs mit random-Farben ausgestattet, brachte Sebastian die Idee ins Spiel Kuler für Farbprofile zu nutzen. Also erfolgte mit Hilfe des Adobe Syndication Packages das Laden und Auslesen des Feeds der 20 beliebtesten Farben von Kuler. Dennoch hat auch der User die Möglichkeit eigene Farben zu verwenden. Ein eigenes ColorPicker-Tool kommt hier zum Einsatz.

Auch die Formen wurden vielfältiger. Anfangs nur mit Kreisen gezeichnet, kamen weitere Grundformen und Polygone hinzu. Auch die Möglichkeiten der Ausgabe erweiterten sich, je mehr ich mich darin „reingetestet“ hatte. Eigene Formate entstanden sowie Hilfstools zur Umrechnung von Pixelwerten aus dem Logger hin zu Zoll und Millimeter. Die Oberfläche bekam ein schickes Design verpasst und weitere Funktionen spendiert, um dem User mehr Möglichkeiten zu geben sein eigenes Plakat zu erstellen.

Ein Problem das es zudem zu bewältigen galt, waren die Probleme der SoundMixer.computeSpectrum() Methode. An sich eine tolle Sache und auch die Möglichkeit den ByteArray als RAW-Daten oder als Daten mit einer schnellen Fourier-Transformation zu erhalten ist sehr viel wert. Aber der SoundMixer hat einen entscheidenden Nachteil. Er ist eine globale Klasse und greift somit auf alle möglichen Sounds zu. Das führte dazu, dass der Visualizer zum Beispiel versucht auf die Sounds eines Videos von YouTube zuzugreifen, wenn dieses in einem anderen Browser Tab oder Fenster läuft. Und ganz klar entsteht dabei ein Sandbox-Problem. Umgangen habe ich diese Problematik mit Hilfe der Sound.extract() Methode. Sie liefert den ByteArray gleich zu Anfang zurück und zwar für den gesamten Audiostream. Daher erfolgt hier die Abtastung anders und etwas komplizierter als bei der computeSpectrum() Methode. Aber auch hierzu gibt es schon einen labs-Eintrag von mir (Link).

So entwickelte sich mit der Zeit eine Oberfläche, die für mich zum einen als Versuchs- und Testprojekt diente, aber letztendlich ein Tool darstellt, das ein breites Spektrum der Flashfunktionen abdeckt und auch zeigt was man performancetechnisch mit Flash so anstellen kann.

Aber nun nicht länger lesen sondern einfach ausprobieren:
http://visualizer.zeroseven.de/

Des weiteren möchte ich noch Thibault Imbert für seine Mühe und Arbeit bei AlivePDF danken, ein wirklich hammerkrasses Tool! Ebenso Sascha Wolter für seinen SystemManager, den Junges von Greensock für TweenLite & TweenMax, den Entwicklern des De MonsterDebugger und denen von pixelbreaker.com für das MacMouseWheel.

www.alivepdf.org
www.wolter.biz
www.greensock.com
www.pixelbreaker.com
www.adobe.com
www.demonsters.nl

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

PDF in PHP mit Seitenzahl generieren

Um mit PHP automatisiert PDF-Dokumente erstellen zu können, bietet sich die kostenlose PHP-Klasse „FPDF“ an. Diese Klasse erkennt automatisch, wann die aktuelle Seite voll ist und erzeugt dann selbstständig eine weitere Seite. Man braucht sich also vorher keine Gedanken über die Seitenanzahl machen. Jedoch ist es hilfreich, nach dem erzeugen des Dokuments, einen schnellen Überblick zu haben, wie viele Seiten die Datei enthält und auf welcher Seit man sich befindet. Auch das ist mit FPDF kein Problem.

Funktion beim Seitenwechsel automatisch aufrufen
Wenn von FPDF eine neue Seite erzeugt oder das Dokument geschlossen wird, wird automatisch die Funktion Footer() aufgerufen. Diese Funktion ist erstmal leer, da FPDF aber schön objektorientiert funktioniert, ist es kein Problem diese Funktion zu überschreiben und den eigenen Bedürfnissen anzupassen.

Anstatt FPDF direkt zu instanziieren, arbeiten wir also mit einer Unterklasse, die wir an unsere Bedürfnisse anpassen können.

<?php
// so wuerden wir eine Instanz von FPDF erzeugen
// $pdf = new FPDF();

// wir erzeugen aber eine eigene Klasse ...
class MyFPDF extends FPDF {

	function Footer() {
		// ... some stuff to do ...
	}
}

// ... um diese dann zu verwenden
$pdf = new MyFPDF();

?>

In dieser Footer()-Funktion können wir Text auf das PDF-Dokument schreiben.

function Footer() {
	$this->SetFont('Arial', 'B', 8);
	$this->Cell(0,10,'Seite A von B',0,0,'C');
}

Dynamische Seitenzahl
Die aktuelle Seitenzahl kann mit der Funktion PageNo() ausgelesen werden und für die Anzahl der Gesamtseiten verwenden wir den Platzhalter {nb} – dazu später mehr.

function Footer() {
	$this->SetFont('Arial', 'B', 8);
	$this->Cell(0,10,'Seite '.$this->PageNo().' von {nb}',0,0,'C');
}

Position der Anzeige
Als nächsten Schritt Positionieren wir die Anzeige auf der Seite dort, wo wir sie erwarten. Nämlich unten. Allerdings müssen wir dazu den Margin-Bereich auf 0 setzen, da wir mit FPDF eigentlich nicht außerhalb dieses Bereichs schreiben dürfen. Die fertige Footer()-Funktion sieht dann wie folgt aus:

function Footer() {
	$this->SetAutoPageBreak(true, 0); // set bottom margin to 0 mm
	$this->SetXY(10,277); // set position
	$this->SetFont('Arial', 'B', 7.98);
	$this->Cell(0,10,'Seite '.$this->PageNo().' von {nb}',0,0,'C');
	$this->SetAutoPageBreak(true, 20); // set bottom margin to 20 mm
}

Zunächst wir der Margin-Bereich auf 0 gesetzt. Dann die Position für das Textfeld bestimmt, anschließend die Schriftart, -schnitt und -größe. Daraufhin wird das Textfeld mit Inhalt und einigen weiteren Parametern erzeugt. Und zum Schluss wird der Margin-Bereich wieder zurück gesetzt.

Update
Die Manipulation mit dem Margin-Bereich ist nicht nötig, wenn die Aktion in der Funktion Footer() erfolgt. Von dieser Funktion aus kann auch unterhalb des Bottom-Margins geschrieben werden.

Gesamt-Anzahl der Seiten anzeigen
Bis jetzt steht in der Ausgabe noch immer der Platzhalter {nb} anstatt der Gesamtzahl der Seiten. Um diesen Alias zu ersetzen muss die Funktion AliasNbPages([string alias]) aufgerufen werden. Über den optionalen Parameter kann dabei der Name des Platzhalters definiert werden. Bleibt der Parameter leer, wird automatisch {nb} verwendet.

Hier also der Komplette Code:

<?php
// wir erzeugen eine eigene Klasse ...
class MyFPDF extends FPDF {

	function Footer() {
		$this->SetAutoPageBreak(true, 0); // set bottom margin to 0 mm
		$this->SetXY(10,277); // set position
		$this->SetFont('Arial', 'B', 7.98);
		$this->Cell(0,10,'Seite '.$this->PageNo().' von {nb}',0,0,'C');
		$this->SetAutoPageBreak(true, 20); // set bottom margin to 20 mm
	}
}

// ... um diese dann zu verwenden
$pdf = new MyFPDF();
$pdf->AliasNbPages();

?>

Weitere Informationen zu FPDF und den jeweiligen Funktionen gibt es auf der offiziellen Webseite: www.fpdf.org