Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Geleitwort des Fachgutachters
Vorwort
1 Einleitung
2 Einführung in eZ Components
3 Die Applikationsbasis
4 Fehlerbehandlung und Debugging
5 Konfiguration
6 Datenbankanbindung
7 ORM mit PersistentObject
8 Template
9 Übersetzung
10 Benutzereingaben validieren
11 Authentifizierung
12 Bildverarbeitung
13 Archive und Dateien
14 Mail
15 Logging
16 Diagramme
17 Feeds und Caching
18 Setup
A Inhalt der Buch-CD
Stichwort
Download: - ZIP, ca. 2,7 MB
Ihre Meinung?
<< zurück | Galileo Computing / <openbook> /eZ Components | vor >>
eZ Components von Tobias Schlitt, Kore Nordmann Das Entwickler-Handbuch
eZ Components geb., mit CD 454 S., 39,90 Euro Galileo Computing ISBN 978-3-8362-1073-7 |
| 12 Bildverarbeitung
|  | 12.1 Bilder analysieren
|  |  | 12.1.1 Architektur
|  |  | 12.1.2 Handler und Backends
|  | 12.2 Bilder manipulieren
|  |  | 12.2.1 Architektur
|  |  | 12.2.2 Handler und Backends
|  |  | 12.2.3 Im GP-Blog
|  | 12.3 Erweiterte Möglichkeiten
|  |  | 12.3.1 Exif-Daten
|  |  | 12.3.2 Weitere Filter
|  |  | 12.3.3 ImageAnalysis erweitern
|  |  | 12.3.4 ImageConversion erweitern
|  | 12.4 Fazit
## 12.2 Bilder manipulieren Im nächsten Schritt sehen Sie die Aktion, die zum Hochladen von Bilddateien dient und in der eine entsprechende Verarbeitung stattfindet. Zuvor soll die Architektur der verwendeten Komponente ImageConversion beleuchtet werden. Anschließend erhalten Sie Einblick in den Code des GP-Blogs und werden noch etwas über eigene Erweiterungen der Komponente erfahren. ### 12.2.1 Architektur Wie ImageAnalysis greift auch die Komponente zur Bildbearbeitung auf das Prinzip der Backend-Handler zurück. Die weitere Architektur gestaltet sich aber durchaus komplexer als die der ImageAnalysis-Komponente. Insgesamt besteht ImageConversion aus fünf Ebenen, wobei Sie die tiefste Ebene zu oberst finden:
1. | Backend-Handler
2. | Konvertierungen
3. | Filter
4. | Transformationen
5. | Konverter
Der untersten Schicht, dem Backend-Handler, wird im Folgenden ein kompletter Abschnitt gewidmet, weshalb an dieser Stelle nur die weiteren Schichten von Interesse sind. Die zweite und dritte Schicht der Konvertierungen (Conversions) und Filter abstrahiert den Zugriff auf die einzelnen Handler. Eine Konvertierung ist dabei im Sinne einer Konvertierung zwischen MIME-Types zu verstehen. Ein Filter hingegen übernimmt Manipulationen an einem Bild. Jeder Backend-Handler unterstützt ein eigens Set von Transformationen und Filtern. Welche das sind, erfahren Sie ausführlich in der Onlinedokumentation der Handler sowie in der Übersicht in Abschnitt 12.3, »Erweiterte Möglichkeiten«. Die Ebene der Transformationen fasst die beiden darunterliegenden Ebenen wieder zusammen, denn eine Transformation besteht aus einer Menge von sequentiell abzuarbeitenden Filterregeln und Regeln für die Konvertierung von MIME-Types. Transformationen können mit Hilfe der obersten Ebene der Architektur, der Hauptklasse der Komponente ezcImageConverter verwaltet werden. Ein Objekt dieser Klasse bietet Ihnen einen abstrahierten Zugriff auf die zugrunde liegenden Handler-Objekte. Außerdem abstrahiert das Objekt mittels Transformationen komplett von diesen weg. #### Konverter Die Klasse ezcImageConverter ist die Hauptklasse der ImageConversion-Komponente und bietet Ihnen mehr Komfort und Struktur zur Verwaltung und Anwendung der genannten Komponenten. Der Konverter abstrahiert die Zugriffe auf die Backend-Handler des Pakets. So müssen Sie sich nicht darum kümmern, welche Backend-Handler zur Verfügung stehen oder welche Filter diese unterstützen. Der Konverter ist in der Lage, für einen Filter oder eine Konvertierung den besten Handler auszuwählen. So gibt Ihnen die Methode getHandler() die Instanz eines passenden Backend-Handlers für eine bestimmte Aufgabe, und applyFilter() erlaubt Ihnen, einen einzelnen Filter auf ein Bild anzuwenden, ohne sich darum kümmern zu müssen, welcher Backend-Handler diese Aufgabe am besten übernehmen kann. Die Verwaltung von Transformationen ist ebenfalls eine Aufgabe der ezcImageConverter-Klasse. Sie stellt Methoden bereit, mit deren Hilfe sich Transformationen erzeugen (createTransformation()), entfernen (removeTransformation()) und auf ein Bild anwenden lassen. Letzteres erreichen Sie mit Hilfe der Methode transform(), welche den Namen der anzuwendenden Transformation sowie Informationen über das zu transformierende Bild als Parameter erhält. #### Transformationen Eine Transformation ist ein Objekt der Klasse ezcImageTransformation und dient dazu, den Prozess der Umwandlung eines Bildes zu beschreiben, zu strukturieren und anzuwenden. Im Normalfall werden Sie keine Instanzen dieser Klasse selbst erzeugen. Zwar ist dies möglich, in der Regel verwenden Sie jedoch die Methode createTransformation() auf einem ezcIm ageConverter-Objekt, da dieses auch die Verwaltung der Transformation für Sie übernimmt und eine Transformation einen Konverter benötigt. Eine Transformation besteht aus einem Namen, einer Menge von Konvertierungsregeln und einer Sequenz von Filtern: Worum es sich bei den letzten beiden konkret handelt, ist Thema des nachfolgenden Abschnitts. Mit Hilfe einer Transformation beschreiben Sie also genau diejenigen Schritte, in denen ein Bild bearbeitet werden soll und legen diese Beschreibung zentral in Ihrer Instanz von ezcImageConverter ab. In der Praxis erzeugen Sie je eine Transformation für jede Bildmanipulation, die Sie in Ihrer Applikation verwenden wollen. Zusätzlich weisen Sie den Konverter an, eine definierte Transformation auf ein Bild anzuwenden. Ein typisches Beispiel ist, eine Transformation namens thumbnail zu definieren, welche Vorschaubilder erzeugt, und eine andere oldphoto, welche den Effekt eines alten Fotos auf ein Bild anwendet. Dabei konfigurieren Sie in den Transformationen die auszuführenden Schritte: Zum Beispiel, wie bei der Erzeugung eines Vorschaubildes die Größe skaliert und beschnitten werden soll. Sie greifen an beliebiger Stelle im Verlauf Ihrer Anwendung darauf zu und äußern lediglich gegenüber dem Konverter den Wunsch, ein thumbnail zu erzeugen. Haben Sie eine gewünschte Transformation im Konverter erzeugt und wenden diese mit seiner Hilfe an, werden die in der Transformation definierten Filter sequentiell abgearbeitet. Dabei ermittelt der Konverter automatisch, welcher Backend-Handler die gewünschten Filter bereitstellt und delegiert die Aufgabe der Filter-Anwendung entsprechend. Zum Schluss wird die Konvertierung zum Ziel-MIME-Type durchgeführt, was ebenfalls durch einen geeigneten Handler geschieht. Eine Transformation stellt dabei eine atomare Operation dar. Ein Bild wird also entweder komplett oder gar nicht transformiert; und benötigte Zwischenschritte werden zunächst auf einer temporären Datei ausgeführt, bevor sie endgültig wirksam werden. #### Konvertierungen Die ImageConversion-Backend-Handler sind in der Lage, Bilddateien zwischen verschiedenen MIME-Types zu konvertieren. Ein typisches Beispiel für eine solche Konvertierung ist die Umwandlung von image/bmp in image/jpeg. Viele Benutzer verwenden Bilder im unkomprimierten BMP-Format, welches sich jedoch durch den inhärenten Speicher-Overhead schlecht für den Einsatz im Web eignet. Aus diesem Grund wird das Format meist nach dem Upload durch den Benutzer vom System entsprechend ins gängigere JPEG-Format umgewandelt. Konvertierungsinformationen können Sie an zwei Stellen in der ImageConversion-Komponente definieren: Zum einen unterstützten Transformationen die Angabe von MIME-Type-Konvertierungen. Für eine Transformation bestimmen Sie eine Menge von Ausgabe-MIME-Types, welche diese erzeugen darf. Erhält die Transformation ein Bild mit einem anderen MIME-Type, führt sie eine Konvertierung in den ersten passenden MIME-Type, der ihr als Ausgabe erlaubt ist, durch. Die Entscheidung einer Transformation, welcher der geeignete MIME-Type für ein Bild ist, ist allerdings von der zweiten Stelle abhängig, an der Sie MIME-Type-Konvertierungen definieren können: In Ihrer ezcImageConverter-Instanz. Während Sie in einer Transformation sogenannte explizite Konvertierungsregeln definieren, beachten Transformationen auch die globalen (impliziten) Konvertierungsregeln. Eine implizite Regel besteht nicht nur aus der Eingrenzung des Ausgabe-MIME-Types, sondern ordnet einem Eingabetyp genau einen Ausgabetyp zu. Angenommen, Sie definieren als implizite Konvertierungsregeln in einem ezcImageConverter-Objekt das folgende Array:
    array(
        'image/bmp'  => 'image/jpeg',
        'image/tiff' => 'application/pdf',
        'image/gif'  => 'image/png',
    )
Listing 12.4 Implizite Konvertierungen definieren Die in diesem Array codierten Anweisungen besagen also, alle BMP-Bilder ins JPEG-Format zu konvertieren, aus TIFF-Daten ein PDF-Dokument zu erzeugen und GIF-Dateien in PNG-Bilder zu verwandeln. Zumindest gilt dies, solange die angewendete Transformation den entsprechenden Ausgabetyp zulässt. Dazu nehmen wir an, dass Sie für eine Transformation die folgenden expliziten Ausgabetypen definieren:
    array( 'image/jpeg', 'image/png' );
Listing 12.5 Explizite Konvertierungen für eine Transformation definieren Die Transformation darf also nur JPEG- und PNG-Bilder ausgeben. Erhält sie ein Bitmap (BMP) als Eingabe, so wird die implizite Regel gefunden, eine Konvertierung nach JPEG vorzunehmen. Da JPEG ein valider Ausgabetyp der Transformation ist, findet diese implizite Regel Anwendung. Gleiches gilt für die Eingabe eines GIF, wofür analog PNG als Ausgabetyp gewählt wird. Ein Konflikt tritt allerdings auf, wenn Sie der Transformation ein Bild im TIFF-Format übergeben: Die impliziten Konvertierungsregeln fordern hier den MIME-Type eines PDF-Dokuments als Ausgabe, der aber nicht von der Transformation gestattet ist. In diesem Fall haben explizite Konvertierungen immer Vorrang vor der impliziten Variante: Anstatt ein PDF-Dokument zu erzeugen, wird die implizite Konvertierung ignoriert und ein JPEG-Bild ist das Ergebnis, da der MIME-Type image/jpeg der erste im Array der expliziten Konvertierungen ist. #### Filter Im Gegensatz zu Konvertierungen, von denen jeweils nur eine einzige letztendlich Bestandteil einer Transformation ist, kann eine Transformation mehrere Filter enthalten. Außerdem gibt es für Filter keine Möglichkeit, globale implizite Regeln zu definieren. Lediglich die an einer Stelle definierten Filteraufrufe werden für eine Transformation herangezogen. Zunächst soll aber geklärt werden, worum es sich bei einem Filter überhaupt handelt. Der Begriff Filter wurde in den letzten Abschnitten meist etwas schwammig verwendet. Und an einer Vielzahl derjenigen Stellen, an denen Sie bisher das Wort Filter gelesen haben, hätte korrekterweise Filter-Definition stehen müssen. Wie bereits öfter erwähnt wurde, führt ein Filter eine konkrete Bildmanipulation aus. In einer Transformation verwenden wir aber nicht den Filter konkret, sondern definieren lediglich, welcher Filter mit welchen Parametern angewendet werden soll. Transformationen enthalten also eigentlich keine Filter, sondern Filter-Definitionen. Sehen Sie es uns aber bitte nach, dass wir diese Feinheit in Zukunft auch weiterhin außer Acht lassen. Die Definition eines Filteraufrufs wird in einer Instanz von ezcImageFilter codiert, die dann eine konkrete Manipulation für ein Bild darstellt. Da Filter letztendlich auch nur Methoden auf einem Handler-Objekt sind, stellt ein Objekt von ezcImageFilter lediglich die Definition eines Methodenaufrufs dar, also eine Art Delegationsmechanismus. Jeder Filter wird durch seinen Namen identifiziert und kann eine beliebige Anzahl von Parametern erwarten, die optional oder verpflichtend sein können. Der Name des Filters bestimmt die aufzurufende Methode, welche mittels der übergebenen Parameter konfiguriert wird. Ein kleines Beispiel zeigt diesen Mechanismus:
    $scaleDown = new ezcImageFilter(
        'scale',
        array(
            'width'     => 320,
            'height'    => 240,
            'direction' => ezcImageGeometryFilters::SCALE_DOWN,
        )
    );
Listing 12.6 Definition eines Filteraufrufs mit Hilfe von ezcImageFilter Der hier definierte Filteraufruf bezieht sich auf den Filter namens 'scale', welcher der einfachen Skalierung von Bildern dient. Der zweite Parameter zum Konstruktor einer ezcImageFilter-Instanz ist ein Array mit Parametern. Der Skalierungsfilter erwartet zumindest die Werte für 'width' und 'height', mit denen die Breite und Höhe des Zielbildes in Pixeln angegeben werden. Der dritte, optionale Parameter 'direction' bestimmt die Richtung des Skalierungseffekts. Sein Standardwert ist durch die Konstante ezcImageGeometryFilters::SCALE_BOTH definiert, womit erlaubt wird, dass die Skalierung sowohl größere als auch kleinere Bilder – in Hinsicht auf das Ursprungsbild – erzeugen darf. Der im Beispiel gesetzte Wert ezcImageGeometryFilters::SCALE_DOWN legt fest, dass lediglich eine Skalierung auf kleinere Formate möglich ist und Bilder, die bereits kleinere Ausmaße haben, unberührt bleiben. Der Standardskalierungsfilter arbeitet derart, dass ein eingegebenes Bild – unter Beibehaltung des Seitenverhältnisses – so skaliert wird, dass es in den angegeben Bereich passt. Ein Bild kann also maximal etwas kleiner sein als die definierten Seitenlängen, jedoch nicht größer. Eine Seite des Bildes passt immer exakt zum angegebenen Format, wobei die andere entsprechend des Seitenverhältnisses ebenfalls skaliert wird und somit potentiell kleiner sein kann als der gewünschte Wert, falls das Seitenverhältnis des Bildes ein anderes ist. Andere Skalierungsfilter erwarten andere Werte, wie Prozentangaben für die Seitenmaße oder lediglich einen einzelnen Wert, und skalieren das Pendant entsprechend des Seitenverhältnisses. Des Weiteren enthält ImageConversion eine Vielzahl anderer Filter. Wie Sie bereits im letzten Beispiel erkennen konnten, existieren für Filter entsprechende Interfaces, in denen sie zusammengefasst werden, wie das Interface ezcImageGeometryFilters, in dem unter anderem der Filter scale lebt. Die Interfaces aller Filter finden Sie ausführlich in der Onlinedokumentation der eZ Components beschrieben. Hier finden Sie auch die Parameterlisten und Typen, um den Aufruf des entsprechenden Filters zu definieren. Ob ein Backend-Handler einen bestimmten Filter bereitstellt, erfahren Sie dadurch, dass er das entsprechende Interface implementiert. Die Namen aller durch ein Filter-Interface definierten Filtermethoden können Sie zur Definition von Filteraufrufen mittels ezcImageFilter verwenden. Zu beachten ist, dass die Verwendung eines Filters, für den in Ihrer Umgebung kein Backend-Handler verfügbar ist, zu einer ezcImageFilterNotAvailableException führt, sobald Sie diesen anwenden wollen. Sie tun also gut daran, von der blinden Anwendung von Filtern, die nicht von allen Handlern unterstützt werden, abzusehen und sich entsprechend zu vergewissern, dass ein gewünschter seltener Filter aktuell verfügbar ist. Sollten Sie einen eigenen Backend-Handler für ImageConversion schreiben oder einen bestehenden erweitern wollen, steht es Ihnen natürlich frei, neue Filter-Interfaces und somit neue Filter zu definieren oder einem Handler beliebige Filter hinzuzufügen. Näheres zur Erweiterung der Komponente erfahren Sie auch im späteren Abschnitt 12.3.4, »ImageConversion erweitern«. ### 12.2.2 Handler und Backends Konvertierungen werden von Backend-Handlern bereitgestellt, Filter ebenfalls. Instanzen der Basisklasse können passende Handler für einen Filter oder eine Konvertierung finden und Transformationen verwalten, welche wiederum Filter und Konvertierungen, die ja von Backend-Handlern ausgeführt werden, zu Paketen zusammenschnüren. Wie Sie bereits bei der Vorstellung der ImageAnalysis-Komponente im vorherigen Abschnitt gesehen haben, dienen Handler-Klassen der Abstraktion verschiedener Instanzen, die in der Lage sind, im Hintergrund der Komponente die eigentliche Arbeit zu verrichten. Wie ImageAnalysis bietet auch ImageConversion von Hause aus zwei Backend-Handler an: Einen auf Basis der PHP-Erweiterung ext/gd und einen weiteren auf Basis des Bildbearbeitungspakets ImageMagick. Nähere Informationen zu Letzterem können Sie dem Kasten in Abschnitt 12.1.2, »Handler und Backends«, zur ImageAnalysis-Komponente entnehmen. Die Instanz einer Handler-Klasse ist also in der Lage, Operationen wie Filter und Konvertierungen an das von ihr unterstützte Backend weiterzuleiten und ausführen zu lassen. Wie dies im Detail aussieht, erfahren Sie in Kürze.
PHP-GD-Erweiterung
Die GD-Erweiterung war eine ursprünglich von Thomas Boutell entwickelte C-Bibliothek zur Grafikerzeugung und Grafikmanipulation, verfügbar unter anderem für PHP und Perl. Mittlerweile wird sie von Pierre Alan-Joye gepflegt und ist die wohl mit Abstand populärste Erweiterung zum Umgang mit Bildern in PHP. Auf die Schwächen und Stärken dieser Erweiterung wird im Kapitel 16, »Diagramme«, noch genauer eingegangen, wenn es um die Generierung von Statistiken geht.
#### Backend-Handler nutzen Aus Sicht des Anwenders bietet Ihnen ein Backend-Handler in ImageConversion alle Möglichkeiten an, Bilder (auch mehrere nebeneinander) zu laden, Filter auf sie anzuwenden, Konvertierungen auszuführen und die resultierenden Bilder anschließend wieder zu speichern. Alle weiteren Architekturebenen sind optional und können von Ihnen nach Belieben verwendet werden. Ein Verzicht auf diese kann durchaus Sinn machen, wenn Sie zum Beispiel nicht mit mehreren Handlern arbeiten und lediglich einfache Manipulationen benötigen, diese aber schnell passieren müssen. Abstraktion findet immer unter Zunahme von Komplexität statt, womit fast immer ein gewisser Performance-Nachteil einhergeht. Benötigen Sie die beste Performance, werden Sie also die Filtermethoden direkt aufrufen und nicht Filterdefinitionen mittels applyFilter()-Methode ausführen lassen, da dies bereits den ersten Abstraktionsschritt darstellt. Mit Hilfe einer Instanz dieser Klasse abstrahieren Sie von der direkten Arbeit mit Backend-Handlern, indem Sie für Aktionen wie Filteranwendungen und Konvertierungen die Wahl des Handlers an den Konverter übergeben. Sie erhalten außerdem den Vorteil, dass Filter, welche nur von einzelnen Handlern bereitgestellt werden, zentral über ein Interface zugreifbar sind. Fordern Sie eine Instanz von ezcImageConverter auf, einen bestimmten Filter auf eine bestimmte Datei anzuwenden, findet der Konverter automatisch einen passenden Handler für diese Aktion. Schließlich bietet ImageConversion Ihnen die Möglichkeit, Transformationen in der Basisklasse zu definieren, anstatt jeden einzelnen Schritt einer Bildmanipulation von Hand durchführen zu müssen. Eine Transformation besteht aus Filtern und Konvertierungsregeln, die unter einem Namen zusammengefasst werden. Die in ihr definierten Filter werden bei ihrer Anwendung auf ein Bild sequentiell von einem Handler ausgeführt, den die Basisklasse bestimmt und bereitstellt. Anschließend wird das Bild unter Berücksichtigung eventueller MIME-Konvertierungen gespeichert. #### Verfolgung einer Transformation Diese komplette Einheit von Anweisungen einer Transformation wird atomar ausgeführt, was bedeutet, dass entweder alle Aktionen erfolgreich oder gar keine Aktion ausgeführt wird. Um dieses Ziel zu erreichen, führt die Konverter-Klasse alle Anweisungen zuerst auf einer temporären Datei aus und verschiebt diese anschließend auf das gewünschte Ziel. So ist es auch möglich, dass verschiedene Anweisungen einer Transformation von verschiedenen Handlern ausgeführt werden. Es entsteht somit kein »Datenmüll« beim Fehlschlagen einer Aktion.
    $settings = new ezcImageConverterSettings(
        array(
            new ezcImageHandlerSettings(
                'GD',
                'ezcImageGdHandler'
            ),
            new ezcImageHandlerSettings(
                'ImageMagick',
                'ezcImageImagemagickHandler'
            ),
        ),
        array(
            'image/gif' => 'image/png',
        )
    );
    $converter = new ezcImageConverter( $settings );
    $filters = array(
        new ezcImageFilter(
            'scale',
            array(
                'width'     => 320,
                'height'    => 240,
                'direction' => ezcImageGeometryFilters::SCALE_DOWN,
            )
        ),
        new ezcImageFilter(
            'colorspace',
            array(
                'space' =>
                    ezcImageColorspaceFilters::COLORSPACE_GREY,
            )
        ),
        new ezcImageFilter(
            'border',
            array(
                'width' => 5,
                'color' => array( 240, 240, 240 ),
            )
        ),
    );
    $converter->createTransformation(
        'oldphoto',
        $filters,
        array( 'image/jpeg', 'image/png' )
    );
Listing 12.7 Erzeugung einer Transformation, die verschiedene Handler verwendet Dieses Beispiel zeigt Ihnen ein erstes konkretes Beispiel, welches alle Abstraktionsebenen der ImageConversion-Komponente beleuchtet. Zunächst wird eine Instanz der Struct-Klasse ezcImageConverterSettings erzeugt, die wiederum eine Liste von Struct-Objekten enthält. Letztere repräsentieren die Definition eines Handlers und können Einstellungen für den Handler beinhalten, wovon in diesem Beispiel kein Gebrauch gemacht wurde. Die Einstellungsmöglichkeiten gleichen denen aus Abschnitt 12.1, »Bilder analysieren«. Beide im Paket mitgelieferten Handler kommen in diesem Beispiel zum Einsatz. Wie Ihnen von ImageAnalysis bereits bekannt ist, bildet die Reihenfolge der Handler-Definitionen eine Priorisierung derselben ab. Der GD-Handler wird also bevorzugt Verwendung finden, da er zuerst definiert wurde. Wenn möglich, wird also dieser Handler der Anwendung von Filtern und Konvertierungen vom Konverter-Objekt bevorzugt, sofern er die benötigte Funktionalität bereitstellt. Erst wenn dies nicht der Fall ist, wird ImageMagick als nächstes Backend herangezogen. Nach der Erzeugung des Konverter-Objekts mit Hilfe dieser Konfiguration wird ein Array von Filtern definiert, wovon der erste bereits bekannt ist. Nach der Skalierung des Bildes auf eine maximale Größe von 320 Pixel Breite und 240 Pixel Höhe wird das Werk in einen anderen Farbraum versetzt, in dem nur Graustufen existieren. Zum Schluss wird ein Rahmen von 5 Pixeln Breite in einem Grauton um das Bild gezogen. Die so definierte Reihenfolge von Filteraufrufen wird schließlich in eine Transformation namens oldphoto verpackt, zusammen mit der Auswahl von zwei MIME-Types, die als Ausgabe erlaubt sind: image/jpeg und image/png. Wenden Sie die so definierte Transformation zum Beispiel mit Hilfe des folgenden Aufrufs auf ein Photo an, das die Ausmaße von 1600 x 1200 Pixel hat und als Bitmap gespeichert ist, wird dieses genau auf die Größe von 320 x 240 Pixel skaliert, anschließend in ein Graustufen-Bild umgewandelt, mit dem entsprechenden Rahmen verziert und als JPEG-Bild gespeichert. Das nächste Beispiel zeigt den entsprechenden Aufruf: Hier klicken, um das Bild zu vergrößern Abbildung 12.1 Durch die Transformation modifiziertes Bild
    $converter->transform(
        'oldphoto',
        'large_photo.bmp',
        'small_foto.jpg'
    );
Listing 12.8 Die Transformation anwenden Allerdings funktioniert diese Transformation nur, wenn der ImageMagick-Handler konfiguriert wurde und verfügbar ist, da nur dieser das Interface ezcImageEffectFilters implementiert, welches den Rahmen-Filter enthält. Ist dieser Handler nicht verfügbar, wird der Konverter beim Anwenden der Transformation eine ezcImageTransformationException werfen. Diese Exception-Klasse dient lediglich dem Auffangen sämtlicher Fehler beim Anwenden einer Transformation. Führen Sie die Schritte einzeln manuell durch, so erhalten Sie spezifischere Exception-Objekte, welche den Fehler näher charakterisieren. Die Transformations-Exception verpackt diese verschiedenen Fehlerobjekte in einen einzigen Exception-Typ, sodass Sie sich beim Aufruf von transform() lediglich um diesen kümmern müssen. #### Handler-Wahl in Transformationen Der Algorithmus zur Bestimmung des passenden Handlers während einer Transformation versucht, möglichst die Waage zu halten zwischen der Wahl des optimalen Handlers, also des Handlers mit möglichst hoher Priorität, und dem Overhead, der durch den Wechsel zwischen zwei Handlern entsteht. Muss der Handler im Laufe einer Transformation gewechselt werden, bedeutet dies, das Bild zunächst in dem Handler zu speichern, in dem es aktuell geöffnet ist, und anschließend im nächsten Handler wieder zu öffnen. Arbeiten Sie nicht gerade auf einer RAM-Disk, bedeutet dies jedes Mal einige Plattenzugriffe, während ein Handler an sich so implementiert ist, dass möglichst alle Manipulationen eines Bildes im Speicher ablaufen und die Zahl der Festplattenzugriffe möglichst gering bleibt. Auf das gezeigte Beispiel angewendet bedeutet dies, dass der Konverter das eingegebene Bild zunächst im GD-Handler öffnet, denn dieser ist priorisiert und unterstützt den benötigten Skalierungsfilter. Das Konverter-Objekt wendet diesen Filter durch den Handler auf das geöffnete Bild an und prüft, ob der nächste Filter ebenfalls im bereits aktiven GD-Handler verfügbar ist. Da dies zutrifft, wird der Filter ebenfalls über diesen Handler abgewickelt. Den letzten Filter zum Hinzufügen des Rahmens stellt der GD-Handler aber nicht bereit, weshalb der Konverter die Speicherung des Bildes unter einem temporären Namen veranlasst, schließt und diese Datei anschließend mit dem ImageMagick-Handler öffnet. Nun kann der Filter durch den aktuellen Handler angewendet werden. Da dieser ebenfalls die Konvertierung von BMP nach JPEG vornehmen kann, wird er dazu ebenfalls verwendet. Danach ist die Transformation abgeschlossen. Die letzten Schritte sind das Speichern und Schließen der Datei und das anschließende Verschieben auf die Zieldatei. Der Konverter verwendet also einen Handler, in dem ein Bild einmal geöffnet wurde, für möglichst viele Aktionen und wechselt nur bei Bedarf. Der bei einem Wechsel eingesetzte Handler wird dann wieder möglichst lange verwendet, bis ein erneuter Wechsel unumgänglich ist. Im Idealfall wechselt der Konverter also nie, sondern führt alle Filter und die Konvertierung mit Hilfe des Handlers mit der höchsten Priorität aus. ### 12.2.3 Im GP-Blog Nachdem Sie nun die Architektur und Struktur der Komponente kennengelernt haben, ist es Zeit, einen weiteren Blick in den Sourcecode des GP-Blogs zu werfen. Wie vorher bei der Illustration der ImageAnalysis-Komponente in Abschnitt 12.1, »Bilder analysieren«, bereits erwähnt wurde, stellen wir Ihnen an dieser Stelle die Möglichkeit vor, dass Bilder in den uploads/-Ordner des GP-Blogs hochgeladen werden. Ort des Geschehens ist der Action-Controller gpBlogActionGallery. Genauer gesagt, werden wir nun die Aktionsmethode save() betrachten, in der die hochgeladene Datei bearbeitet wird. Der hier analysierten Aktion wird im Ablauf der Anwendung stets die Aktion create_media vorausgegangen sein, welche das Upload-Formular darstellt und beim Absenden des Formulars auf den von der hier vorgestellten Methode save() bearbeiteten Slot save_media verweist. Nähere Informationen zum Testen und über die Architektur der Beispielanwendung finden Sie in Kapitel 1, »Einleitung«, sowie in Kapitel 3, »Die Applikationsbasis«, wo Ihnen die Konzepte von Action-Controllern und Slots nähergebracht werden. Die dritte Aktion der in diesem Kapitel vorgestellten Action-Klasse mit dem Namen view_media haben Sie bereits in Abschnitt 12.1, »Bilder analysieren«, kennengelernt. #### Die save()-Methode Die eigentliche Methode zur Realisierung der Aktion beschränkt sich auf die Bereitstellung der aus den vorherigen Kapiteln bekannten Infrastruktur wie das Ermitteln der benötigten Parameter und deren Validierung:
    public static function save( ezcUrl $url,
        ezcUrlConfiguration $config )
    {
        if ( !isset( $_FILES['medium'] ) )
        {
            gpBlogController::getInstance()->mainSignals->emit(
                "error",
                "No file uploaded."
            );
            return;
        }
        if ( !is_uploaded_file( $_FILES['medium']['tmp_name'] ) )
        {
            gpBlogController::getInstance()->mainSignals->emit(
                "error",
                "Uploaded file compromised. Please try again!"
            );
            return;
        }
       try
        {
            $uploadedInfo = self::processImage(
                $_FILES['medium']['tmp_name'],
                $_FILES['medium']['name']
            );
        }
        catch ( Exception $e )
        {
            gpBlogController::getInstance()->mainSignals->emit(
                "error",
                $e->getMessage()
            );
            return;
        }
       gpBlogController::getInstance()->mainSignals->emit(
            "display",
            "gallery_success",
            array(
                'mediaName' => $uploadedInfo['filename'],
            )
        );
    }
Listing 12.9 Die save()-Methode der gpBlogActionGallery-Klasse Die Methode überprüft zunächst, ob eine Datei entsprechend des zu verarbeitenden Formulars hochgeladen wurde. Hierbei wird nicht, wie aus Kapitel 10, »Benutzereingaben validieren«, bekannt, die UserInput-Komponente verwendet, sondern direkt auf das PHP-$_FILES-Array zugegriffen, da die Komponente zur Absicherung von Benutzereingaben den Upload von Dateien nicht unterstützt. Allerdings ist dies auch nicht notwendig, da PHP mit is_uploaded_file() [http://php.net/is_uploaded_file ] und der hier nicht zu sehenden Funktion move_uploaded_file() bereits intern ein Mittel bereitstellt, die Integrität der Datei zu sichern. Tritt der Fall ein, dass keine oder eine kompromittierte Datei hochgeladen wurde, wird das entsprechende Fehlersignal, bekannt aus Kapitel 3, »Die Applikationsbasis«, gesendet und die Aktion beendet. Der interessante Teil der Methode beschränkt sich auf den Aufruf der statischen Methode processImage(). Diese widmet sich der eigentlichen Verarbeitung der gewünschten Datei und aller Operationen in Zusammenhang mit ImageConversion. Die Bereitstellung als eigenständige Methode erfolgt hier zum einen zu Strukturierungszwecken, und zum anderen wird diese Methode in späteren Kapiteln für weitere Features genutzt. #### Analyse der Manipulation Die statische Methode processImage() erwartet als Parameter zwei Dateinamen: Der erste zeigt auf eine temporäre Datei, in der sich das Bild aktuell befindet, der zweite bestimmt den Namen für die Zieldatei. Diese Trennung ist notwendig, da PHP die hochgeladene Datei zunächst unter einem unanschaulichen, temporären Namen speichert und den eigentlichen Namen der Datei in einem anderen Feld des $_FILES-Arrays angibt. Da jedoch der korrekte Name zur Speicherung des Bildes verwendet werden soll, werden an dieser Stelle beide Pfade übergeben. In der Verarbeitung haben wir einige Prinzipien anständiger Software-Entwicklung missachtet, um das Beispiel an dieser Stelle nicht unnötig aufzublähen. So wird der ursprüngliche Name der hochgeladenen Datei einfach zum Speichern verwendet, ohne darauf zu achten, eine bereits existierende Datei dabei zu überschreiben. Weiterhin wirft die Methode processImage() unter Umständen eine RuntimeException, wie sie SPL bereitstellt, um keine eigene Exception-Klasse für einen Fehler definieren zu müssen. In realen Projekten bitten wir Sie, von beiden Vorgehensweisen Abstand zu nehmen. Da die Methode processImage() recht lang ist, teilen wir die Präsentation des Codes in mehrere Teile auf. Zunächst betrachten wir die Methoden-Signatur und die ersten paar Zeilen.
    public static function processImage( $tmpPath, $filename )
    {
        $fileInfo = pathinfo( $filename );
        $destDir  = dirname( __FILE__ ) . '/../../uploads/';
        // Check image validity
        $analyzer = new ezcImageAnalyzer( $tmpPath );
        if ( !isset( self::$conversionMap[$analyzer->mime] ) )
        {
            throw new RuntimeException(
                "Invalid image type. Cannot process MIME type
                    {$analyzer->mime}."
            );
        }
        if ( $analyzer->data->isAnimated )
        {
            throw new RuntimeException(
                "Invalid image type. Cannot process animated
                    content."
            );
        }
        // ...
    }
Listing 12.10 Anfang der processImage()-Methode, Analyse des Bildes Zu Beginn der Methode wird der erhaltene Dateiname des Uploads mit Hilfe der PHP-Funktion pathinfo() in seine Bestandteile zerlegt. Den Grund hierfür werden Sie in Kürze kennenlernen. Anschließend wird eine Instanz von ezcImageAnalyzer erzeugt, mit deren Hilfe die temporäre Datei analysiert wird. Nachdem geprüft wurde, ob der erhaltene MIME-Type verarbeitet werden kann (womit wir uns umgehend beschäftigen), wird ein Test auf animierte GIF-Dateien durchgeführt. Die Verarbeitung dieses Datentyps verweigern alle Handler des ImageConversion-Pakets strikt, da Bilder dieses Typs nur sehr unzulänglich verarbeitet werden können und die meisten Filter hier versagen. Der Test auf die Validität des MIME-Types erfolgt über das statische Attribut $conversionMap der Klasse, das wie folgt definiert ist:
    private static $conversionMap = array(
        'image/jpeg' => 'image/jpeg',
        'image/bmp'  => 'image/jpeg',
        'image/tiff' => 'image/jpeg',
        'image/png'  => 'image/png',
        'image/gif'  => 'image/png',
    );
Listing 12.11 Das statische Attribut $conversionMap definiert Konvertierungen. Der Inhalt dieses Arrays beschreibt Konvertierungsregeln, wie Sie sie bereits in den vorangegangenen Abschnitten kennengelernt haben. Lediglich die als Array-Schlüssel verwendeten MIME-Types werden als Eingaben akzeptiert. Zwar kann insbesondere der ImageMagick-Handler mit einer weit größeren Zahl von Formaten umgehen, wir schränken die Auswahl an dieser Stelle aber ein, um zu gewährleisten, dass zumindest die Konvertierung zwischen den Typen mit dem GD-Handler möglich ist. Außerdem sind viele weitere Formate eher uninteressant, da sie nur wenig verbreitet sind. Weiterhin haben Sie mit diesem Array implizit schon gesehen, welche Ausgabeformate unsere späteren Transformationen unterstützen: image/jpeg und image/png, wie es typisch für Webanwendungen sein dürfte. Kommt der MIME-Type der erhaltenen Datei nicht als Schlüssel im $conversionMap-Array vor, so wird die Verarbeitung der Datei verweigert und eine Exception geworfen. Sie erinnern sich: Diese Exception wird in der aufrufenden Methode gefangen und ihre Meldung als Fehlersignal gesendet. #### Initialisierung
        // ...
        // Initialize converter
        $converterSettings = new ezcImageConverterSettings(
            array(
                new ezcImageHandlerSettings(
                    'GD',
                    'ezcImageGdHandler'
                ),
                new ezcImageHandlerSettings(
                    'ImageMagick',
                    'ezcImageImagemagickHandler'
                ),
            )
        );
        $converter = new ezcImageConverter(
            $converterSettings,
            self::$conversionMap
        );
        $mimeTypes       = array_values( self::$conversionMap );
        $transformations = self::getTransformations();
        // ...
Listing 12.12 Fortsetzung von processImage(), Initialisierung von ImageConversion Als nächster Schritt wird in der processImage()-Methode eine Instanz von ezc ImageConverter erzeugt, welche die Bearbeitung des hochgeladenen Bildes übernimmt. Beide Handler werden konfiguriert, um alle Möglichkeiten der Komponente ausreizen zu können. Der GD-Handler jedoch aus Performance-Gründen mit höherer Priorität. Daher wird er als Erster im Konfigurations-Array angegeben. Wie bereits vom letzten Abschnitt her erwartet, wird das Klassen-Attribut $conversionMap als Set von impliziten Konvertierungsregeln für den Konverter verwendet. Die Werte dieses Arrays, also die erlaubten Ausgabetypen, werden im Array $mimeTypes zur späteren Verwendung zwischengespeichert. In der letzten Zeile dieses Beispiels wird eine geschützte Methode aufgerufen, welche die benötigten Filterregeln erzeugt und zurückgibt.
    protected static function getTransformations()
    {
        $trans['original'] = array(
            new ezcImageFilter(
                'watermarkPercent',
                array(
                    'image' => dirname( __FILE__ ) .ð
        '/../../htdocs/images/galileo_press_watermark.png',
                    'posX' => 80,
                    'posY' => 80,
                    'size' => 10,
                )
            ),
        );
        $trans['medium'] = array(
            new ezcImageFilter(
                'scale',
                array(
                    'width'  => 400,
                    'height' => 300,
                    ezcImageGeometryFilters::SCALE_DOWN,
                )
            ),
        );
        $trans['thumb'] = array(
            new ezcImageFilter(
                'croppedThumbnail',
                array(
                    'width'  => 150,
                    'height' => 140,
                )
            ),
            new ezcImageFilter(
                'colorspace',
                array(
                    'space' =>
                        ezcImageColorspaceFilters::COLORSPACE_GREY,
                )
            ),
        );
        return $trans;
    }
Listing 12.13 getTransformations() definiert mehrere Transformationen. Die Methode gibt ein Array zurück, das Filterdefinitionen für die Transformationen original, medium und thumb enthält. Dies waren genau die drei Variationen eines Bildes, die mit Hilfe der Aktion view in Abschnitt 12.1, »Bilder analysieren«, vorgestellt wurden. Hier klicken, um das Bild zu vergrößern Abbildung 12.2 Endergebnis der thumb-Transformation Die Transformation original verändert das eigentliche Bild nicht, sondern fügt lediglich ein Wasserzeichen hinzu. Diese kleinen Logos in einem Bild finden Sie häufig auf Webseiten, die ihr Copyright gesichert wissen wollen. Der hier verwendete Filter erwartet zum einen den Pfad zum Wasserzeichen-Bild als Parameter, zum anderen Informationen über die Lage und Größe des Wasserzeichens im Zielbild als Prozentangaben. Das Wasserzeichen-Bild wird also auf 10 Prozent der Größe des Zielbildes skaliert und in dessen unteren rechten Ecke platziert. Dort liegt es 20 Prozent der Breite und den gleichen Anteil der Höhe von den Rändern des Originalbildes entfernt. Bei den Angaben der Koordinaten handelt es sich um die obere linke Ecke des Wasserzeichens. Rechnet man also dessen Größe zu den Lagekoordinaten, so liegen die rechte und untere Kante des Wasserzeichens je 10 Prozent von den entsprechenden Kanten des Zielbildes entfernt. Da das Erzeugen von Transparenz-Effekten eine schwierige und rechenintensive Aufgabe ist, unterstützt der Wasserzeichen-Filter keine Einstellung für Transparenz. Um trotzdem durchsichtige oder durchscheinende Flächen bei der Überlagerung zu erzeugen, verwenden Sie einfach ein Bildformat, das diese Informationen für Ihr Wasserzeichen speichert. Deshalb verwenden wir ein halbtransparentes PNG-Bild als Wasserzeichen für das GP-Blog, welches Sie sich unter htdocs/images/watermark.png im aktuellen Sourcecode auf der Heft-CD unter stage09/ ansehen können. Die zweite Transformation beinhaltet ebenfalls nur einen einzelnen Filter, der das Bild auf eine für Blog-Einträge angenehme Größe skaliert. Sie werden sehen, dass alle Transformationen, die hier definiert werden, aufeinander aufbauen, womit das Wasserzeichen später auch auf diesem Bild zu sehen ist. Die Skalierung erfolgt erneut nur, wenn das Bild größer ist als der angegebene Bereich, und erhält die Seitenverhältnisse. Sie kennen den entsprechenden Filter bereits aus dem vorherigen Abschnitt. Durch die Reihung von Transformationen sparen Sie ein wenig Rechenzeit, da zum Beispiel die letzte Transformation nur noch von der medium-Variante herunter skaliert werden muss und nicht mehr vom original-Bild, welches vermutlich größer war. Innerhalb der letzten Transformation für die thumb-Variante wird ein weiterer Spezialfilter der ImageConversion-Komponente verwendet: croppedThumbnail. Dieser Filter, der im Interface ezcImageThumbnailFilters definiert ist, übernimmt die automatische Erzeugung eines Vorschaubildes anhand definierter Parameter und ist ausgerüstet, dafür zu sorgen, dass jedes Ihrer Vorschaubilder genau die gleiche Abmessung hat. Zunächst wird das Bild soweit skaliert, dass eine der beiden Seite exakt in den gewünschten Bereich passt. Allerdings wird die Pendant-Seite nicht, wie Sie es vom Filter scale kennen, kleiner als der angegebene Bereich skaliert, sondern potentiell größer, sodass Teile des Bildes über den Ausschnitt ragen. Der Überhang wird anschließend beidseitig gleichmäßig abgeschnitten, sodass jedes Vorschaubild exakt gleich groß ist, egal in welchem Seitenformat es vorliegt. Abschließend versetzt die letzte Transformation das Vorschaubild in den Graustufen-Farbraum, was eine Art Schwarz-Weiß-Photoeffekt erzeugt. Die soeben besprochene Methode wurde aus processImage() heraus aufgerufen. Nach Beendigung dieses Methodenaufrufs stehen die hier definierten Arrays von Filtern in processImage() zur Verfügung, um auf das hochgeladene Bild angewendet zu werden. Dies sehen Sie im nächsten Abschnitt. #### Die eigentliche Verarbeitung In den letzten Schritten der processImage()-Methode werden die soeben aus der getTransformations()-Methode bezogenen Filterdefinitionen auf das hochgeladene Bild angewandt. Zunächst bestimmt die Methode aber noch die Dateinamen für alle zu erzeugenden Bildvarianten:
    $fileDestinations = array();
    foreach ( $transformations as $name => $def )
    {
        $trans = $converter->createTransformation(
            $name, $def, $mimeTypes
        );
        $fileExt = self::$fileExtMap[$trans->getOutMime( $tmpPath )];
        $fileDestinations[$name] =
            "{$fileInfo['filename']}_{$name}.{$fileExt}";
    }
    $res = rename(
        $tmpPath,
        $destDir . $fileDestinations['original']
    );
    if ( $res === false )
    {
        throw new RuntimeException( "Moving uploaded file failed." );
    }
    // ...
Listing 12.14 Transformationen und Dateinamen vorbereiten Mittels einer Iteration über das Filter-Array werden zunächst alle Transformationen im Converter erzeugt. Dazu erhält die createTransforation()-Methode den Namen der zu erzeugenden Transformation, das im vorherigen Abschnitt definierte Teil-Array mit Filtern sowie die passenden MIME-Types, welche zuvor aus der entsprechenden Map-Variablen extrahiert wurden. Das Array $fileDestinations wird so vorbereitet, dass für jede Transformation ein Dateiname zur Verfügung steht. Dazu wird jeweils aus den Werten, die per pathinfo() aus dem Originaldateinamen sowie dem Namen der jeweiligen Bildvariante extrahiert wurden, der Dateiname für das Zielbild generiert. Laden Sie also ein Bild namens mein_urlaub.bmp hoch, würden daraus die drei Dateien mein_urlaub_original.jpg, mein_urlaub_medium.jpg und mein_urlaub_thumb.jpg erzeugt. Wie Sie sich erinnern, wird in der Klasse ein statisches Attribut gehalten, das bereits die globalen MIME-Type-Konvertierungen sowie zugelassene Ausgabetypen für die Transformationen bestimmt. Natürlich soll die Dateiendung der neu erzeugten Bilder deren Inhalt entsprechen. Aus diesem Grund wird nach dem Erzeugen einer Transformation in Erfahrung gebracht, welchen Ausgabe-MIME-Type die Transformation für das vorliegende Bild erzeugen wird. Um diesen String dann auf eine korrekte Dateiendung abzubilden, stellt die Klasse ein statisches Array bereit:
    private static $fileExtMap = array(
        'image/jpeg' => 'jpg',
        'image/png'  => 'png',
    );
Listing 12.15 Dateiendung mappen Da nur zwei MIME-Types als Ausgabe valide sind, benötigt auch dieses Array nur zwei Einträge. Praktisch ist, dass beide Arrays, also die Abbildung zur Konvertierung von MIME-Types und das Dateiendungs-Array, zentral in der Klasse definiert werden. Fügen Sie also einen neuen MIME-Type als valide Ausgabe ein, fällt sofort auf, dass auch eine entsprechende Dateiendung codiert werden muss. Die letzte Aktion im gezeigten Ausschnitt aus processImage() verschiebt das temporäre Originalbild bereits in den uploads/-Ordner. Damit wird das Aufräumen dieser temporären Datei am Ende des Requests gespart und die Transformationen beginnen direkt auf dieser Datei:
        // ...
        try
        {
            // Perform the transformations
            $source = $destDir . $fileDestinations['original'];
            foreach ( $fileDestinations as $name => $dest )
            {
                // Each transformation is based on the previous one
                $converter->transform(
                    $name,
                    $source,
                    "{$destDir}{$dest}"
                );
                $source = "{$destDir}{$dest}";
            }
        }
        catch ( ezcImageException $e )
        {
            // Clean up all created files
            foreach ( $fileDestinations as $dest )
            {
                if ( file_exists( $dest ) )
                {
                    unlink( $dest );
                }
            }
            throw new RuntimeException(
                "Image could not be converted."
            );
        }
        return $fileInfo;
    }
Listing 12.16 Die Transformationen werden am Ende von processImage() angewendet. Innerhalb des try-Blocks werden mittels einer weiteren foreach-Schleife die Transformationen nacheinander angewendet. Dabei baut, wie vorher schon erwähnt, jeweils eine Transformation auf der vorhergehenden auf. Der Aufruf von transform(), welche für die Anwendung von Transformationen zuständig ist, nimmt drei Parameter entgegen: Den Namen der anzuwendenden Transformation sowie jeweils den Pfad zum Ursprungs- und zum Zielbild. Tritt während einer Transformation ein Fehler auf, so wird der entsprechende catch-Block aufgerufen, der alle bisher erzeugten Bildvarianten wieder bereinigt, damit kein Datenmüll auf der Festplatte zurückbleibt. Anschließend wirft die Methode ihrerseits eine Exception. An dieser Stelle wird nicht sofort ein Fehlersignal gesendet, da die Methode später an mehreren Stellen des GP-Blogs wiederverwendet wird. Der Aufrufer muss also dafür sorgen, dass die Exception korrekt behandelt wird, was Sie im Fall der Gallery-Action bereits gesehen haben. Verlaufen alle Transformationen reibungslos, so terminiert die Methode korrekt und gibt das aus pathinfo() erzeugte Array zurück, das Informationen zum Zieldateinamen enthält. Ganz zu Anfang dieses Abschnitts haben Sie gesehen, dass der darin erhaltene Dateiname bei der Ausgabe verwendet wird. Das Ausgabe-Template zeigt zur Erfolgsindikation alle drei Bildvarianten an und erzeugt die passenden URLs zur View-Methode der Aktion anhand des Dateinamens. Damit ist der »Rundflug« durch die gpBlogActionGallery-Klasse abgeschlossen. Sie haben gesehen, wie im GP-Blog hochgeladene Bilddateien praktisch verarbeitet werden. Neben der Konfiguration von Backend-Handlern, der Definition und Anwendung von Transformationen haben Sie zu Anfang dieses Abschnitts gesehen, wie Bilddaten analysiert werden können. ### Ihr Kommentar Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen. >> Zum Feedback-Formular
<< zurück | <top> | vor >>
Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen? Ihre Meinung
Buchempfehlungen
| PHP 5.3 und MySQL 5.1
| Besser PHP programmieren
| Webshops mit Magento
| Sichere Webanwendungen
| PHP 5.3 und MySQL 5.1 - Videotraining
| Apache 2
| Suchmaschinen- Optimierung für Webentwickler
| Joomla! 1.5
Shopping
Versandkostenfrei bestellen in Deutschland und Österreich Info

Copyright © Galileo Press 2008
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

[Galileo Computing]
Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de