Image File Formats, Gamma Correction and POV-Ray


JPEG

Originally this was not even a file format but just a codec for a DCT-compressed data stream. But for it's high compression rate (when used for photographic images) it immediately did become (mis-)used as a file format - and interchangeability was not much of an issue at this time (ca. 1990). But these simple JPEG 'file-format' is still in use. To overcome the limitation two different extensions for the JPEG-codec where introduced, JFIF and EXIF. Both provide some basic ways to embed additional informations like PPI/DPI, comments and such but sadly no way to specify the color space (including gamma correction) that was used for the original image.
Meanwhile the WWW was here and JPEG extensively used there for photo-like images. Interchangeability was now a real issue and the average JPEG's in the web had a gamma correction of about 2.2 (or sRGB as proposed by HP, Microsoft and others). Now (as reaction to this already existing kind of usage) the W3C quasi defined JPEG being in sRGB color space.
As a side note, I do own an old (from about 1994) but still fully functional SGI Indigo graphics workstation. JPEG files generated there (that are completely valid ones) are not displayable as intended on any current Windows, Linux or Mac system (and visa-versa) because of lack of information about used color space and gamma correction within the JPEG format.
To make things a bit more complicated Adobe software did start to embed ICC profiles into JPEG. This works very well when only programs are used that do actually handle ICC profiles but most (including POV-Ray) just do ignore them. Poser (IIRC since version 5) uses the FreeImage open-source-library for image import/export and this library does handle ICC color profiles, on the other hand DAZ-Studio (the posing/rendering software from DAZ) does not. And most vendors for Poser content (like DAZ itself) do use Adobe Photoshop for image map generation - so we have the quite funny situation that DAZ provides two different sets of image maps in JPEG format, one for Poser and a modified one for DAZ-Studio (that seems to do gamma correction somehow strange anyway). And the bad news for POV-Ray users: usually none of these image sets will work within POV-Ray as intended.
Recently I had a discussion with Warp from the POV-Ray NG who claimed that there have never been any problems with jpeg-images, so if this sounds to you like no problems - I really can't help.

PNG

I know there are myths and misconceptions about gamma correction and the PNG file format and maybe I will elaborate on this in detail some day but for the moment I'll just state my opinion that there is and never was anything wrong with the PNG format and its specification. But there have been (and still are) very poor implementations within software that did claim to support PNG. This is in fact something I have a very hard time to understand because with libpng was from the very beginning a ready-to-use open source reference library available. E.g. the correct handling of the gamma chunk can be done with one single line of code without even the need to understand what this 'gamma-thing' is about. All this is well documented and compared to TIFF the PNG format is simple and straightforward.

And (as usual) things get worse when Adobe Photoshop (I am referring to CS3 - the current version I do own) is used.
The first strange surprise happens when opening any simple (and valid) PNG file that was not written by Photoshop itself. A message appears saying:
"The RGB document "bla.png" has a file format that does not support embedded color profiles."
WTF? This is a plain lie. PNG does support ICC profiles very well and has an own chunk for this purpose. The problem is that Photoshop does ignore this chunk and also any profile that might be there. But after clicking that dialog away Photoshop opens the PNG just fine and the real problem occurs when Photoshop is used to save an image as PNG file. To better understand this a short explanation how the PNG header is organized: It consists of so called 'chunks' and some of them are mandatory (like the one used to define the image dimension or the used bit depth) but most are just optional.
To define the color space used by the image 4 optional chunks are available:
gamma chunk - it defines an exponent that was used for the gamma correction of the image data.
sRGB chunk - the existence of this chunk means: this image is in sRGB color space with gamma correction close to 2.2.
ICC chunk - that includes an ICC color profile to define the used color space (including gamma correction).
If none of these chunks is present the PNG specification (and the W3C) recommends that a gamma correction of 2.2 should be assumed. In addition there is also a chroma chunk to define the xyz primaries for the RGB components of the image and should *always* be accompanied by an gamma chunk to completely define a color space.
Photoshop writes *only* the chroma chunk (which is strictly seen valid because together with PNG/W3C recommendation this does indeed fully define the color space) but it is hard to understand why it does not also add the gamma chunk. Especially as the chroma chunk is ignored by every application I'm aware of (besides Photoshop and IC) but meanwhile most applications handle the gamma chunk as they should.
And finally the consequence for POV-Ray users: PNG files written by Photoshop will not work as image map within POV-Ray as expected because POV-Ray does only recognize and use the gamma chunk and does not follow the PNG/W3C recommendation when this chunk is missing.

TGA

A completely outdated image file format that even has been misused by some dirty hack (introduced by a fractal generator in the early 90ies) to store high resolution hight-field like information. It *is* just a dirty hack because the TGA header does not indicate in any way that the data does not represent a conventional RGB image so every image processing software has no chance but showing a mess of green and black pixels in this case.

TIFF

Some people say that TIFF does not stand for 'Tagged Image File Format' but does indeed mean 'Thousands of Incompatible File Formats'. There is some truth in it as TIFF supports such a wide range of compression methods, data order and storage methods, color spaces, bit and sample depth, (and all this in all combinations) that EVERY application (including Photoshop, IC and POV-Ray) does only support a subset of all image representations that are possible within TIFF. POV-Ray does also ignore ICC profiles and all other colorimetric information that might be embedded within TIFF. It has just to be tried out to make a decision if a particular TIFF (or TIFF's created by a particular application) do work with POV-Ray as expected or not.
Adobe 'owns' the TIFF specification which is still revision 6.0 from 1992, but sometimes publishes a technical note about new features (usually *after* having implemented them into Photoshop) within the TIF-Format. Since Photoshop CS2 Adobe added support for various floating point formats to Photoshop and TIFF:
16 BPS - the same 'half' format as used by OpenEXR and IC. 24 BPS - a strange 'uneven' floating point format. (It took me quite a while to figure out how mantissa, exponent and NAN is represented there - I am a so called 'Adobe-Partner' and own the Photoshop SDK, but details like this are not mentioned there).
32 BPS - the 'normal' floating point type as used by every compiler. Strictly seen this floating point HDRI represention within TIFF is not a real 'new' feature - as already mentioned TIFF does already 'by design' support almost everything.
POV-Ray is unable to recognize and work with those 'new' HDR TIFF files and is also unable to work with 'old' LogLUV TIFF HDR images.

And POV-Ray?

Well, I think when image maps where introduced into POV-Ray interoperability was also not much of an issue. When you did use POV-Ray with e.g. an Amiga you did use image files as maps that where also created on an Amiga - and all was fine. To make it possible to render such a scene created by an Amige on a (lets say at this time) DOS box assumed_gamma was introduced.
Once I did recreate some of the very first scenes that did use the raytracing algorithm (back in the early 80ies, mostly variations of glass and chrome spheres hovering over checkered planes but at this time it took hours and days to render such a scene) and for nostalgic reasons I did use the Indigo for this task (where it took minutes to render them). Finally I ported the scene description files from the Indigo to my current quad-core windows machine, changes the assumed_gamma setting from 1.0 to 2.2 (as needed to use the scene files created on the Indigo) and rendered it there with POV-Ray 3.7beta (in backwards compatibility mode). Needless to say that the render time dropped to less than a second but the important thing: this is exactly the kind of usage assumed_gamma was meant for.

Solutions

In fact currently no real one, but some workarounds. I'll try to summarize and present the pros and cons.

Set assumed_gamma to 2.2

pro: Simple. JPEG and PNG files for image maps can be used as they are.
con: Transparency via pigment_pattern does not work as expected because the maps used are also gamma corrected and HDR images cannot be used for the same reason (HDR images are 'per definition' in a linear color space and not gamma corrected).
All used pigment/color statements have to be adjusted in the scene file and all include files. Antialiasing does produce colored 'shadows'. POV-Ray 3.7 does no longer allow to fumble with assumed_gamma when #version is set to 3.7.

Process JPEG image_map by a function to invert the gamma correction (1)

pro: Simple to use and implement. JPEG and PNG files for image maps can be used as they are.
con: this will (especially with good AA settings) increase the render time because this function has to be evaluated at runtime for every ray that hits an object with that pigment.

Use an external program to inverse gamma correct the JPEG image files and use those modified ones with POV-Ray. (Jaime does use this method in his 'Chief Architect Tutorial'.)

pro: It works. Additional bonus: If a program is used that can handle ICC profiles and also does support sRGB output (like IC) the resulting image will look as originally intended.
con: An external program is needed. As JPEG compression is always lossy, block artifacts may become quite strong and visible. 29% of information within the original image is just thrown away so color banding might occur (2).

Use an external program to convert JPEG image files to PNG and use those with POV-Ray. (I do use this method most of the time.)

pro: It works when a program is used that writes a correct gamma chunk into the PNG file (like IC). Additional bonus: If a program is used that can handle ICC profiles and also does support sRGB output (like IC) the resulting image will look as originally intended.
con: An external program is needed. In case 8bit/sample PNG files are used the same loss of information happens as with JPEG but within POV-Ray. (POV-Ray just uses the function provided by libpng to make use of the png gamma chunk, so the correction - and loss of information - is already applied to the 8bps image data before it is transferred into the buffer used by POV-Ray.)
So to avoid any loss a conversion to 16bps PNG files is needed (also supported by IC) but this results in quite a waste of disk space.


So for short thats what I usually do:

I use IC to convert all JPEG files that are used as image_map to 16bps PNG files. (Open the JPEG file, select 'Image->Mode->RGB 16 bps', 'Image->File->Save image...' select PNG and use the 'Format Option' button to make sure 'Gamma chunk' is checked within the 'Save as PNG' dialog.) Disk space is cheap nowadays so I can live with the fact that the resulting PNG files are quite huge compared to the original JPEG ones.

Use all JPEG files that are meant as transparency map or bump map as they are.

Set 'assumed_gamma' in the scene file to 1.0 when any POV-Ray version prior 3.7 is used or completely remove it for 3.7.

For a real solution POV-Ray should recognize ICC profiles within JPEG, PNG and TIFF images (lcms an open source color management library would do this job just fine) and in addition a new keyword for the image_map statement like e.g:

image_map {jpeg "MyImage.jpg" interpolate 2 image_gamma 2.2}

would be needed. Well this and someone who volunteers to implement it ;)


Ive - April 2009



This side states only my personal opinion and all company, product and brand names referred to are trademarks or registered trademarks of their respective owners.



(1) example how to inverse gamma correct sRGB jpeg files

#declare sRGB_Inv = function(C) { select(C-0.04045, C/12.92, pow((C+0.055)/1.055,2.4)) }

#macro sRGB_JpgMap(ImageName)

#local fn = function { pigment {image_map {jpeg ImageName interpolate 2}} }

pigment {
average
pigment_map {
[function {sRGB_Inv(fn(x,y,z).red)} color_map {[0 rgb<0,0,0>][1 rgb<3,0,0>]}]
[function {sRGB_Inv(fn(x,y,z).green)} color_map {[0 rgb<0,0,0>][1 rgb<0,3,0>]}]
[function {sRGB_Inv(fn(x,y,z).blue)} color_map {[0 rgb<0,0,0>][1 rgb<0,0,3>]}]
}
}
#end

// used like:
pigment { sRGB_JpgMap("MyTexture.jpg") }



(2) Inverse gamma correction of an existing image in 8 BPS format (like JPEG) reduces the possible 256 values that are used to represent one color component to 183. So only 71% of the original information is preserved or in other words we have a loss of 29% of information. As a result visible color banding is very likely.
IC uses an ordered dithering method to minimize the *visibility* of that banding effect, but this does not change the fact that the loss of information is still there and within POV-Ray it might (in the worst case when used as image_map and viewed from some specific distance and angle) result in the appearance of moire-patterns - and to get rid of them higher AA settings are required.