/* * Copyright (c) 1997 Greg Ward Larson * Copyright (c) 1997 Silicon Graphics, Inc. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names of * Sam Leffler, Greg Larson and Silicon Graphics may not be used in any * advertising or publicity relating to the software without the specific, * prior written permission of Sam Leffler, Greg Larson and Silicon Graphics. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL SAM LEFFLER, GREG LARSON OR SILICON GRAPHICS BE LIABLE * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ #include "tiffiop.h" #ifdef LOGLUV_SUPPORT /* * TIFF Library. * LogLuv compression support for high dynamic range images. * * Contributed by Greg Larson. * * LogLuv image support uses the TIFF library to store 16 or 10-bit * log luminance values with 8 bits each of u and v or a 14-bit index. * * The codec can take as input and produce as output 32-bit IEEE float values * as well as 16-bit integer values. A 16-bit luminance is interpreted * as a sign bit followed by a 15-bit integer that is converted * to and from a linear magnitude using the transformation: * * L = 2^( (Le+.5)/256 - 64 ) # real from 15-bit * * Le = floor( 256*(log2(L) + 64) ) # 15-bit from real * * The actual conversion to world luminance units in candelas per sq. meter * requires an additional multiplier, which is stored in the TIFFTAG_STONITS. * This value is usually set such that a reasonable exposure comes from * clamping decoded luminances above 1 to 1 in the displayed image. * * The 16-bit values for u and v may be converted to real values by dividing * each by 32768. (This allows for negative values, which aren't useful as * far as we know, but are left in case of future improvements in human * color vision.) * * Conversion from (u,v), which is actually the CIE (u',v') system for * you color scientists, is accomplished by the following transformation: * * u = 4*x / (-2*x + 12*y + 3) * v = 9*y / (-2*x + 12*y + 3) * * x = 9*u / (6*u - 16*v + 12) * y = 4*v / (6*u - 16*v + 12) * * This process is greatly simplified by passing 32-bit IEEE floats * for each of three CIE XYZ coordinates. The codec then takes care * of conversion to and from LogLuv, though the application is still * responsible for interpreting the TIFFTAG_STONITS calibration factor. * * By definition, a CIE XYZ vector of [1 1 1] corresponds to a neutral white * point of (x,y)=(1/3,1/3). However, most color systems assume some other * white point, such as D65, and an absolute color conversion to XYZ then * to another color space with a different white point may introduce an * unwanted color cast to the image. It is often desirable, therefore, to * perform a white point conversion that maps the input white to [1 1 1] * in XYZ, then record the original white point using the TIFFTAG_WHITEPOINT * tag value. A decoder that demands absolute color calibration may use * this white point tag to get back the original colors, but usually it * will be ignored and the new white point will be used instead that * matches the output color space. * * Pixel information is compressed into one of two basic encodings, depending * on the setting of the compression tag, which is one of COMPRESSION_SGILOG * or COMPRESSION_SGILOG24. For COMPRESSION_SGILOG, greyscale data is * stored as: * * 1 15 * |-+---------------| * * COMPRESSION_SGILOG color data is stored as: * * 1 15 8 8 * |-+---------------|--------+--------| * S Le ue ve * * For the 24-bit COMPRESSION_SGILOG24 color format, the data is stored as: * * 10 14 * |----------|--------------| * Le' Ce * * There is no sign bit in the 24-bit case, and the (u,v) chromaticity is * encoded as an index for optimal color resolution. The 10 log bits are * defined by the following conversions: * * L = 2^((Le'+.5)/64 - 12) # real from 10-bit * * Le' = floor( 64*(log2(L) + 12) ) # 10-bit from real * * The 10 bits of the smaller format may be converted into the 15 bits of * the larger format by multiplying by 4 and adding 13314. Obviously, * a smaller range of magnitudes is covered (about 5 orders of magnitude * instead of 38), and the lack of a sign bit means that negative luminances * are not allowed. (Well, they aren't allowed in the real world, either, * but they are useful for certain types of image processing.) * * The desired user format is controlled by the setting the internal * pseudo tag TIFFTAG_SGILOGDATAFMT to one of: * SGILOGDATAFMT_FLOAT = IEEE 32-bit float XYZ values * SGILOGDATAFMT_16BIT = 16-bit integer encodings of logL, u and v * Raw data i/o is also possible using: * SGILOGDATAFMT_RAW = 32-bit unsigned integer with encoded pixel * In addition, the following decoding is provided for ease of display: * SGILOGDATAFMT_8BIT = 8-bit default RGB gamma-corrected values * * For grayscale images, we provide the following data formats: * SGILOGDATAFMT_FLOAT = IEEE 32-bit float Y values * SGILOGDATAFMT_16BIT = 16-bit integer w/ encoded luminance * SGILOGDATAFMT_8BIT = 8-bit gray monitor values * * Note that the COMPRESSION_SGILOG applies a simple run-length encoding * scheme by separating the logL, u and v bytes for each row and applying * a PackBits type of compression. Since the 24-bit encoding is not * adaptive, the 32-bit color format takes less space in many cases. * * Further control is provided over the conversion from higher-resolution * formats to final encoded values through the pseudo tag * TIFFTAG_SGILOGENCODE: * SGILOGENCODE_NODITHER = do not dither encoded values * SGILOGENCODE_RANDITHER = apply random dithering during encoding * * The default value of this tag is SGILOGENCODE_NODITHER for * COMPRESSION_SGILOG to maximize run-length encoding and * SGILOGENCODE_RANDITHER for COMPRESSION_SGILOG24 to turn * quantization errors into noise. */ #include <math.h> #include <stdio.h> #include <stdlib.h> /* * State block for each open TIFF * file using LogLuv compression/decompression. */ LogLuvState; struct logLuvState { … }; #define DecoderState(tif) … #define EncoderState(tif) … #define SGILOGDATAFMT_UNKNOWN … #define MINRUN … /* * Decode a string of 16-bit gray pixels. */ static int LogL16Decode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) { … } /* * Decode a string of 24-bit pixels. */ static int LogLuvDecode24(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) { … } /* * Decode a string of 32-bit pixels. */ static int LogLuvDecode32(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) { … } /* * Decode a strip of pixels. We break it into rows to * maintain synchrony with the encode algorithm, which * is row by row. */ static int LogLuvDecodeStrip(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { … } /* * Decode a tile of pixels. We break it into rows to * maintain synchrony with the encode algorithm, which * is row by row. */ static int LogLuvDecodeTile(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { … } /* * Encode a row of 16-bit pixels. */ static int LogL16Encode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { … } /* * Encode a row of 24-bit pixels. */ static int LogLuvEncode24(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { … } /* * Encode a row of 32-bit pixels. */ static int LogLuvEncode32(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { … } /* * Encode a strip of pixels. We break it into rows to * avoid encoding runs across row boundaries. */ static int LogLuvEncodeStrip(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { … } /* * Encode a tile of pixels. We break it into rows to * avoid encoding runs across row boundaries. */ static int LogLuvEncodeTile(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { … } /* * Encode/Decode functions for converting to and from user formats. */ #include "uvcode.h" #ifndef UVSCALE #define U_NEU … #define V_NEU … #define UVSCALE … #endif #ifndef M_LN2 #define M_LN2 … #endif #ifndef M_PI #define M_PI … #endif #undef log2 /* Conflict with C'99 function */ #define log2(x) … #undef exp2 /* Conflict with C'99 function */ #define exp2(x) … static int tiff_itrunc(double x, int m) { … } #if !LOGLUV_PUBLIC static #endif double LogL16toY(int p16) /* compute luminance from 16-bit LogL */ { … } #if !LOGLUV_PUBLIC static #endif int LogL16fromY(double Y, int em) /* get 16-bit LogL from Y */ { … } static void L16toY(LogLuvState *sp, uint8_t *op, tmsize_t n) { … } static void L16toGry(LogLuvState *sp, uint8_t *op, tmsize_t n) { … } static void L16fromY(LogLuvState *sp, uint8_t *op, tmsize_t n) { … } #if !LOGLUV_PUBLIC static #endif void XYZtoRGB24(float *xyz, uint8_t *rgb) { … } #if !LOGLUV_PUBLIC static #endif double LogL10toY(int p10) /* compute luminance from 10-bit LogL */ { … } #if !LOGLUV_PUBLIC static #endif int LogL10fromY(double Y, int em) /* get 10-bit LogL from Y */ { … } #define NANGLES … #define uv2ang … static int oog_encode(double u, double v) /* encode out-of-gamut chroma */ { … } #undef uv2ang #undef NANGLES #if !LOGLUV_PUBLIC static #endif int uv_encode(double u, double v, int em) /* encode (u',v') coordinates */ { … } #if !LOGLUV_PUBLIC static #endif int uv_decode(double *up, double *vp, int c) /* decode (u',v') index */ { … } #if !LOGLUV_PUBLIC static #endif void LogLuv24toXYZ(uint32_t p, float *XYZ) { … } #if !LOGLUV_PUBLIC static #endif uint32_t LogLuv24fromXYZ(float *XYZ, int em) { … } static void Luv24toXYZ(LogLuvState *sp, uint8_t *op, tmsize_t n) { … } static void Luv24toLuv48(LogLuvState *sp, uint8_t *op, tmsize_t n) { … } static void Luv24toRGB(LogLuvState *sp, uint8_t *op, tmsize_t n) { … } static void Luv24fromXYZ(LogLuvState *sp, uint8_t *op, tmsize_t n) { … } static void Luv24fromLuv48(LogLuvState *sp, uint8_t *op, tmsize_t n) { … } #if !LOGLUV_PUBLIC static #endif void LogLuv32toXYZ(uint32_t p, float *XYZ) { … } #if !LOGLUV_PUBLIC static #endif uint32_t LogLuv32fromXYZ(float *XYZ, int em) { … } static void Luv32toXYZ(LogLuvState *sp, uint8_t *op, tmsize_t n) { … } static void Luv32toLuv48(LogLuvState *sp, uint8_t *op, tmsize_t n) { … } static void Luv32toRGB(LogLuvState *sp, uint8_t *op, tmsize_t n) { … } static void Luv32fromXYZ(LogLuvState *sp, uint8_t *op, tmsize_t n) { … } static void Luv32fromLuv48(LogLuvState *sp, uint8_t *op, tmsize_t n) { … } static void _logLuvNop(LogLuvState *sp, uint8_t *op, tmsize_t n) { … } static int LogL16GuessDataFmt(TIFFDirectory *td) { … } static tmsize_t multiply_ms(tmsize_t m1, tmsize_t m2) { … } static int LogL16InitState(TIFF *tif) { … } static int LogLuvGuessDataFmt(TIFFDirectory *td) { … } static int LogLuvInitState(TIFF *tif) { … } static int LogLuvFixupTags(TIFF *tif) { … } static int LogLuvSetupDecode(TIFF *tif) { … } static int LogLuvSetupEncode(TIFF *tif) { … } static void LogLuvClose(TIFF *tif) { … } static void LogLuvCleanup(TIFF *tif) { … } static int LogLuvVSetField(TIFF *tif, uint32_t tag, va_list ap) { … } static int LogLuvVGetField(TIFF *tif, uint32_t tag, va_list ap) { … } static const TIFFField LogLuvFields[] = …; int TIFFInitSGILog(TIFF *tif, int scheme) { … } #endif /* LOGLUV_SUPPORT */