| #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 |