GNOME Bugzilla – Bug 72869
Incorrect RGBA resampling in Value Propagate plug-in
Last modified: 2015-02-15 21:20:16 UTC
If two pixels have different opacity values (alpha channel), then their colors are not averaged correctly by the Distorts->Value Propagate plug-in. Try for example with the Propagate Mode set to "Middle Value to Peaks" or "More Black" if you use the (white) test images provided in bug #70335. It looks like the RGB channels are resampled without taking the opacity into account. As a result, the (invisible) color of a transparent pixel can bleed into an opaque pixel. The resulting image is incorrect. See bug #70335 for some test images and a longer description of the problem. This problem affects many other tools and plug-ins.
Some observations. This plug-in probably needs a bit of redesign to handle alpha correctly. For images with an alpha channel, two checkboxes, "Propagating Alpha Channel" and "Propagating Value Channel" are shown, apparently defining four submodes for each main Propagate Mode. But: Alpha off and Value off means the plugin does nothing. Alpha on and Value off means More Opaque makes the color of transparent pixels visible by definition. And it does nothing for color(value)-propagating main modes. Alpha off and Value on does nothing when the main mode is alpha-propagating, i.e. More Transparent or More Opaque. I'm not sure whether More Transparent has some correct definition for Alpha on and Value on, probably yes; for Alpha on and Value off it seems to work correctly already. So, what remains? Two and sometimes only one posibility for each Propagation Mode. IMHO the GUI should reflect this and not allow selection of inherently bad propagation submodes at the first place. Then of course, most of the good ones still has to be fixed. For reference, this plugin is also accessible as Filters -> Generic -> Dilate and Filters -> Generic -> Erode (in current CVS), with the same alpha handling problems.
Changed target milestone of several bugs to 2.0 - these are not features, and don't look to me like blockers for a pre-release, but they have to be addressed before 2.0. Dave.
I'm not sure what the way to fix this would be - this isn't a plug-in that does blending of pixels - its a "test and replace" algorithm. I tend to think that it handles what it does correctly, even if the results are somewhat suprising.
Seth, you should take a look at the (unfortunately long) discussion in bug #72853 (which is a bit similar to this one) and in the tracking bug #70335. A quick summary of my opinion: no matter what the algorithm does, a plug-in should never reveal the hidden RGB data of a fully transparent pixel. This data is undefined and should be skipped in the algorithm or should be replaced by some arbitrary value (e.g., black or current background or whatever is appropriate). Using undefined data in the output of a plug-in is a bug that should be fixed.
Hello Raphaël, as long as you use words like `hidden' to describe the pixel, you are not true. If the RGB information is only hidden, it's prefecly OK to reveal it again. If you switch off the light in your room, you expect to find the same furniture as before there when you switch it on again, and not some arbitrary default... This is the viewpoint all the controversal plug-in were written from, and it's perfectly valid. But most GIMP developers now think Alpha channel should not represent visibility of the pixels, but their presence in the image instead (this is an arbitrary decision, e.g. PoV-Ray has two kinds of `Alpha channels', transparency and filter, ...). So decreasing Alpha doesn't make the pixel hidden but makes it cease to exist (together with the information it contains). And thus Alpha is renamed to Transparency (i.e., a word describing the visibility concept) in the menus and dialogs at the same time, to confuse everyone even more... As I wrote before, the idea of these plug-ins doesn't make any sense in the world of Alpha-as-presence. You can't fix them there. Yes, they still can do *something*, but not what they were created for. Put them to the stamping-mill. We don't need plug-ins doing useful things, we need plug-ins that are correct (anything it means), don't we? Note there is not a signle thing one couldn't do in the Alpha-as-visibility world what one can do in the Alpha-as-presence one, but not vice versa.
I thought that I had clarified this issue before, but I used the word "undefined" on purpose. This is not simply "hidden". Some version of the GIMP could handle the fully transparent pixels in a special way if this makes sense for some optimizations (i.e., not allocating memory for these pixels if they are not used). As a result, the contents of the RGB data can be totally unpredictable: if you clear an area, the previous color of the pixels could be kept there for a while. But if the GIMP runs out of memory and frees the fully transparent tiles, you may get random data if you try to fetch the RGB values some moments later. This could also happen if someone decides to optimize the wire protocol so that fully transparent tiles are not passed to the plug-ins. Again, you would probably get random bits of memory if you try to access the RGB values. And some ugly square artifacts showing the boundaries of the tiles. There is nothing in the GIMP docs (user or developer) that says that the GIMP should try to preserve the RGB values of fully transparent pixels. And I think that it would be wrong to have such a requirement. The GIMP should be able to discard this data if it makes sense for some optimizations. So you should consider this as "undefined data". Undefined data should never be used in the output of a plug-in.
Well, if I believed there's at least a slight chance of changing anything I'd fill a bugreport exactly for this, i.e. for destroying color information only because a pixel is incidentally made transparent during the course of editing. Transparent is not undefined, just ... transparent. When there's no visual step between epsilon and zero opacity and there shouldn't be any conceptual, too. Transparency is just a property of the pixel, like the red component or it's position in the image. If the model is well designed, the properties are orthogonal, so changing one doesn't change others. But you seem to prefer situation where changing the green component also changes horizontal position of the pixel... The optimization arguments are void, because when making pixels transparent destroys them instead of making them transparent, one has to use layer masks excessively, thus no memory is saved at the end. Layer masks may be cleaner, but ofter they are also an expensive substitute for simple Alpha-as-visibility.
I don't understand the last part of your argument about layer masks. The GIMP stores and exchanges image data using tiles. It could mark a tile as being empty, just like it could use the same pointer for several identical tiles (transparent or not) and use copy-on-write only when the data has to be modified. This is a standard technique for optimization that was used in Adam's copy-on-write patches some time ago. Optimizing the GIMP by discarding fully transparent areas would be something very useful if we decide to implement some of the suggestions about "layers without boundaries": space is allocated automatically when the user draws outside the current layer, and is reclaimed when some contiguous areas are cleared. If we want to be able to do this later, then it is necessary to consider fully transparent areas as having no pixels, instead of having existing but hidden pixels. And even if we do not plan to do this later, it could still be useful to be able to optimize the communication between the core and the plug-ins.
Ad the previous last part. If you want to mix decreasing and increasing visibility of pixels during editing in RGB-Visibility, you simply need memory for these channels. In RGB-Presence, you can start losing pixels, so you have to use a layer mask, that allows doing it without losing pixels. But the layer mask has to be stored somewhere, too; so in summary, you may save save memory when many tiles are discardable (or duplicite), but when they aren't you may actually need more memory than before (for the layer mask). Ad infinite layers. OK, this shows why presence may be necessary (though this doesn't mean visibility is bad, I'm trying to imagine them to coexist, but that would probably be really silly).
I still don't understand why you would need a layer mask. If you edit a layer and clear an area, this is a destructive operation so the pixels are gone (they may still be available in the undo history). If you simply want to change the opacity of the whole layer or modify the opacity in non-destructive ways, then of course this should be done directly in the alpha channel and there is no need to add a layer mask. Anyway, the kind of optimizations that I mentioned above would never be performed while you are in the middle of some drawing operations. The detection of fully transparent tiles would be done when sending the image data to a plug-in (or getting it back) or when loading or saving images in XCF format, etc. It could also be done in an idle task, but this could do more harm than good. Basically, there is no need to be over-zealous about it. But I think that it is important to consider that a pixel that has been cleared (fully transparent) has simply ceased to exist and its RGB data is undefined. It may or may not be kept in memory for a while, but this is just undefined behavior.
It seems to me that Yeti and Seth are thinking premultipliedly, while raph is thinking postmultipliedly. One way is usually more natural for a person than the other, but the same way is not more natural for everyone. :) Aren't differences in mental models fun? (hint: the answer is "not when both can be applied meaningfully to a program")
Actually, come to think of it, we already have both transparency and presence. Transparency is called "layer mask" and presence is called "alpha". But then we have this wierd operation called "apply layer mask" that transmutes visablilty into presence. No wonder people are confused. "Out of sight, out of mind" I guess, but when a bird tries to fly through a closed window, they get a (warning! bad pun!) hard lesson on the difference. :) (that last sentence is irrelevent and should be deleted before I hit submit. :) )
Bumping the milestone for this bug, and all that depend on it, to 2.2. In the absence of someone actively working on this, there is no point keeping it on the 2.0 milestone. If someone wants to work on this, fixes to this family would also be accepted on the stable branch. Dave.
To use Dave's famous words: In the absence of someone actively working on this, there is no point keeping it on the 2.2 milestone.
value-propagate has been removed from git master and a GEGL operation is used instead.