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.