* 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.
*/
* 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:
* 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:
*
* 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>
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 */
/*
* 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);
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) {
/*
* 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);
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;
/*
* 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;
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) {
* 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);
* 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);
/*
* 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);
}
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)
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;
/*
* 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);
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;
/*
* 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);
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;
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;
* 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);
* 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);
/*
* Encode/Decode functions for converting to and from user formats.
*/
+
#include "uvcode.h"
-#define U_NEU 0.210526316
-#define V_NEU 0.473684211
+#ifndef UVSCALE
+#define U_NEU 0.210526316
+#define V_NEU 0.473684211
+#define UVSCALE 410.
+#endif
-#ifdef M_LN2
-#define LOGOF2 M_LN2
-#else
-#define LOGOF2 0.69314718055994530942
+#ifndef M_LN2
+#define M_LN2 0.69314718055994530942
+#endif
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
#endif
-#define log2(x) ((1./LOGOF2)*log(x))
-#define exp2(x) exp(LOGOF2*(x))
+#define log2(x) ((1./M_LN2)*log(x))
+#define exp2(x) exp(M_LN2*(x))
-#define UVSCALE 410.
+#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);
}
float* yp = (float*) op;
while (n-- > 0)
- *yp++ = pix16toY(*l16++);
+ *yp++ = (float)LogL16toY(*l16++);
}
static void
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)));
}
}
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;
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) {
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);
}
float* xyz = (float*) op;
while (n-- > 0) {
- pix24toXYZ(*luv, xyz);
+ LogLuv24toXYZ(*luv, xyz);
xyz += 3;
luv++;
}
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++;
}
}
while (n-- > 0) {
float xyz[3];
- pix24toXYZ(*luv++, xyz);
+ LogLuv24toXYZ(*luv++, xyz);
XYZtoRGB24(xyz, rgb);
rgb += 3;
}
float* xyz = (float*) op;
while (n-- > 0) {
- *luv++ = pix24fromXYZ(xyz);
+ *luv++ = LogLuv24fromXYZ(xyz, sp->encode_meth);
xyz += 3;
}
}
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;
}
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 {
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);
float* xyz = (float*) op;
while (n-- > 0) {
- pix32toXYZ(*luv++, xyz);
+ LogLuv32toXYZ(*luv++, xyz);
xyz += 3;
}
}
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++;
}
}
while (n-- > 0) {
float xyz[3];
- pix32toXYZ(*luv++, xyz);
+ LogLuv32toXYZ(*luv++, xyz);
XYZtoRGB24(xyz, rgb);
rgb += 3;
}
float* xyz = (float*) op;
while (n-- > 0) {
- *luv++ = pix32fromXYZ(xyz);
+ *luv++ = LogLuv32fromXYZ(xyz, sp->encode_meth);
xyz += 3;
}
}
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;
}
}
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)
{
"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);
"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);
break;
case SGILOGDATAFMT_RAW:
bps = 32, fmt = SAMPLEFORMAT_UINT;
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
break;
case SGILOGDATAFMT_8BIT:
bps = 8, fmt = SAMPLEFORMAT_UINT;
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);
}
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
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;
/*
/* 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: