|
|
On 3/22/21 7:34 AM, William F Pokorny wrote:
...
>
> More on the png greyscale (single channel png) differences when I
> decipher more.
>
OK. In png.cpp there is a conditional block starting with:
...
else if ((color_type == PNG_COLOR_TYPE_GRAY) && (bit_depth <= 8))
...
and near the bottom of the block there is the conditional:
ImageDataType imagetype = options.itype;
if (imagetype == ImageDataType::Undefined)
{
imagetype = has_alpha ?
ImageDataType::GrayA_Int8 : ImageDataType::Gray_Int8;
}
and this should read:
ImageDataType imagetype = options.itype;
if (imagetype == ImageDataType::Undefined)
{
imagetype = ImageDataType::Colour_Map;
}
The code is creating a color map type image in the way the conditional
block previous does for 'actual' color mapped png images.
The bug is sitting there in v3.7 too, but I guess because greyscale
output in v3.7 is 16 bit we don't trip it.
What this means is a valid work around for v3.8 based users is to
specify bit depths >8 (9..16) greyscale out as that code appears to work OK.
Detail:
-------
That conditional block in question looks to be an attempt to 'pretend'
<= 8 bit gray images are palleted images. It allows each of the 256
valid greys to be gamma converted once instead of by pixel. The trouble
is in setting the image type to either of those Gray*Int8 types, we end
up getting the 'image' class's Image::SetIndexedValue method instead of
the ColourMapImage class's Image::SetIndexedValue method (got to love c++).
This results in the incoming grey values not being used as index values
into the created faked color map directly, but rather as indexes into
code setting explicit RGBA values using the color map. The mystery to me
is partly how the class mechanisms work at all(1) here and further that
the result is as close as it is.
(1) - The compile should probably die here, but as the classes set up,
somehow things don't.
There are some further questions too with this conditional block...
First, for images with no mapped alpha channels, or single transparent
color, the block isn't needed. It can be commented and the code already
handling the >8 bit depths works too for <=8 bit depths with 'perhaps'
some performance impact.
There are png encodings which can mark a particular color as transparent
and this block 'perhaps' can handle some of them - though who knows. It
looks to me like there is no actual png palette grey encoding, but
rather only a color one. Further, the >8 bit grey scale READ code in
POV-Ray does not handle single transparent colors that I can see. So
guess on the surface, looks to me like grey encoding of more specialized
palette or value transparency is iffy.
In my own code I've also added:
// PNG variously supports bit depths of 1,2,4,8 and 16. Below only
// depths of 8 and 16 look reliable to me.
POV_IMAGE_ASSERT((bit_depth == 8) || (bit_depth == 16));
to see if I turn up some of the odd encodings at some point and then I
can perhaps look at what's happening in those cases.
(The above is the storage channel depth, not the 'value' bit depth
(bucketing) v3.8 now allows to be set 1..16.)
There are in the current png library, methods which promote odd
encodings and grey encodings to 8 or 16 bit rgb(a). Perhaps it's
possible to make the current png read code simpler and more robust - if
'perhaps' not quite as fast in some cases.
Lastly
------
Yes, this last bug a bit off in the weeds as most people writing grey
pngs for height fields will probably use 16 bits. It's only those
wanting to read <=8 bit png grey scale images.
Bill P.
Post a reply to this message
|
|