1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2013 Academy of Motion Picture Arts and Sciences
3 // ("A.M.P.A.S."). Portions contributed by others as indicated.
4 // All rights reserved.
5 //
6 // A worldwide, royalty-free, non-exclusive right to copy, modify, create
7 // derivatives, and use, in source and binary forms, is hereby granted,
8 // subject to acceptance of this license. Performance of any of the
9 // aforementioned acts indicates acceptance to be bound by the following
10 // terms and conditions:
11 //
12 //  * Copies of source code, in whole or in part, must retain the
13 //    above copyright notice, this list of conditions and the
14 //    Disclaimer of Warranty.
15 //
16 //  * Use in binary form must retain the above copyright notice,
17 //    this list of conditions and the Disclaimer of Warranty in the
18 //    documentation and/or other materials provided with the distribution.
19 //
20 //  * Nothing in this license shall be deemed to grant any rights to
21 //    trademarks, copyrights, patents, trade secrets or any other
22 //    intellectual property of A.M.P.A.S. or any contributors, except
23 //    as expressly stated herein.
24 //
25 //  * Neither the name "A.M.P.A.S." nor the name of any other
26 //    contributors to this software may be used to endorse or promote
27 //    products derivative of or based on this software without express
28 //    prior written permission of A.M.P.A.S. or the contributors, as
29 //    appropriate.
30 //
31 // This license shall be construed pursuant to the laws of the State of
32 // California, and any disputes related thereto shall be subject to the
33 // jurisdiction of the courts therein.
34 //
35 // Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND
36 // CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
37 // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
38 // FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO
39 // EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE
40 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY,
41 // OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
42 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
43 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
44 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
46 // THE POSSIBILITY OF SUCH DAMAGE.
47 //
48 // WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY
49 // SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER
50 // RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY
51 // COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER
52 // THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED.
53 ///////////////////////////////////////////////////////////////////////////
54 
55 #include "tiff_file.hh"
56 #include <cstdlib>
57 #include <stdarg.h>
58 #include <dpx.hh>
59 #if defined(HAVE_LIBTIFF)
60 #include <tiff.h>
61 #include <tiffio.h>
62 #include <sys/param.h>
63 #include <math.h>
64 #include <Iex.h>
65 
66 void tiff_read_multiplane(TIFF *t, float scale, ctl::dpx::fb<float> * pixels);
67 void tiff_read_interleaved(TIFF *t, float scale, ctl::dpx::fb<float> * pixels);
68 void tiff_read_failsafe(TIFF *t, float scale, ctl::dpx::fb<float> * pixels);
69 
70 void tiff_interleave_int8(float *row, int offset, float scale,
71                           uint8_t *r, int r_stride, uint8_t *g, int g_stride,
72                           uint8_t *b, int b_stride, uint8_t *a, int a_stride,
73                           uint32_t width);
74 
75 void tiff_interleave_int16(float *row, int offset, float scale,
76                            uint16_t *r, int r_stride, uint16_t *g, int g_stride,
77                            uint16_t *b, int b_stride, uint16_t *a, int a_stride,
78                            uint32_t width);
79 
80 void tiff_interleave_float(float *row, float scale,
81                            float *r, int r_stride, float *g, int g_stride,
82                            float *b, int b_stride, float *a, int a_stride,
83                            uint32_t width);
84 
ErrorHandler(const char * module,const char * fmt,va_list ap)85 void ErrorHandler(const char *module, const char *fmt, va_list ap) {
86 	fprintf(stderr, "Unable to read tiff file: ");
87 	vfprintf(stderr, fmt, ap);
88 }
89 
WarningHandler(const char * module,const char * fmt,va_list ap)90 void WarningHandler(const char *module, const char *fmt, va_list ap) {
91 //	fprintf(stderr, "tiff wrn: %s - ");
92 //	vfprintf(stderr, fmt, ap);
93 }
94 
tiff_read(const char * name,float scale,ctl::dpx::fb<float> * pixels,format_t * format)95 bool tiff_read(const char *name, float scale, ctl::dpx::fb<float> *pixels,
96                format_t *format) {
97 	TIFF *t;
98 	uint16_t samples_per_pixel;
99 	uint16_t bits_per_sample;
100 	uint16_t sample_format;
101 	uint16_t planar_config;
102 	uint16_t photometric;
103 	uint16_t orientation;
104 
105 	TIFFSetErrorHandler(ErrorHandler);
106 	TIFFSetWarningHandler(WarningHandler);
107 
108 	t=TIFFOpen(name, "r");
109 	if(t==NULL) {
110 		// This is set if the file is not a tiff, we just sort of punt.
111 		return FALSE;
112 	}
113 
114 	TIFFGetFieldDefaulted(t, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel);
115 	TIFFGetFieldDefaulted(t, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
116 	format->src_bps=bits_per_sample;
117 	TIFFGetFieldDefaulted(t, TIFFTAG_SAMPLEFORMAT, &sample_format);
118 	TIFFGetFieldDefaulted(t, TIFFTAG_PHOTOMETRIC, &photometric);
119 	TIFFGetFieldDefaulted(t, TIFFTAG_ORIENTATION, &orientation);
120 
121 //	tiff_read_failsafe(t, scale, pixels);
122 //	return TRUE;
123 
124 	if(!(bits_per_sample==16 && sample_format<3) &&
125 	   !(bits_per_sample==32 && sample_format==3) &&
126 	   photometric!=PHOTOMETRIC_RGB &&
127 	   orientation!=ORIENTATION_TOPLEFT &&
128 	   orientation!=ORIENTATION_BOTLEFT) {
129 
130 		if(bits_per_sample!=8) {
131 			fprintf(stderr, "falling back to failsafe TIFF reader. Reading "
132 			        "as \n8 bits per sample RGBA.\n");
133 		}
134 		tiff_read_failsafe(t, scale, pixels);
135 		TIFFClose(t);
136 		return TRUE;
137 	}
138 
139 	TIFFGetField(t, TIFFTAG_PLANARCONFIG, &planar_config);
140 	if(planar_config==PLANARCONFIG_CONTIG) {
141 		tiff_read_interleaved(t, scale, pixels);
142 	} else if(planar_config==PLANARCONFIG_SEPARATE) {
143 		tiff_read_multiplane(t, scale, pixels);
144 	}
145 
146 	TIFFClose(t);
147 
148 	return TRUE;
149 }
150 
tiff_interleave_int8(float * o,int offset,float scale,uint8_t * r,int r_stride,uint8_t * g,int g_stride,uint8_t * b,int b_stride,uint8_t * a,int a_stride,uint32_t width)151 void tiff_interleave_int8(float *o, int offset, float scale,
152                           uint8_t *r, int r_stride, uint8_t *g, int g_stride,
153                           uint8_t *b, int b_stride, uint8_t *a, int a_stride,
154                           uint32_t width) {
155 	uint32_t i;
156 	float f;
157 
158 	if(scale==0) {
159 		scale=255.0;
160 	}
161 
162 	for(i=0; i<width; i++) {
163 		if(r!=NULL) {
164 			f=*r+offset;
165 			r=r+r_stride;
166 			*(o++)=f/scale;
167 		}
168 		if(g!=NULL) {
169 			f=*g+offset;
170 			g=g+g_stride;
171 			*(o++)=f/scale;
172 		}
173 		if(b!=NULL) {
174 			f=*b+offset;
175 			b=b+b_stride;
176 			*(o++)=f/scale;
177 		}
178 		if(a!=NULL) {
179 			f=*a+offset;
180 			a=a+a_stride;
181 			*(o++)=f/scale;
182 		}
183 	}
184 }
185 
186 
tiff_interleave_int16(float * o,uint16_t offset,float scale,uint16_t * r,int r_stride,uint16_t * g,int g_stride,uint16_t * b,int b_stride,uint16_t * a,int a_stride,uint32_t width)187 void tiff_interleave_int16(float *o, uint16_t offset, float scale,
188                            uint16_t *r, int r_stride, uint16_t *g, int g_stride,
189                            uint16_t *b, int b_stride, uint16_t *a, int a_stride,
190                            uint32_t width) {
191 	uint32_t i;
192 	float f;
193 
194 	if(scale==0) {
195 		scale=65535.0;
196 	}
197 
198 	for(i=0; i<width; i++) {
199 		if(r!=NULL) {
200 			f=*r+offset;
201 			r=r+r_stride;
202 			*(o++)=f/scale;
203 		}
204 		if(g!=NULL) {
205 			f=*g+offset;
206 			g=g+g_stride;
207 			*(o++)=f/scale;
208 		}
209 		if(b!=NULL) {
210 			f=*b+offset;
211 			b=b+b_stride;
212 			*(o++)=f/scale;
213 		}
214 		if(a!=NULL) {
215 			f=*a+offset;
216 			a=a+a_stride;
217 			*(o++)=f/scale;
218 		}
219 	}
220 }
221 
tiff_interleave_float(float * o,float scale,float * r,int r_stride,float * g,int g_stride,float * b,int b_stride,float * a,int a_stride,uint32_t width)222 void tiff_interleave_float(float *o, float scale,
223                            float *r, int r_stride, float *g, int g_stride,
224                            float *b, int b_stride, float *a, int a_stride,
225                            uint32_t width) {
226 	uint32_t i;
227 	float f;
228 
229 	if(scale==0) {
230 		scale=1.0;
231 	}
232 
233 	for(i=0; i<width; i++) {
234 		if(r!=NULL) {
235 			f=*r;
236 			r=r+r_stride;
237 			*(o++)=f/scale;
238 		}
239 		if(g!=NULL) {
240 			f=*g;
241 			g=g+g_stride;
242 			*(o++)=f/scale;
243 		}
244 		if(b!=NULL) {
245 			f=*b;
246 			b=b+b_stride;
247 			*(o++)=f/scale;
248 		}
249 		if(a!=NULL) {
250 			f=*a;
251 			a=a+a_stride;
252 			*(o++)=f/scale;
253 		}
254 	}
255 }
256 
tiff_read_multiplane(TIFF * t,float scale,ctl::dpx::fb<float> * pixels)257 void tiff_read_multiplane(TIFF *t, float scale, ctl::dpx::fb<float> * pixels) {
258 	uint8_t *scanline_buffer_uint8[4];
259 	uint16_t *scanline_buffer_uint16[4];
260 	float *scanline_buffer_float[4];
261 	uint16_t samples_per_pixel;
262 	uint16_t bits_per_sample;
263 	uint32_t w;
264 	uint32_t h;
265 	uint16_t sample_format;
266 	uint16_t offset;
267 	uint16_t orientation;
268 	tsize_t scanline_size;
269 	float *row_ptr;
270 	uint32_t row;
271 	uint32_t orientation_offset;
272 	uint16_t d;
273 
274 	TIFFGetFieldDefaulted(t, TIFFTAG_IMAGEWIDTH, &w);
275 	TIFFGetFieldDefaulted(t, TIFFTAG_IMAGELENGTH, &h);
276 	TIFFGetFieldDefaulted(t, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel);
277 	TIFFGetFieldDefaulted(t, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
278 	TIFFGetFieldDefaulted(t, TIFFTAG_SAMPLEFORMAT, &sample_format);
279 	TIFFGetFieldDefaulted(t, TIFFTAG_ORIENTATION, &orientation);
280 
281 	pixels->init(w, h, samples_per_pixel);
282 
283 	orientation_offset=0;
284 	if(orientation==ORIENTATION_LEFTTOP) {
285 		// We only deal with the bottom->top flip, not the other orientation
286 		// modes (the actual check for this is in tiff_read).
287 		orientation_offset=(uint32_t)-h;
288 	}
289 
290 	scanline_size=TIFFScanlineSize(t);
291 	if(bits_per_sample==8) {
292 		for(row=0; row<4; row++) {
293 			if(row<samples_per_pixel) {
294 				scanline_buffer_uint8[row]=(uint8_t *)alloca(scanline_size);
295 				for(d=0; d<w; d++) {
296 					scanline_buffer_uint8[row][d]= row==3 ? 255 : 0;
297 				}
298 			} else {
299 				scanline_buffer_uint8[row]=NULL;
300 			}
301 		}
302 		for(;row<4; row++) {
303 		}
304 		offset=0;
305 		if(sample_format==2) {
306 			offset=1<<7;
307 		}
308 		for(row=0; row<h; row++) {
309 			for(d=0; d<samples_per_pixel; d++) {
310 				TIFFReadScanline(t, scanline_buffer_uint8[d],
311 				                 row+orientation_offset, d);
312 			}
313 			row_ptr=pixels->ptr()+row*pixels->width()*pixels->depth();
314 			tiff_interleave_int8(row_ptr, offset, scale,
315 			                     scanline_buffer_uint8[0], 1,
316 			                     scanline_buffer_uint8[1], 1,
317 			                     scanline_buffer_uint8[2], 1,
318 			                     scanline_buffer_uint8[3], 1,
319 			                     w);
320 		}
321 	} else if(bits_per_sample==16) {
322 		for(row=0; row<4; row++) {
323 			if(row<samples_per_pixel) {
324 				scanline_buffer_uint16[row]=(uint16_t *)alloca(scanline_size);
325 				for(d=0; d<w; d++) {
326 					scanline_buffer_uint16[row][d]= row==3 ? 65535 : 0;
327 				}
328 			} else {
329 				scanline_buffer_uint16[row]=NULL;
330 			}
331 		}
332 		offset=0;
333 		if(sample_format==2) {
334 			offset=1<<15;
335 		}
336 		for(row=0; row<h; row++) {
337 			for(d=0; d<samples_per_pixel; d++) {
338 				TIFFReadScanline(t, scanline_buffer_uint16[d],
339 				                 row+orientation_offset, d);
340 			}
341 			row_ptr=pixels->ptr()+row*pixels->width()*pixels->depth();
342 			tiff_interleave_int16(row_ptr, offset, scale,
343 			                      scanline_buffer_uint16[0], 1,
344 			                      scanline_buffer_uint16[1], 1,
345 			                      scanline_buffer_uint16[2], 1,
346 			                      scanline_buffer_uint16[3], 1,
347 			                      w);
348 		}
349 	} else if(sample_format==3) {
350 		for(row=0; row<4; row++) {
351 			if(row<samples_per_pixel) {
352 				scanline_buffer_float[row]=(float *)alloca(scanline_size);
353 				for(d=0; d<w; d++) {
354 					scanline_buffer_float[row][d]= row==3 ? 1.0 : 0.0;
355 				}
356 			} else {
357 				scanline_buffer_float[row]=NULL;
358 			}
359 		}
360 		for(row=0; row<h; row++) {
361 			for(d=0; d<samples_per_pixel; d++) {
362 				TIFFReadScanline(t, scanline_buffer_float[d],
363 				                 row+orientation_offset, d);
364 			}
365 			row_ptr=pixels->ptr()+row*pixels->width()*pixels->depth();
366 			tiff_interleave_float(row_ptr, scale,
367 			                      scanline_buffer_float[0], 1,
368 			                      scanline_buffer_float[1], 1,
369 			                      scanline_buffer_float[2], 1,
370 			                      scanline_buffer_float[3], 1,
371 			                      w);
372 		}
373 	}
374 }
375 
tiff_read_interleaved(TIFF * t,float scale,ctl::dpx::fb<float> * pixels)376 void tiff_read_interleaved(TIFF *t, float scale, ctl::dpx::fb<float> * pixels) {
377 	uint8_t *scanline_buffer_uint8;
378 	uint16_t *scanline_buffer_uint16;
379 	float *scanline_buffer_float;
380 	uint16_t samples_per_pixel;
381 	uint16_t bits_per_sample;
382 	uint32_t w;
383 	uint32_t h;
384 	uint16_t sample_format;
385 	uint16_t offset;
386 	uint32_t row;
387 	float *row_ptr;
388 
389 	TIFFGetFieldDefaulted(t, TIFFTAG_IMAGEWIDTH, &w);
390 	TIFFGetFieldDefaulted(t, TIFFTAG_IMAGELENGTH, &h);
391 	TIFFGetFieldDefaulted(t, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel);
392 	TIFFGetFieldDefaulted(t, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
393 	TIFFGetFieldDefaulted(t, TIFFTAG_SAMPLEFORMAT, &sample_format);
394 	pixels->init(w, h, samples_per_pixel);
395 
396 	if(bits_per_sample==8) {
397 		scanline_buffer_uint8=(uint8_t *)alloca(TIFFScanlineSize(t));
398 		offset=0;
399 		if(sample_format==2) {
400 			offset=127;
401 		}
402 		for(row=0; row<h; row++) {
403 			TIFFReadScanline(t, scanline_buffer_uint8, row, 0);
404 			row_ptr=pixels->ptr()+row*pixels->width()*pixels->depth();
405 			if(samples_per_pixel==3) {
406 				tiff_interleave_int8(row_ptr, offset, scale,
407 				                     scanline_buffer_uint8+0, 3,
408 				                     scanline_buffer_uint8+1, 3,
409 				                     scanline_buffer_uint8+2, 3,
410 				                     NULL, 0,
411 				                     w);
412 			} else {
413 				tiff_interleave_int8(row_ptr, offset, scale,
414 				                     scanline_buffer_uint8+0, 4,
415 				                     scanline_buffer_uint8+1, 4,
416 				                     scanline_buffer_uint8+2, 4,
417 				                     scanline_buffer_uint8+3, 4,
418 				                     w);
419 			}
420 		}
421 	} else if(bits_per_sample==16) {
422 		scanline_buffer_uint16=(uint16_t *)alloca(TIFFScanlineSize(t));
423 		offset=0;
424 		if(sample_format==2) {
425 			offset=32767;
426 		}
427 		for(row=0; row<h; row++) {
428 			TIFFReadScanline(t, scanline_buffer_uint16, row, 0);
429 			row_ptr=pixels->ptr()+row*pixels->width()*pixels->depth();
430 			if(samples_per_pixel==3) {
431 				tiff_interleave_int16(row_ptr, offset, scale,
432 				                      scanline_buffer_uint16+0, 3,
433 				                      scanline_buffer_uint16+1, 3,
434 				                      scanline_buffer_uint16+2, 3,
435 				                      NULL, 0,
436 				                      w);
437 			} else {
438 				tiff_interleave_int16(row_ptr, offset, scale,
439 				                      scanline_buffer_uint16+0, 4,
440 				                      scanline_buffer_uint16+1, 4,
441 				                      scanline_buffer_uint16+2, 4,
442 				                      scanline_buffer_uint16+3, 4,
443 				                      w);
444 			}
445 		}
446 	} else if(sample_format==3) {
447 		scanline_buffer_float=(float *)alloca(TIFFScanlineSize(t));
448 		for(row=0; row<h; row++) {
449 			TIFFReadScanline(t, scanline_buffer_float, row, 0);
450 			row_ptr=pixels->ptr()+row*pixels->width()*pixels->depth();
451 			if(samples_per_pixel==3) {
452 				tiff_interleave_float(row_ptr, scale,
453 				                      scanline_buffer_float+0, 3,
454 				                      scanline_buffer_float+1, 3,
455 				                      scanline_buffer_float+2, 3,
456 				                      NULL, 0,
457 				                      w);
458 			} else {
459 				tiff_interleave_float(row_ptr, scale,
460 				                      scanline_buffer_float+0, 4,
461 				                      scanline_buffer_float+1, 4,
462 				                      scanline_buffer_float+2, 4,
463 				                      scanline_buffer_float+3, 4,
464 				                      w);
465 			}
466 		}
467 	}
468 }
469 
tiff_read_failsafe(TIFF * t,float scale,ctl::dpx::fb<float> * pixels)470 void tiff_read_failsafe(TIFF *t, float scale, ctl::dpx::fb<float> *pixels) {
471 	uint8_t *temp_buffer;
472 	uint8_t *flip;
473 	uint32_t i;
474 	uint32_t w, h;
475 
476 	TIFFGetFieldDefaulted(t, TIFFTAG_IMAGEWIDTH, &w);
477 	TIFFGetFieldDefaulted(t, TIFFTAG_IMAGELENGTH, &h);
478 	pixels->init(w, h, 4);
479 
480 	temp_buffer=(uint8_t *)alloca(w*h*4);
481 	TIFFReadRGBAImage(t, w, h, (uint32 *)temp_buffer, 0);
482 
483 	for(i=0; i<h; i++) {
484 		flip=temp_buffer+sizeof(uint32_t)*w*(h-i-1);
485 		tiff_interleave_int8(pixels->ptr()+w*i*4, 0, scale,
486 		                     flip+0, 4, flip+1, 4, flip+2, 4, flip+3, 4, w);
487 	}
488 }
489 
tiff_convert_uint8(uint8_t * data,const float * in,float scale,uint32_t width)490 void tiff_convert_uint8(uint8_t *data, const float *in,
491                         float scale, uint32_t width) {
492 #if 1
493 	ctl::dpx::convert(data, in, 0.0, width);
494 #else
495 	uint32_t i;
496 	float f;
497 
498 	if(scale==0.0) {
499 		scale=1ULL<<15;
500 	}
501 
502 	for(i=0; i<width; i++) {
503 		f=*in;
504 		f=f*scale;
505 		if(f<0.0) { f=0.0; }
506 		if(f>254.999) { f=254.999; }
507 		*(data++)=lrint(f);
508 		in++;
509 	}
510 #endif
511 }
512 
tiff_convert_uint16(uint16_t * data,const float * in,float scale,uint32_t width)513 void tiff_convert_uint16(uint16_t *data, const float *in,
514                          float scale, uint32_t width) {
515 #if 1
516 	ctl::dpx::convert(data, in, 0.0, width);
517 #else
518 	uint32_t i;
519 	float f;
520 
521 	if(scale==0.0) {
522 		scale=1ULL<<15;
523 	}
524 
525 	// Yes... I know... You can do this with a lookup table...
526 	// And it would be much faster... And you should round these...
527 	for(i=0; i<width; i++) {
528 		f=*in;
529 		f=f*scale;
530 		if(f<0.0) { f=0.0; }
531 		if(f>65534.999) { f=65534.999; }
532 		*(data++)=lrint(f);
533 		in++;
534 	}
535 #endif
536 }
537 
tiff_convert_float(float * out,const float * in,float scale,uint32_t width)538 void tiff_convert_float(float *out, const float *in,
539                         float scale, uint32_t width) {
540 #if 1
541 	ctl::dpx::convert(out, in, 1.0, width);
542 #else
543 	uint32_t i;
544 
545 	if(scale==0.0) {
546 		scale=1.0;
547 	}
548 	for(i=0; i<width; i++) {
549 		*(out++)=*in*scale;
550 		in++;
551 	}
552 #endif
553 }
554 
tiff_write(const char * name,float scale,const ctl::dpx::fb<float> & pixels,format_t * format)555 void tiff_write(const char *name, float scale,
556                 const ctl::dpx::fb<float> &pixels,
557                 format_t *format) {
558 	TIFF *t;
559 	uint16_t bits_per_sample;
560 	tdata_t scanline_buffer;
561 	uint32_t y;
562 	uint8_t channel;
563 	const float *row;
564 
565 	TIFFSetErrorHandler(ErrorHandler);
566 	TIFFSetWarningHandler(WarningHandler);
567 
568 	bits_per_sample=format->bps;
569 	if(format->bps<=8) {
570 		bits_per_sample=8;
571 	} else if(format->bps<=16) {
572 		bits_per_sample=16;
573 	} else if(format->bps!=32) {
574 		THROW(Iex::ArgExc, "TIFF files can only support files with <=16 bps "
575 		      "(integer) or 32 bps (float).");
576 	}
577 
578 	t=TIFFOpen(name, "w");
579 	if(t==NULL) {
580 		// What went wrong
581 	}
582 
583 	TIFFSetField(t, TIFFTAG_SAMPLESPERPIXEL, pixels.depth());
584 	TIFFSetField(t, TIFFTAG_BITSPERSAMPLE, bits_per_sample);
585 	TIFFSetField(t, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
586 	TIFFSetField(t, TIFFTAG_IMAGEWIDTH, pixels.width());
587 	TIFFSetField(t, TIFFTAG_IMAGELENGTH, pixels.height());
588 	TIFFSetField(t, TIFFTAG_ROWSPERSTRIP, 1);
589 	TIFFSetField(t, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
590 	// Worst case...
591 	scanline_buffer=alloca(sizeof(float)*pixels.depth()*pixels.width());
592 
593 	if(bits_per_sample==8) {
594 		TIFFSetField(t, TIFFTAG_SAMPLEFORMAT, 1);
595 		for(y=0; y<pixels.height(); y++) {
596 			row=pixels.ptr()+y*pixels.width()*pixels.depth();
597 			tiff_convert_uint8((uint8_t *)scanline_buffer, row,
598 			                   scale, pixels.depth()*pixels.width());
599 			TIFFWriteScanline(t, scanline_buffer, y, 0);
600 		}
601 	} else if(bits_per_sample==16) {
602 		TIFFSetField(t, TIFFTAG_SAMPLEFORMAT, 1);
603 		for(y=0; y<pixels.height(); y++) {
604 			row=pixels.ptr()+y*pixels.width()*pixels.depth();
605 			tiff_convert_uint16((uint16_t *)scanline_buffer, row,
606 			                    scale, pixels.depth()*pixels.width());
607 			TIFFWriteScanline(t, scanline_buffer, y, channel);
608 		}
609 	} else if(bits_per_sample==32) {
610 		TIFFSetField(t, TIFFTAG_SAMPLEFORMAT, 3);
611 		for(y=0; y<pixels.height(); y++) {
612 			row=pixels.ptr()+y*pixels.width()*pixels.depth();
613 			tiff_convert_float((float *)scanline_buffer, row,
614 			                   scale, pixels.depth()*pixels.width());
615 			TIFFWriteScanline(t, scanline_buffer, y, channel);
616 		}
617 	}
618 
619 	TIFFClose(t);
620 }
621 
622 #else
tiff_read(const char * name,float scale,ctl::dpx::fb<float> * pixels,format_t * bps)623 bool tiff_read(const char *name, float scale, ctl::dpx::fb<float> *pixels,
624                format_t *bps) {
625 	return FALSE;
626 }
tiff_write(const char * name,float scale,const ctl::dpx::fb<float> & pixels,format_t * format)627 void tiff_write(const char *name, float scale,
628                 const ctl::dpx::fb<float> &pixels, format_t *format) {
629 	// thow tiff is unsupported message.
630 }
631 #endif
632