📄 tif_luv.c
字号:
/* $Id: tif_luv.c,v 1.4 2004/10/16 15:34:33 drolon Exp $ */
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <math.h>
/*
* State block for each open TIFF
* file using LogLuv compression/decompression.
*/
typedef struct logLuvState LogLuvState;
struct logLuvState {
int user_datafmt; /* user data format */
int encode_meth; /* encoding method */
int pixel_size; /* bytes per pixel */
tidata_t* tbuf; /* translation buffer */
int tbuflen; /* buffer length */
void (*tfunc)(LogLuvState*, tidata_t, int);
TIFFVSetMethod vgetparent; /* super-class method */
TIFFVSetMethod vsetparent; /* super-class method */
};
#define DecoderState(tif) ((LogLuvState*) (tif)->tif_data)
#define EncoderState(tif) ((LogLuvState*) (tif)->tif_data)
#define N(a) (sizeof(a)/sizeof(a[0]))
#define SGILOGDATAFMT_UNKNOWN -1
#define MINRUN 4 /* minimum run length */
/*
* Decode a string of 16-bit gray pixels.
*/
static int
LogL16Decode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s)
{
LogLuvState* sp = DecoderState(tif);
int shft, i, npixels;
unsigned char* bp;
int16* tp;
int16 b;
int cc, rc;
assert(s == 0);
assert(sp != NULL);
npixels = occ / sp->pixel_size;
if (sp->user_datafmt == SGILOGDATAFMT_16BIT)
tp = (int16*) op;
else {
assert(sp->tbuflen >= npixels);
tp = (int16*) sp->tbuf;
}
_TIFFmemset((tdata_t) tp, 0, npixels*sizeof (tp[0]));
bp = (unsigned char*) tif->tif_rawcp;
cc = tif->tif_rawcc;
/* get each byte string */
for (shft = 2*8; (shft -= 8) >= 0; ) {
for (i = 0; i < npixels && cc > 0; )
if (*bp >= 128) { /* run */
rc = *bp++ + (2-128);
b = (int16)(*bp++ << shft);
cc -= 2;
while (rc-- && i < npixels)
tp[i++] |= b;
} else { /* non-run */
rc = *bp++; /* nul is noop */
while (--cc && rc-- && i < npixels)
tp[i++] |= (int16)*bp++ << shft;
}
if (i != npixels) {
TIFFError(tif->tif_name,
"LogL16Decode: Not enough data at row %d (short %d pixels)",
tif->tif_row, npixels - i);
tif->tif_rawcp = (tidata_t) bp;
tif->tif_rawcc = cc;
return (0);
}
}
(*sp->tfunc)(sp, op, npixels);
tif->tif_rawcp = (tidata_t) bp;
tif->tif_rawcc = cc;
return (1);
}
/*
* Decode a string of 24-bit pixels.
*/
static int
LogLuvDecode24(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s)
{
LogLuvState* sp = DecoderState(tif);
int cc, i, npixels;
unsigned char* bp;
uint32* tp;
assert(s == 0);
assert(sp != NULL);
npixels = occ / sp->pixel_size;
if (sp->user_datafmt == SGILOGDATAFMT_RAW)
tp = (uint32 *)op;
else {
assert(sp->tbuflen >= npixels);
tp = (uint32 *) sp->tbuf;
}
/* copy to array of uint32 */
bp = (unsigned char*) tif->tif_rawcp;
cc = tif->tif_rawcc;
for (i = 0; i < npixels && cc > 0; i++) {
tp[i] = bp[0] << 16 | bp[1] << 8 | bp[2];
bp += 3;
cc -= 3;
}
tif->tif_rawcp = (tidata_t) bp;
tif->tif_rawcc = cc;
if (i != npixels) {
TIFFError(tif->tif_name,
"LogLuvDecode24: Not enough data at row %d (short %d pixels)",
tif->tif_row, npixels - i);
return (0);
}
(*sp->tfunc)(sp, op, npixels);
return (1);
}
/*
* Decode a string of 32-bit pixels.
*/
static int
LogLuvDecode32(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s)
{
LogLuvState* sp;
int shft, i, npixels;
unsigned char* bp;
uint32* tp;
uint32 b;
int cc, rc;
assert(s == 0);
sp = DecoderState(tif);
assert(sp != NULL);
npixels = occ / sp->pixel_size;
if (sp->user_datafmt == SGILOGDATAFMT_RAW)
tp = (uint32*) op;
else {
assert(sp->tbuflen >= npixels);
tp = (uint32*) sp->tbuf;
}
_TIFFmemset((tdata_t) tp, 0, npixels*sizeof (tp[0]));
bp = (unsigned char*) tif->tif_rawcp;
cc = tif->tif_rawcc;
/* get each byte string */
for (shft = 4*8; (shft -= 8) >= 0; ) {
for (i = 0; i < npixels && cc > 0; )
if (*bp >= 128) { /* run */
rc = *bp++ + (2-128);
b = (uint32)*bp++ << shft;
cc -= 2;
while (rc-- && i < npixels)
tp[i++] |= b;
} else { /* non-run */
rc = *bp++; /* nul is noop */
while (--cc && rc-- && i < npixels)
tp[i++] |= (uint32)*bp++ << shft;
}
if (i != npixels) {
TIFFError(tif->tif_name,
"LogLuvDecode32: Not enough data at row %d (short %d pixels)",
tif->tif_row, npixels - i);
tif->tif_rawcp = (tidata_t) bp;
tif->tif_rawcc = cc;
return (0);
}
}
(*sp->tfunc)(sp, op, npixels);
tif->tif_rawcp = (tidata_t) bp;
tif->tif_rawcc = cc;
return (1);
}
/*
* 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, tidata_t bp, tsize_t cc, tsample_t s)
{
tsize_t rowlen = TIFFScanlineSize(tif);
assert(cc%rowlen == 0);
while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s))
bp += rowlen, cc -= rowlen;
return (cc == 0);
}
/*
* 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, tidata_t bp, tsize_t cc, tsample_t s)
{
tsize_t rowlen = TIFFTileRowSize(tif);
assert(cc%rowlen == 0);
while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s))
bp += rowlen, cc -= rowlen;
return (cc == 0);
}
/*
* Encode a row of 16-bit pixels.
*/
static int
LogL16Encode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
{
LogLuvState* sp = EncoderState(tif);
int shft, i, j, npixels;
tidata_t op;
int16* tp;
int16 b;
int occ, rc=0, mask, beg;
assert(s == 0);
assert(sp != NULL);
npixels = cc / sp->pixel_size;
if (sp->user_datafmt == SGILOGDATAFMT_16BIT)
tp = (int16*) bp;
else {
tp = (int16*) sp->tbuf;
assert(sp->tbuflen >= npixels);
(*sp->tfunc)(sp, bp, npixels);
}
/* compress each byte string */
op = tif->tif_rawcp;
occ = tif->tif_rawdatasize - tif->tif_rawcc;
for (shft = 2*8; (shft -= 8) >= 0; )
for (i = 0; i < npixels; i += rc) {
if (occ < 4) {
tif->tif_rawcp = op;
tif->tif_rawcc = tif->tif_rawdatasize - occ;
if (!TIFFFlushData1(tif))
return (-1);
op = tif->tif_rawcp;
occ = tif->tif_rawdatasize - tif->tif_rawcc;
}
mask = 0xff << shft; /* find next run */
for (beg = i; beg < npixels; beg += rc) {
b = (int16) (tp[beg] & mask);
rc = 1;
while (rc < 127+2 && beg+rc < npixels &&
(tp[beg+rc] & mask) == b)
rc++;
if (rc >= MINRUN)
break; /* long enough */
}
if (beg-i > 1 && beg-i < MINRUN) {
b = (int16) (tp[i] & mask);/*check short run */
j = i+1;
while ((tp[j++] & mask) == b)
if (j == beg) {
*op++ = (tidataval_t)(128-2+j-i);
*op++ = (tidataval_t) (b >> shft);
occ -= 2;
i = beg;
break;
}
}
while (i < beg) { /* write out non-run */
if ((j = beg-i) > 127) j = 127;
if (occ < j+3) {
tif->tif_rawcp = op;
tif->tif_rawcc = tif->tif_rawdatasize - occ;
if (!TIFFFlushData1(tif))
return (-1);
op = tif->tif_rawcp;
occ = tif->tif_rawdatasize - tif->tif_rawcc;
}
*op++ = (tidataval_t) j; occ--;
while (j--) {
*op++ = (tidataval_t) (tp[i++] >> shft & 0xff);
occ--;
}
}
if (rc >= MINRUN) { /* write out run */
*op++ = (tidataval_t) (128-2+rc);
*op++ = (tidataval_t) (tp[beg] >> shft & 0xff);
occ -= 2;
} else
rc = 0;
}
tif->tif_rawcp = op;
tif->tif_rawcc = tif->tif_rawdatasize - occ;
return (0);
}
/*
* Encode a row of 24-bit pixels.
*/
static int
LogLuvEncode24(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
{
LogLuvState* sp = EncoderState(tif);
int i, npixels, occ;
tidata_t op;
uint32* tp;
assert(s == 0);
assert(sp != NULL);
npixels = cc / sp->pixel_size;
if (sp->user_datafmt == SGILOGDATAFMT_RAW)
tp = (uint32*) bp;
else {
tp = (uint32*) sp->tbuf;
assert(sp->tbuflen >= npixels);
(*sp->tfunc)(sp, bp, npixels);
}
/* write out encoded pixels */
op = tif->tif_rawcp;
occ = tif->tif_rawdatasize - tif->tif_rawcc;
for (i = npixels; i--; ) {
if (occ < 3) {
tif->tif_rawcp = op;
tif->tif_rawcc = tif->tif_rawdatasize - occ;
if (!TIFFFlushData1(tif))
return (-1);
op = tif->tif_rawcp;
occ = tif->tif_rawdatasize - tif->tif_rawcc;
}
*op++ = (tidataval_t)(*tp >> 16);
*op++ = (tidataval_t)(*tp >> 8 & 0xff);
*op++ = (tidataval_t)(*tp++ & 0xff);
occ -= 3;
}
tif->tif_rawcp = op;
tif->tif_rawcc = tif->tif_rawdatasize - occ;
return (0);
}
/*
* Encode a row of 32-bit pixels.
*/
static int
LogLuvEncode32(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
{
LogLuvState* sp = EncoderState(tif);
int shft, i, j, npixels;
tidata_t op;
uint32* tp;
uint32 b;
int occ, rc=0, mask, beg;
assert(s == 0);
assert(sp != NULL);
npixels = cc / sp->pixel_size;
if (sp->user_datafmt == SGILOGDATAFMT_RAW)
tp = (uint32*) bp;
else {
tp = (uint32*) sp->tbuf;
assert(sp->tbuflen >= npixels);
(*sp->tfunc)(sp, bp, npixels);
}
/* compress each byte string */
op = tif->tif_rawcp;
occ = tif->tif_rawdatasize - tif->tif_rawcc;
for (shft = 4*8; (shft -= 8) >= 0; )
for (i = 0; i < npixels; i += rc) {
if (occ < 4) {
tif->tif_rawcp = op;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -