Ich hab gerade mal wieder richtig Lust auf einen Nuklearschlag gegen das Microsoft-Hauptquartier. Vor vier Stunden wollte ich noch mal eben schnell ein kleines CSS-Experiment wagen und dann Feierabend machen. Dem IE habe ich es zu verdanken, dass ich erst jetzt darüber schreiben darf und die letzten Stunden ganz schön am basteln war. Aber der Reihe nach.
Das Ziel: Automatisch bessere Qualität bei Client-side Image Resizing
Gestern bin ich via Nico über Client-side Image Resizing gestolpert. Darin geht es darum, wie man durch Browser verkleinerte Bilder (also per height
und width
-Attribut oder CSS) im IE mit etwas besserer Bildqualität ausstattet. Normale Browser liefern standardmäßig eine anständige Qualität, beim Internet Explorer 6 und 7 muss man da etwas proprietäres CSS auffahren. Andernfalls sehen verkleinerte Bilder so aus:
Um das im IE7 zu verbessern, muss man dem Bild die CSS-Eigenschaft -ms-interpolation-mode:bicubic;
verpassen und im IE6 das Bild mit dem vom PNG-Fix bekannten AlphaImageLoader
laden. Macht man das, kommt das hier dabei heraus:
Es lohnt sich also. Nur ist es etwas uncool, solchen MS-eigenen Krempel fest einzubauen, also wollte ich die Qualitätsverbesserung mitttels Javascript automatisieren.
Der Code
Dieser Mootools-Code prüft, ob ein Bild verkleinert, vergrößert oder verzerrt ist und wendet dann einen der beiden IE-Fixes an, je nachdem, welcher Browser verwendet wird.
var transparent = 'transparent.gif';
window.addEvent('domready', function(){
if (Browser.Engine.trident) {
var version = Browser.Engine.version;
if (version < 6) {
var img = $$('#hack img');
img.each(function(el){
var tmp = new Element('img', { src: el.get('src') })
if (el.width != tmp.width || el.height != tmp.height) {
if (version == 5) {
el.style.msInterpolationMode = 'bicubic';
}
else if (version == 4) {
el.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + el.get('src') + "',sizingMethod='scale')";
el.set('src', transparent);
}
}
tmp.destroy();
});
}
}
});
Zur Erläuterung:
- Es wird geprüft, ob die IE-Engine Trident verwendet wird (
Browser.Engine.trident
) und ob wir es mit IE6 oder IE7 zu tun haben (if (version < 6)
) - Ist das der Fall, werden alle Bilder ausgewählt, die geprüft und ggf. bearbeitet werden sollen (
var img = $$('#hack img');
) - Von jedem dieser Bilder nehmen wir die Bildadresse und erzeugen damit ein neues
<img>
ohne festgelegte Maße. Die Größe dieser Kopie wird mit dem Original verglichen; weicht sie ab, werden je nach Trident-Version die proprietären CSS-Attribute in das Original eingefügt. Im Falle des Filters beim IE6 muss außerdem dassrc
des Bildes durch ein komplett transparentes GIF ersetzt werden. Am Ende wird die Kopie wieder zerstört.
Der Code ist auf dieser Demoseite in Aktion zu sehen. Die Bilder in der rechten Spalte wurden vom Script optimiert, die linken sind im Originalzustand.
Und warum der Nuklearschlag?
Es scheint so zu sein, dass der IE7-Fix, das MS-eigene -ms-interpolation-mode
, nicht bei jeder Form von Bilddatei funktioniert. Getestet werden kann das auf dieser Seite. Ich bin noch nicht dahinter gekommen was die beiden pngs, die nicht geglättet dargestellt werden, vom Rest unterscheidet. In der Dokumentation steht nichts hilfreiches. Ich weiß nur, dass das erste Bild, mit dem ich experimentiert habe, natürlich eines von denen war, die nicht funktioniert haben. Ohne diese Macke hätte das hier sicher nicht vier Stunden Entstehungszeit in Anspruch genommen.
Falls irgendwer eine Idee hat, was mit den Bildern los sein könnte, nur raus damit!
Kommentare (9)
John ¶
14. November 2008, 22:41 Uhr
Statt erst Browser-Engine und dann Version abzufragen, kannst Du übrigens auch gleich auf Browser.Engine.trident4 (IE6) und/oder Browser.Engine.trident5 (IE7) testen.
Dann würde if/else reichen. Ob das Punkte bringt... keine Ahnung. Spart ne Zeile Code. ;-)
Peter ¶
14. November 2008, 23:10 Uhr
Das ist ja das gute an Mootools. Kleiner machen geht immer irgendwie.
wahsaga ¶
15. November 2008, 09:43 Uhr
Wenn ich mich jetzt nicht verkuckt hab, scheinen das die beiden einzigen 32Bit PNGs in deinem Test zu sein.
8Bit und 24Bit OK, 32Bit nicht? Waere immerhin eine denkbare Moeglichkeit.
Das MooTools-Gehampel ist mir allerdings zu aufwendig - vor allem neues Bildobjekt erzeugen, um an die Masze zu kommen. Koennte mir vorstellen, dass das im IE bei unguenstiger Cache-Einstellung zum Neuladen des Bildes fuehrt ...
Ich wuerd's eher im IE 7 einfach allen Bildern verpassen (das duerfte ja keinen Schaden anrichten, Zitat: "The msInterpolationMode property applies to stretched images only." ), und im IE 6 auf den Workaround verzichten (genereller Einsatz waere hier wohl eher harmful, denn der AlphaImageLoader bringt ja eine Reihe weiterer Probleme mit sich).
Ingo ¶
15. November 2008, 09:48 Uhr
Wieso _überhaupt_ auf dem Client verkleinern (ein Bildverarbeitungsprogramm macht das immer besser) - em-basiertes Layout?
Peter ¶
15. November 2008, 10:12 Uhr
Zitat wahsaga:
Ja, wenn „ungünstig“ soviel wie „aus“ bedeutet vielleicht. Aber wie warscheinlich ist das?
Zitat Ingo:
Naja, der eigentliche Urheber dieses Tricks ist ja Flickr und in dem Fall kann ich mir dann durchaus vorstellen, warum man nicht alle Bilder richtig verkleinert.
Jens Grochtdreis ¶
15. November 2008, 15:03 Uhr
Ich bin ja gerne dabei, Redmon zu verfluchen. Aber in diesem Falle eher nicht. Warum willst Du cliengtseitig ein Bild skalieren? DAS ist der Fehler, nicht das Verhalten des IE.
Peter ¶
15. November 2008, 16:05 Uhr
Zitat Jens Grochtdreis:
Also mir fallen viele Beispiele ein, wo das clientseitige Verkleinern von Bildern sinnvoll ist. Dass man davon, wann immer es geht, Abstand nehmen sollte, versteht sich von selbst. Nur es geht eben nicht immer.
Nehmen wir doch Flickr, die haben sich das schließlich ursprünglich ausgedacht. Sollen die jedes mal, wenn sie ihrem Design etwas basteln all ihre Thumbnails neu skalieren? Ich glaube nicht dass das besonders praktikabel ist. Oder (eine Nummer kleiner) eine technisch nicht besonders versierte Person hat ein Blog mit 500 Beiträgen und die alle haben Bilder in einer bestimmten Größe eingebunden. Und dann möchte die Person das Theme wechseln und das hat dann eine kleinere Spalte – da wäre es doch gut, wenn der Theme-Autor vorsorgt und für bestmögliche Ergebnisse sorgt.
Und auf Microsoft bin ich nur böse, weil sie diese Geschichte mit den 32-Bit-PNGs nirgendwo aufgeschrieben haben (vorausgesetzt sie wissen selbst davon). Das Script und die Hackereien selbst sind ja nun kein Drama.
Christian Bayerlein ¶
27. Januar 2009, 00:09 Uhr
Hallo und danke für die prima Idee! Ich finde es schon wichtig, Bilder im Browser skalieren zu können. Nicht nur für em, auch für %! Ich hab nämlich des öfteren Layouts, bei denen die Spalten per % eine breite zugewiesen. Und da sähe es doch hübsch aus, wenn z. B. ein Spaltenkopf mit Bild angezeigt würde. Oder Header-Grafik bei flüssigen Layouts, die immer 90% der breite einnehmen. Da könnte man dann auch skalieren. Ich hab da öfter mal rum gespielt aber bisher immer nur unschöne Ergebnisse bekommen. Übrigens allerdings auch (meiner Meinung nach) im Firefox! Ich hab dann die Bilder mehrfach hinterlegt und per JavaScript auf die Auflösung angepaßte Header-Grafiken nachgeladen. Fand ich aber irgendwie nicht ganz ideal: das Bild wird erst später ordentlich dargestellt und ohne JavaScript geht es garnicht...
Whoppy ¶
10. Februar 2009, 19:21 Uhr
Habe zwar nicht die Codes benötigt, bin aber durch deinen Beitrag auf die Ursache für die pixelige Darstellung gekommen. Eine Verkleinerung der Bilder war in meinem Fall der einfache Weg, es waren noch nicht viele.