X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4a13f6e37eaa63fc3871015a7a1ae171c58d8a34..5e80ff3d31fde40c3cef5a3b47d08850d95b5d1a:/src/tiff/tif_luv.c

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 <stdio.h>
@@ -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: