POV-Ray : Newsgroups : povray.beta-test : File png/ppm gamma issues. v3.8. : Re: File png/ppm gamma issues. v3.8. Server Time
14 Aug 2022 03:12:46 EDT (-0400)
  Re: File png/ppm gamma issues. v3.8.  
From: William F Pokorny
Date: 25 Mar 2021 02:48:29
Message: <605c323d@news.povray.org>
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.

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.

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

Copyright 2003-2021 Persistence of Vision Raytracer Pty. Ltd.