Premultiplied Alpha and the 2D rendering context
Rolf B
- html
- javascript
- wiki
0 Der Martin0 Rolf B0 Der Martin0 Rolf B
Hallo alle,
ist irgendjemand im Stande, mit verständlichen Worten das Problem zu beschreiben, das von der genannten "problematischen Seite" (HTML Spec §4.12.5.7) gelöst werden soll, und wie die Lösung sich auswirkt? Steht es vielleicht sogar schon im Canvas-Bereich des Wiki und ich finde es lediglich nicht?
Ich bin darauf gestoßen, als ich die createImageBitmap Methode beschreiben wollte. Da gibt's eine Option, mit der man angibt, ob premultiplyalpha stattfinden soll oder nicht. Der Sinn wird aber nicht näher dargestellt. Schlimmer noch, die Spec faselt in der Beschreibung der Methodenabläufe in dem Abschnitt, der "crop with formatting" beschreibt, im Punkt 10 dermaßen krude herum, dass man danach gar nichts mehr weiß.
Was in §4.12.5.7 beschrieben wird, ist ja schön mit Bildern und Beispielen versehen, aber ich sehe vermutlich die Bitmap vor lauter Pixeln nicht und es ist mutmaßlich völlig selbsterklärend für jemanden, der weiß, wovon da überhaupt geredet wird. Oder der weiß, in welcher Situation dieses Problem auftritt. Für mich ist es zu abstrakt, und ich habe keinen Nerv, lange herumzuprobieren. Ich werde es wohl tun wenn niemand eine Antwort in der Tasche hat, aber würde es gern vermeiden.
Rolf
Hallo Rolf,
ist irgendjemand im Stande, mit verständlichen Worten das Problem zu beschreiben, das von der genannten "problematischen Seite" (HTML Spec §4.12.5.7) gelöst werden soll
ich verstehe noch nicht, um welches Problem oder um welches Ziel es da geht, oder ob die da bloß eine tolle Farb-Konvertierung beschreiben, weil sie's halt können.
Bei RGBA-Farbangaben haben wir die drei Farbkomponenten Rot, Grün, Blau, und den Alphakanal, der die Deckkraft angibt. Das ist, wenn ich es richtig verstanden habe, non-premultiplied.
Bei der Anzeige eines Pixels mit diesem Farbwert werden die RGB-Komponenten um den Faktor reduziert, der im Alphakanal angegeben ist, gleichzeitig die RGB-Komponenten des darunterliegenden Pixels mit dem komplementären Faktor (1-A) dazugezählt. So ergibt sich die tatsächliche neue Farbe des Pixels.
Um beim Zeichnen drei Multiplikationen einzusparen, kann man die RGB-Komponenten auch gleich im Voraus mit dem Alphakanal multiplizieren und so speichern. Das ist dann premultiplied.
Die non-premultiplied representation in der letzten Zeile der Tabelle ist übrigens IMO falsch (vermutlich ein Copy&Paste Error, vgl. den Wert in der Zeile darüber), es müsste 0, 127, 255, 0 sein.
und wie die Lösung sich auswirkt? Steht es vielleicht sogar schon im Canvas-Bereich des Wiki und ich finde es lediglich nicht?
Mein Eindruck ist, dass hier nur eine interne Optimierung durch die Rendering Engine beschrieben wird, also eine eher akademische als wirklich nützliche Information. Aber vielleicht habe ich den Sinn und Zweck auch bisher genausowenig erkannt wie du.
Ich bin darauf gestoßen, als ich die createImageBitmap Methode beschreiben wollte. Da gibt's eine Option, mit der man angibt, ob premultiplyalpha stattfinden soll oder nicht. Der Sinn wird aber nicht näher dargestellt. Schlimmer noch, die Spec faselt in der Beschreibung der Methodenabläufe in dem Abschnitt, der "crop with formatting" beschreibt, im Punkt 10 dermaßen krude herum, dass man danach gar nichts mehr weiß.
Ah. Okay. Dann fehlen mir tatsächlich auch die Zusammenhänge.
Live long and pros healthy,
Martin
Hallo Martin,
ich glaube, Du hast es etwas erhellt.
Vermutlich muss man die Mischalgorithem vergleichen, die bei premultiplied und non-premultiplied Farben verwendet werden - die können wohl nicht die gleichen sein.
Du sagst: Wenn ich eine RGBA-Farbangabe $$(c_r,c_g,c_b,c_\alpha)$$ habe und die mit einem existierenden Bildpunkt $$(p_r, p_g, p_b, p_\alpha)$$ mische, dann wird für das neue Pixel $$c_{r,g,b}\cdot c_\alpha + p_{r,g,b} \cdot (1-c_\alpha)$$ gerechnet. Wobei das $$p_\alpha$$ außer Acht lässt.
Man müsste jetzt also noch wissen, wie $$p_\alpha$$ berücksichtigt wird, und dann vergleichen, wie die Formel bei premultiplied Farben aussieht. Einfach so: $$c_{r,g,b} + p_{r,g,b} \cdot (1-c_\alpha)$$?
Das wäre möglich, bräuchte dann aber ein Clipping (weil die Summe im Kanal über 255 steigen kann), oder es wird nicht + verwendet, sondern max. Für das Clipping spricht, dass die Vektor-Operationen der Intelprozessoren genau auf diese Weise mit Überläufen umgehen.
Und das erklärt dann, warum ein premultiplied-Wert von (255,127,0,0.5) nicht non-premultiplied darstellbar ist, weil ich dafür die 255 durch 0.5 teilen müsste und 510 nicht in einem 8-bit Farbvektor darstellbar ist.
Das führt dann auch zu Sinn bei der Frage, warum man eine Bitmap als "premultiplied" oder "non-premultiplied" deklarieren muss; allerdings nicht unbedingt zum Sinn einer Konvertierung (außer, weil bestimmte Abläufe eine Bitmap in der einen oder anderen Form erwarten).
Es ist etwas Licht, aber noch viel Finsternis. 😀
Rolf
Hallo,
ich glaube, Du hast es etwas erhellt.
immerhin, das freut mich.
Vermutlich muss man die Mischalgorithem vergleichen, die bei premultiplied und non-premultiplied Farben verwendet werden - die können wohl nicht die gleichen sein.
Nein, sicher nicht.
Du sagst: Wenn ich eine RGBA-Farbangabe $$(c_r,c_g,c_b,c_\alpha)$$ habe und die mit einem existierenden Bildpunkt $$(p_r, p_g, p_b, p_\alpha)$$ mische, dann wird für das neue Pixel $$c_{r,g,b}\cdot c_\alpha + p_{r,g,b} \cdot (1-c_\alpha)$$ gerechnet. Wobei das $$p_\alpha$$ außer Acht lässt.
Richtig, denn $$p_\alpha$$ ist für diesen Schritt bedeutungslos. Der Faktor ging in die Berechnung des bisherigen Farbtons ein.
Man müsste jetzt also noch wissen, wie $$p_\alpha$$ berücksichtigt wird
Nach meinem Verständnis gar nicht - der ist schon durch den vorherigen Schritt abgefrühstückt. Beim Hinzumischen eines neuen Farbtons kommt nur dessen Opazität zum Tragen - vergleiche die Gewichtungsfaktoren A und (1-A) aus meinem vorherigen Posting. Das Resultat kann nicht größer als 100% (respektive 0xFF) werden.
Und das erklärt dann, warum ein premultiplied-Wert von (255,127,0,0.5) nicht non-premultiplied darstellbar ist, weil ich dafür die 255 durch 0.5 teilen müsste und 510 nicht in einem 8-bit Farbvektor darstellbar ist.
Man könnte es auch umgekehrt sagen: Ein pre-multplied von (255,127,0,0.5) kann gar nicht erst entstehen, weil der ursprüngliche Wert einer Komponente nur noch zu 50% wirkt, also nur noch maximal 128 betragen könnte.
Das führt dann auch zu Sinn bei der Frage, warum man eine Bitmap als "premultiplied" oder "non-premultiplied" deklarieren muss; allerdings nicht unbedingt zum Sinn einer Konvertierung (außer, weil bestimmte Abläufe eine Bitmap in der einen oder anderen Form erwarten).
Ich sehe den Sinn tatsächlich nur in der Einsparung von drei Multiplikationen pro Pixel bei der Anzeige, die man dann halt einmalig vorzieht.
Live long and pros healthy,
Martin
Hallo Martin,
Richtig, denn $$p_\alpha$$ ist für diesen Schritt bedeutungslos.
Hm - kommt drauf an. Wenn das Zielpixel ein Video-Pixel ist, dann gibt's kein Alpha mehr, aber wenn ich zwei alpha-haltige Bitmaps mische, dann schon. Sind aber zwei verschiedene Output-Devices, insofern auch zwei verschiedene Fragestellungen, und dies:
Man müsste jetzt also noch wissen, wie $$p_\alpha$$ berücksichtigt wird
ist nur für eine davon relevant. Aber dann durchaus, denn ein Mischpixel aus zwei teiltransparenten Pixeln ist ja wieder teiltransparent.
ein premultiplied-Wert von (255,127,0,0.5) nicht non-premultiplied darstellbar ist
Man könnte es auch umgekehrt sagen: Ein pre-multiplied von (255,127,0,0.5) kann gar nicht erst entstehen
Doch, schon. Ich muss nur eine Bitmap haben, die als "premultiplied" gekennzeichnet ist und dort diesen Wert einsetzen. Das scheint mir doch der Sinn dieser ganzen Flags und Optionen in der Spec zu sein, dass man mit solchen Bitmaps Dinge tun kann, die eine non-premultiplied Bitmap nicht gehen. Wenn es eine reine Effizienzsache wäre, die keine Auswirkung auf das visuelle Ergebnis hat, bräuchte man vermutlich keine Flags im API und könnte das den Browser überlassen. Diese Meinung von dir teile ich (noch) nicht:
Ich sehe den Sinn tatsächlich nur in der Einsparung von drei Multiplikationen pro Pixel bei der Anzeige, die man dann halt einmalig vorzieht.
Danke für's Helfen beim Denken 😀
Rolf