Skip to content

Commit

Permalink
png: Add "png:alpha_srgb" configuration hint for PNG read
Browse files Browse the repository at this point in the history
Although PNG seems clear that the alpha channel should always be
encoded linearly (even of RGB is sRGB or gamma corrected), I think
that some PNG files seem to run the alpha through the sRGB encoding as
well. We need a way to read those files with that interpretation,
even though it's technically wrong.

This patch adds a configuration hint when opening a PNG file,
"png:alpha_srgb", which if nonzero will (ugh) interpret the alpha
channel as if it, too, is srgb encoded.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
  • Loading branch information
lgritz committed Aug 21, 2024
1 parent 6b2d140 commit 1efb5f4
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 7 deletions.
11 changes: 11 additions & 0 deletions src/doc/builtinplugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1723,6 +1723,11 @@ attributes are supported:
* - Input Configuration Attribute
- Type
- Meaning
* - ``png:alpha_srgb``
- int
- If nonzero, will assume that the alpha channel is in sRGB space
(versus linear space). This is technically incorrect, but sometimes
PNG files are this way.
* - ``oiio:UnassociatedAlpha``
- int
- If nonzero, will leave alpha unassociated (versus the default of
Expand All @@ -1732,6 +1737,12 @@ attributes are supported:
- ptr
- Pointer to a ``Filesystem::IOProxy`` that will handle the I/O, for
example by reading from memory rather than the file system.
* - ``oiio:UnassociatedAlpha``
- int
- If nonzero, indicates that the data being passed is already in
unassociated form (non-premultiplied colors) and should stay that way
for output rather than being assumed to be associated and get automatic
un-association to store in the file as PNG requires.

**Configuration settings for PNG output**

Expand Down
20 changes: 13 additions & 7 deletions src/png.imageio/pnginput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ class PNGInput final : public ImageInput {
Imath::Color3f m_bg; ///< Background color
int m_next_scanline;
bool m_keep_unassociated_alpha; ///< Do not convert unassociated alpha
bool m_srgb = false; ///< It's an sRGB image (not gamma)
bool m_err = false;
float m_gamma = 1.0f;
bool m_srgb = false; ///< It's an sRGB image (not gamma)
bool m_alpha_srgb = false; ///< Alpha is encoded as sRGB (incorrect)
bool m_err = false;
float m_gamma = 1.0f;
std::unique_ptr<ImageSpec> m_config; // Saved copy of configuration spec

/// Reset everything to initial state
Expand All @@ -61,6 +62,7 @@ class PNGInput final : public ImageInput {
m_next_scanline = 0;
m_keep_unassociated_alpha = false;
m_srgb = false;
m_alpha_srgb = false;
m_err = false;
m_gamma = 1.0;
m_config.reset();
Expand Down Expand Up @@ -89,7 +91,8 @@ class PNGInput final : public ImageInput {

template<class T>
static void associateAlpha(T* data, int size, int channels,
int alpha_channel, bool srgb, float gamma);
int alpha_channel, bool srgb, float gamma,
bool alpha_srgb);
};


Expand Down Expand Up @@ -188,6 +191,7 @@ PNGInput::open(const std::string& name, ImageSpec& newspec,
// Check 'config' for any special requests
if (config.get_int_attribute("oiio:UnassociatedAlpha", 0) == 1)
m_keep_unassociated_alpha = true;
m_alpha_srgb = config.get_int_attribute("png:alpha_srgb", 0);
ioproxy_retrieve_from_config(config);
m_config.reset(new ImageSpec(config)); // save config spec
return open(name, newspec);
Expand Down Expand Up @@ -224,7 +228,7 @@ PNGInput::close()
template<class T>
void
PNGInput::associateAlpha(T* data, int size, int channels, int alpha_channel,
bool srgb, float gamma)
bool srgb, float gamma, bool alpha_srgb)
{
// We need to transform to linear space, associate the alpha, and then
// transform back.
Expand All @@ -233,6 +237,8 @@ PNGInput::associateAlpha(T* data, int size, int channels, int alpha_channel,
DataArrayProxy<T, float> val(data);
float alpha = val[alpha_channel];
if (alpha != 1.0f) {
if (alpha_srgb)
alpha = sRGB_to_linear(alpha);
for (int c = 0; c < channels; c++) {
if (c != alpha_channel) {
float f = sRGB_to_linear(val[c]);
Expand Down Expand Up @@ -323,10 +329,10 @@ PNGInput::read_native_scanline(int subimage, int miplevel, int y, int /*z*/,
if (m_spec.format == TypeDesc::UINT16)
associateAlpha((unsigned short*)data, m_spec.width,
m_spec.nchannels, m_spec.alpha_channel, m_srgb,
m_gamma);
m_gamma, m_alpha_srgb);
else
associateAlpha((unsigned char*)data, m_spec.width, m_spec.nchannels,
m_spec.alpha_channel, m_srgb, m_gamma);
m_spec.alpha_channel, m_srgb, m_gamma, m_alpha_srgb);
}

return true;
Expand Down

0 comments on commit 1efb5f4

Please sign in to comment.