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