- From: Christian Brunschen <cb@df.lth.se>
- Date: Wed, 2 Feb 2000 12:28:12 +0100 (CET)
- To: www-svg@w3.org
Hi, I've previously made a nuisance of myself on this list on the subject of premultiplied vs non-premultiplied Alpha channels in filters. But please bear with me nevertheless. I beleive that I have found an instance where the SVG specification (WD-SVG-19991203) does not define how a conformant viewer should behave - in a place where such guidance is necessary. I will present two examples which will hopefully help clarify what I mean. Contemplate first this example: --------------------------------------- <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG December 1999//EN" "http://www.w3.org/Graphics/SVG/SVG-19991203.dtd"> <svg> <defs> <filter id="MakeLessTransparent"> <feColorMatrix in="SourceGraphic" type="matrix" matrix="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.5 0.5" result="lessTransparent" /> <feMerge> <feMergeNode in="lessTransparent" /> </feMerge> </filter> </defs> <desc>Example undefinedBehaviour01 - what happens to the previously transparent stuff which is now partially opaque?</desc> <text style="font-size:36px; fill:red; filter:url(#MakeLessTransparent)" x="10px" y="70px">Undefined Behaviour</text> </svg> -------------------------------------- The 'text' element draws the string 'Undefined behaviour' onto an empty, clear background, with some level of anti-aliasing. Thus we end up with an array of pixels containing Alpha values from 0 (untouuched) to 1 (where the text is displayed), possibly with some pixels having values in between (where anti-aliasing has taken place). Now, the 'MakeLessTransparent' filter quite simply and legally applies a 'feColorMatrix' transformation to the pixels, leacing their R G and B values intact, but changin the Alpha values: A' = 0.5*A + 0.5; basically making all pixels at least somewhat (50%) opaque. So, what colour will that part of the image be which was left untouched by the drawing of the string itself? Now consider a second example. For this we will need an external image, 'hideAndSeek.png', a PNG image which has some pixels which are transparent and some which are opaque. However, as PNG stores RGBA in a non-premultiplied format, this permits that there be actual useful data stored in the RGB parts even of pixels whose A=0. Now sau that we want to use the 'MakeLessTransparent' filter from the previous example on this PNG image, thus revealing some of what is 'hidden' in the image: ---------------------------------------- <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG December 1999//EN" "http://www.w3.org/Graphics/SVG/SVG-19991203.dtd"> <svg> <defs> <filter id="MakeLessTransparent"> <feColorMatrix in="SourceGraphic" type="matrix" matrix="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.5 0.5" result="lessTransparent" /> <feMerge> <feMergeNode in="lessTransparent" /> </feMerge> </filter> </defs> <desc>Example undefinedBehaviour02 - will those pixels which are at alpha=0, but (r,g,b)!=(0,0,0) show their original colour when their alpha is changed from 0 to non-zero?</desc> <image xlink:href="hideAndSeek.png" style="filter:url(#MakeLessTransparent)"> </image> </svg> ---------------------------------------- Now, to quote from the spec: ----- 15.8 Filter Processing Nodes [...] Unless otherwise stated, all image filters operate on linear premultiplied RGBA samples. Filters which work more naturally on non premultiplied data (feColorMatrix and feComponentTransfer) will temporarily undo and redo premultiplication as specified. [...] ---- According to this, conceptually, the source image data will arrive at the feColorMatrix node in premultiplied form, get unpremultiplied, then pass through the node, and get repremultiplied. But: In the process of premultiplying the RGBA data from the PNG image, for all pixels with A=0, the resulting R G and B will also become = 0, regardless of their original colour in the PNG file; so, the only thing that will be 'revealed' by the feColorMatrix node (and this the whole MakeLessTransparent filter) will be a homogenous black area wherever the PNG image had an Alpha value of exactly 0. Now, problem 2 above arises from the fact that, even if premultiplied samples are stored with sufficient accuracy to un-premultiply successfully for any non-zero Alpha value, multiplication of any R G or B value with an Alpha of 0 will result in a new R G or B value of 0 as well - from which no non-premultiplied color can be retrieved, no matter how hard one tries. This can be 'solved' by acknowledging the data loss in this situation, but I would consider that unsatisfactory; the only 'complete' solution to this that I see is to store the non-premultiplied values alongside the premultiplied ones as the image passes through the filter nodes, but perhaps there is a better one? The first problem of course can be solved by defining default R G and B values for 'untouched' pixels - basically, explicitly stating the full RGBA value which is assigned to the 'background' into which a to-be-filtered element gets painted, rather than (as the case seems to be now) stating only that its Alpha value is 0. Comments? Am I making any sense at all? Best regards // Christian Brunschen
Received on Wednesday, 2 February 2000 06:28:16 UTC