X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4a13f6e37eaa63fc3871015a7a1ae171c58d8a34..7c2f14eeb84c08651a96050ff1f05d195fe3db7f:/src/tiff/tif_luv.c?ds=inline diff --git a/src/tiff/tif_luv.c b/src/tiff/tif_luv.c index 5adaa54e0f..4c3d06e449 100644 --- a/src/tiff/tif_luv.c +++ b/src/tiff/tif_luv.c @@ -2,23 +2,23 @@ * Copyright (c) 1997 Greg Ward Larson * Copyright (c) 1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -34,7 +34,7 @@ * 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 + * 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: @@ -67,8 +67,20 @@ * of conversion to and from LogLuv, though the application is still * responsible for interpreting the TIFFTAG_STONITS calibration factor. * - * The information is compressed into one of two basic encodings, depending on - * the setting of the compression tag, which is one of COMPRESSION_SGILOG + * 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: * @@ -120,6 +132,17 @@ * 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 @@ -135,10 +158,11 @@ 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 */ - short tbuflen; /* buffer length */ + int tbuflen; /* buffer length */ void (*tfunc)(LogLuvState*, tidata_t, int); TIFFVSetMethod vgetparent; /* super-class method */ @@ -156,7 +180,7 @@ struct logLuvState { /* * Decode a string of 16-bit gray pixels. */ -static int LINKAGEMODE +static int LogL16Decode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) { LogLuvState* sp = DecoderState(tif); @@ -186,13 +210,13 @@ LogL16Decode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) for (i = 0; i < npixels && cc > 0; ) if (*bp >= 128) { /* run */ rc = *bp++ + (2-128); - b = (int16)*bp++ << shft; + b = (int16)(*bp++ << shft); cc -= 2; - while (rc--) + while (rc-- && i < npixels) tp[i++] |= b; } else { /* non-run */ rc = *bp++; /* nul is noop */ - while (--cc && rc--) + while (--cc && rc-- && i < npixels) tp[i++] |= (int16)*bp++ << shft; } if (i != npixels) { @@ -213,7 +237,7 @@ LogL16Decode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) /* * Decode a string of 24-bit pixels. */ -static int LINKAGEMODE +static int LogLuvDecode24(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) { LogLuvState* sp = DecoderState(tif); @@ -232,7 +256,6 @@ LogLuvDecode24(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) assert(sp->tbuflen >= npixels); tp = (uint32 *) sp->tbuf; } - _TIFFmemset((tdata_t) tp, 0, npixels*sizeof (tp[0])); /* copy to array of uint32 */ bp = (u_char*) tif->tif_rawcp; cc = tif->tif_rawcc; @@ -256,7 +279,7 @@ LogLuvDecode24(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) /* * Decode a string of 32-bit pixels. */ -static int LINKAGEMODE +static int LogLuvDecode32(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) { LogLuvState* sp; @@ -289,11 +312,11 @@ LogLuvDecode32(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) rc = *bp++ + (2-128); b = (uint32)*bp++ << shft; cc -= 2; - while (rc--) + while (rc-- && i < npixels) tp[i++] |= b; } else { /* non-run */ rc = *bp++; /* nul is noop */ - while (--cc && rc--) + while (--cc && rc-- && i < npixels) tp[i++] |= (uint32)*bp++ << shft; } if (i != npixels) { @@ -316,7 +339,7 @@ LogLuvDecode32(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) * maintain synchrony with the encode algorithm, which * is row by row. */ -static int LINKAGEMODE +static int LogLuvDecodeStrip(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) { tsize_t rowlen = TIFFScanlineSize(tif); @@ -332,7 +355,7 @@ LogLuvDecodeStrip(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) * maintain synchrony with the encode algorithm, which * is row by row. */ -static int LINKAGEMODE +static int LogLuvDecodeTile(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) { tsize_t rowlen = TIFFTileRowSize(tif); @@ -346,7 +369,7 @@ LogLuvDecodeTile(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) /* * Encode a row of 16-bit pixels. */ -static int LINKAGEMODE +static int LogL16Encode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) { LogLuvState* sp = EncoderState(tif); @@ -382,7 +405,7 @@ LogL16Encode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) } mask = 0xff << shft; /* find next run */ for (beg = i; beg < npixels; beg += rc) { - b = tp[beg] & mask; + b = (int16) (tp[beg] & mask); rc = 1; while (rc < 127+2 && beg+rc < npixels && (tp[beg+rc] & mask) == b) @@ -391,36 +414,36 @@ LogL16Encode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) break; /* long enough */ } if (beg-i > 1 && beg-i < MINRUN) { - b = tp[i] & mask; /* check short run */ + b = (int16) (tp[i] & mask);/*check short run */ j = i+1; while ((tp[j++] & mask) == b) - if (j == beg) { - *op++ = 128-2+j-i; - *op++ = b >> shft; - occ -= 2; - i = beg; - break; - } + 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; + 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++ = j; occ--; + *op++ = (tidataval_t) j; occ--; while (j--) { - *op++ = tp[i++] >> shft & 0xff; + *op++ = (tidataval_t) (tp[i++] >> shft & 0xff); occ--; } } if (rc >= MINRUN) { /* write out run */ - *op++ = 128-2+rc; - *op++ = tp[beg] >> shft & 0xff; + *op++ = (tidataval_t) (128-2+rc); + *op++ = (tidataval_t) (tp[beg] >> shft & 0xff); occ -= 2; } else rc = 0; @@ -434,7 +457,7 @@ LogL16Encode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) /* * Encode a row of 24-bit pixels. */ -static int LINKAGEMODE +static int LogLuvEncode24(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) { LogLuvState* sp = EncoderState(tif); @@ -465,9 +488,9 @@ LogLuvEncode24(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) op = tif->tif_rawcp; occ = tif->tif_rawdatasize - tif->tif_rawcc; } - *op++ = *tp >> 16; - *op++ = *tp >> 8 & 0xff; - *op++ = *tp++ & 0xff; + *op++ = (tidataval_t)(*tp >> 16); + *op++ = (tidataval_t)(*tp >> 8 & 0xff); + *op++ = (tidataval_t)(*tp++ & 0xff); occ -= 3; } tif->tif_rawcp = op; @@ -479,7 +502,7 @@ LogLuvEncode24(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) /* * Encode a row of 32-bit pixels. */ -static int LINKAGEMODE +static int LogLuvEncode32(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) { LogLuvState* sp = EncoderState(tif); @@ -529,8 +552,8 @@ LogLuvEncode32(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) j = i+1; while ((tp[j++] & mask) == b) if (j == beg) { - *op++ = 128-2+j-i; - *op++ = b >> shft; + *op++ = (tidataval_t)(128-2+j-i); + *op++ = (tidataval_t)(b >> shft); occ -= 2; i = beg; break; @@ -546,15 +569,15 @@ LogLuvEncode32(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) op = tif->tif_rawcp; occ = tif->tif_rawdatasize - tif->tif_rawcc; } - *op++ = j; occ--; + *op++ = (tidataval_t) j; occ--; while (j--) { - *op++ = tp[i++] >> shft & 0xff; + *op++ = (tidataval_t)(tp[i++] >> shft & 0xff); occ--; } } if (rc >= MINRUN) { /* write out run */ - *op++ = 128-2+rc; - *op++ = tp[beg] >> shft & 0xff; + *op++ = (tidataval_t) (128-2+rc); + *op++ = (tidataval_t)(tp[beg] >> shft & 0xff); occ -= 2; } else rc = 0; @@ -569,7 +592,7 @@ LogLuvEncode32(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) * Encode a strip of pixels. We break it into rows to * avoid encoding runs across row boundaries. */ -static int LINKAGEMODE +static int LogLuvEncodeStrip(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) { tsize_t rowlen = TIFFScanlineSize(tif); @@ -584,7 +607,7 @@ LogLuvEncodeStrip(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) * Encode a tile of pixels. We break it into rows to * avoid encoding runs across row boundaries. */ -static int LINKAGEMODE +static int LogLuvEncodeTile(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) { tsize_t rowlen = TIFFTileRowSize(tif); @@ -598,49 +621,57 @@ LogLuvEncodeTile(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) /* * Encode/Decode functions for converting to and from user formats. */ -#include "uvcode.h" -#define U_NEU 0.210526316 -#define V_NEU 0.473684211 +#include "uvcode.h" -#ifdef M_LN2 -#define LOGOF2 M_LN2 -#else -#define LOGOF2 0.69314718055994530942 +#ifndef UVSCALE +#define U_NEU 0.210526316 +#define V_NEU 0.473684211 +#define UVSCALE 410. #endif -#ifndef log2 -#define log2(x) ((1./LOGOF2)*log(x)) + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 #endif -#ifndef exp2 -#define exp2(x) exp(LOGOF2*(x)) +#ifndef M_PI +#define M_PI 3.14159265358979323846 #endif -#define UVSCALE 410. +#define log2(x) ((1./M_LN2)*log(x)) +#define exp2(x) exp(M_LN2*(x)) + +#define itrunc(x,m) ((m)==SGILOGENCODE_NODITHER ? \ + (int)(x) : \ + (int)((x) + rand()*(1./RAND_MAX) - .5)) -static double -pix16toY(int p16) +#if !LOGLUV_PUBLIC +static +#endif +double +LogL16toY(int p16) /* compute luminance from 16-bit LogL */ { int Le = p16 & 0x7fff; double Y; if (!Le) return (0.); - Y = exp(LOGOF2/256.*(Le+.5) - LOGOF2*64.); - if (p16 & 0x8000) - return (-Y); - return (Y); + Y = exp(M_LN2/256.*(Le+.5) - M_LN2*64.); + return (!(p16 & 0x8000) ? Y : -Y); } -static int -pix16fromY(double Y) +#if !LOGLUV_PUBLIC +static +#endif +int +LogL16fromY(double Y, int em) /* get 16-bit LogL from Y */ { - if (Y >= 1.84467e19) + if (Y >= 1.8371976e19) return (0x7fff); - if (Y <= -1.84467e19) + if (Y <= -1.8371976e19) return (0xffff); - if (Y > 5.43571e-20) - return (int)(256.*(log2(Y) + 64.)); - if (Y < -5.43571e-20) - return (~0x7fff | (int)(256.*(log2(-Y) + 64.))); + if (Y > 5.4136769e-20) + return itrunc(256.*(log2(Y) + 64.), em); + if (Y < -5.4136769e-20) + return (~0x7fff | itrunc(256.*(log2(-Y) + 64.), em)); return (0); } @@ -651,7 +682,7 @@ L16toY(LogLuvState* sp, tidata_t op, int n) float* yp = (float*) op; while (n-- > 0) - *yp++ = pix16toY(*l16++); + *yp++ = (float)LogL16toY(*l16++); } static void @@ -661,8 +692,8 @@ L16toGry(LogLuvState* sp, tidata_t op, int n) uint8* gp = (uint8*) op; while (n-- > 0) { - double Y = pix16toY(*l16++); - *gp++ = (Y <= 0.) ? 0 : (Y >= 1.) ? 255 : (int)(256.*sqrt(Y)); + double Y = LogL16toY(*l16++); + *gp++ = (uint8) ((Y <= 0.) ? 0 : (Y >= 1.) ? 255 : (int)(256.*sqrt(Y))); } } @@ -673,10 +704,13 @@ L16fromY(LogLuvState* sp, tidata_t op, int n) float* yp = (float*) op; while (n-- > 0) - *l16++ = pix16fromY(*yp++); + *l16++ = (int16) (LogL16fromY(*yp++, sp->encode_meth)); } -static void +#if !LOGLUV_PUBLIC +static +#endif +void XYZtoRGB24(float xyz[3], uint8 rgb[3]) { double r, g, b; @@ -686,68 +720,161 @@ XYZtoRGB24(float xyz[3], uint8 rgb[3]) b = 0.061*xyz[0] + -0.224*xyz[1] + 1.163*xyz[2]; /* assume 2.0 gamma for speed */ /* could use integer sqrt approx., but this is probably faster */ - rgb[0] = (r <= 0.) ? 0 : (r >= 1.) ? 255 : (int)(256.*sqrt(r)); - rgb[1] = (g <= 0.) ? 0 : (g >= 1.) ? 255 : (int)(256.*sqrt(g)); - rgb[2] = (b <= 0.) ? 0 : (b >= 1.) ? 255 : (int)(256.*sqrt(b)); + rgb[0] = (uint8)((r<=0.) ? 0 : (r >= 1.) ? 255 : (int)(256.*sqrt(r))); + rgb[1] = (uint8)((g<=0.) ? 0 : (g >= 1.) ? 255 : (int)(256.*sqrt(g))); + rgb[2] = (uint8)((b<=0.) ? 0 : (b >= 1.) ? 255 : (int)(256.*sqrt(b))); +} + +#if !LOGLUV_PUBLIC +static +#endif +double +LogL10toY(int p10) /* compute luminance from 10-bit LogL */ +{ + if (p10 == 0) + return (0.); + return (exp(M_LN2/64.*(p10+.5) - M_LN2*12.)); } +#if !LOGLUV_PUBLIC +static +#endif +int +LogL10fromY(double Y, int em) /* get 10-bit LogL from Y */ +{ + if (Y >= 15.742) + return (0x3ff); + else if (Y <= .00024283) + return (0); + else + return itrunc(64.*(log2(Y) + 12.), em); +} + +#define NANGLES 100 +#define uv2ang(u, v) ( (NANGLES*.499999999/M_PI) \ + * atan2((v)-V_NEU,(u)-U_NEU) + .5*NANGLES ) + static int -uv_encode(double u, double v) /* encode (u',v') coordinates */ +oog_encode(double u, double v) /* encode out-of-gamut chroma */ +{ + static int oog_table[NANGLES]; + static int initialized = 0; + register int i; + + if (!initialized) { /* set up perimeter table */ + double eps[NANGLES], ua, va, ang, epsa; + int ui, vi, ustep; + for (i = NANGLES; i--; ) + eps[i] = 2.; + for (vi = UV_NVS; vi--; ) { + va = UV_VSTART + (vi+.5)*UV_SQSIZ; + ustep = uv_row[vi].nus-1; + if (vi == UV_NVS-1 || vi == 0 || ustep <= 0) + ustep = 1; + for (ui = uv_row[vi].nus-1; ui >= 0; ui -= ustep) { + ua = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ; + ang = uv2ang(ua, va); + i = (int) ang; + epsa = fabs(ang - (i+.5)); + if (epsa < eps[i]) { + oog_table[i] = uv_row[vi].ncum + ui; + eps[i] = epsa; + } + } + } + for (i = NANGLES; i--; ) /* fill any holes */ + if (eps[i] > 1.5) { + int i1, i2; + for (i1 = 1; i1 < NANGLES/2; i1++) + if (eps[(i+i1)%NANGLES] < 1.5) + break; + for (i2 = 1; i2 < NANGLES/2; i2++) + if (eps[(i+NANGLES-i2)%NANGLES] < 1.5) + break; + if (i1 < i2) + oog_table[i] = + oog_table[(i+i1)%NANGLES]; + else + oog_table[i] = + oog_table[(i+NANGLES-i2)%NANGLES]; + } + initialized = 1; + } + i = (int) uv2ang(u, v); /* look up hue angle */ + return (oog_table[i]); +} + +#undef uv2ang +#undef NANGLES + +#if !LOGLUV_PUBLIC +static +#endif +int +uv_encode(double u, double v, int em) /* encode (u',v') coordinates */ { register int vi, ui; if (v < UV_VSTART) - return(-1); - vi = (v - UV_VSTART)*(1./UV_SQSIZ); + return oog_encode(u, v); + vi = itrunc((v - UV_VSTART)*(1./UV_SQSIZ), em); if (vi >= UV_NVS) - return(-1); + return oog_encode(u, v); if (u < uv_row[vi].ustart) - return(-1); - ui = (u - uv_row[vi].ustart)*(1./UV_SQSIZ); + return oog_encode(u, v); + ui = itrunc((u - uv_row[vi].ustart)*(1./UV_SQSIZ), em); if (ui >= uv_row[vi].nus) - return(-1); - return(uv_row[vi].ncum + ui); + return oog_encode(u, v); + + return (uv_row[vi].ncum + ui); } -static int +#if !LOGLUV_PUBLIC +static +#endif +int uv_decode(double *up, double *vp, int c) /* decode (u',v') index */ { int upper, lower; register int ui, vi; if (c < 0 || c >= UV_NDIVS) - return(-1); - lower = 0; /* binary search */ + return (-1); + lower = 0; /* binary search */ upper = UV_NVS; - do { + while (upper - lower > 1) { vi = (lower + upper) >> 1; ui = c - uv_row[vi].ncum; if (ui > 0) lower = vi; else if (ui < 0) upper = vi; - else + else { + lower = vi; break; - } while (upper - lower > 1); + } + } vi = lower; ui = c - uv_row[vi].ncum; *up = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ; *vp = UV_VSTART + (vi+.5)*UV_SQSIZ; - return(0); + return (0); } -static void -pix24toXYZ(uint32 p, float XYZ[3]) +#if !LOGLUV_PUBLIC +static +#endif +void +LogLuv24toXYZ(uint32 p, float XYZ[3]) { - int Le, Ce; + int Ce; double L, u, v, s, x, y; /* decode luminance */ - Le = p >> 14 & 0x3ff; - if (Le == 0) { + L = LogL10toY(p>>14 & 0x3ff); + if (L <= 0.) { XYZ[0] = XYZ[1] = XYZ[2] = 0.; return; } - L = exp(LOGOF2/64.*(Le+.5) - LOGOF2*12.); /* decode color */ Ce = p & 0x3fff; if (uv_decode(&u, &v, Ce) < 0) { @@ -757,36 +884,33 @@ pix24toXYZ(uint32 p, float XYZ[3]) x = 9.*u * s; y = 4.*v * s; /* convert to XYZ */ - XYZ[0] = x/y * L; - XYZ[1] = L; - XYZ[2] = (1.-x-y)/y * L; + XYZ[0] = (float)(x/y * L); + XYZ[1] = (float)L; + XYZ[2] = (float)((1.-x-y)/y * L); } -static uint32 -pix24fromXYZ(float XYZ[3]) +#if !LOGLUV_PUBLIC +static +#endif +uint32 +LogLuv24fromXYZ(float XYZ[3], int em) { int Le, Ce; - double L, u, v, s; + double u, v, s; /* encode luminance */ - L = XYZ[1]; - if (L >= 16.) - Le = 0x3ff; - else if (L <= 1./4096.) - Le = 0; - else - Le = 64.*(log2(L) + 12.); + Le = LogL10fromY(XYZ[1], em); /* encode color */ s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2]; - if (s == 0.) { + if (!Le || s <= 0.) { u = U_NEU; v = V_NEU; } else { u = 4.*XYZ[0] / s; v = 9.*XYZ[1] / s; } - Ce = uv_encode(u, v); - if (Ce < 0) - Ce = uv_encode(U_NEU, V_NEU); + Ce = uv_encode(u, v, em); + if (Ce < 0) /* never happens */ + Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER); /* combine encodings */ return (Le << 14 | Ce); } @@ -798,7 +922,7 @@ Luv24toXYZ(LogLuvState* sp, tidata_t op, int n) float* xyz = (float*) op; while (n-- > 0) { - pix24toXYZ(*luv, xyz); + LogLuv24toXYZ(*luv, xyz); xyz += 3; luv++; } @@ -813,13 +937,13 @@ Luv24toLuv48(LogLuvState* sp, tidata_t op, int n) while (n-- > 0) { double u, v; - *luv3++ = (*luv >> 12 & 0xffd) + 13314; + *luv3++ = (int16)((*luv >> 12 & 0xffd) + 13314); if (uv_decode(&u, &v, *luv&0x3fff) < 0) { u = U_NEU; v = V_NEU; } - *luv3++ = u * (1L<<15); - *luv3++ = v * (1L<<15); + *luv3++ = (int16)(u * (1L<<15)); + *luv3++ = (int16)(v * (1L<<15)); luv++; } } @@ -833,7 +957,7 @@ Luv24toRGB(LogLuvState* sp, tidata_t op, int n) while (n-- > 0) { float xyz[3]; - pix24toXYZ(*luv++, xyz); + LogLuv24toXYZ(*luv++, xyz); XYZtoRGB24(xyz, rgb); rgb += 3; } @@ -846,7 +970,7 @@ Luv24fromXYZ(LogLuvState* sp, tidata_t op, int n) float* xyz = (float*) op; while (n-- > 0) { - *luv++ = pix24fromXYZ(xyz); + *luv++ = LogLuv24fromXYZ(xyz, sp->encode_meth); xyz += 3; } } @@ -864,23 +988,30 @@ Luv24fromLuv48(LogLuvState* sp, tidata_t op, int n) Le = 0; else if (luv3[0] >= (1<<12)+3314) Le = (1<<10) - 1; - else + else if (sp->encode_meth == SGILOGENCODE_NODITHER) Le = (luv3[0]-3314) >> 2; - Ce = uv_encode((luv[1]+.5)/(1<<15), (luv[2]+.5)/(1<<15)); - if (Ce < 0) - Ce = uv_encode(U_NEU, V_NEU); + else + Le = itrunc(.25*(luv3[0]-3314.), sp->encode_meth); + + Ce = uv_encode((luv3[1]+.5)/(1<<15), (luv3[2]+.5)/(1<<15), + sp->encode_meth); + if (Ce < 0) /* never happens */ + Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER); *luv++ = (uint32)Le << 14 | Ce; luv3 += 3; } } -static void -pix32toXYZ(uint32 p, float XYZ[3]) +#if !LOGLUV_PUBLIC +static +#endif +void +LogLuv32toXYZ(uint32 p, float XYZ[3]) { double L, u, v, s, x, y; /* decode luminance */ - L = pix16toY((int)p >> 16); - if (L == 0.) { + L = LogL16toY((int)p >> 16); + if (L <= 0.) { XYZ[0] = XYZ[1] = XYZ[2] = 0.; return; } @@ -891,21 +1022,24 @@ pix32toXYZ(uint32 p, float XYZ[3]) x = 9.*u * s; y = 4.*v * s; /* convert to XYZ */ - XYZ[0] = x/y * L; - XYZ[1] = L; - XYZ[2] = (1.-x-y)/y * L; + XYZ[0] = (float)(x/y * L); + XYZ[1] = (float)L; + XYZ[2] = (float)((1.-x-y)/y * L); } -static uint32 -pix32fromXYZ(float XYZ[3]) +#if !LOGLUV_PUBLIC +static +#endif +uint32 +LogLuv32fromXYZ(float XYZ[3], int em) { unsigned int Le, ue, ve; double u, v, s; /* encode luminance */ - Le = (unsigned int)pix16fromY(XYZ[1]); + Le = (unsigned int)LogL16fromY(XYZ[1], em); /* encode color */ s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2]; - if (s == 0.) { + if (!Le || s <= 0.) { u = U_NEU; v = V_NEU; } else { @@ -913,10 +1047,10 @@ pix32fromXYZ(float XYZ[3]) v = 9.*XYZ[1] / s; } if (u <= 0.) ue = 0; - else ue = UVSCALE * u; + else ue = itrunc(UVSCALE*u, em); if (ue > 255) ue = 255; if (v <= 0.) ve = 0; - else ve = UVSCALE * v; + else ve = itrunc(UVSCALE*v, em); if (ve > 255) ve = 255; /* combine encodings */ return (Le << 16 | ue << 8 | ve); @@ -929,7 +1063,7 @@ Luv32toXYZ(LogLuvState* sp, tidata_t op, int n) float* xyz = (float*) op; while (n-- > 0) { - pix32toXYZ(*luv++, xyz); + LogLuv32toXYZ(*luv++, xyz); xyz += 3; } } @@ -943,11 +1077,11 @@ Luv32toLuv48(LogLuvState* sp, tidata_t op, int n) while (n-- > 0) { double u, v; - *luv3++ = *luv >> 16; + *luv3++ = (int16)(*luv >> 16); u = 1./UVSCALE * ((*luv>>8 & 0xff) + .5); v = 1./UVSCALE * ((*luv & 0xff) + .5); - *luv3++ = u * (1L<<15); - *luv3++ = v * (1L<<15); + *luv3++ = (int16)(u * (1L<<15)); + *luv3++ = (int16)(v * (1L<<15)); luv++; } } @@ -961,7 +1095,7 @@ Luv32toRGB(LogLuvState* sp, tidata_t op, int n) while (n-- > 0) { float xyz[3]; - pix32toXYZ(*luv++, xyz); + LogLuv32toXYZ(*luv++, xyz); XYZtoRGB24(xyz, rgb); rgb += 3; } @@ -974,7 +1108,7 @@ Luv32fromXYZ(LogLuvState* sp, tidata_t op, int n) float* xyz = (float*) op; while (n-- > 0) { - *luv++ = pix32fromXYZ(xyz); + *luv++ = LogLuv32fromXYZ(xyz, sp->encode_meth); xyz += 3; } } @@ -985,10 +1119,19 @@ Luv32fromLuv48(LogLuvState* sp, tidata_t op, int n) uint32* luv = (uint32*) sp->tbuf; int16* luv3 = (int16*) op; + if (sp->encode_meth == SGILOGENCODE_NODITHER) { + while (n-- > 0) { + *luv++ = (uint32)luv3[0] << 16 | + (luv3[1]*(uint32)(UVSCALE+.5) >> 7 & 0xff00) | + (luv3[2]*(uint32)(UVSCALE+.5) >> 15 & 0xff); + luv3 += 3; + } + return; + } while (n-- > 0) { *luv++ = (uint32)luv3[0] << 16 | - (luv3[1]*(uint32)(UVSCALE+.5) >> 7 & 0xff00) | - (luv3[2]*(uint32)(UVSCALE+.5) >> 15 & 0xff); + (itrunc(luv3[1]*(UVSCALE/(1<<15)), sp->encode_meth) << 8 & 0xff00) | + (itrunc(luv3[2]*(UVSCALE/(1<<15)), sp->encode_meth) & 0xff); luv3 += 3; } } @@ -1018,6 +1161,17 @@ LogL16GuessDataFmt(TIFFDirectory *td) return (SGILOGDATAFMT_UNKNOWN); } +static uint32 +multiply(size_t m1, size_t m2) +{ + uint32 bytes = m1 * m2; + + if (m1 && bytes / m1 != m2) + bytes = 0; + + return bytes; +} + static int LogL16InitState(TIFF* tif) { @@ -1046,9 +1200,9 @@ LogL16InitState(TIFF* tif) "No support for converting user data format to LogL"); return (0); } - sp->tbuflen = td->td_imagewidth * td->td_rowsperstrip; - sp->tbuf = (tidata_t*) _TIFFmalloc(sp->tbuflen * sizeof (int16)); - if (sp->tbuf == NULL) { + sp->tbuflen = multiply(td->td_imagewidth, td->td_rowsperstrip); + if (multiply(sp->tbuflen, sizeof (int16)) == 0 || + (sp->tbuf = (tidata_t*) _TIFFmalloc(sp->tbuflen * sizeof (int16))) == NULL) { TIFFError(module, "%s: No space for SGILog translation buffer", tif->tif_name); return (0); @@ -1144,9 +1298,9 @@ LogLuvInitState(TIFF* tif) "No support for converting user data format to LogLuv"); return (0); } - sp->tbuflen = td->td_imagewidth * td->td_rowsperstrip; - sp->tbuf = (tidata_t*) _TIFFmalloc(sp->tbuflen * sizeof (uint32)); - if (sp->tbuf == NULL) { + sp->tbuflen = multiply(td->td_imagewidth, td->td_rowsperstrip); + if (multiply(sp->tbuflen, sizeof (uint32)) == 0 || + (sp->tbuf = (tidata_t*) _TIFFmalloc(sp->tbuflen * sizeof (uint32))) == NULL) { TIFFError(module, "%s: No space for SGILog translation buffer", tif->tif_name); return (0); @@ -1338,6 +1492,7 @@ LogLuvVSetField(TIFF* tif, ttag_t tag, va_list ap) break; case SGILOGDATAFMT_RAW: bps = 32, fmt = SAMPLEFORMAT_UINT; + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); break; case SGILOGDATAFMT_8BIT: bps = 8, fmt = SAMPLEFORMAT_UINT; @@ -1356,6 +1511,16 @@ LogLuvVSetField(TIFF* tif, ttag_t tag, va_list ap) tif->tif_tilesize = TIFFTileSize(tif); tif->tif_scanlinesize = TIFFScanlineSize(tif); return (1); + case TIFFTAG_SGILOGENCODE: + sp->encode_meth = va_arg(ap, int); + if (sp->encode_meth != SGILOGENCODE_NODITHER && + sp->encode_meth != SGILOGENCODE_RANDITHER) { + TIFFError(tif->tif_name, + "Unknown encoding %d for LogLuv compression", + sp->encode_meth); + return (0); + } + return (1); default: return (*sp->vsetparent)(tif, tag, ap); } @@ -1377,7 +1542,9 @@ LogLuvVGetField(TIFF* tif, ttag_t tag, va_list ap) static const TIFFFieldInfo LogLuvFieldInfo[] = { { TIFFTAG_SGILOGDATAFMT, 0, 0, TIFF_SHORT, FIELD_PSEUDO, - TRUE, FALSE, "SGILogDataFmt"} + TRUE, FALSE, "SGILogDataFmt"}, + { TIFFTAG_SGILOGENCODE, 0, 0, TIFF_SHORT, FIELD_PSEUDO, + TRUE, FALSE, "SGILogEncode"} }; int @@ -1395,8 +1562,10 @@ TIFFInitSGILog(TIFF* tif, int scheme) if (tif->tif_data == NULL) goto bad; sp = (LogLuvState*) tif->tif_data; - memset(sp, 0, sizeof (*sp)); + _TIFFmemset((tdata_t)sp, 0, sizeof (*sp)); sp->user_datafmt = SGILOGDATAFMT_UNKNOWN; + sp->encode_meth = (scheme == COMPRESSION_SGILOG24) ? + SGILOGENCODE_RANDITHER : SGILOGENCODE_NODITHER; sp->tfunc = _logLuvNop; /* @@ -1415,10 +1584,10 @@ TIFFInitSGILog(TIFF* tif, int scheme) /* override SetField so we can handle our private pseudo-tag */ _TIFFMergeFieldInfo(tif, LogLuvFieldInfo, N(LogLuvFieldInfo)); - sp->vgetparent = tif->tif_vgetfield; - tif->tif_vgetfield = LogLuvVGetField; /* hook for codec tags */ - sp->vsetparent = tif->tif_vsetfield; - tif->tif_vsetfield = LogLuvVSetField; /* hook for codec tags */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = LogLuvVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = LogLuvVSetField; /* hook for codec tags */ return (1); bad: