249 lines
8.0 KiB
C
249 lines
8.0 KiB
C
|
#ifndef INCLUDED_IMF_RGBA_YCA_H
|
||
|
#define INCLUDED_IMF_RGBA_YCA_H
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucasfilm
|
||
|
// Entertainment Company Ltd. Portions contributed and copyright held by
|
||
|
// others as indicated. All rights reserved.
|
||
|
//
|
||
|
// Redistribution and use in source and binary forms, with or without
|
||
|
// modification, are permitted provided that the following conditions are
|
||
|
// met:
|
||
|
//
|
||
|
// * Redistributions of source code must retain the above
|
||
|
// copyright notice, this list of conditions and the following
|
||
|
// disclaimer.
|
||
|
//
|
||
|
// * Redistributions in binary form must reproduce the above
|
||
|
// copyright notice, this list of conditions and the following
|
||
|
// disclaimer in the documentation and/or other materials provided with
|
||
|
// the distribution.
|
||
|
//
|
||
|
// * Neither the name of Industrial Light & Magic nor the names of
|
||
|
// any other contributors to this software may be used to endorse or
|
||
|
// promote products derived from this software without specific prior
|
||
|
// written permission.
|
||
|
//
|
||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||
|
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||
|
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||
|
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||
|
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||
|
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||
|
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Conversion between RGBA (red, green, blue alpha)
|
||
|
// and YCA (luminance, subsampled chroma, alpha) data:
|
||
|
//
|
||
|
// Luminance, Y, is computed as a weighted sum of R, G, and B:
|
||
|
//
|
||
|
// Y = yw.x * R + yw.y * G + yw.z * B
|
||
|
//
|
||
|
// Function computeYw() computes a set of RGB-to-Y weights, yw,
|
||
|
// from a set of primary and white point chromaticities.
|
||
|
//
|
||
|
// Chroma, C, consists of two components, RY and BY:
|
||
|
//
|
||
|
// RY = (R - Y) / Y
|
||
|
// BY = (B - Y) / Y
|
||
|
//
|
||
|
// For efficiency, the x and y subsampling rates for chroma are
|
||
|
// hardwired to 2, and the chroma subsampling and reconstruction
|
||
|
// filters are fixed 27-pixel wide windowed sinc functions.
|
||
|
//
|
||
|
// Starting with an image that has RGBA data for all pixels,
|
||
|
//
|
||
|
// RGBA RGBA RGBA RGBA ... RGBA RGBA
|
||
|
// RGBA RGBA RGBA RGBA ... RGBA RGBA
|
||
|
// RGBA RGBA RGBA RGBA ... RGBA RGBA
|
||
|
// RGBA RGBA RGBA RGBA ... RGBA RGBA
|
||
|
// ...
|
||
|
// RGBA RGBA RGBA RGBA ... RGBA RGBA
|
||
|
// RGBA RGBA RGBA RGBA ... RGBA RGBA
|
||
|
//
|
||
|
// function RGBAtoYCA() converts the pixels to YCA format:
|
||
|
//
|
||
|
// YCA YCA YCA YCA ... YCA YCA
|
||
|
// YCA YCA YCA YCA ... YCA YCA
|
||
|
// YCA YCA YCA YCA ... YCA YCA
|
||
|
// YCA YCA YCA YCA ... YCA YCA
|
||
|
// ...
|
||
|
// YCA YCA YCA YCA ... YCA YCA
|
||
|
// YCA YCA YCA YCA ... YCA YCA
|
||
|
//
|
||
|
// Next, decimateChomaHoriz() eliminates the chroma values from
|
||
|
// the odd-numbered pixels in every scan line:
|
||
|
//
|
||
|
// YCA YA YCA YA ... YCA YA
|
||
|
// YCA YA YCA YA ... YCA YA
|
||
|
// YCA YA YCA YA ... YCA YA
|
||
|
// YCA YA YCA YA ... YCA YA
|
||
|
// ...
|
||
|
// YCA YA YCA YA ... YCA YA
|
||
|
// YCA YA YCA YA ... YCA YA
|
||
|
//
|
||
|
// decimateChromaVert() eliminates all chroma values from the
|
||
|
// odd-numbered scan lines:
|
||
|
//
|
||
|
// YCA YA YCA YA ... YCA YA
|
||
|
// YA YA YA YA ... YA YA
|
||
|
// YCA YA YCA YA ... YCA YA
|
||
|
// YA YA YA YA ... YA YA
|
||
|
// ...
|
||
|
// YCA YA YCA YA ... YCA YA
|
||
|
// YA YA YA YA ... YA YA
|
||
|
//
|
||
|
// Finally, roundYCA() reduces the precision of the luminance
|
||
|
// and chroma values so that the pixel data shrink more when
|
||
|
// they are saved in a compressed file.
|
||
|
//
|
||
|
// The output of roundYCA() can be converted back to a set
|
||
|
// of RGBA pixel data that is visually very similar to the
|
||
|
// original RGBA image, by calling reconstructChromaHoriz(),
|
||
|
// reconstructChromaVert(), YCAtoRGBA(), and finally
|
||
|
// fixSaturation().
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
#include <ImfRgba.h>
|
||
|
#include <ImfChromaticities.h>
|
||
|
|
||
|
namespace Imf {
|
||
|
namespace RgbaYca {
|
||
|
|
||
|
|
||
|
//
|
||
|
// Width of the chroma subsampling and reconstruction filters
|
||
|
//
|
||
|
|
||
|
static const int N = 27;
|
||
|
static const int N2 = N / 2;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Convert a set of primary chromaticities into a set of weighting
|
||
|
// factors for computing a pixels's luminance, Y, from R, G and B
|
||
|
//
|
||
|
|
||
|
Imath::V3f computeYw (const Chromaticities &cr);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Convert an array of n RGBA pixels, rgbaIn, to YCA (luminance/chroma/alpha):
|
||
|
//
|
||
|
// ycaOut[i].g = Y (rgbaIn[i]);
|
||
|
// ycaOut[i].r = RY (rgbaIn[i]);
|
||
|
// ycaOut[i].b = BY (rgbaIn[i]);
|
||
|
// ycaOut[i].a = aIsValid? rgbaIn[i].a: 1
|
||
|
//
|
||
|
// yw is a set of RGB-to-Y weighting factors, as computed by computeYw().
|
||
|
//
|
||
|
|
||
|
void RGBAtoYCA (const Imath::V3f &yw,
|
||
|
int n,
|
||
|
bool aIsValid,
|
||
|
const Rgba rgbaIn[/*n*/],
|
||
|
Rgba ycaOut[/*n*/]);
|
||
|
|
||
|
//
|
||
|
// Perform horizontal low-pass filtering and subsampling of
|
||
|
// the chroma channels of an array of n pixels. In order
|
||
|
// to avoid indexing off the ends of the input array during
|
||
|
// low-pass filtering, ycaIn must have N2 extra pixels at
|
||
|
// both ends. Before calling decimateChromaHoriz(), the extra
|
||
|
// pixels should be filled with copies of the first and last
|
||
|
// "real" input pixel.
|
||
|
//
|
||
|
|
||
|
void decimateChromaHoriz (int n,
|
||
|
const Rgba ycaIn[/*n+N-1*/],
|
||
|
Rgba ycaOut[/*n*/]);
|
||
|
|
||
|
//
|
||
|
// Perform vertical chroma channel low-pass filtering and subsampling.
|
||
|
// N scan lines of input pixels are combined into a single scan line
|
||
|
// of output pixels.
|
||
|
//
|
||
|
|
||
|
void decimateChromaVert (int n,
|
||
|
const Rgba * const ycaIn[N],
|
||
|
Rgba ycaOut[/*n*/]);
|
||
|
|
||
|
//
|
||
|
// Round the luminance and chroma channels of an array of YCA
|
||
|
// pixels that has already been filtered and subsampled.
|
||
|
// The signifcands of the pixels' luminance and chroma values
|
||
|
// are rounded to roundY and roundC bits respectively.
|
||
|
//
|
||
|
|
||
|
void roundYCA (int n,
|
||
|
unsigned int roundY,
|
||
|
unsigned int roundC,
|
||
|
const Rgba ycaIn[/*n*/],
|
||
|
Rgba ycaOut[/*n*/]);
|
||
|
|
||
|
//
|
||
|
// For a scan line that has valid chroma data only for every other pixel,
|
||
|
// reconstruct the missing chroma values.
|
||
|
//
|
||
|
|
||
|
void reconstructChromaHoriz (int n,
|
||
|
const Rgba ycaIn[/*n+N-1*/],
|
||
|
Rgba ycaOut[/*n*/]);
|
||
|
|
||
|
//
|
||
|
// For a scan line that has only luminance and no valid chroma data,
|
||
|
// reconstruct chroma from the surronding N scan lines.
|
||
|
//
|
||
|
|
||
|
void reconstructChromaVert (int n,
|
||
|
const Rgba * const ycaIn[N],
|
||
|
Rgba ycaOut[/*n*/]);
|
||
|
|
||
|
//
|
||
|
// Convert an array of n YCA (luminance/chroma/alpha) pixels to RGBA.
|
||
|
// This function is the inverse of RGBAtoYCA().
|
||
|
// yw is a set of RGB-to-Y weighting factors, as computed by computeYw().
|
||
|
//
|
||
|
|
||
|
void YCAtoRGBA (const Imath::V3f &yw,
|
||
|
int n,
|
||
|
const Rgba ycaIn[/*n*/],
|
||
|
Rgba rgbaOut[/*n*/]);
|
||
|
|
||
|
//
|
||
|
// Eliminate super-saturated pixels:
|
||
|
//
|
||
|
// Converting an image from RGBA to YCA, low-pass filtering chroma,
|
||
|
// and converting the result back to RGBA can produce pixels with
|
||
|
// super-saturated colors, where one or two of the RGB components
|
||
|
// become zero or negative. (The low-pass and reconstruction filters
|
||
|
// introduce some amount of ringing into the chroma components.
|
||
|
// This can lead to negative RGB values near high-contrast edges.)
|
||
|
//
|
||
|
// The fixSaturation() function finds super-saturated pixels and
|
||
|
// corrects them by desaturating their colors while maintaining
|
||
|
// their luminance. fixSaturation() takes three adjacent input
|
||
|
// scan lines, rgbaIn[0], rgbaIn[1], rgbaIn[2], adjusts the
|
||
|
// saturation of rgbaIn[1], and stores the result in rgbaOut.
|
||
|
//
|
||
|
|
||
|
void fixSaturation (const Imath::V3f &yw,
|
||
|
int n,
|
||
|
const Rgba * const rgbaIn[3],
|
||
|
Rgba rgbaOut[/*n*/]);
|
||
|
|
||
|
} // namespace RgbaYca
|
||
|
} // namespace Imf
|
||
|
|
||
|
#endif
|