1c2c66affSColin Finck /*
2c2c66affSColin Finck * Copyright (c) 1997 Greg Ward Larson
3c2c66affSColin Finck * Copyright (c) 1997 Silicon Graphics, Inc.
4c2c66affSColin Finck *
5c2c66affSColin Finck * Permission to use, copy, modify, distribute, and sell this software and
6c2c66affSColin Finck * its documentation for any purpose is hereby granted without fee, provided
7c2c66affSColin Finck * that (i) the above copyright notices and this permission notice appear in
8c2c66affSColin Finck * all copies of the software and related documentation, and (ii) the names of
9c2c66affSColin Finck * Sam Leffler, Greg Larson and Silicon Graphics may not be used in any
10c2c66affSColin Finck * advertising or publicity relating to the software without the specific,
11c2c66affSColin Finck * prior written permission of Sam Leffler, Greg Larson and Silicon Graphics.
12c2c66affSColin Finck *
13c2c66affSColin Finck * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
14c2c66affSColin Finck * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
15c2c66affSColin Finck * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16c2c66affSColin Finck *
17c2c66affSColin Finck * IN NO EVENT SHALL SAM LEFFLER, GREG LARSON OR SILICON GRAPHICS BE LIABLE
18c2c66affSColin Finck * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
19c2c66affSColin Finck * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20c2c66affSColin Finck * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
21c2c66affSColin Finck * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22c2c66affSColin Finck * OF THIS SOFTWARE.
23c2c66affSColin Finck */
24c2c66affSColin Finck
25c2c66affSColin Finck #include <precomp.h>
26c2c66affSColin Finck #ifdef LOGLUV_SUPPORT
27c2c66affSColin Finck
28c2c66affSColin Finck /*
29c2c66affSColin Finck * TIFF Library.
30c2c66affSColin Finck * LogLuv compression support for high dynamic range images.
31c2c66affSColin Finck *
32c2c66affSColin Finck * Contributed by Greg Larson.
33c2c66affSColin Finck *
34c2c66affSColin Finck * LogLuv image support uses the TIFF library to store 16 or 10-bit
35c2c66affSColin Finck * log luminance values with 8 bits each of u and v or a 14-bit index.
36c2c66affSColin Finck *
37c2c66affSColin Finck * The codec can take as input and produce as output 32-bit IEEE float values
38c2c66affSColin Finck * as well as 16-bit integer values. A 16-bit luminance is interpreted
39c2c66affSColin Finck * as a sign bit followed by a 15-bit integer that is converted
40c2c66affSColin Finck * to and from a linear magnitude using the transformation:
41c2c66affSColin Finck *
42c2c66affSColin Finck * L = 2^( (Le+.5)/256 - 64 ) # real from 15-bit
43c2c66affSColin Finck *
44c2c66affSColin Finck * Le = floor( 256*(log2(L) + 64) ) # 15-bit from real
45c2c66affSColin Finck *
46c2c66affSColin Finck * The actual conversion to world luminance units in candelas per sq. meter
47c2c66affSColin Finck * requires an additional multiplier, which is stored in the TIFFTAG_STONITS.
48c2c66affSColin Finck * This value is usually set such that a reasonable exposure comes from
49c2c66affSColin Finck * clamping decoded luminances above 1 to 1 in the displayed image.
50c2c66affSColin Finck *
51c2c66affSColin Finck * The 16-bit values for u and v may be converted to real values by dividing
52c2c66affSColin Finck * each by 32768. (This allows for negative values, which aren't useful as
53c2c66affSColin Finck * far as we know, but are left in case of future improvements in human
54c2c66affSColin Finck * color vision.)
55c2c66affSColin Finck *
56c2c66affSColin Finck * Conversion from (u,v), which is actually the CIE (u',v') system for
57c2c66affSColin Finck * you color scientists, is accomplished by the following transformation:
58c2c66affSColin Finck *
59c2c66affSColin Finck * u = 4*x / (-2*x + 12*y + 3)
60c2c66affSColin Finck * v = 9*y / (-2*x + 12*y + 3)
61c2c66affSColin Finck *
62c2c66affSColin Finck * x = 9*u / (6*u - 16*v + 12)
63c2c66affSColin Finck * y = 4*v / (6*u - 16*v + 12)
64c2c66affSColin Finck *
65c2c66affSColin Finck * This process is greatly simplified by passing 32-bit IEEE floats
66c2c66affSColin Finck * for each of three CIE XYZ coordinates. The codec then takes care
67c2c66affSColin Finck * of conversion to and from LogLuv, though the application is still
68c2c66affSColin Finck * responsible for interpreting the TIFFTAG_STONITS calibration factor.
69c2c66affSColin Finck *
70c2c66affSColin Finck * By definition, a CIE XYZ vector of [1 1 1] corresponds to a neutral white
71c2c66affSColin Finck * point of (x,y)=(1/3,1/3). However, most color systems assume some other
72c2c66affSColin Finck * white point, such as D65, and an absolute color conversion to XYZ then
73c2c66affSColin Finck * to another color space with a different white point may introduce an
74c2c66affSColin Finck * unwanted color cast to the image. It is often desirable, therefore, to
75c2c66affSColin Finck * perform a white point conversion that maps the input white to [1 1 1]
76c2c66affSColin Finck * in XYZ, then record the original white point using the TIFFTAG_WHITEPOINT
77c2c66affSColin Finck * tag value. A decoder that demands absolute color calibration may use
78c2c66affSColin Finck * this white point tag to get back the original colors, but usually it
79c2c66affSColin Finck * will be ignored and the new white point will be used instead that
80c2c66affSColin Finck * matches the output color space.
81c2c66affSColin Finck *
82c2c66affSColin Finck * Pixel information is compressed into one of two basic encodings, depending
83c2c66affSColin Finck * on the setting of the compression tag, which is one of COMPRESSION_SGILOG
84c2c66affSColin Finck * or COMPRESSION_SGILOG24. For COMPRESSION_SGILOG, greyscale data is
85c2c66affSColin Finck * stored as:
86c2c66affSColin Finck *
87c2c66affSColin Finck * 1 15
88c2c66affSColin Finck * |-+---------------|
89c2c66affSColin Finck *
90c2c66affSColin Finck * COMPRESSION_SGILOG color data is stored as:
91c2c66affSColin Finck *
92c2c66affSColin Finck * 1 15 8 8
93c2c66affSColin Finck * |-+---------------|--------+--------|
94c2c66affSColin Finck * S Le ue ve
95c2c66affSColin Finck *
96c2c66affSColin Finck * For the 24-bit COMPRESSION_SGILOG24 color format, the data is stored as:
97c2c66affSColin Finck *
98c2c66affSColin Finck * 10 14
99c2c66affSColin Finck * |----------|--------------|
100c2c66affSColin Finck * Le' Ce
101c2c66affSColin Finck *
102c2c66affSColin Finck * There is no sign bit in the 24-bit case, and the (u,v) chromaticity is
103c2c66affSColin Finck * encoded as an index for optimal color resolution. The 10 log bits are
104c2c66affSColin Finck * defined by the following conversions:
105c2c66affSColin Finck *
106c2c66affSColin Finck * L = 2^((Le'+.5)/64 - 12) # real from 10-bit
107c2c66affSColin Finck *
108c2c66affSColin Finck * Le' = floor( 64*(log2(L) + 12) ) # 10-bit from real
109c2c66affSColin Finck *
110c2c66affSColin Finck * The 10 bits of the smaller format may be converted into the 15 bits of
111c2c66affSColin Finck * the larger format by multiplying by 4 and adding 13314. Obviously,
112c2c66affSColin Finck * a smaller range of magnitudes is covered (about 5 orders of magnitude
113c2c66affSColin Finck * instead of 38), and the lack of a sign bit means that negative luminances
114c2c66affSColin Finck * are not allowed. (Well, they aren't allowed in the real world, either,
115c2c66affSColin Finck * but they are useful for certain types of image processing.)
116c2c66affSColin Finck *
117c2c66affSColin Finck * The desired user format is controlled by the setting the internal
118c2c66affSColin Finck * pseudo tag TIFFTAG_SGILOGDATAFMT to one of:
119c2c66affSColin Finck * SGILOGDATAFMT_FLOAT = IEEE 32-bit float XYZ values
120c2c66affSColin Finck * SGILOGDATAFMT_16BIT = 16-bit integer encodings of logL, u and v
121c2c66affSColin Finck * Raw data i/o is also possible using:
122c2c66affSColin Finck * SGILOGDATAFMT_RAW = 32-bit unsigned integer with encoded pixel
123c2c66affSColin Finck * In addition, the following decoding is provided for ease of display:
124c2c66affSColin Finck * SGILOGDATAFMT_8BIT = 8-bit default RGB gamma-corrected values
125c2c66affSColin Finck *
126c2c66affSColin Finck * For grayscale images, we provide the following data formats:
127c2c66affSColin Finck * SGILOGDATAFMT_FLOAT = IEEE 32-bit float Y values
128c2c66affSColin Finck * SGILOGDATAFMT_16BIT = 16-bit integer w/ encoded luminance
129c2c66affSColin Finck * SGILOGDATAFMT_8BIT = 8-bit gray monitor values
130c2c66affSColin Finck *
131c2c66affSColin Finck * Note that the COMPRESSION_SGILOG applies a simple run-length encoding
132c2c66affSColin Finck * scheme by separating the logL, u and v bytes for each row and applying
133c2c66affSColin Finck * a PackBits type of compression. Since the 24-bit encoding is not
134c2c66affSColin Finck * adaptive, the 32-bit color format takes less space in many cases.
135c2c66affSColin Finck *
136c2c66affSColin Finck * Further control is provided over the conversion from higher-resolution
137c2c66affSColin Finck * formats to final encoded values through the pseudo tag
138c2c66affSColin Finck * TIFFTAG_SGILOGENCODE:
139c2c66affSColin Finck * SGILOGENCODE_NODITHER = do not dither encoded values
140c2c66affSColin Finck * SGILOGENCODE_RANDITHER = apply random dithering during encoding
141c2c66affSColin Finck *
142c2c66affSColin Finck * The default value of this tag is SGILOGENCODE_NODITHER for
143c2c66affSColin Finck * COMPRESSION_SGILOG to maximize run-length encoding and
144c2c66affSColin Finck * SGILOGENCODE_RANDITHER for COMPRESSION_SGILOG24 to turn
145c2c66affSColin Finck * quantization errors into noise.
146c2c66affSColin Finck */
147c2c66affSColin Finck
148c2c66affSColin Finck #include <stdio.h>
149c2c66affSColin Finck #include <stdlib.h>
150c2c66affSColin Finck #include <math.h>
151c2c66affSColin Finck
152c2c66affSColin Finck /*
153c2c66affSColin Finck * State block for each open TIFF
154c2c66affSColin Finck * file using LogLuv compression/decompression.
155c2c66affSColin Finck */
156c2c66affSColin Finck typedef struct logLuvState LogLuvState;
157c2c66affSColin Finck
158c2c66affSColin Finck struct logLuvState {
159c2c66affSColin Finck int encoder_state; /* 1 if encoder correctly initialized */
160c2c66affSColin Finck int user_datafmt; /* user data format */
161c2c66affSColin Finck int encode_meth; /* encoding method */
162c2c66affSColin Finck int pixel_size; /* bytes per pixel */
163c2c66affSColin Finck
164c2c66affSColin Finck uint8* tbuf; /* translation buffer */
165c2c66affSColin Finck tmsize_t tbuflen; /* buffer length */
166c2c66affSColin Finck void (*tfunc)(LogLuvState*, uint8*, tmsize_t);
167c2c66affSColin Finck
168c2c66affSColin Finck TIFFVSetMethod vgetparent; /* super-class method */
169c2c66affSColin Finck TIFFVSetMethod vsetparent; /* super-class method */
170c2c66affSColin Finck };
171c2c66affSColin Finck
172c2c66affSColin Finck #define DecoderState(tif) ((LogLuvState*) (tif)->tif_data)
173c2c66affSColin Finck #define EncoderState(tif) ((LogLuvState*) (tif)->tif_data)
174c2c66affSColin Finck
175c2c66affSColin Finck #define SGILOGDATAFMT_UNKNOWN -1
176c2c66affSColin Finck
177c2c66affSColin Finck #define MINRUN 4 /* minimum run length */
178c2c66affSColin Finck
179c2c66affSColin Finck /*
180c2c66affSColin Finck * Decode a string of 16-bit gray pixels.
181c2c66affSColin Finck */
182c2c66affSColin Finck static int
LogL16Decode(TIFF * tif,uint8 * op,tmsize_t occ,uint16 s)183c2c66affSColin Finck LogL16Decode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
184c2c66affSColin Finck {
185c2c66affSColin Finck static const char module[] = "LogL16Decode";
186c2c66affSColin Finck LogLuvState* sp = DecoderState(tif);
187c2c66affSColin Finck int shft;
188c2c66affSColin Finck tmsize_t i;
189c2c66affSColin Finck tmsize_t npixels;
190c2c66affSColin Finck unsigned char* bp;
191c2c66affSColin Finck int16* tp;
192c2c66affSColin Finck int16 b;
193c2c66affSColin Finck tmsize_t cc;
194c2c66affSColin Finck int rc;
195c2c66affSColin Finck
196c2c66affSColin Finck assert(s == 0);
197c2c66affSColin Finck assert(sp != NULL);
198c2c66affSColin Finck
199c2c66affSColin Finck npixels = occ / sp->pixel_size;
200c2c66affSColin Finck
201c2c66affSColin Finck if (sp->user_datafmt == SGILOGDATAFMT_16BIT)
202c2c66affSColin Finck tp = (int16*) op;
203c2c66affSColin Finck else {
204c2c66affSColin Finck if(sp->tbuflen < npixels) {
205c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
206c2c66affSColin Finck "Translation buffer too short");
207c2c66affSColin Finck return (0);
208c2c66affSColin Finck }
209c2c66affSColin Finck tp = (int16*) sp->tbuf;
210c2c66affSColin Finck }
211c2c66affSColin Finck _TIFFmemset((void*) tp, 0, npixels*sizeof (tp[0]));
212c2c66affSColin Finck
213c2c66affSColin Finck bp = (unsigned char*) tif->tif_rawcp;
214c2c66affSColin Finck cc = tif->tif_rawcc;
215c2c66affSColin Finck /* get each byte string */
216743951ecSThomas Faber for (shft = 8; shft >= 0; shft -=8) {
217c2c66affSColin Finck for (i = 0; i < npixels && cc > 0; ) {
218c2c66affSColin Finck if (*bp >= 128) { /* run */
219c2c66affSColin Finck if( cc < 2 )
220c2c66affSColin Finck break;
221c2c66affSColin Finck rc = *bp++ + (2-128);
222c2c66affSColin Finck b = (int16)(*bp++ << shft);
223c2c66affSColin Finck cc -= 2;
224c2c66affSColin Finck while (rc-- && i < npixels)
225c2c66affSColin Finck tp[i++] |= b;
226c2c66affSColin Finck } else { /* non-run */
227c2c66affSColin Finck rc = *bp++; /* nul is noop */
228c2c66affSColin Finck while (--cc && rc-- && i < npixels)
229c2c66affSColin Finck tp[i++] |= (int16)*bp++ << shft;
230c2c66affSColin Finck }
231c2c66affSColin Finck }
232c2c66affSColin Finck if (i != npixels) {
233c2c66affSColin Finck #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
234c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
235c2c66affSColin Finck "Not enough data at row %lu (short %I64d pixels)",
236c2c66affSColin Finck (unsigned long) tif->tif_row,
237c2c66affSColin Finck (unsigned __int64) (npixels - i));
238c2c66affSColin Finck #else
239c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
240c2c66affSColin Finck "Not enough data at row %lu (short %llu pixels)",
241c2c66affSColin Finck (unsigned long) tif->tif_row,
242c2c66affSColin Finck (unsigned long long) (npixels - i));
243c2c66affSColin Finck #endif
244c2c66affSColin Finck tif->tif_rawcp = (uint8*) bp;
245c2c66affSColin Finck tif->tif_rawcc = cc;
246c2c66affSColin Finck return (0);
247c2c66affSColin Finck }
248c2c66affSColin Finck }
249c2c66affSColin Finck (*sp->tfunc)(sp, op, npixels);
250c2c66affSColin Finck tif->tif_rawcp = (uint8*) bp;
251c2c66affSColin Finck tif->tif_rawcc = cc;
252c2c66affSColin Finck return (1);
253c2c66affSColin Finck }
254c2c66affSColin Finck
255c2c66affSColin Finck /*
256c2c66affSColin Finck * Decode a string of 24-bit pixels.
257c2c66affSColin Finck */
258c2c66affSColin Finck static int
LogLuvDecode24(TIFF * tif,uint8 * op,tmsize_t occ,uint16 s)259c2c66affSColin Finck LogLuvDecode24(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
260c2c66affSColin Finck {
261c2c66affSColin Finck static const char module[] = "LogLuvDecode24";
262c2c66affSColin Finck LogLuvState* sp = DecoderState(tif);
263c2c66affSColin Finck tmsize_t cc;
264c2c66affSColin Finck tmsize_t i;
265c2c66affSColin Finck tmsize_t npixels;
266c2c66affSColin Finck unsigned char* bp;
267c2c66affSColin Finck uint32* tp;
268c2c66affSColin Finck
269c2c66affSColin Finck assert(s == 0);
270c2c66affSColin Finck assert(sp != NULL);
271c2c66affSColin Finck
272c2c66affSColin Finck npixels = occ / sp->pixel_size;
273c2c66affSColin Finck
274c2c66affSColin Finck if (sp->user_datafmt == SGILOGDATAFMT_RAW)
275c2c66affSColin Finck tp = (uint32 *)op;
276c2c66affSColin Finck else {
277c2c66affSColin Finck if(sp->tbuflen < npixels) {
278c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
279c2c66affSColin Finck "Translation buffer too short");
280c2c66affSColin Finck return (0);
281c2c66affSColin Finck }
282c2c66affSColin Finck tp = (uint32 *) sp->tbuf;
283c2c66affSColin Finck }
284c2c66affSColin Finck /* copy to array of uint32 */
285c2c66affSColin Finck bp = (unsigned char*) tif->tif_rawcp;
286c2c66affSColin Finck cc = tif->tif_rawcc;
287c2c66affSColin Finck for (i = 0; i < npixels && cc >= 3; i++) {
288c2c66affSColin Finck tp[i] = bp[0] << 16 | bp[1] << 8 | bp[2];
289c2c66affSColin Finck bp += 3;
290c2c66affSColin Finck cc -= 3;
291c2c66affSColin Finck }
292c2c66affSColin Finck tif->tif_rawcp = (uint8*) bp;
293c2c66affSColin Finck tif->tif_rawcc = cc;
294c2c66affSColin Finck if (i != npixels) {
295c2c66affSColin Finck #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
296c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
297c2c66affSColin Finck "Not enough data at row %lu (short %I64d pixels)",
298c2c66affSColin Finck (unsigned long) tif->tif_row,
299c2c66affSColin Finck (unsigned __int64) (npixels - i));
300c2c66affSColin Finck #else
301c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
302c2c66affSColin Finck "Not enough data at row %lu (short %llu pixels)",
303c2c66affSColin Finck (unsigned long) tif->tif_row,
304c2c66affSColin Finck (unsigned long long) (npixels - i));
305c2c66affSColin Finck #endif
306c2c66affSColin Finck return (0);
307c2c66affSColin Finck }
308c2c66affSColin Finck (*sp->tfunc)(sp, op, npixels);
309c2c66affSColin Finck return (1);
310c2c66affSColin Finck }
311c2c66affSColin Finck
312c2c66affSColin Finck /*
313c2c66affSColin Finck * Decode a string of 32-bit pixels.
314c2c66affSColin Finck */
315c2c66affSColin Finck static int
LogLuvDecode32(TIFF * tif,uint8 * op,tmsize_t occ,uint16 s)316c2c66affSColin Finck LogLuvDecode32(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
317c2c66affSColin Finck {
318c2c66affSColin Finck static const char module[] = "LogLuvDecode32";
319c2c66affSColin Finck LogLuvState* sp;
320c2c66affSColin Finck int shft;
321c2c66affSColin Finck tmsize_t i;
322c2c66affSColin Finck tmsize_t npixels;
323c2c66affSColin Finck unsigned char* bp;
324c2c66affSColin Finck uint32* tp;
325c2c66affSColin Finck uint32 b;
326c2c66affSColin Finck tmsize_t cc;
327c2c66affSColin Finck int rc;
328c2c66affSColin Finck
329c2c66affSColin Finck assert(s == 0);
330c2c66affSColin Finck sp = DecoderState(tif);
331c2c66affSColin Finck assert(sp != NULL);
332c2c66affSColin Finck
333c2c66affSColin Finck npixels = occ / sp->pixel_size;
334c2c66affSColin Finck
335c2c66affSColin Finck if (sp->user_datafmt == SGILOGDATAFMT_RAW)
336c2c66affSColin Finck tp = (uint32*) op;
337c2c66affSColin Finck else {
338c2c66affSColin Finck if(sp->tbuflen < npixels) {
339c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
340c2c66affSColin Finck "Translation buffer too short");
341c2c66affSColin Finck return (0);
342c2c66affSColin Finck }
343c2c66affSColin Finck tp = (uint32*) sp->tbuf;
344c2c66affSColin Finck }
345c2c66affSColin Finck _TIFFmemset((void*) tp, 0, npixels*sizeof (tp[0]));
346c2c66affSColin Finck
347c2c66affSColin Finck bp = (unsigned char*) tif->tif_rawcp;
348c2c66affSColin Finck cc = tif->tif_rawcc;
349c2c66affSColin Finck /* get each byte string */
350743951ecSThomas Faber for (shft = 24; shft >= 0; shft -=8) {
351c2c66affSColin Finck for (i = 0; i < npixels && cc > 0; ) {
352c2c66affSColin Finck if (*bp >= 128) { /* run */
353c2c66affSColin Finck if( cc < 2 )
354c2c66affSColin Finck break;
355c2c66affSColin Finck rc = *bp++ + (2-128);
356c2c66affSColin Finck b = (uint32)*bp++ << shft;
357c2c66affSColin Finck cc -= 2;
358c2c66affSColin Finck while (rc-- && i < npixels)
359c2c66affSColin Finck tp[i++] |= b;
360c2c66affSColin Finck } else { /* non-run */
361c2c66affSColin Finck rc = *bp++; /* nul is noop */
362c2c66affSColin Finck while (--cc && rc-- && i < npixels)
363c2c66affSColin Finck tp[i++] |= (uint32)*bp++ << shft;
364c2c66affSColin Finck }
365c2c66affSColin Finck }
366c2c66affSColin Finck if (i != npixels) {
367c2c66affSColin Finck #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
368c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
369c2c66affSColin Finck "Not enough data at row %lu (short %I64d pixels)",
370c2c66affSColin Finck (unsigned long) tif->tif_row,
371c2c66affSColin Finck (unsigned __int64) (npixels - i));
372c2c66affSColin Finck #else
373c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
374c2c66affSColin Finck "Not enough data at row %lu (short %llu pixels)",
375c2c66affSColin Finck (unsigned long) tif->tif_row,
376c2c66affSColin Finck (unsigned long long) (npixels - i));
377c2c66affSColin Finck #endif
378c2c66affSColin Finck tif->tif_rawcp = (uint8*) bp;
379c2c66affSColin Finck tif->tif_rawcc = cc;
380c2c66affSColin Finck return (0);
381c2c66affSColin Finck }
382c2c66affSColin Finck }
383c2c66affSColin Finck (*sp->tfunc)(sp, op, npixels);
384c2c66affSColin Finck tif->tif_rawcp = (uint8*) bp;
385c2c66affSColin Finck tif->tif_rawcc = cc;
386c2c66affSColin Finck return (1);
387c2c66affSColin Finck }
388c2c66affSColin Finck
389c2c66affSColin Finck /*
390c2c66affSColin Finck * Decode a strip of pixels. We break it into rows to
391c2c66affSColin Finck * maintain synchrony with the encode algorithm, which
392c2c66affSColin Finck * is row by row.
393c2c66affSColin Finck */
394c2c66affSColin Finck static int
LogLuvDecodeStrip(TIFF * tif,uint8 * bp,tmsize_t cc,uint16 s)395c2c66affSColin Finck LogLuvDecodeStrip(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
396c2c66affSColin Finck {
397c2c66affSColin Finck tmsize_t rowlen = TIFFScanlineSize(tif);
398c2c66affSColin Finck
399c2c66affSColin Finck if (rowlen == 0)
400c2c66affSColin Finck return 0;
401c2c66affSColin Finck
402c2c66affSColin Finck assert(cc%rowlen == 0);
403c2c66affSColin Finck while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s)) {
404c2c66affSColin Finck bp += rowlen;
405c2c66affSColin Finck cc -= rowlen;
406c2c66affSColin Finck }
407c2c66affSColin Finck return (cc == 0);
408c2c66affSColin Finck }
409c2c66affSColin Finck
410c2c66affSColin Finck /*
411c2c66affSColin Finck * Decode a tile of pixels. We break it into rows to
412c2c66affSColin Finck * maintain synchrony with the encode algorithm, which
413c2c66affSColin Finck * is row by row.
414c2c66affSColin Finck */
415c2c66affSColin Finck static int
LogLuvDecodeTile(TIFF * tif,uint8 * bp,tmsize_t cc,uint16 s)416c2c66affSColin Finck LogLuvDecodeTile(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
417c2c66affSColin Finck {
418c2c66affSColin Finck tmsize_t rowlen = TIFFTileRowSize(tif);
419c2c66affSColin Finck
420c2c66affSColin Finck if (rowlen == 0)
421c2c66affSColin Finck return 0;
422c2c66affSColin Finck
423c2c66affSColin Finck assert(cc%rowlen == 0);
424c2c66affSColin Finck while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s)) {
425c2c66affSColin Finck bp += rowlen;
426c2c66affSColin Finck cc -= rowlen;
427c2c66affSColin Finck }
428c2c66affSColin Finck return (cc == 0);
429c2c66affSColin Finck }
430c2c66affSColin Finck
431c2c66affSColin Finck /*
432c2c66affSColin Finck * Encode a row of 16-bit pixels.
433c2c66affSColin Finck */
434c2c66affSColin Finck static int
LogL16Encode(TIFF * tif,uint8 * bp,tmsize_t cc,uint16 s)435c2c66affSColin Finck LogL16Encode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
436c2c66affSColin Finck {
437c2c66affSColin Finck static const char module[] = "LogL16Encode";
438c2c66affSColin Finck LogLuvState* sp = EncoderState(tif);
439c2c66affSColin Finck int shft;
440c2c66affSColin Finck tmsize_t i;
441c2c66affSColin Finck tmsize_t j;
442c2c66affSColin Finck tmsize_t npixels;
443c2c66affSColin Finck uint8* op;
444c2c66affSColin Finck int16* tp;
445c2c66affSColin Finck int16 b;
446c2c66affSColin Finck tmsize_t occ;
447c2c66affSColin Finck int rc=0, mask;
448c2c66affSColin Finck tmsize_t beg;
449c2c66affSColin Finck
450c2c66affSColin Finck assert(s == 0);
451c2c66affSColin Finck assert(sp != NULL);
452c2c66affSColin Finck npixels = cc / sp->pixel_size;
453c2c66affSColin Finck
454c2c66affSColin Finck if (sp->user_datafmt == SGILOGDATAFMT_16BIT)
455c2c66affSColin Finck tp = (int16*) bp;
456c2c66affSColin Finck else {
457c2c66affSColin Finck tp = (int16*) sp->tbuf;
458c2c66affSColin Finck if(sp->tbuflen < npixels) {
459c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
460c2c66affSColin Finck "Translation buffer too short");
461c2c66affSColin Finck return (0);
462c2c66affSColin Finck }
463c2c66affSColin Finck (*sp->tfunc)(sp, bp, npixels);
464c2c66affSColin Finck }
465c2c66affSColin Finck /* compress each byte string */
466c2c66affSColin Finck op = tif->tif_rawcp;
467c2c66affSColin Finck occ = tif->tif_rawdatasize - tif->tif_rawcc;
468743951ecSThomas Faber for (shft = 8; shft >= 0; shft -=8) {
469c2c66affSColin Finck for (i = 0; i < npixels; i += rc) {
470c2c66affSColin Finck if (occ < 4) {
471c2c66affSColin Finck tif->tif_rawcp = op;
472c2c66affSColin Finck tif->tif_rawcc = tif->tif_rawdatasize - occ;
473c2c66affSColin Finck if (!TIFFFlushData1(tif))
474c2c66affSColin Finck return (0);
475c2c66affSColin Finck op = tif->tif_rawcp;
476c2c66affSColin Finck occ = tif->tif_rawdatasize - tif->tif_rawcc;
477c2c66affSColin Finck }
478c2c66affSColin Finck mask = 0xff << shft; /* find next run */
479c2c66affSColin Finck for (beg = i; beg < npixels; beg += rc) {
480c2c66affSColin Finck b = (int16) (tp[beg] & mask);
481c2c66affSColin Finck rc = 1;
482c2c66affSColin Finck while (rc < 127+2 && beg+rc < npixels &&
483c2c66affSColin Finck (tp[beg+rc] & mask) == b)
484c2c66affSColin Finck rc++;
485c2c66affSColin Finck if (rc >= MINRUN)
486c2c66affSColin Finck break; /* long enough */
487c2c66affSColin Finck }
488c2c66affSColin Finck if (beg-i > 1 && beg-i < MINRUN) {
489c2c66affSColin Finck b = (int16) (tp[i] & mask);/*check short run */
490c2c66affSColin Finck j = i+1;
491c2c66affSColin Finck while ((tp[j++] & mask) == b)
492c2c66affSColin Finck if (j == beg) {
493c2c66affSColin Finck *op++ = (uint8)(128-2+j-i);
494c2c66affSColin Finck *op++ = (uint8)(b >> shft);
495c2c66affSColin Finck occ -= 2;
496c2c66affSColin Finck i = beg;
497c2c66affSColin Finck break;
498c2c66affSColin Finck }
499c2c66affSColin Finck }
500c2c66affSColin Finck while (i < beg) { /* write out non-run */
501c2c66affSColin Finck if ((j = beg-i) > 127) j = 127;
502c2c66affSColin Finck if (occ < j+3) {
503c2c66affSColin Finck tif->tif_rawcp = op;
504c2c66affSColin Finck tif->tif_rawcc = tif->tif_rawdatasize - occ;
505c2c66affSColin Finck if (!TIFFFlushData1(tif))
506c2c66affSColin Finck return (0);
507c2c66affSColin Finck op = tif->tif_rawcp;
508c2c66affSColin Finck occ = tif->tif_rawdatasize - tif->tif_rawcc;
509c2c66affSColin Finck }
510c2c66affSColin Finck *op++ = (uint8) j; occ--;
511c2c66affSColin Finck while (j--) {
512c2c66affSColin Finck *op++ = (uint8) (tp[i++] >> shft & 0xff);
513c2c66affSColin Finck occ--;
514c2c66affSColin Finck }
515c2c66affSColin Finck }
516c2c66affSColin Finck if (rc >= MINRUN) { /* write out run */
517c2c66affSColin Finck *op++ = (uint8) (128-2+rc);
518c2c66affSColin Finck *op++ = (uint8) (tp[beg] >> shft & 0xff);
519c2c66affSColin Finck occ -= 2;
520c2c66affSColin Finck } else
521c2c66affSColin Finck rc = 0;
522c2c66affSColin Finck }
523743951ecSThomas Faber }
524c2c66affSColin Finck tif->tif_rawcp = op;
525c2c66affSColin Finck tif->tif_rawcc = tif->tif_rawdatasize - occ;
526c2c66affSColin Finck
527c2c66affSColin Finck return (1);
528c2c66affSColin Finck }
529c2c66affSColin Finck
530c2c66affSColin Finck /*
531c2c66affSColin Finck * Encode a row of 24-bit pixels.
532c2c66affSColin Finck */
533c2c66affSColin Finck static int
LogLuvEncode24(TIFF * tif,uint8 * bp,tmsize_t cc,uint16 s)534c2c66affSColin Finck LogLuvEncode24(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
535c2c66affSColin Finck {
536c2c66affSColin Finck static const char module[] = "LogLuvEncode24";
537c2c66affSColin Finck LogLuvState* sp = EncoderState(tif);
538c2c66affSColin Finck tmsize_t i;
539c2c66affSColin Finck tmsize_t npixels;
540c2c66affSColin Finck tmsize_t occ;
541c2c66affSColin Finck uint8* op;
542c2c66affSColin Finck uint32* tp;
543c2c66affSColin Finck
544c2c66affSColin Finck assert(s == 0);
545c2c66affSColin Finck assert(sp != NULL);
546c2c66affSColin Finck npixels = cc / sp->pixel_size;
547c2c66affSColin Finck
548c2c66affSColin Finck if (sp->user_datafmt == SGILOGDATAFMT_RAW)
549c2c66affSColin Finck tp = (uint32*) bp;
550c2c66affSColin Finck else {
551c2c66affSColin Finck tp = (uint32*) sp->tbuf;
552c2c66affSColin Finck if(sp->tbuflen < npixels) {
553c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
554c2c66affSColin Finck "Translation buffer too short");
555c2c66affSColin Finck return (0);
556c2c66affSColin Finck }
557c2c66affSColin Finck (*sp->tfunc)(sp, bp, npixels);
558c2c66affSColin Finck }
559c2c66affSColin Finck /* write out encoded pixels */
560c2c66affSColin Finck op = tif->tif_rawcp;
561c2c66affSColin Finck occ = tif->tif_rawdatasize - tif->tif_rawcc;
562c2c66affSColin Finck for (i = npixels; i--; ) {
563c2c66affSColin Finck if (occ < 3) {
564c2c66affSColin Finck tif->tif_rawcp = op;
565c2c66affSColin Finck tif->tif_rawcc = tif->tif_rawdatasize - occ;
566c2c66affSColin Finck if (!TIFFFlushData1(tif))
567c2c66affSColin Finck return (0);
568c2c66affSColin Finck op = tif->tif_rawcp;
569c2c66affSColin Finck occ = tif->tif_rawdatasize - tif->tif_rawcc;
570c2c66affSColin Finck }
571c2c66affSColin Finck *op++ = (uint8)(*tp >> 16);
572c2c66affSColin Finck *op++ = (uint8)(*tp >> 8 & 0xff);
573c2c66affSColin Finck *op++ = (uint8)(*tp++ & 0xff);
574c2c66affSColin Finck occ -= 3;
575c2c66affSColin Finck }
576c2c66affSColin Finck tif->tif_rawcp = op;
577c2c66affSColin Finck tif->tif_rawcc = tif->tif_rawdatasize - occ;
578c2c66affSColin Finck
579c2c66affSColin Finck return (1);
580c2c66affSColin Finck }
581c2c66affSColin Finck
582c2c66affSColin Finck /*
583c2c66affSColin Finck * Encode a row of 32-bit pixels.
584c2c66affSColin Finck */
585c2c66affSColin Finck static int
LogLuvEncode32(TIFF * tif,uint8 * bp,tmsize_t cc,uint16 s)586c2c66affSColin Finck LogLuvEncode32(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
587c2c66affSColin Finck {
588c2c66affSColin Finck static const char module[] = "LogLuvEncode32";
589c2c66affSColin Finck LogLuvState* sp = EncoderState(tif);
590c2c66affSColin Finck int shft;
591c2c66affSColin Finck tmsize_t i;
592c2c66affSColin Finck tmsize_t j;
593c2c66affSColin Finck tmsize_t npixels;
594c2c66affSColin Finck uint8* op;
595c2c66affSColin Finck uint32* tp;
596c2c66affSColin Finck uint32 b;
597c2c66affSColin Finck tmsize_t occ;
598c2c66affSColin Finck int rc=0, mask;
599c2c66affSColin Finck tmsize_t beg;
600c2c66affSColin Finck
601c2c66affSColin Finck assert(s == 0);
602c2c66affSColin Finck assert(sp != NULL);
603c2c66affSColin Finck
604c2c66affSColin Finck npixels = cc / sp->pixel_size;
605c2c66affSColin Finck
606c2c66affSColin Finck if (sp->user_datafmt == SGILOGDATAFMT_RAW)
607c2c66affSColin Finck tp = (uint32*) bp;
608c2c66affSColin Finck else {
609c2c66affSColin Finck tp = (uint32*) sp->tbuf;
610c2c66affSColin Finck if(sp->tbuflen < npixels) {
611c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
612c2c66affSColin Finck "Translation buffer too short");
613c2c66affSColin Finck return (0);
614c2c66affSColin Finck }
615c2c66affSColin Finck (*sp->tfunc)(sp, bp, npixels);
616c2c66affSColin Finck }
617c2c66affSColin Finck /* compress each byte string */
618c2c66affSColin Finck op = tif->tif_rawcp;
619c2c66affSColin Finck occ = tif->tif_rawdatasize - tif->tif_rawcc;
620743951ecSThomas Faber for (shft = 24; shft >= 0; shft -=8) {
621c2c66affSColin Finck for (i = 0; i < npixels; i += rc) {
622c2c66affSColin Finck if (occ < 4) {
623c2c66affSColin Finck tif->tif_rawcp = op;
624c2c66affSColin Finck tif->tif_rawcc = tif->tif_rawdatasize - occ;
625c2c66affSColin Finck if (!TIFFFlushData1(tif))
626c2c66affSColin Finck return (0);
627c2c66affSColin Finck op = tif->tif_rawcp;
628c2c66affSColin Finck occ = tif->tif_rawdatasize - tif->tif_rawcc;
629c2c66affSColin Finck }
630c2c66affSColin Finck mask = 0xff << shft; /* find next run */
631c2c66affSColin Finck for (beg = i; beg < npixels; beg += rc) {
632c2c66affSColin Finck b = tp[beg] & mask;
633c2c66affSColin Finck rc = 1;
634c2c66affSColin Finck while (rc < 127+2 && beg+rc < npixels &&
635c2c66affSColin Finck (tp[beg+rc] & mask) == b)
636c2c66affSColin Finck rc++;
637c2c66affSColin Finck if (rc >= MINRUN)
638c2c66affSColin Finck break; /* long enough */
639c2c66affSColin Finck }
640c2c66affSColin Finck if (beg-i > 1 && beg-i < MINRUN) {
641c2c66affSColin Finck b = tp[i] & mask; /* check short run */
642c2c66affSColin Finck j = i+1;
643c2c66affSColin Finck while ((tp[j++] & mask) == b)
644c2c66affSColin Finck if (j == beg) {
645c2c66affSColin Finck *op++ = (uint8)(128-2+j-i);
646c2c66affSColin Finck *op++ = (uint8)(b >> shft);
647c2c66affSColin Finck occ -= 2;
648c2c66affSColin Finck i = beg;
649c2c66affSColin Finck break;
650c2c66affSColin Finck }
651c2c66affSColin Finck }
652c2c66affSColin Finck while (i < beg) { /* write out non-run */
653c2c66affSColin Finck if ((j = beg-i) > 127) j = 127;
654c2c66affSColin Finck if (occ < j+3) {
655c2c66affSColin Finck tif->tif_rawcp = op;
656c2c66affSColin Finck tif->tif_rawcc = tif->tif_rawdatasize - occ;
657c2c66affSColin Finck if (!TIFFFlushData1(tif))
658c2c66affSColin Finck return (0);
659c2c66affSColin Finck op = tif->tif_rawcp;
660c2c66affSColin Finck occ = tif->tif_rawdatasize - tif->tif_rawcc;
661c2c66affSColin Finck }
662c2c66affSColin Finck *op++ = (uint8) j; occ--;
663c2c66affSColin Finck while (j--) {
664c2c66affSColin Finck *op++ = (uint8)(tp[i++] >> shft & 0xff);
665c2c66affSColin Finck occ--;
666c2c66affSColin Finck }
667c2c66affSColin Finck }
668c2c66affSColin Finck if (rc >= MINRUN) { /* write out run */
669c2c66affSColin Finck *op++ = (uint8) (128-2+rc);
670c2c66affSColin Finck *op++ = (uint8)(tp[beg] >> shft & 0xff);
671c2c66affSColin Finck occ -= 2;
672c2c66affSColin Finck } else
673c2c66affSColin Finck rc = 0;
674c2c66affSColin Finck }
675743951ecSThomas Faber }
676c2c66affSColin Finck tif->tif_rawcp = op;
677c2c66affSColin Finck tif->tif_rawcc = tif->tif_rawdatasize - occ;
678c2c66affSColin Finck
679c2c66affSColin Finck return (1);
680c2c66affSColin Finck }
681c2c66affSColin Finck
682c2c66affSColin Finck /*
683c2c66affSColin Finck * Encode a strip of pixels. We break it into rows to
684c2c66affSColin Finck * avoid encoding runs across row boundaries.
685c2c66affSColin Finck */
686c2c66affSColin Finck static int
LogLuvEncodeStrip(TIFF * tif,uint8 * bp,tmsize_t cc,uint16 s)687c2c66affSColin Finck LogLuvEncodeStrip(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
688c2c66affSColin Finck {
689c2c66affSColin Finck tmsize_t rowlen = TIFFScanlineSize(tif);
690c2c66affSColin Finck
691c2c66affSColin Finck if (rowlen == 0)
692c2c66affSColin Finck return 0;
693c2c66affSColin Finck
694c2c66affSColin Finck assert(cc%rowlen == 0);
695c2c66affSColin Finck while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1) {
696c2c66affSColin Finck bp += rowlen;
697c2c66affSColin Finck cc -= rowlen;
698c2c66affSColin Finck }
699c2c66affSColin Finck return (cc == 0);
700c2c66affSColin Finck }
701c2c66affSColin Finck
702c2c66affSColin Finck /*
703c2c66affSColin Finck * Encode a tile of pixels. We break it into rows to
704c2c66affSColin Finck * avoid encoding runs across row boundaries.
705c2c66affSColin Finck */
706c2c66affSColin Finck static int
LogLuvEncodeTile(TIFF * tif,uint8 * bp,tmsize_t cc,uint16 s)707c2c66affSColin Finck LogLuvEncodeTile(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
708c2c66affSColin Finck {
709c2c66affSColin Finck tmsize_t rowlen = TIFFTileRowSize(tif);
710c2c66affSColin Finck
711c2c66affSColin Finck if (rowlen == 0)
712c2c66affSColin Finck return 0;
713c2c66affSColin Finck
714c2c66affSColin Finck assert(cc%rowlen == 0);
715c2c66affSColin Finck while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1) {
716c2c66affSColin Finck bp += rowlen;
717c2c66affSColin Finck cc -= rowlen;
718c2c66affSColin Finck }
719c2c66affSColin Finck return (cc == 0);
720c2c66affSColin Finck }
721c2c66affSColin Finck
722c2c66affSColin Finck /*
723c2c66affSColin Finck * Encode/Decode functions for converting to and from user formats.
724c2c66affSColin Finck */
725c2c66affSColin Finck
726c2c66affSColin Finck #include "uvcode.h"
727c2c66affSColin Finck
728c2c66affSColin Finck #ifndef UVSCALE
729c2c66affSColin Finck #define U_NEU 0.210526316
730c2c66affSColin Finck #define V_NEU 0.473684211
731c2c66affSColin Finck #define UVSCALE 410.
732c2c66affSColin Finck #endif
733c2c66affSColin Finck
734c2c66affSColin Finck #ifndef M_LN2
735c2c66affSColin Finck #define M_LN2 0.69314718055994530942
736c2c66affSColin Finck #endif
737c2c66affSColin Finck #ifndef M_PI
738c2c66affSColin Finck #define M_PI 3.14159265358979323846
739c2c66affSColin Finck #endif
740c2c66affSColin Finck #undef log2 /* Conflict with C'99 function */
741c2c66affSColin Finck #define log2(x) ((1./M_LN2)*log(x))
742c2c66affSColin Finck #undef exp2 /* Conflict with C'99 function */
743c2c66affSColin Finck #define exp2(x) exp(M_LN2*(x))
744c2c66affSColin Finck
itrunc(double x,int m)745*f87faf67SThomas Faber static int itrunc(double x, int m)
746*f87faf67SThomas Faber {
747*f87faf67SThomas Faber if( m == SGILOGENCODE_NODITHER )
748*f87faf67SThomas Faber return (int)x;
749*f87faf67SThomas Faber /* Silence CoverityScan warning about bad crypto function */
750*f87faf67SThomas Faber /* coverity[dont_call] */
751*f87faf67SThomas Faber return (int)(x + rand()*(1./RAND_MAX) - .5);
752*f87faf67SThomas Faber }
753c2c66affSColin Finck
754c2c66affSColin Finck #if !LOGLUV_PUBLIC
755c2c66affSColin Finck static
756c2c66affSColin Finck #endif
757c2c66affSColin Finck double
LogL16toY(int p16)758c2c66affSColin Finck LogL16toY(int p16) /* compute luminance from 16-bit LogL */
759c2c66affSColin Finck {
760c2c66affSColin Finck int Le = p16 & 0x7fff;
761c2c66affSColin Finck double Y;
762c2c66affSColin Finck
763c2c66affSColin Finck if (!Le)
764c2c66affSColin Finck return (0.);
765c2c66affSColin Finck Y = exp(M_LN2/256.*(Le+.5) - M_LN2*64.);
766c2c66affSColin Finck return (!(p16 & 0x8000) ? Y : -Y);
767c2c66affSColin Finck }
768c2c66affSColin Finck
769c2c66affSColin Finck #if !LOGLUV_PUBLIC
770c2c66affSColin Finck static
771c2c66affSColin Finck #endif
772c2c66affSColin Finck int
LogL16fromY(double Y,int em)773c2c66affSColin Finck LogL16fromY(double Y, int em) /* get 16-bit LogL from Y */
774c2c66affSColin Finck {
775c2c66affSColin Finck if (Y >= 1.8371976e19)
776c2c66affSColin Finck return (0x7fff);
777c2c66affSColin Finck if (Y <= -1.8371976e19)
778c2c66affSColin Finck return (0xffff);
779c2c66affSColin Finck if (Y > 5.4136769e-20)
780c2c66affSColin Finck return itrunc(256.*(log2(Y) + 64.), em);
781c2c66affSColin Finck if (Y < -5.4136769e-20)
782c2c66affSColin Finck return (~0x7fff | itrunc(256.*(log2(-Y) + 64.), em));
783c2c66affSColin Finck return (0);
784c2c66affSColin Finck }
785c2c66affSColin Finck
786c2c66affSColin Finck static void
L16toY(LogLuvState * sp,uint8 * op,tmsize_t n)787c2c66affSColin Finck L16toY(LogLuvState* sp, uint8* op, tmsize_t n)
788c2c66affSColin Finck {
789c2c66affSColin Finck int16* l16 = (int16*) sp->tbuf;
790c2c66affSColin Finck float* yp = (float*) op;
791c2c66affSColin Finck
792c2c66affSColin Finck while (n-- > 0)
793c2c66affSColin Finck *yp++ = (float)LogL16toY(*l16++);
794c2c66affSColin Finck }
795c2c66affSColin Finck
796c2c66affSColin Finck static void
L16toGry(LogLuvState * sp,uint8 * op,tmsize_t n)797c2c66affSColin Finck L16toGry(LogLuvState* sp, uint8* op, tmsize_t n)
798c2c66affSColin Finck {
799c2c66affSColin Finck int16* l16 = (int16*) sp->tbuf;
800c2c66affSColin Finck uint8* gp = (uint8*) op;
801c2c66affSColin Finck
802c2c66affSColin Finck while (n-- > 0) {
803c2c66affSColin Finck double Y = LogL16toY(*l16++);
804c2c66affSColin Finck *gp++ = (uint8) ((Y <= 0.) ? 0 : (Y >= 1.) ? 255 : (int)(256.*sqrt(Y)));
805c2c66affSColin Finck }
806c2c66affSColin Finck }
807c2c66affSColin Finck
808c2c66affSColin Finck static void
L16fromY(LogLuvState * sp,uint8 * op,tmsize_t n)809c2c66affSColin Finck L16fromY(LogLuvState* sp, uint8* op, tmsize_t n)
810c2c66affSColin Finck {
811c2c66affSColin Finck int16* l16 = (int16*) sp->tbuf;
812c2c66affSColin Finck float* yp = (float*) op;
813c2c66affSColin Finck
814c2c66affSColin Finck while (n-- > 0)
815c2c66affSColin Finck *l16++ = (int16) (LogL16fromY(*yp++, sp->encode_meth));
816c2c66affSColin Finck }
817c2c66affSColin Finck
818c2c66affSColin Finck #if !LOGLUV_PUBLIC
819c2c66affSColin Finck static
820c2c66affSColin Finck #endif
821c2c66affSColin Finck void
XYZtoRGB24(float xyz[3],uint8 rgb[3])822c2c66affSColin Finck XYZtoRGB24(float xyz[3], uint8 rgb[3])
823c2c66affSColin Finck {
824c2c66affSColin Finck double r, g, b;
825c2c66affSColin Finck /* assume CCIR-709 primaries */
826c2c66affSColin Finck r = 2.690*xyz[0] + -1.276*xyz[1] + -0.414*xyz[2];
827c2c66affSColin Finck g = -1.022*xyz[0] + 1.978*xyz[1] + 0.044*xyz[2];
828c2c66affSColin Finck b = 0.061*xyz[0] + -0.224*xyz[1] + 1.163*xyz[2];
829c2c66affSColin Finck /* assume 2.0 gamma for speed */
830c2c66affSColin Finck /* could use integer sqrt approx., but this is probably faster */
831c2c66affSColin Finck rgb[0] = (uint8)((r<=0.) ? 0 : (r >= 1.) ? 255 : (int)(256.*sqrt(r)));
832c2c66affSColin Finck rgb[1] = (uint8)((g<=0.) ? 0 : (g >= 1.) ? 255 : (int)(256.*sqrt(g)));
833c2c66affSColin Finck rgb[2] = (uint8)((b<=0.) ? 0 : (b >= 1.) ? 255 : (int)(256.*sqrt(b)));
834c2c66affSColin Finck }
835c2c66affSColin Finck
836c2c66affSColin Finck #if !LOGLUV_PUBLIC
837c2c66affSColin Finck static
838c2c66affSColin Finck #endif
839c2c66affSColin Finck double
LogL10toY(int p10)840c2c66affSColin Finck LogL10toY(int p10) /* compute luminance from 10-bit LogL */
841c2c66affSColin Finck {
842c2c66affSColin Finck if (p10 == 0)
843c2c66affSColin Finck return (0.);
844c2c66affSColin Finck return (exp(M_LN2/64.*(p10+.5) - M_LN2*12.));
845c2c66affSColin Finck }
846c2c66affSColin Finck
847c2c66affSColin Finck #if !LOGLUV_PUBLIC
848c2c66affSColin Finck static
849c2c66affSColin Finck #endif
850c2c66affSColin Finck int
LogL10fromY(double Y,int em)851c2c66affSColin Finck LogL10fromY(double Y, int em) /* get 10-bit LogL from Y */
852c2c66affSColin Finck {
853c2c66affSColin Finck if (Y >= 15.742)
854c2c66affSColin Finck return (0x3ff);
855c2c66affSColin Finck else if (Y <= .00024283)
856c2c66affSColin Finck return (0);
857c2c66affSColin Finck else
858c2c66affSColin Finck return itrunc(64.*(log2(Y) + 12.), em);
859c2c66affSColin Finck }
860c2c66affSColin Finck
861c2c66affSColin Finck #define NANGLES 100
862c2c66affSColin Finck #define uv2ang(u, v) ( (NANGLES*.499999999/M_PI) \
863c2c66affSColin Finck * atan2((v)-V_NEU,(u)-U_NEU) + .5*NANGLES )
864c2c66affSColin Finck
865c2c66affSColin Finck static int
oog_encode(double u,double v)866c2c66affSColin Finck oog_encode(double u, double v) /* encode out-of-gamut chroma */
867c2c66affSColin Finck {
868c2c66affSColin Finck static int oog_table[NANGLES];
869c2c66affSColin Finck static int initialized = 0;
870c2c66affSColin Finck register int i;
871c2c66affSColin Finck
872c2c66affSColin Finck if (!initialized) { /* set up perimeter table */
873c2c66affSColin Finck double eps[NANGLES], ua, va, ang, epsa;
874c2c66affSColin Finck int ui, vi, ustep;
875c2c66affSColin Finck for (i = NANGLES; i--; )
876c2c66affSColin Finck eps[i] = 2.;
877c2c66affSColin Finck for (vi = UV_NVS; vi--; ) {
878c2c66affSColin Finck va = UV_VSTART + (vi+.5)*UV_SQSIZ;
879c2c66affSColin Finck ustep = uv_row[vi].nus-1;
880c2c66affSColin Finck if (vi == UV_NVS-1 || vi == 0 || ustep <= 0)
881c2c66affSColin Finck ustep = 1;
882c2c66affSColin Finck for (ui = uv_row[vi].nus-1; ui >= 0; ui -= ustep) {
883c2c66affSColin Finck ua = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ;
884c2c66affSColin Finck ang = uv2ang(ua, va);
885c2c66affSColin Finck i = (int) ang;
886c2c66affSColin Finck epsa = fabs(ang - (i+.5));
887c2c66affSColin Finck if (epsa < eps[i]) {
888c2c66affSColin Finck oog_table[i] = uv_row[vi].ncum + ui;
889c2c66affSColin Finck eps[i] = epsa;
890c2c66affSColin Finck }
891c2c66affSColin Finck }
892c2c66affSColin Finck }
893c2c66affSColin Finck for (i = NANGLES; i--; ) /* fill any holes */
894c2c66affSColin Finck if (eps[i] > 1.5) {
895c2c66affSColin Finck int i1, i2;
896c2c66affSColin Finck for (i1 = 1; i1 < NANGLES/2; i1++)
897c2c66affSColin Finck if (eps[(i+i1)%NANGLES] < 1.5)
898c2c66affSColin Finck break;
899c2c66affSColin Finck for (i2 = 1; i2 < NANGLES/2; i2++)
900c2c66affSColin Finck if (eps[(i+NANGLES-i2)%NANGLES] < 1.5)
901c2c66affSColin Finck break;
902c2c66affSColin Finck if (i1 < i2)
903c2c66affSColin Finck oog_table[i] =
904c2c66affSColin Finck oog_table[(i+i1)%NANGLES];
905c2c66affSColin Finck else
906c2c66affSColin Finck oog_table[i] =
907c2c66affSColin Finck oog_table[(i+NANGLES-i2)%NANGLES];
908c2c66affSColin Finck }
909c2c66affSColin Finck initialized = 1;
910c2c66affSColin Finck }
911c2c66affSColin Finck i = (int) uv2ang(u, v); /* look up hue angle */
912c2c66affSColin Finck return (oog_table[i]);
913c2c66affSColin Finck }
914c2c66affSColin Finck
915c2c66affSColin Finck #undef uv2ang
916c2c66affSColin Finck #undef NANGLES
917c2c66affSColin Finck
918c2c66affSColin Finck #if !LOGLUV_PUBLIC
919c2c66affSColin Finck static
920c2c66affSColin Finck #endif
921c2c66affSColin Finck int
uv_encode(double u,double v,int em)922c2c66affSColin Finck uv_encode(double u, double v, int em) /* encode (u',v') coordinates */
923c2c66affSColin Finck {
924c2c66affSColin Finck register int vi, ui;
925c2c66affSColin Finck
926c2c66affSColin Finck if (v < UV_VSTART)
927c2c66affSColin Finck return oog_encode(u, v);
928c2c66affSColin Finck vi = itrunc((v - UV_VSTART)*(1./UV_SQSIZ), em);
929c2c66affSColin Finck if (vi >= UV_NVS)
930c2c66affSColin Finck return oog_encode(u, v);
931c2c66affSColin Finck if (u < uv_row[vi].ustart)
932c2c66affSColin Finck return oog_encode(u, v);
933c2c66affSColin Finck ui = itrunc((u - uv_row[vi].ustart)*(1./UV_SQSIZ), em);
934c2c66affSColin Finck if (ui >= uv_row[vi].nus)
935c2c66affSColin Finck return oog_encode(u, v);
936c2c66affSColin Finck
937c2c66affSColin Finck return (uv_row[vi].ncum + ui);
938c2c66affSColin Finck }
939c2c66affSColin Finck
940c2c66affSColin Finck #if !LOGLUV_PUBLIC
941c2c66affSColin Finck static
942c2c66affSColin Finck #endif
943c2c66affSColin Finck int
uv_decode(double * up,double * vp,int c)944c2c66affSColin Finck uv_decode(double *up, double *vp, int c) /* decode (u',v') index */
945c2c66affSColin Finck {
946c2c66affSColin Finck int upper, lower;
947c2c66affSColin Finck register int ui, vi;
948c2c66affSColin Finck
949c2c66affSColin Finck if (c < 0 || c >= UV_NDIVS)
950c2c66affSColin Finck return (-1);
951c2c66affSColin Finck lower = 0; /* binary search */
952c2c66affSColin Finck upper = UV_NVS;
953c2c66affSColin Finck while (upper - lower > 1) {
954c2c66affSColin Finck vi = (lower + upper) >> 1;
955c2c66affSColin Finck ui = c - uv_row[vi].ncum;
956c2c66affSColin Finck if (ui > 0)
957c2c66affSColin Finck lower = vi;
958c2c66affSColin Finck else if (ui < 0)
959c2c66affSColin Finck upper = vi;
960c2c66affSColin Finck else {
961c2c66affSColin Finck lower = vi;
962c2c66affSColin Finck break;
963c2c66affSColin Finck }
964c2c66affSColin Finck }
965c2c66affSColin Finck vi = lower;
966c2c66affSColin Finck ui = c - uv_row[vi].ncum;
967c2c66affSColin Finck *up = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ;
968c2c66affSColin Finck *vp = UV_VSTART + (vi+.5)*UV_SQSIZ;
969c2c66affSColin Finck return (0);
970c2c66affSColin Finck }
971c2c66affSColin Finck
972c2c66affSColin Finck #if !LOGLUV_PUBLIC
973c2c66affSColin Finck static
974c2c66affSColin Finck #endif
975c2c66affSColin Finck void
LogLuv24toXYZ(uint32 p,float XYZ[3])976c2c66affSColin Finck LogLuv24toXYZ(uint32 p, float XYZ[3])
977c2c66affSColin Finck {
978c2c66affSColin Finck int Ce;
979c2c66affSColin Finck double L, u, v, s, x, y;
980c2c66affSColin Finck /* decode luminance */
981c2c66affSColin Finck L = LogL10toY(p>>14 & 0x3ff);
982c2c66affSColin Finck if (L <= 0.) {
983c2c66affSColin Finck XYZ[0] = XYZ[1] = XYZ[2] = 0.;
984c2c66affSColin Finck return;
985c2c66affSColin Finck }
986c2c66affSColin Finck /* decode color */
987c2c66affSColin Finck Ce = p & 0x3fff;
988c2c66affSColin Finck if (uv_decode(&u, &v, Ce) < 0) {
989c2c66affSColin Finck u = U_NEU; v = V_NEU;
990c2c66affSColin Finck }
991c2c66affSColin Finck s = 1./(6.*u - 16.*v + 12.);
992c2c66affSColin Finck x = 9.*u * s;
993c2c66affSColin Finck y = 4.*v * s;
994c2c66affSColin Finck /* convert to XYZ */
995c2c66affSColin Finck XYZ[0] = (float)(x/y * L);
996c2c66affSColin Finck XYZ[1] = (float)L;
997c2c66affSColin Finck XYZ[2] = (float)((1.-x-y)/y * L);
998c2c66affSColin Finck }
999c2c66affSColin Finck
1000c2c66affSColin Finck #if !LOGLUV_PUBLIC
1001c2c66affSColin Finck static
1002c2c66affSColin Finck #endif
1003c2c66affSColin Finck uint32
LogLuv24fromXYZ(float XYZ[3],int em)1004c2c66affSColin Finck LogLuv24fromXYZ(float XYZ[3], int em)
1005c2c66affSColin Finck {
1006c2c66affSColin Finck int Le, Ce;
1007c2c66affSColin Finck double u, v, s;
1008c2c66affSColin Finck /* encode luminance */
1009c2c66affSColin Finck Le = LogL10fromY(XYZ[1], em);
1010c2c66affSColin Finck /* encode color */
1011c2c66affSColin Finck s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2];
1012c2c66affSColin Finck if (!Le || s <= 0.) {
1013c2c66affSColin Finck u = U_NEU;
1014c2c66affSColin Finck v = V_NEU;
1015c2c66affSColin Finck } else {
1016c2c66affSColin Finck u = 4.*XYZ[0] / s;
1017c2c66affSColin Finck v = 9.*XYZ[1] / s;
1018c2c66affSColin Finck }
1019c2c66affSColin Finck Ce = uv_encode(u, v, em);
1020c2c66affSColin Finck if (Ce < 0) /* never happens */
1021c2c66affSColin Finck Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER);
1022c2c66affSColin Finck /* combine encodings */
1023c2c66affSColin Finck return (Le << 14 | Ce);
1024c2c66affSColin Finck }
1025c2c66affSColin Finck
1026c2c66affSColin Finck static void
Luv24toXYZ(LogLuvState * sp,uint8 * op,tmsize_t n)1027c2c66affSColin Finck Luv24toXYZ(LogLuvState* sp, uint8* op, tmsize_t n)
1028c2c66affSColin Finck {
1029c2c66affSColin Finck uint32* luv = (uint32*) sp->tbuf;
1030c2c66affSColin Finck float* xyz = (float*) op;
1031c2c66affSColin Finck
1032c2c66affSColin Finck while (n-- > 0) {
1033c2c66affSColin Finck LogLuv24toXYZ(*luv, xyz);
1034c2c66affSColin Finck xyz += 3;
1035c2c66affSColin Finck luv++;
1036c2c66affSColin Finck }
1037c2c66affSColin Finck }
1038c2c66affSColin Finck
1039c2c66affSColin Finck static void
Luv24toLuv48(LogLuvState * sp,uint8 * op,tmsize_t n)1040c2c66affSColin Finck Luv24toLuv48(LogLuvState* sp, uint8* op, tmsize_t n)
1041c2c66affSColin Finck {
1042c2c66affSColin Finck uint32* luv = (uint32*) sp->tbuf;
1043c2c66affSColin Finck int16* luv3 = (int16*) op;
1044c2c66affSColin Finck
1045c2c66affSColin Finck while (n-- > 0) {
1046c2c66affSColin Finck double u, v;
1047c2c66affSColin Finck
1048c2c66affSColin Finck *luv3++ = (int16)((*luv >> 12 & 0xffd) + 13314);
1049c2c66affSColin Finck if (uv_decode(&u, &v, *luv&0x3fff) < 0) {
1050c2c66affSColin Finck u = U_NEU;
1051c2c66affSColin Finck v = V_NEU;
1052c2c66affSColin Finck }
1053c2c66affSColin Finck *luv3++ = (int16)(u * (1L<<15));
1054c2c66affSColin Finck *luv3++ = (int16)(v * (1L<<15));
1055c2c66affSColin Finck luv++;
1056c2c66affSColin Finck }
1057c2c66affSColin Finck }
1058c2c66affSColin Finck
1059c2c66affSColin Finck static void
Luv24toRGB(LogLuvState * sp,uint8 * op,tmsize_t n)1060c2c66affSColin Finck Luv24toRGB(LogLuvState* sp, uint8* op, tmsize_t n)
1061c2c66affSColin Finck {
1062c2c66affSColin Finck uint32* luv = (uint32*) sp->tbuf;
1063c2c66affSColin Finck uint8* rgb = (uint8*) op;
1064c2c66affSColin Finck
1065c2c66affSColin Finck while (n-- > 0) {
1066c2c66affSColin Finck float xyz[3];
1067c2c66affSColin Finck
1068c2c66affSColin Finck LogLuv24toXYZ(*luv++, xyz);
1069c2c66affSColin Finck XYZtoRGB24(xyz, rgb);
1070c2c66affSColin Finck rgb += 3;
1071c2c66affSColin Finck }
1072c2c66affSColin Finck }
1073c2c66affSColin Finck
1074c2c66affSColin Finck static void
Luv24fromXYZ(LogLuvState * sp,uint8 * op,tmsize_t n)1075c2c66affSColin Finck Luv24fromXYZ(LogLuvState* sp, uint8* op, tmsize_t n)
1076c2c66affSColin Finck {
1077c2c66affSColin Finck uint32* luv = (uint32*) sp->tbuf;
1078c2c66affSColin Finck float* xyz = (float*) op;
1079c2c66affSColin Finck
1080c2c66affSColin Finck while (n-- > 0) {
1081c2c66affSColin Finck *luv++ = LogLuv24fromXYZ(xyz, sp->encode_meth);
1082c2c66affSColin Finck xyz += 3;
1083c2c66affSColin Finck }
1084c2c66affSColin Finck }
1085c2c66affSColin Finck
1086c2c66affSColin Finck static void
Luv24fromLuv48(LogLuvState * sp,uint8 * op,tmsize_t n)1087c2c66affSColin Finck Luv24fromLuv48(LogLuvState* sp, uint8* op, tmsize_t n)
1088c2c66affSColin Finck {
1089c2c66affSColin Finck uint32* luv = (uint32*) sp->tbuf;
1090c2c66affSColin Finck int16* luv3 = (int16*) op;
1091c2c66affSColin Finck
1092c2c66affSColin Finck while (n-- > 0) {
1093c2c66affSColin Finck int Le, Ce;
1094c2c66affSColin Finck
1095c2c66affSColin Finck if (luv3[0] <= 0)
1096c2c66affSColin Finck Le = 0;
1097c2c66affSColin Finck else if (luv3[0] >= (1<<12)+3314)
1098c2c66affSColin Finck Le = (1<<10) - 1;
1099c2c66affSColin Finck else if (sp->encode_meth == SGILOGENCODE_NODITHER)
1100c2c66affSColin Finck Le = (luv3[0]-3314) >> 2;
1101c2c66affSColin Finck else
1102c2c66affSColin Finck Le = itrunc(.25*(luv3[0]-3314.), sp->encode_meth);
1103c2c66affSColin Finck
1104c2c66affSColin Finck Ce = uv_encode((luv3[1]+.5)/(1<<15), (luv3[2]+.5)/(1<<15),
1105c2c66affSColin Finck sp->encode_meth);
1106c2c66affSColin Finck if (Ce < 0) /* never happens */
1107c2c66affSColin Finck Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER);
1108c2c66affSColin Finck *luv++ = (uint32)Le << 14 | Ce;
1109c2c66affSColin Finck luv3 += 3;
1110c2c66affSColin Finck }
1111c2c66affSColin Finck }
1112c2c66affSColin Finck
1113c2c66affSColin Finck #if !LOGLUV_PUBLIC
1114c2c66affSColin Finck static
1115c2c66affSColin Finck #endif
1116c2c66affSColin Finck void
LogLuv32toXYZ(uint32 p,float XYZ[3])1117c2c66affSColin Finck LogLuv32toXYZ(uint32 p, float XYZ[3])
1118c2c66affSColin Finck {
1119c2c66affSColin Finck double L, u, v, s, x, y;
1120c2c66affSColin Finck /* decode luminance */
1121c2c66affSColin Finck L = LogL16toY((int)p >> 16);
1122c2c66affSColin Finck if (L <= 0.) {
1123c2c66affSColin Finck XYZ[0] = XYZ[1] = XYZ[2] = 0.;
1124c2c66affSColin Finck return;
1125c2c66affSColin Finck }
1126c2c66affSColin Finck /* decode color */
1127c2c66affSColin Finck u = 1./UVSCALE * ((p>>8 & 0xff) + .5);
1128c2c66affSColin Finck v = 1./UVSCALE * ((p & 0xff) + .5);
1129c2c66affSColin Finck s = 1./(6.*u - 16.*v + 12.);
1130c2c66affSColin Finck x = 9.*u * s;
1131c2c66affSColin Finck y = 4.*v * s;
1132c2c66affSColin Finck /* convert to XYZ */
1133c2c66affSColin Finck XYZ[0] = (float)(x/y * L);
1134c2c66affSColin Finck XYZ[1] = (float)L;
1135c2c66affSColin Finck XYZ[2] = (float)((1.-x-y)/y * L);
1136c2c66affSColin Finck }
1137c2c66affSColin Finck
1138c2c66affSColin Finck #if !LOGLUV_PUBLIC
1139c2c66affSColin Finck static
1140c2c66affSColin Finck #endif
1141c2c66affSColin Finck uint32
LogLuv32fromXYZ(float XYZ[3],int em)1142c2c66affSColin Finck LogLuv32fromXYZ(float XYZ[3], int em)
1143c2c66affSColin Finck {
1144c2c66affSColin Finck unsigned int Le, ue, ve;
1145c2c66affSColin Finck double u, v, s;
1146c2c66affSColin Finck /* encode luminance */
1147c2c66affSColin Finck Le = (unsigned int)LogL16fromY(XYZ[1], em);
1148c2c66affSColin Finck /* encode color */
1149c2c66affSColin Finck s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2];
1150c2c66affSColin Finck if (!Le || s <= 0.) {
1151c2c66affSColin Finck u = U_NEU;
1152c2c66affSColin Finck v = V_NEU;
1153c2c66affSColin Finck } else {
1154c2c66affSColin Finck u = 4.*XYZ[0] / s;
1155c2c66affSColin Finck v = 9.*XYZ[1] / s;
1156c2c66affSColin Finck }
1157c2c66affSColin Finck if (u <= 0.) ue = 0;
1158c2c66affSColin Finck else ue = itrunc(UVSCALE*u, em);
1159c2c66affSColin Finck if (ue > 255) ue = 255;
1160c2c66affSColin Finck if (v <= 0.) ve = 0;
1161c2c66affSColin Finck else ve = itrunc(UVSCALE*v, em);
1162c2c66affSColin Finck if (ve > 255) ve = 255;
1163c2c66affSColin Finck /* combine encodings */
1164c2c66affSColin Finck return (Le << 16 | ue << 8 | ve);
1165c2c66affSColin Finck }
1166c2c66affSColin Finck
1167c2c66affSColin Finck static void
Luv32toXYZ(LogLuvState * sp,uint8 * op,tmsize_t n)1168c2c66affSColin Finck Luv32toXYZ(LogLuvState* sp, uint8* op, tmsize_t n)
1169c2c66affSColin Finck {
1170c2c66affSColin Finck uint32* luv = (uint32*) sp->tbuf;
1171c2c66affSColin Finck float* xyz = (float*) op;
1172c2c66affSColin Finck
1173c2c66affSColin Finck while (n-- > 0) {
1174c2c66affSColin Finck LogLuv32toXYZ(*luv++, xyz);
1175c2c66affSColin Finck xyz += 3;
1176c2c66affSColin Finck }
1177c2c66affSColin Finck }
1178c2c66affSColin Finck
1179c2c66affSColin Finck static void
Luv32toLuv48(LogLuvState * sp,uint8 * op,tmsize_t n)1180c2c66affSColin Finck Luv32toLuv48(LogLuvState* sp, uint8* op, tmsize_t n)
1181c2c66affSColin Finck {
1182c2c66affSColin Finck uint32* luv = (uint32*) sp->tbuf;
1183c2c66affSColin Finck int16* luv3 = (int16*) op;
1184c2c66affSColin Finck
1185c2c66affSColin Finck while (n-- > 0) {
1186c2c66affSColin Finck double u, v;
1187c2c66affSColin Finck
1188c2c66affSColin Finck *luv3++ = (int16)(*luv >> 16);
1189c2c66affSColin Finck u = 1./UVSCALE * ((*luv>>8 & 0xff) + .5);
1190c2c66affSColin Finck v = 1./UVSCALE * ((*luv & 0xff) + .5);
1191c2c66affSColin Finck *luv3++ = (int16)(u * (1L<<15));
1192c2c66affSColin Finck *luv3++ = (int16)(v * (1L<<15));
1193c2c66affSColin Finck luv++;
1194c2c66affSColin Finck }
1195c2c66affSColin Finck }
1196c2c66affSColin Finck
1197c2c66affSColin Finck static void
Luv32toRGB(LogLuvState * sp,uint8 * op,tmsize_t n)1198c2c66affSColin Finck Luv32toRGB(LogLuvState* sp, uint8* op, tmsize_t n)
1199c2c66affSColin Finck {
1200c2c66affSColin Finck uint32* luv = (uint32*) sp->tbuf;
1201c2c66affSColin Finck uint8* rgb = (uint8*) op;
1202c2c66affSColin Finck
1203c2c66affSColin Finck while (n-- > 0) {
1204c2c66affSColin Finck float xyz[3];
1205c2c66affSColin Finck
1206c2c66affSColin Finck LogLuv32toXYZ(*luv++, xyz);
1207c2c66affSColin Finck XYZtoRGB24(xyz, rgb);
1208c2c66affSColin Finck rgb += 3;
1209c2c66affSColin Finck }
1210c2c66affSColin Finck }
1211c2c66affSColin Finck
1212c2c66affSColin Finck static void
Luv32fromXYZ(LogLuvState * sp,uint8 * op,tmsize_t n)1213c2c66affSColin Finck Luv32fromXYZ(LogLuvState* sp, uint8* op, tmsize_t n)
1214c2c66affSColin Finck {
1215c2c66affSColin Finck uint32* luv = (uint32*) sp->tbuf;
1216c2c66affSColin Finck float* xyz = (float*) op;
1217c2c66affSColin Finck
1218c2c66affSColin Finck while (n-- > 0) {
1219c2c66affSColin Finck *luv++ = LogLuv32fromXYZ(xyz, sp->encode_meth);
1220c2c66affSColin Finck xyz += 3;
1221c2c66affSColin Finck }
1222c2c66affSColin Finck }
1223c2c66affSColin Finck
1224c2c66affSColin Finck static void
Luv32fromLuv48(LogLuvState * sp,uint8 * op,tmsize_t n)1225c2c66affSColin Finck Luv32fromLuv48(LogLuvState* sp, uint8* op, tmsize_t n)
1226c2c66affSColin Finck {
1227c2c66affSColin Finck uint32* luv = (uint32*) sp->tbuf;
1228c2c66affSColin Finck int16* luv3 = (int16*) op;
1229c2c66affSColin Finck
1230c2c66affSColin Finck if (sp->encode_meth == SGILOGENCODE_NODITHER) {
1231c2c66affSColin Finck while (n-- > 0) {
1232c2c66affSColin Finck *luv++ = (uint32)luv3[0] << 16 |
1233c2c66affSColin Finck (luv3[1]*(uint32)(UVSCALE+.5) >> 7 & 0xff00) |
1234c2c66affSColin Finck (luv3[2]*(uint32)(UVSCALE+.5) >> 15 & 0xff);
1235c2c66affSColin Finck luv3 += 3;
1236c2c66affSColin Finck }
1237c2c66affSColin Finck return;
1238c2c66affSColin Finck }
1239c2c66affSColin Finck while (n-- > 0) {
1240c2c66affSColin Finck *luv++ = (uint32)luv3[0] << 16 |
1241c2c66affSColin Finck (itrunc(luv3[1]*(UVSCALE/(1<<15)), sp->encode_meth) << 8 & 0xff00) |
1242c2c66affSColin Finck (itrunc(luv3[2]*(UVSCALE/(1<<15)), sp->encode_meth) & 0xff);
1243c2c66affSColin Finck luv3 += 3;
1244c2c66affSColin Finck }
1245c2c66affSColin Finck }
1246c2c66affSColin Finck
1247c2c66affSColin Finck static void
_logLuvNop(LogLuvState * sp,uint8 * op,tmsize_t n)1248c2c66affSColin Finck _logLuvNop(LogLuvState* sp, uint8* op, tmsize_t n)
1249c2c66affSColin Finck {
1250c2c66affSColin Finck (void) sp; (void) op; (void) n;
1251c2c66affSColin Finck }
1252c2c66affSColin Finck
1253c2c66affSColin Finck static int
LogL16GuessDataFmt(TIFFDirectory * td)1254c2c66affSColin Finck LogL16GuessDataFmt(TIFFDirectory *td)
1255c2c66affSColin Finck {
1256c2c66affSColin Finck #define PACK(s,b,f) (((b)<<6)|((s)<<3)|(f))
1257c2c66affSColin Finck switch (PACK(td->td_samplesperpixel, td->td_bitspersample, td->td_sampleformat)) {
1258c2c66affSColin Finck case PACK(1, 32, SAMPLEFORMAT_IEEEFP):
1259c2c66affSColin Finck return (SGILOGDATAFMT_FLOAT);
1260c2c66affSColin Finck case PACK(1, 16, SAMPLEFORMAT_VOID):
1261c2c66affSColin Finck case PACK(1, 16, SAMPLEFORMAT_INT):
1262c2c66affSColin Finck case PACK(1, 16, SAMPLEFORMAT_UINT):
1263c2c66affSColin Finck return (SGILOGDATAFMT_16BIT);
1264c2c66affSColin Finck case PACK(1, 8, SAMPLEFORMAT_VOID):
1265c2c66affSColin Finck case PACK(1, 8, SAMPLEFORMAT_UINT):
1266c2c66affSColin Finck return (SGILOGDATAFMT_8BIT);
1267c2c66affSColin Finck }
1268c2c66affSColin Finck #undef PACK
1269c2c66affSColin Finck return (SGILOGDATAFMT_UNKNOWN);
1270c2c66affSColin Finck }
1271c2c66affSColin Finck
1272c2c66affSColin Finck static tmsize_t
multiply_ms(tmsize_t m1,tmsize_t m2)1273c2c66affSColin Finck multiply_ms(tmsize_t m1, tmsize_t m2)
1274c2c66affSColin Finck {
1275*f87faf67SThomas Faber return _TIFFMultiplySSize(NULL, m1, m2, NULL);
1276c2c66affSColin Finck }
1277c2c66affSColin Finck
1278c2c66affSColin Finck static int
LogL16InitState(TIFF * tif)1279c2c66affSColin Finck LogL16InitState(TIFF* tif)
1280c2c66affSColin Finck {
1281c2c66affSColin Finck static const char module[] = "LogL16InitState";
1282c2c66affSColin Finck TIFFDirectory *td = &tif->tif_dir;
1283c2c66affSColin Finck LogLuvState* sp = DecoderState(tif);
1284c2c66affSColin Finck
1285c2c66affSColin Finck assert(sp != NULL);
1286c2c66affSColin Finck assert(td->td_photometric == PHOTOMETRIC_LOGL);
1287c2c66affSColin Finck
1288c2c66affSColin Finck if( td->td_samplesperpixel != 1 )
1289c2c66affSColin Finck {
1290c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
1291c2c66affSColin Finck "Sorry, can not handle LogL image with %s=%d",
1292c2c66affSColin Finck "Samples/pixel", td->td_samplesperpixel);
1293c2c66affSColin Finck return 0;
1294c2c66affSColin Finck }
1295c2c66affSColin Finck
1296c2c66affSColin Finck /* for some reason, we can't do this in TIFFInitLogL16 */
1297c2c66affSColin Finck if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN)
1298c2c66affSColin Finck sp->user_datafmt = LogL16GuessDataFmt(td);
1299c2c66affSColin Finck switch (sp->user_datafmt) {
1300c2c66affSColin Finck case SGILOGDATAFMT_FLOAT:
1301c2c66affSColin Finck sp->pixel_size = sizeof (float);
1302c2c66affSColin Finck break;
1303c2c66affSColin Finck case SGILOGDATAFMT_16BIT:
1304c2c66affSColin Finck sp->pixel_size = sizeof (int16);
1305c2c66affSColin Finck break;
1306c2c66affSColin Finck case SGILOGDATAFMT_8BIT:
1307c2c66affSColin Finck sp->pixel_size = sizeof (uint8);
1308c2c66affSColin Finck break;
1309c2c66affSColin Finck default:
1310c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
1311c2c66affSColin Finck "No support for converting user data format to LogL");
1312c2c66affSColin Finck return (0);
1313c2c66affSColin Finck }
1314c2c66affSColin Finck if( isTiled(tif) )
1315c2c66affSColin Finck sp->tbuflen = multiply_ms(td->td_tilewidth, td->td_tilelength);
1316f46b177eSThomas Faber else if( td->td_rowsperstrip < td->td_imagelength )
1317c2c66affSColin Finck sp->tbuflen = multiply_ms(td->td_imagewidth, td->td_rowsperstrip);
1318c2c66affSColin Finck else
1319c2c66affSColin Finck sp->tbuflen = multiply_ms(td->td_imagewidth, td->td_imagelength);
1320c2c66affSColin Finck if (multiply_ms(sp->tbuflen, sizeof (int16)) == 0 ||
1321c2c66affSColin Finck (sp->tbuf = (uint8*) _TIFFmalloc(sp->tbuflen * sizeof (int16))) == NULL) {
1322c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module, "No space for SGILog translation buffer");
1323c2c66affSColin Finck return (0);
1324c2c66affSColin Finck }
1325c2c66affSColin Finck return (1);
1326c2c66affSColin Finck }
1327c2c66affSColin Finck
1328c2c66affSColin Finck static int
LogLuvGuessDataFmt(TIFFDirectory * td)1329c2c66affSColin Finck LogLuvGuessDataFmt(TIFFDirectory *td)
1330c2c66affSColin Finck {
1331c2c66affSColin Finck int guess;
1332c2c66affSColin Finck
1333c2c66affSColin Finck /*
1334c2c66affSColin Finck * If the user didn't tell us their datafmt,
1335c2c66affSColin Finck * take our best guess from the bitspersample.
1336c2c66affSColin Finck */
1337c2c66affSColin Finck #define PACK(a,b) (((a)<<3)|(b))
1338c2c66affSColin Finck switch (PACK(td->td_bitspersample, td->td_sampleformat)) {
1339c2c66affSColin Finck case PACK(32, SAMPLEFORMAT_IEEEFP):
1340c2c66affSColin Finck guess = SGILOGDATAFMT_FLOAT;
1341c2c66affSColin Finck break;
1342c2c66affSColin Finck case PACK(32, SAMPLEFORMAT_VOID):
1343c2c66affSColin Finck case PACK(32, SAMPLEFORMAT_UINT):
1344c2c66affSColin Finck case PACK(32, SAMPLEFORMAT_INT):
1345c2c66affSColin Finck guess = SGILOGDATAFMT_RAW;
1346c2c66affSColin Finck break;
1347c2c66affSColin Finck case PACK(16, SAMPLEFORMAT_VOID):
1348c2c66affSColin Finck case PACK(16, SAMPLEFORMAT_INT):
1349c2c66affSColin Finck case PACK(16, SAMPLEFORMAT_UINT):
1350c2c66affSColin Finck guess = SGILOGDATAFMT_16BIT;
1351c2c66affSColin Finck break;
1352c2c66affSColin Finck case PACK( 8, SAMPLEFORMAT_VOID):
1353c2c66affSColin Finck case PACK( 8, SAMPLEFORMAT_UINT):
1354c2c66affSColin Finck guess = SGILOGDATAFMT_8BIT;
1355c2c66affSColin Finck break;
1356c2c66affSColin Finck default:
1357c2c66affSColin Finck guess = SGILOGDATAFMT_UNKNOWN;
1358c2c66affSColin Finck break;
1359c2c66affSColin Finck #undef PACK
1360c2c66affSColin Finck }
1361c2c66affSColin Finck /*
1362c2c66affSColin Finck * Double-check samples per pixel.
1363c2c66affSColin Finck */
1364c2c66affSColin Finck switch (td->td_samplesperpixel) {
1365c2c66affSColin Finck case 1:
1366c2c66affSColin Finck if (guess != SGILOGDATAFMT_RAW)
1367c2c66affSColin Finck guess = SGILOGDATAFMT_UNKNOWN;
1368c2c66affSColin Finck break;
1369c2c66affSColin Finck case 3:
1370c2c66affSColin Finck if (guess == SGILOGDATAFMT_RAW)
1371c2c66affSColin Finck guess = SGILOGDATAFMT_UNKNOWN;
1372c2c66affSColin Finck break;
1373c2c66affSColin Finck default:
1374c2c66affSColin Finck guess = SGILOGDATAFMT_UNKNOWN;
1375c2c66affSColin Finck break;
1376c2c66affSColin Finck }
1377c2c66affSColin Finck return (guess);
1378c2c66affSColin Finck }
1379c2c66affSColin Finck
1380c2c66affSColin Finck static int
LogLuvInitState(TIFF * tif)1381c2c66affSColin Finck LogLuvInitState(TIFF* tif)
1382c2c66affSColin Finck {
1383c2c66affSColin Finck static const char module[] = "LogLuvInitState";
1384c2c66affSColin Finck TIFFDirectory* td = &tif->tif_dir;
1385c2c66affSColin Finck LogLuvState* sp = DecoderState(tif);
1386c2c66affSColin Finck
1387c2c66affSColin Finck assert(sp != NULL);
1388c2c66affSColin Finck assert(td->td_photometric == PHOTOMETRIC_LOGLUV);
1389c2c66affSColin Finck
1390c2c66affSColin Finck /* for some reason, we can't do this in TIFFInitLogLuv */
1391c2c66affSColin Finck if (td->td_planarconfig != PLANARCONFIG_CONTIG) {
1392c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
1393c2c66affSColin Finck "SGILog compression cannot handle non-contiguous data");
1394c2c66affSColin Finck return (0);
1395c2c66affSColin Finck }
1396c2c66affSColin Finck if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN)
1397c2c66affSColin Finck sp->user_datafmt = LogLuvGuessDataFmt(td);
1398c2c66affSColin Finck switch (sp->user_datafmt) {
1399c2c66affSColin Finck case SGILOGDATAFMT_FLOAT:
1400c2c66affSColin Finck sp->pixel_size = 3*sizeof (float);
1401c2c66affSColin Finck break;
1402c2c66affSColin Finck case SGILOGDATAFMT_16BIT:
1403c2c66affSColin Finck sp->pixel_size = 3*sizeof (int16);
1404c2c66affSColin Finck break;
1405c2c66affSColin Finck case SGILOGDATAFMT_RAW:
1406c2c66affSColin Finck sp->pixel_size = sizeof (uint32);
1407c2c66affSColin Finck break;
1408c2c66affSColin Finck case SGILOGDATAFMT_8BIT:
1409c2c66affSColin Finck sp->pixel_size = 3*sizeof (uint8);
1410c2c66affSColin Finck break;
1411c2c66affSColin Finck default:
1412c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
1413c2c66affSColin Finck "No support for converting user data format to LogLuv");
1414c2c66affSColin Finck return (0);
1415c2c66affSColin Finck }
1416c2c66affSColin Finck if( isTiled(tif) )
1417c2c66affSColin Finck sp->tbuflen = multiply_ms(td->td_tilewidth, td->td_tilelength);
1418f46b177eSThomas Faber else if( td->td_rowsperstrip < td->td_imagelength )
1419c2c66affSColin Finck sp->tbuflen = multiply_ms(td->td_imagewidth, td->td_rowsperstrip);
1420f46b177eSThomas Faber else
1421f46b177eSThomas Faber sp->tbuflen = multiply_ms(td->td_imagewidth, td->td_imagelength);
1422c2c66affSColin Finck if (multiply_ms(sp->tbuflen, sizeof (uint32)) == 0 ||
1423c2c66affSColin Finck (sp->tbuf = (uint8*) _TIFFmalloc(sp->tbuflen * sizeof (uint32))) == NULL) {
1424c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module, "No space for SGILog translation buffer");
1425c2c66affSColin Finck return (0);
1426c2c66affSColin Finck }
1427c2c66affSColin Finck return (1);
1428c2c66affSColin Finck }
1429c2c66affSColin Finck
1430c2c66affSColin Finck static int
LogLuvFixupTags(TIFF * tif)1431c2c66affSColin Finck LogLuvFixupTags(TIFF* tif)
1432c2c66affSColin Finck {
1433c2c66affSColin Finck (void) tif;
1434c2c66affSColin Finck return (1);
1435c2c66affSColin Finck }
1436c2c66affSColin Finck
1437c2c66affSColin Finck static int
LogLuvSetupDecode(TIFF * tif)1438c2c66affSColin Finck LogLuvSetupDecode(TIFF* tif)
1439c2c66affSColin Finck {
1440c2c66affSColin Finck static const char module[] = "LogLuvSetupDecode";
1441c2c66affSColin Finck LogLuvState* sp = DecoderState(tif);
1442c2c66affSColin Finck TIFFDirectory* td = &tif->tif_dir;
1443c2c66affSColin Finck
1444c2c66affSColin Finck tif->tif_postdecode = _TIFFNoPostDecode;
1445c2c66affSColin Finck switch (td->td_photometric) {
1446c2c66affSColin Finck case PHOTOMETRIC_LOGLUV:
1447c2c66affSColin Finck if (!LogLuvInitState(tif))
1448c2c66affSColin Finck break;
1449c2c66affSColin Finck if (td->td_compression == COMPRESSION_SGILOG24) {
1450c2c66affSColin Finck tif->tif_decoderow = LogLuvDecode24;
1451c2c66affSColin Finck switch (sp->user_datafmt) {
1452c2c66affSColin Finck case SGILOGDATAFMT_FLOAT:
1453c2c66affSColin Finck sp->tfunc = Luv24toXYZ;
1454c2c66affSColin Finck break;
1455c2c66affSColin Finck case SGILOGDATAFMT_16BIT:
1456c2c66affSColin Finck sp->tfunc = Luv24toLuv48;
1457c2c66affSColin Finck break;
1458c2c66affSColin Finck case SGILOGDATAFMT_8BIT:
1459c2c66affSColin Finck sp->tfunc = Luv24toRGB;
1460c2c66affSColin Finck break;
1461c2c66affSColin Finck }
1462c2c66affSColin Finck } else {
1463c2c66affSColin Finck tif->tif_decoderow = LogLuvDecode32;
1464c2c66affSColin Finck switch (sp->user_datafmt) {
1465c2c66affSColin Finck case SGILOGDATAFMT_FLOAT:
1466c2c66affSColin Finck sp->tfunc = Luv32toXYZ;
1467c2c66affSColin Finck break;
1468c2c66affSColin Finck case SGILOGDATAFMT_16BIT:
1469c2c66affSColin Finck sp->tfunc = Luv32toLuv48;
1470c2c66affSColin Finck break;
1471c2c66affSColin Finck case SGILOGDATAFMT_8BIT:
1472c2c66affSColin Finck sp->tfunc = Luv32toRGB;
1473c2c66affSColin Finck break;
1474c2c66affSColin Finck }
1475c2c66affSColin Finck }
1476c2c66affSColin Finck return (1);
1477c2c66affSColin Finck case PHOTOMETRIC_LOGL:
1478c2c66affSColin Finck if (!LogL16InitState(tif))
1479c2c66affSColin Finck break;
1480c2c66affSColin Finck tif->tif_decoderow = LogL16Decode;
1481c2c66affSColin Finck switch (sp->user_datafmt) {
1482c2c66affSColin Finck case SGILOGDATAFMT_FLOAT:
1483c2c66affSColin Finck sp->tfunc = L16toY;
1484c2c66affSColin Finck break;
1485c2c66affSColin Finck case SGILOGDATAFMT_8BIT:
1486c2c66affSColin Finck sp->tfunc = L16toGry;
1487c2c66affSColin Finck break;
1488c2c66affSColin Finck }
1489c2c66affSColin Finck return (1);
1490c2c66affSColin Finck default:
1491c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
1492c2c66affSColin Finck "Inappropriate photometric interpretation %d for SGILog compression; %s",
1493c2c66affSColin Finck td->td_photometric, "must be either LogLUV or LogL");
1494c2c66affSColin Finck break;
1495c2c66affSColin Finck }
1496c2c66affSColin Finck return (0);
1497c2c66affSColin Finck }
1498c2c66affSColin Finck
1499c2c66affSColin Finck static int
LogLuvSetupEncode(TIFF * tif)1500c2c66affSColin Finck LogLuvSetupEncode(TIFF* tif)
1501c2c66affSColin Finck {
1502c2c66affSColin Finck static const char module[] = "LogLuvSetupEncode";
1503c2c66affSColin Finck LogLuvState* sp = EncoderState(tif);
1504c2c66affSColin Finck TIFFDirectory* td = &tif->tif_dir;
1505c2c66affSColin Finck
1506c2c66affSColin Finck switch (td->td_photometric) {
1507c2c66affSColin Finck case PHOTOMETRIC_LOGLUV:
1508c2c66affSColin Finck if (!LogLuvInitState(tif))
1509*f87faf67SThomas Faber return (0);
1510c2c66affSColin Finck if (td->td_compression == COMPRESSION_SGILOG24) {
1511c2c66affSColin Finck tif->tif_encoderow = LogLuvEncode24;
1512c2c66affSColin Finck switch (sp->user_datafmt) {
1513c2c66affSColin Finck case SGILOGDATAFMT_FLOAT:
1514c2c66affSColin Finck sp->tfunc = Luv24fromXYZ;
1515c2c66affSColin Finck break;
1516c2c66affSColin Finck case SGILOGDATAFMT_16BIT:
1517c2c66affSColin Finck sp->tfunc = Luv24fromLuv48;
1518c2c66affSColin Finck break;
1519c2c66affSColin Finck case SGILOGDATAFMT_RAW:
1520c2c66affSColin Finck break;
1521c2c66affSColin Finck default:
1522c2c66affSColin Finck goto notsupported;
1523c2c66affSColin Finck }
1524c2c66affSColin Finck } else {
1525c2c66affSColin Finck tif->tif_encoderow = LogLuvEncode32;
1526c2c66affSColin Finck switch (sp->user_datafmt) {
1527c2c66affSColin Finck case SGILOGDATAFMT_FLOAT:
1528c2c66affSColin Finck sp->tfunc = Luv32fromXYZ;
1529c2c66affSColin Finck break;
1530c2c66affSColin Finck case SGILOGDATAFMT_16BIT:
1531c2c66affSColin Finck sp->tfunc = Luv32fromLuv48;
1532c2c66affSColin Finck break;
1533c2c66affSColin Finck case SGILOGDATAFMT_RAW:
1534c2c66affSColin Finck break;
1535c2c66affSColin Finck default:
1536c2c66affSColin Finck goto notsupported;
1537c2c66affSColin Finck }
1538c2c66affSColin Finck }
1539c2c66affSColin Finck break;
1540c2c66affSColin Finck case PHOTOMETRIC_LOGL:
1541c2c66affSColin Finck if (!LogL16InitState(tif))
1542*f87faf67SThomas Faber return (0);
1543c2c66affSColin Finck tif->tif_encoderow = LogL16Encode;
1544c2c66affSColin Finck switch (sp->user_datafmt) {
1545c2c66affSColin Finck case SGILOGDATAFMT_FLOAT:
1546c2c66affSColin Finck sp->tfunc = L16fromY;
1547c2c66affSColin Finck break;
1548c2c66affSColin Finck case SGILOGDATAFMT_16BIT:
1549c2c66affSColin Finck break;
1550c2c66affSColin Finck default:
1551c2c66affSColin Finck goto notsupported;
1552c2c66affSColin Finck }
1553c2c66affSColin Finck break;
1554c2c66affSColin Finck default:
1555c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
1556c2c66affSColin Finck "Inappropriate photometric interpretation %d for SGILog compression; %s",
1557c2c66affSColin Finck td->td_photometric, "must be either LogLUV or LogL");
1558*f87faf67SThomas Faber return (0);
1559c2c66affSColin Finck }
1560c2c66affSColin Finck sp->encoder_state = 1;
1561c2c66affSColin Finck return (1);
1562c2c66affSColin Finck notsupported:
1563c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
1564c2c66affSColin Finck "SGILog compression supported only for %s, or raw data",
1565c2c66affSColin Finck td->td_photometric == PHOTOMETRIC_LOGL ? "Y, L" : "XYZ, Luv");
1566c2c66affSColin Finck return (0);
1567c2c66affSColin Finck }
1568c2c66affSColin Finck
1569c2c66affSColin Finck static void
LogLuvClose(TIFF * tif)1570c2c66affSColin Finck LogLuvClose(TIFF* tif)
1571c2c66affSColin Finck {
1572c2c66affSColin Finck LogLuvState* sp = (LogLuvState*) tif->tif_data;
1573c2c66affSColin Finck TIFFDirectory *td = &tif->tif_dir;
1574c2c66affSColin Finck
1575c2c66affSColin Finck assert(sp != 0);
1576c2c66affSColin Finck /*
1577c2c66affSColin Finck * For consistency, we always want to write out the same
1578c2c66affSColin Finck * bitspersample and sampleformat for our TIFF file,
1579c2c66affSColin Finck * regardless of the data format being used by the application.
1580c2c66affSColin Finck * Since this routine is called after tags have been set but
1581c2c66affSColin Finck * before they have been recorded in the file, we reset them here.
1582c2c66affSColin Finck * Note: this is really a nasty approach. See PixarLogClose
1583c2c66affSColin Finck */
1584c2c66affSColin Finck if( sp->encoder_state )
1585c2c66affSColin Finck {
1586c2c66affSColin Finck /* See PixarLogClose. Might avoid issues with tags whose size depends
1587c2c66affSColin Finck * on those below, but not completely sure this is enough. */
1588c2c66affSColin Finck td->td_samplesperpixel =
1589c2c66affSColin Finck (td->td_photometric == PHOTOMETRIC_LOGL) ? 1 : 3;
1590c2c66affSColin Finck td->td_bitspersample = 16;
1591c2c66affSColin Finck td->td_sampleformat = SAMPLEFORMAT_INT;
1592c2c66affSColin Finck }
1593c2c66affSColin Finck }
1594c2c66affSColin Finck
1595c2c66affSColin Finck static void
LogLuvCleanup(TIFF * tif)1596c2c66affSColin Finck LogLuvCleanup(TIFF* tif)
1597c2c66affSColin Finck {
1598c2c66affSColin Finck LogLuvState* sp = (LogLuvState *)tif->tif_data;
1599c2c66affSColin Finck
1600c2c66affSColin Finck assert(sp != 0);
1601c2c66affSColin Finck
1602c2c66affSColin Finck tif->tif_tagmethods.vgetfield = sp->vgetparent;
1603c2c66affSColin Finck tif->tif_tagmethods.vsetfield = sp->vsetparent;
1604c2c66affSColin Finck
1605c2c66affSColin Finck if (sp->tbuf)
1606c2c66affSColin Finck _TIFFfree(sp->tbuf);
1607c2c66affSColin Finck _TIFFfree(sp);
1608c2c66affSColin Finck tif->tif_data = NULL;
1609c2c66affSColin Finck
1610c2c66affSColin Finck _TIFFSetDefaultCompressionState(tif);
1611c2c66affSColin Finck }
1612c2c66affSColin Finck
1613c2c66affSColin Finck static int
LogLuvVSetField(TIFF * tif,uint32 tag,va_list ap)1614c2c66affSColin Finck LogLuvVSetField(TIFF* tif, uint32 tag, va_list ap)
1615c2c66affSColin Finck {
1616c2c66affSColin Finck static const char module[] = "LogLuvVSetField";
1617c2c66affSColin Finck LogLuvState* sp = DecoderState(tif);
1618c2c66affSColin Finck int bps, fmt;
1619c2c66affSColin Finck
1620c2c66affSColin Finck switch (tag) {
1621c2c66affSColin Finck case TIFFTAG_SGILOGDATAFMT:
1622c2c66affSColin Finck sp->user_datafmt = (int) va_arg(ap, int);
1623c2c66affSColin Finck /*
1624c2c66affSColin Finck * Tweak the TIFF header so that the rest of libtiff knows what
1625c2c66affSColin Finck * size of data will be passed between app and library, and
1626c2c66affSColin Finck * assume that the app knows what it is doing and is not
1627c2c66affSColin Finck * confused by these header manipulations...
1628c2c66affSColin Finck */
1629c2c66affSColin Finck switch (sp->user_datafmt) {
1630c2c66affSColin Finck case SGILOGDATAFMT_FLOAT:
1631c2c66affSColin Finck bps = 32;
1632c2c66affSColin Finck fmt = SAMPLEFORMAT_IEEEFP;
1633c2c66affSColin Finck break;
1634c2c66affSColin Finck case SGILOGDATAFMT_16BIT:
1635c2c66affSColin Finck bps = 16;
1636c2c66affSColin Finck fmt = SAMPLEFORMAT_INT;
1637c2c66affSColin Finck break;
1638c2c66affSColin Finck case SGILOGDATAFMT_RAW:
1639c2c66affSColin Finck bps = 32;
1640c2c66affSColin Finck fmt = SAMPLEFORMAT_UINT;
1641c2c66affSColin Finck TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
1642c2c66affSColin Finck break;
1643c2c66affSColin Finck case SGILOGDATAFMT_8BIT:
1644c2c66affSColin Finck bps = 8;
1645c2c66affSColin Finck fmt = SAMPLEFORMAT_UINT;
1646c2c66affSColin Finck break;
1647c2c66affSColin Finck default:
1648c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
1649c2c66affSColin Finck "Unknown data format %d for LogLuv compression",
1650c2c66affSColin Finck sp->user_datafmt);
1651c2c66affSColin Finck return (0);
1652c2c66affSColin Finck }
1653c2c66affSColin Finck TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps);
1654c2c66affSColin Finck TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, fmt);
1655c2c66affSColin Finck /*
1656c2c66affSColin Finck * Must recalculate sizes should bits/sample change.
1657c2c66affSColin Finck */
1658c2c66affSColin Finck tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tmsize_t) -1;
1659c2c66affSColin Finck tif->tif_scanlinesize = TIFFScanlineSize(tif);
1660c2c66affSColin Finck return (1);
1661c2c66affSColin Finck case TIFFTAG_SGILOGENCODE:
1662c2c66affSColin Finck sp->encode_meth = (int) va_arg(ap, int);
1663c2c66affSColin Finck if (sp->encode_meth != SGILOGENCODE_NODITHER &&
1664c2c66affSColin Finck sp->encode_meth != SGILOGENCODE_RANDITHER) {
1665c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
1666c2c66affSColin Finck "Unknown encoding %d for LogLuv compression",
1667c2c66affSColin Finck sp->encode_meth);
1668c2c66affSColin Finck return (0);
1669c2c66affSColin Finck }
1670c2c66affSColin Finck return (1);
1671c2c66affSColin Finck default:
1672c2c66affSColin Finck return (*sp->vsetparent)(tif, tag, ap);
1673c2c66affSColin Finck }
1674c2c66affSColin Finck }
1675c2c66affSColin Finck
1676c2c66affSColin Finck static int
LogLuvVGetField(TIFF * tif,uint32 tag,va_list ap)1677c2c66affSColin Finck LogLuvVGetField(TIFF* tif, uint32 tag, va_list ap)
1678c2c66affSColin Finck {
1679c2c66affSColin Finck LogLuvState *sp = (LogLuvState *)tif->tif_data;
1680c2c66affSColin Finck
1681c2c66affSColin Finck switch (tag) {
1682c2c66affSColin Finck case TIFFTAG_SGILOGDATAFMT:
1683c2c66affSColin Finck *va_arg(ap, int*) = sp->user_datafmt;
1684c2c66affSColin Finck return (1);
1685c2c66affSColin Finck default:
1686c2c66affSColin Finck return (*sp->vgetparent)(tif, tag, ap);
1687c2c66affSColin Finck }
1688c2c66affSColin Finck }
1689c2c66affSColin Finck
1690c2c66affSColin Finck static const TIFFField LogLuvFields[] = {
1691c2c66affSColin Finck { TIFFTAG_SGILOGDATAFMT, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "SGILogDataFmt", NULL},
1692c2c66affSColin Finck { TIFFTAG_SGILOGENCODE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "SGILogEncode", NULL}
1693c2c66affSColin Finck };
1694c2c66affSColin Finck
1695c2c66affSColin Finck int
TIFFInitSGILog(TIFF * tif,int scheme)1696c2c66affSColin Finck TIFFInitSGILog(TIFF* tif, int scheme)
1697c2c66affSColin Finck {
1698c2c66affSColin Finck static const char module[] = "TIFFInitSGILog";
1699c2c66affSColin Finck LogLuvState* sp;
1700c2c66affSColin Finck
1701c2c66affSColin Finck assert(scheme == COMPRESSION_SGILOG24 || scheme == COMPRESSION_SGILOG);
1702c2c66affSColin Finck
1703c2c66affSColin Finck /*
1704c2c66affSColin Finck * Merge codec-specific tag information.
1705c2c66affSColin Finck */
1706c2c66affSColin Finck if (!_TIFFMergeFields(tif, LogLuvFields,
1707c2c66affSColin Finck TIFFArrayCount(LogLuvFields))) {
1708c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
1709c2c66affSColin Finck "Merging SGILog codec-specific tags failed");
1710c2c66affSColin Finck return 0;
1711c2c66affSColin Finck }
1712c2c66affSColin Finck
1713c2c66affSColin Finck /*
1714c2c66affSColin Finck * Allocate state block so tag methods have storage to record values.
1715c2c66affSColin Finck */
1716c2c66affSColin Finck tif->tif_data = (uint8*) _TIFFmalloc(sizeof (LogLuvState));
1717c2c66affSColin Finck if (tif->tif_data == NULL)
1718c2c66affSColin Finck goto bad;
1719c2c66affSColin Finck sp = (LogLuvState*) tif->tif_data;
1720c2c66affSColin Finck _TIFFmemset((void*)sp, 0, sizeof (*sp));
1721c2c66affSColin Finck sp->user_datafmt = SGILOGDATAFMT_UNKNOWN;
1722c2c66affSColin Finck sp->encode_meth = (scheme == COMPRESSION_SGILOG24) ?
1723c2c66affSColin Finck SGILOGENCODE_RANDITHER : SGILOGENCODE_NODITHER;
1724c2c66affSColin Finck sp->tfunc = _logLuvNop;
1725c2c66affSColin Finck
1726c2c66affSColin Finck /*
1727c2c66affSColin Finck * Install codec methods.
1728c2c66affSColin Finck * NB: tif_decoderow & tif_encoderow are filled
1729c2c66affSColin Finck * in at setup time.
1730c2c66affSColin Finck */
1731c2c66affSColin Finck tif->tif_fixuptags = LogLuvFixupTags;
1732c2c66affSColin Finck tif->tif_setupdecode = LogLuvSetupDecode;
1733c2c66affSColin Finck tif->tif_decodestrip = LogLuvDecodeStrip;
1734c2c66affSColin Finck tif->tif_decodetile = LogLuvDecodeTile;
1735c2c66affSColin Finck tif->tif_setupencode = LogLuvSetupEncode;
1736c2c66affSColin Finck tif->tif_encodestrip = LogLuvEncodeStrip;
1737c2c66affSColin Finck tif->tif_encodetile = LogLuvEncodeTile;
1738c2c66affSColin Finck tif->tif_close = LogLuvClose;
1739c2c66affSColin Finck tif->tif_cleanup = LogLuvCleanup;
1740c2c66affSColin Finck
1741c2c66affSColin Finck /*
1742c2c66affSColin Finck * Override parent get/set field methods.
1743c2c66affSColin Finck */
1744c2c66affSColin Finck sp->vgetparent = tif->tif_tagmethods.vgetfield;
1745c2c66affSColin Finck tif->tif_tagmethods.vgetfield = LogLuvVGetField; /* hook for codec tags */
1746c2c66affSColin Finck sp->vsetparent = tif->tif_tagmethods.vsetfield;
1747c2c66affSColin Finck tif->tif_tagmethods.vsetfield = LogLuvVSetField; /* hook for codec tags */
1748c2c66affSColin Finck
1749c2c66affSColin Finck return (1);
1750c2c66affSColin Finck bad:
1751c2c66affSColin Finck TIFFErrorExt(tif->tif_clientdata, module,
1752c2c66affSColin Finck "%s: No space for LogLuv state block", tif->tif_name);
1753c2c66affSColin Finck return (0);
1754c2c66affSColin Finck }
1755c2c66affSColin Finck #endif /* LOGLUV_SUPPORT */
1756c2c66affSColin Finck
1757c2c66affSColin Finck /* vim: set ts=8 sts=8 sw=8 noet: */
1758c2c66affSColin Finck /*
1759c2c66affSColin Finck * Local Variables:
1760c2c66affSColin Finck * mode: c
1761c2c66affSColin Finck * c-basic-offset: 8
1762c2c66affSColin Finck * fill-column: 78
1763c2c66affSColin Finck * End:
1764c2c66affSColin Finck */
1765