Artikel - Detailansicht

Icon Aktuelles Serverseitiges Resizing von Bilddateien mit CF und Fireworks

Wenn man im Kundenauftrag Online-Shops mit Administrations-Interface erstellt, kommt man gezwungenermaßen irgendwo an einen Punkt, an dem es um die Bereitstellung von Artikelbildern geht. Das größte Problem sind nicht die Bilddateien an sich, sondern deren kleinere Kollegen: die Thumbnails. Man kann den Kunden entweder direkt beide Versionen hochladen lassen, die er vorab "von Hand" bearbeitet (hier mangelt es aber meist an Erfahrung in Sachen Bildbearbeitung und -optimierung) oder die größeren Bilder durch den Browser verkleinert darstellen lassen, was aber arg zu Lasten der Ladezeit geht.

Lösungsansätze wie z.B. , welche als Freeware in der Taggallery von allaire zu bekommen sind, lassen zwar eine serverseitige Bildmanipulation zu, arbeiten aber in einer weniger akzeptablen Qualität. Es gibt meines Erachtens nichts schlimmeres, als dass sich ein sonst sehr professionell wirkender Shop durch pixelige Thumbnails selbst degradiert - als Beispiel fällt mir hier spontan ein großer Anbieter für Tierbedarf ein.

Macromedia Fireworks ist bekannt für sehr gutes Resizing in Verbindung mit maximaler Optimierung der Dateigröße und läßt sich, wie meines Wissens alle MM-Tools, per Javascript komplett fernsteuern. Nach einigem Experimentieren habe ich einen relativ simplen Weg gefunden, wie man FW dazu bringt, per cfexecute eine vorab definierte Dateiliste abzuarbeiten und von den Orignialdateien Thumbnails in gewohnter FW-Qualität zu erstellen. Dies klingt wirklich sehr viel komplizierter als es letzten Endes ist und benötigt nur sehr wenig Programmierzeit. Noch dazu ist dies keine CF-spezifisches Thema, also sollte es prblemlos möglich sein, das Prinzip auch in PHP, ASP ö.ä. zu realisieren.

Die einzelnen Schritte lauten wie folgt:
  • Erstellen eines Batch-Scripts in Fireworks, Export des Scripts
  • Anpassen der Script-Datei
  • Erstellen des CF-Templates, welches dynamisch die abzuarbeitende Dateiliste vorgibt
  • Aufruf des generierten Skriptes in Fireworks
Erstellen eines Batch-Scripts in Fireworks, Export des Scripts

Der erste Schritt ist auch der einfachste: in FW wird über das Menü Datei / Batch-Verarbeitung ein Script exportiert.
Man erhält unter diesem Menüpunkt folgende Eingabemaske:



Damit das Script erfolgreich exportiert werden kann, wählt man einige beliebige Dateien zur Verabeitung aus (sie werden an dieser Stelle nicht manipuliert) und passt die Exporteinstellungen beispielsweise wie folgt an:



Ich habe mich hier für ein Resizing der Bilder auf eine variable Breite (0) und eine Höhe von 72 Pixeln entschieden. Den Thumbnails wird das Präfix "th_" vor den Dateinamen gestellt und sie werden als JPG mit Qualität 80 exportiert.

Dies genügt eigentlich schon und kann mit OK bestätigt werden. Im Menü "Batch-Verarbeitung" wird nun der Menüpunkt "Skript..." gewählt und die gerade festgelegten Batch-Vorgaben somit als Javascript-File exportiert.

Anpassen der Script-Datei

An dieser Stelle kann man das Script bereits ausprobieren, indem man es im Win-Explorer doppelklickt: Fireworks startet und fragt nach, welche Dateien es verarbeiten soll. Diese Abfrage ist jedoch extrem hinderlich - man muss FW also vorab mitteilen, welche Dateien zu verkleinern sind.
Öffnet man die exportierte jsf-Datei in einem Texteditor, so wird schnell deutlich, dass FW die Liste der zu verarbeitenden Dokumente der Variable "theDocList" speichert:

// ----------------------------------------------------------

if (this.fw == null) {
var msg = Errors.EBadJsVersion;
if (msg == null)
msg = 'This script does not work in this version of Fireworks.';
alert(msg);
theDocList = null;
} else {
fw.checkFwJsVersion(0);
if (theDocList == null || theDocList.length == 0) {
theDocList = App.chooseScriptTargetDialog(App.getPref('MultiFileBatchTypes'));
}
}
// ----------------------------------------------------------

Dieser Codeblock befindet sich in der oberen Hälfte des Scripts und ist nicht innerhalb einer Funktion aufgeführt. In ihm wird einerseits die FW-Version abgefragt, was hier weniger wichtig ist, andererseits aber geprüft, ob theDocList leer (NULL) ist oder keine Einträge enthält (theDocList ist ein globales, eindimensionales Array). Ist dies der Fall, so wird der Datei-Wählen-Dialog geöffnet. Man kann ihn also umgehen, indem man vor der Abfrage die zu bearbeitenden Dateien in theDocList hinterlegt.

Idealerweise fügt man die Zuweisung in die erste Zeile des Scriptes (ja, ich weiß, unter den Kommentar wäre stilistisch schöner, aber so ist es in CF einfacher zu lösen) ;), also beispielsweise wie folgt:

theDocList = ['file:///c|/apache/htdocs/test/image1.jpg', 'file:///c|/apache/htdocs/test/image2.gif', 'file:///c|/apache/htdocs/test/image1.jpg'];

// Macromedia Fireworks Batch Script Template
// Copyright (c) 1998, 1999 Macromedia. All rights reserved.

var batchArray = [
{
findAndReplaceParms:null,
exportOptions:{
useFormatOptionsFromEachFile:false,
[usw, usw...]

Wichtig ist nur, dass die Pfade zu den Bildern absolut und in HTML-Manier geschrieben sind. Noch wichtiger ist, dass diese Zeile später wieder entfernt wird, da sie im Live-Betrieb per CFFILE geschrieben werden soll.
Ist theDocList entsprechend gesetzt, kann man das Script testweise noch einmal doppelklicken - und siehe da, es funktioniert, hat aber immer noch einen Nachteil: FW meldet zum Schluss stolz, dass die Batch-Verarbeitung normal beendet wurde. Dagegen wäre nun wirklich nichts einzuwenden, aber - wie sollte es anders sein, FW wartet auf den Klick auf "OK" und ignoriert gnadenlos alle externen Scriptaufrufe... :-/

Ein Workaround muss also her. Eine Funktion à la "fw.clickOKButton()" o. ä. habe ich in der sonst hervorragenden Dokumentation "Extending Fireworks" leider nicht gefunden, also bleibt mir hier nichts anderes, als FW nach dem Batch-Verlauf zu schließen, was aber auch wieder RAM im Server freigibt...
Hierzu findet man weiter unten im Script die geeingnete Stelle, nämlich dort, wo FW die Dokumente durchzählt:

if (theDocList == null) {
// The user must have canceled the 'select files' dialog.
} else if (theDocList.length == 0) {
// The user did something like 'current files' when no files are open.
alert(Errors.ENoFilesSelected);
} else {
App.progressCountCurrent = 0;
App.progressCountTotal = theDocList.length;
for (var i = 0; i < theDocList.length; i++) {
App.progressCountCurrent = i + 1;
App.batchStatusString = ';
if (ProcessOneDocPath(theDocList[i]) == false)
break;
}
}

Eine kleiner Vergleich genügt, um FW nach getaner Arbeit zu schließen:

if (ProcessOneDocPath(theDocList[i]) == false)
break;
if (App.progressCountCurrent == App.progressCountTotal)App.quit();
}
}


Das war's auch schon - das Script ist fertig. Zum Testen kann man es nun doppelklicken - Fireworks wird dann die Bilder verkleinern und sich anschließend selbst beenden.

WICHTIG: Jetzt muss die Deklaration von theDocList wieder entfernt werden!
Erstellen des CF-Templates, welches dynamisch die abzuarbeitende Dateiliste vorgibt

Ich denke, dass der CF-Code größtenteils selbsterklärend ist, also:

<!---festlegen des verzeichnisses--->
<cfset thepath="c:\apache\htdocs\test">
<cfset htmlpath="file:///c|/apache/htdocs/test/">

<!---verzeichnis mit den bilddateien einlesen--->
<cfdirectory action="list"
  directory="#thepath#"
  name="images">

<!---filelist ist die liste der zu bearbeitenden dateien--->
<cfset filelist="">

<!---durchs directory loopen...
hierbei werden nur dateien mit den endungen jpg,gif und png
der liste angefuegt.--->
<cfloop query="images">
  <cfif type eq 'file'
    and (listlast(images.name,'.') eq 'jpg'
    or listlast(images.name,'.') eq 'gif'
    or listlast(images.name,'.') eq 'png')>
    <cfset filelist=listappend(filelist,images.name,'*')>
  </cfif>
</cfloop>

<!---
jetzt wird das javascript-array gebaut...
ich habe hier einen * als trennzeichen festgelegt, weil win-dateinamen
unnützerweise auch kommata im dateinamen haben können
--->
<cfset fwdoclist="theDocList=[">

<cfloop list="#filelist#" index="thefile" delimiters="*">
  <cfif listfind(filelist,thefile,'*') neq 1>
    <cfset fwdoclist=fwdoclist&",">
  </cfif>
  <cfset fwdoclist=fwdoclist&"'"&htmlpath&thefile&"'">
</cfloop>

<cfset fwdoclist=fwdoclist&"];">

<!---letzten endes wird der script-rohling eingelesen...--->
<cffile action="read"
  file="c:\thumb.jsf"
  variable="script">

<!---...um theDocList ergaenzt...--->
<cfset script=fwdoclist&script>

<!--- ...und in eine neue datei geschrieben. --->
<cfif fileexists('c:\new.jsf')>
  <cffile action="delete" file="c:\new.jsf">
</cfif>

<cffile action="write"
  file="c:\new.jsf"
  output="#script#">

<!---jetzt wird fireworks per cfexecute gestartet.
als argument wird der pfad der scriptdatei angegeben, so dass
FW diese abarbeitet.
ich habe bewusst "firewo~1" als datei- und verzeichnisnamen
angegeben, damit das script mit FW 3&4 gleichermaßen läuft.
--->

<cfexecute name="c:\programme\macromedia\firewo~1\firewo~1.exe"
  arguments="c:\new.jsf">
</cfexecute>

<!---fertig!--->

Das war's in der Tat schon! Nach dem Aufruf des Scripts hat man perfekte Thumbnails. ;-)
Abschließend habe ich nur noch zu sagen, dass diese Methode natürlich nur sinn macht, wenn man einen eigenen Server hat, da ein Provider wahrscheinlich bei der Anfrage, doch bitte FW auf dem Server zu installieren, wahrscheinlich nur müde lächeln wird. Auch muss man abwägen, ob der Server es von der Prozessorleistung her schafft, mit FW fertigzuwerden, während beispielsweise tausende http-Zugriffe verarbeitet werden müssen.

Marcus Raphelt marcus@raphelt.de - 11.06.2001

Zurück


Das deutsche ColdFusion-Forum cfml.de ist das Portal für Einsteiger und Experten zum Thema ColdFusion und der ColdFusion Markup Language (CFML).

© 2017 Webdesign & Hosting: CHC ONLINE Kassel | SOLVA Content-Management-System CMS
Urlaub-Angebote.de - Urlaub mit Bestpreis-Garantie buchen