1 /*****************************************************************
2 * gmerlin - a general purpose multimedia framework and applications
3 *
4 * Copyright (c) 2001 - 2011 Members of the Gmerlin project
5 * gmerlin-general@lists.sourceforge.net
6 * http://gmerlin.sourceforge.net
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * *****************************************************************/
21
22 #include <math.h>
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <tiffio.h>
28 #include <inttypes.h>
29
30 #include <config.h>
31 #include <gmerlin/translation.h>
32
33 #include <gmerlin/plugin.h>
34
35 #include <gmerlin/log.h>
36 #define LOG_DOMAIN "ir_tiff"
37
38 #include <gavl/metatags.h>
39
40
41 typedef struct
42 {
43 uint8_t *buffer;
44 uint64_t buffer_size;
45 uint32_t buffer_position;
46 uint32_t buffer_alloc;
47 uint32_t Width;
48 uint32_t Height;
49 uint16_t BitsPerSample;
50 uint16 SamplesPerPixel;
51 uint16 SampleFormat;
52 uint16 Orientation;
53 uint16 Photometric;
54 uint16 Compression;
55 gavl_video_format_t format;
56 TIFF * tiff;
57
58 int is_planar;
59
60 void (*convert_scanline)(uint8_t * dst, uint8_t * src,
61 int width, int plane);
62
63 gavl_metadata_t m;
64
65 } tiff_t;
66
create_tiff()67 static void * create_tiff()
68 {
69 tiff_t * ret;
70 ret = calloc(1, sizeof(*ret));
71 return ret;
72 }
73
destroy_tiff(void * priv)74 static void destroy_tiff(void* priv)
75 {
76 tiff_t * tiff = priv;
77 if(tiff->buffer)
78 free(tiff->buffer);
79 gavl_metadata_free(&tiff->m);
80 free(tiff);
81 }
82
read_function(thandle_t fd,tdata_t data,tsize_t length)83 static tsize_t read_function(thandle_t fd, tdata_t data, tsize_t length)
84 {
85 uint32_t bytes_read;
86 tiff_t *p = (tiff_t*)fd;
87
88 bytes_read = length;
89 if(length > p->buffer_size - p->buffer_position)
90 bytes_read = p->buffer_size - p->buffer_position;
91
92 memcpy(data, p->buffer + p->buffer_position, bytes_read);
93 p->buffer_position += bytes_read;
94 return bytes_read;
95 }
96
seek_function(thandle_t fd,toff_t off,int whence)97 static toff_t seek_function(thandle_t fd, toff_t off, int whence)
98 {
99 tiff_t *p = (tiff_t*)fd;
100
101 if (whence == SEEK_SET) p->buffer_position = off;
102 else if (whence == SEEK_CUR) p->buffer_position += off;
103 else if (whence == SEEK_END) p->buffer_size += off;
104
105 if (p->buffer_position > p->buffer_size) {
106 bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Seeked beyond buffer.");
107 return -1;
108 }
109
110 if (p->buffer_position > p->buffer_size)
111 p->buffer_position = p->buffer_size;
112
113 return (p->buffer_position);
114 }
115
size_function(thandle_t fd)116 static toff_t size_function(thandle_t fd)
117 {
118 tiff_t *p = (tiff_t*)fd;
119 return p->buffer_size;
120 }
121
close_function(thandle_t fd)122 static int close_function(thandle_t fd)
123 {
124 return (0);
125 }
write_function(thandle_t fd,tdata_t data,tsize_t length)126 static tsize_t write_function(thandle_t fd, tdata_t data, tsize_t length)
127 {
128 return 0;
129 }
130
map_file_proc(thandle_t a,tdata_t * b,toff_t * c)131 static int map_file_proc(thandle_t a, tdata_t* b, toff_t* c)
132 {
133 return 0;
134 }
135
unmap_file_proc(thandle_t a,tdata_t b,toff_t c)136 static void unmap_file_proc(thandle_t a, tdata_t b, toff_t c)
137 {
138 }
139
open_tiff_mem(char * mode,tiff_t * p)140 static TIFF* open_tiff_mem(char *mode, tiff_t* p)
141 {
142 return TIFFClientOpen("Gmerlin tiff plugin", mode, (thandle_t)p,
143 read_function,write_function ,
144 seek_function, close_function,
145 size_function, map_file_proc ,unmap_file_proc);
146 }
147
tiff_read_mem(tiff_t * tiff,const char * filename)148 static int tiff_read_mem(tiff_t *tiff, const char *filename)
149 {
150 FILE * file;
151
152 if(!(file = fopen(filename,"r")))return 0;
153
154 fseek(file, 0, SEEK_END);
155
156 if((tiff->buffer_size = ftell(file))<0) return 0;
157
158 fseek(file, 0, SEEK_SET);
159
160 if(tiff->buffer_size > tiff->buffer_alloc)
161 {
162 tiff->buffer_alloc = tiff->buffer_size + 128;
163 tiff->buffer = realloc(tiff->buffer, tiff->buffer_alloc);
164 }
165
166 if((fread(tiff->buffer, 1, tiff->buffer_size, file)) < tiff->buffer_size)
167 return 0;
168
169 tiff->buffer_position = 0;
170
171 fclose(file);
172 return 1;
173 }
174
175 static void
convert_scanline_RGB_16(uint8_t * dst,uint8_t * src,int width,int plane)176 convert_scanline_RGB_16(uint8_t * dst, uint8_t * src,
177 int width, int plane)
178 {
179 memcpy(dst, src, width * 3 * 2);
180 }
181
182 static void
convert_scanline_RGB_16_planar(uint8_t * _dst,uint8_t * _src,int width,int plane)183 convert_scanline_RGB_16_planar(uint8_t * _dst, uint8_t * _src,
184 int width, int plane)
185 {
186 int i;
187 uint16_t * dst = (uint16_t *)_dst;
188 uint16_t * src = (uint16_t *)_src;
189
190 dst += plane;
191 for(i = 0; i < width; i++)
192 {
193 *dst = *src;
194 dst += 3;
195 src++;
196 }
197 }
198
convert_scanline_gray_16(uint8_t * _dst,uint8_t * _src,int width,int plane)199 static void convert_scanline_gray_16(uint8_t * _dst,
200 uint8_t * _src,
201 int width, int plane)
202 {
203 int i;
204 uint16_t * dst = (uint16_t *)_dst;
205 uint16_t * src = (uint16_t *)_src;
206
207 for(i = 0; i < width; i++)
208 {
209 *dst = *src;
210 dst++;
211 src++;
212 }
213 }
214
215 static void
convert_scanline_RGBA_16(uint8_t * dst,uint8_t * src,int width,int plane)216 convert_scanline_RGBA_16(uint8_t * dst, uint8_t * src,
217 int width, int plane)
218 {
219 memcpy(dst, src, width * 4 * 2);
220 }
221
222 static void
convert_scanline_RGBA_16_planar(uint8_t * _dst,uint8_t * _src,int width,int plane)223 convert_scanline_RGBA_16_planar(uint8_t * _dst, uint8_t * _src,
224 int width, int plane)
225 {
226 int i;
227 uint16_t * dst = (uint16_t *)_dst;
228 uint16_t * src = (uint16_t *)_src;
229
230 dst += plane;
231 for(i = 0; i < width; i++)
232 {
233 *dst = *src;
234 dst += 4;
235 src++;
236 }
237 }
238
239 /* 32 bit uint */
240
241 static void
convert_scanline_RGB_32(uint8_t * _dst,uint8_t * _src,int width,int plane)242 convert_scanline_RGB_32(uint8_t * _dst, uint8_t * _src,
243 int width, int plane)
244 {
245 int i;
246 float * dst = (float *)_dst;
247 uint32_t * src = (uint32_t *)_src;
248
249 for(i = 0; i < width*3; i++)
250 {
251 *dst = (float)(*src)/4294967295.0;
252 dst++;
253 src++;
254 }
255 }
256
257 static void
convert_scanline_RGB_32_planar(uint8_t * _dst,uint8_t * _src,int width,int plane)258 convert_scanline_RGB_32_planar(uint8_t * _dst, uint8_t * _src,
259 int width, int plane)
260 {
261 int i;
262 float * dst = (float *)_dst;
263 uint32_t * src = (uint32_t *)_src;
264
265 dst += plane;
266
267 for(i = 0; i < width; i++)
268 {
269 *dst = (float)(*src)/4294967295.0;
270 dst+=3;
271 src++;
272 }
273 }
274
275 static void
convert_scanline_RGBA_32(uint8_t * _dst,uint8_t * _src,int width,int plane)276 convert_scanline_RGBA_32(uint8_t * _dst, uint8_t * _src,
277 int width, int plane)
278 {
279 int i;
280 float * dst = (float *)_dst;
281 uint32_t * src = (uint32_t *)_src;
282
283 for(i = 0; i < width*4; i++)
284 {
285 *dst = (float)(*src)/4294967295.0;
286 dst++;
287 src++;
288 }
289 }
290
291 static void
convert_scanline_RGBA_32_planar(uint8_t * _dst,uint8_t * _src,int width,int plane)292 convert_scanline_RGBA_32_planar(uint8_t * _dst, uint8_t * _src,
293 int width, int plane)
294 {
295 int i;
296 float * dst = (float *)_dst;
297 uint32_t * src = (uint32_t *)_src;
298
299 dst += plane;
300
301 for(i = 0; i < width*3; i++)
302 {
303 *dst = (float)(*src)/4294967295.0;
304 dst+=3;
305 src++;
306 }
307 }
308
309
310 static void
convert_scanline_gray_32(uint8_t * _dst,uint8_t * _src,int width,int plane)311 convert_scanline_gray_32(uint8_t * _dst, uint8_t * _src,
312 int width, int plane)
313 {
314 int i;
315 float * dst = (float*)_dst;
316 uint32_t * src = (uint32_t *)_src;
317
318 for(i = 0; i < width; i++)
319 {
320 dst[0] = (float)(*src)/4294967295.0;
321 dst[1] = (float)(*src)/4294967295.0;
322 dst[2] = (float)(*src)/4294967295.0;
323 dst += 3;
324 src++;
325 }
326 }
327
328 /* Big/Little endian floating point routines taken from libsndfile */
329
330 #if 0
331
332 #ifndef WORDS_BIGENDIAN
333 static float
334 float32_read (unsigned char *cptr)
335 { int exponent, mantissa, negative ;
336 float fvalue ;
337
338 negative = cptr [3] & 0x80 ;
339 exponent = ((cptr [3] & 0x7F) << 1) | ((cptr [2] & 0x80) ? 1 : 0) ;
340 mantissa = ((cptr [2] & 0x7F) << 16) | (cptr [1] << 8) | (cptr [0]) ;
341
342 if (! (exponent || mantissa))
343 return 0.0 ;
344
345 mantissa |= 0x800000 ;
346 exponent = exponent ? exponent - 127 : 0 ;
347
348 fvalue = mantissa ? ((float) mantissa) / ((float) 0x800000) : 0.0 ;
349
350 if (negative)
351 fvalue *= -1 ;
352
353 if (exponent > 0)
354 fvalue *= (1 << exponent) ;
355 else if (exponent < 0)
356 fvalue /= (1 << abs (exponent)) ;
357
358 return fvalue ;
359 } /* float32_le_read */
360 #endif
361 static double
362 double64_read (unsigned char *cptr)
363 { int exponent, negative ;
364 double dvalue ;
365
366 negative = (cptr [7] & 0x80) ? 1 : 0 ;
367 exponent = ((cptr [7] & 0x7F) << 4) | ((cptr [6] >> 4) & 0xF) ;
368
369 /* Might not have a 64 bit long, so load the mantissa into a double. */
370 dvalue = (((cptr [6] & 0xF) << 24) | (cptr [5] << 16) | (cptr [4] << 8)
371 | cptr [3]) ;
372 dvalue += ((cptr [2] << 16) | (cptr [1] << 8) | cptr [0]) / ((double) 0x1000000) ;
373
374 if (exponent == 0 && dvalue == 0.0)
375 return 0.0 ;
376
377 dvalue += 0x10000000 ;
378
379 exponent = exponent - 0x3FF ;
380
381 dvalue = dvalue / ((double) 0x10000000) ;
382
383 if (negative)
384 dvalue *= -1 ;
385
386 if (exponent > 0)
387 dvalue *= (1 << exponent) ;
388 else if (exponent < 0)
389 dvalue /= (1 << abs (exponent)) ;
390
391 return dvalue ;
392 } /* double64_le_read */
393 #else
394
395 #if 0
396 static float
397 float32_read (unsigned char *cptr)
398 { int exponent, mantissa, negative ;
399 float fvalue ;
400
401 negative = cptr [0] & 0x80 ;
402 exponent = ((cptr [0] & 0x7F) << 1) | ((cptr [1] & 0x80) ? 1 : 0) ;
403 mantissa = ((cptr [1] & 0x7F) << 16) | (cptr [2] << 8) | (cptr [3]) ;
404
405 if (! (exponent || mantissa))
406 return 0.0 ;
407
408 mantissa |= 0x800000 ;
409 exponent = exponent ? exponent - 127 : 0 ;
410
411 fvalue = mantissa ? ((float) mantissa) / ((float) 0x800000) : 0.0 ;
412
413 if (negative)
414 fvalue *= -1 ;
415
416 if (exponent > 0)
417 fvalue *= (1 << exponent) ;
418 else if (exponent < 0)
419 fvalue /= (1 << abs (exponent)) ;
420
421 return fvalue ;
422 } /* float32_be_read */
423 #endif
424
425 static double
double64_read(unsigned char * cptr)426 double64_read (unsigned char *cptr)
427 { int exponent, negative ;
428 double dvalue ;
429
430 negative = (cptr [0] & 0x80) ? 1 : 0 ;
431 exponent = ((cptr [0] & 0x7F) << 4) | ((cptr [1] >> 4) & 0xF) ;
432
433 /* Might not have a 64 bit long, so load the mantissa into a double. */
434 dvalue = (((cptr [1] & 0xF) << 24) | (cptr [2] << 16) | (cptr [3] << 8)
435 | cptr [4]) ;
436 dvalue += ((cptr [5] << 16) | (cptr [6] << 8) | cptr [7]) / ((double) 0x1000000) ;
437
438 if (exponent == 0 && dvalue == 0.0)
439 return 0.0 ;
440
441 dvalue += 0x10000000 ;
442
443 exponent = exponent - 0x3FF ;
444
445 dvalue = dvalue / ((double) 0x10000000) ;
446
447 if (negative)
448 dvalue *= -1 ;
449
450 if (exponent > 0)
451 dvalue *= (1 << exponent) ;
452 else if (exponent < 0)
453 dvalue /= (1 << abs (exponent)) ;
454
455 return dvalue ;
456 } /* double64_be_read */
457 #endif
458
459 #if 0
460 static void convert_scanline_RGB_float_32(uint8_t * dst, uint8_t * src, int width, int plane)
461 {
462
463 }
464 #endif
465
466 static void
convert_scanline_RGB_float_64(uint8_t * _dst,uint8_t * src,int width,int plane)467 convert_scanline_RGB_float_64(uint8_t * _dst, uint8_t * src,
468 int width, int plane)
469 {
470 int i;
471 float * dst = (float*)_dst;
472
473 for(i = 0; i < width*3; i++)
474 {
475 *dst = double64_read(src);
476 dst++;
477 src += 8;
478 }
479 }
480
481 static void
convert_scanline_RGB_float_64_planar(uint8_t * _dst,uint8_t * src,int width,int plane)482 convert_scanline_RGB_float_64_planar(uint8_t * _dst, uint8_t * src,
483 int width, int plane)
484 {
485 int i;
486 float * dst = (float*)_dst;
487
488
489 dst += plane;
490
491 for(i = 0; i < width; i++)
492 {
493 *dst = double64_read(src);
494
495
496 dst+=3;
497 src += 8;
498 }
499 }
500
501 #if 0
502 static void
503 convert_scanline_RGBA_float_32(uint8_t * dst, uint8_t * src,
504 int width, int plane)
505 {
506 }
507
508 static void
509 convert_scanline_RGBA_float_64(uint8_t * dst, uint8_t * src,
510 int width, int plane)
511 {
512 }
513 #endif
514
515 static void
convert_scanline_logl(uint8_t * _dst,uint8_t * _src,int width,int plane)516 convert_scanline_logl(uint8_t * _dst, uint8_t * _src,
517 int width, int plane)
518 {
519 int i;
520 float * dst = (float*)_dst;
521 float * src = (float*)_src;
522
523
524 for(i = 0; i < width; i++)
525 {
526 dst[0] = *src < 0.0 ? 0.0 : *src > 1.0 ? 1.0 : sqrt(*src);
527 dst[1] = dst[0];
528 dst[2] = dst[0];
529 dst+=3;
530 src++;
531 }
532
533 }
534
XYZtoRGB(float * xyz,float * rgb)535 static void XYZtoRGB(float * xyz, float * rgb)
536 {
537 double r, g, b;
538 /* assume CCIR-709 primaries */
539 r = 2.690*xyz[0] + -1.276*xyz[1] + -0.414*xyz[2];
540 g = -1.022*xyz[0] + 1.978*xyz[1] + 0.044*xyz[2];
541 b = 0.061*xyz[0] + -0.224*xyz[1] + 1.163*xyz[2];
542 /* assume 2.0 gamma for speed */
543 /* could use integer sqrt approx., but this is probably faster */
544 rgb[0] = (r<=0.) ? 0 : (r >= 1.) ? 1.0 : sqrt(r);
545 rgb[1] = (g<=0.) ? 0 : (g >= 1.) ? 1.0 : sqrt(g);
546 rgb[2] = (b<=0.) ? 0 : (b >= 1.) ? 1.0 : sqrt(b);
547 }
548
549
convert_scanline_logluv(uint8_t * _dst,uint8_t * _src,int width,int plane)550 static void convert_scanline_logluv(uint8_t * _dst, uint8_t * _src,
551 int width, int plane)
552 {
553 int i;
554 float * dst = (float*)_dst;
555 float * src = (float*)_src;
556
557
558 for(i = 0; i < width; i++)
559 {
560 XYZtoRGB(src, dst);
561 dst+=3;
562 src+=3;
563 }
564 }
565
566 static int
read_header_tiff(void * priv,const char * filename,gavl_video_format_t * format)567 read_header_tiff(void *priv,const char *filename,
568 gavl_video_format_t * format)
569 {
570 double minmax_d[4];
571 uint16_t tmp_16;
572 tiff_t *p = priv;
573
574 tiff_read_mem(priv, filename);
575
576 if(!(p->tiff = open_tiff_mem("rm", p))) return 0;
577 if(!(TIFFGetField(p->tiff, TIFFTAG_IMAGEWIDTH, &p->Width))) return 0;
578 if(!(TIFFGetField(p->tiff, TIFFTAG_IMAGELENGTH, &p->Height))) return 0;
579 if(!(TIFFGetField(p->tiff, TIFFTAG_PHOTOMETRIC, &p->Photometric))) return 0;
580
581 if(!TIFFGetField(p->tiff, TIFFTAG_COMPRESSION, &p->Compression)) p->Compression = COMPRESSION_NONE;
582
583 if(!(TIFFGetField(p->tiff, TIFFTAG_SAMPLESPERPIXEL, &p->SamplesPerPixel)))p->SamplesPerPixel = 1;
584 if(!(TIFFGetField(p->tiff, TIFFTAG_BITSPERSAMPLE, &p->BitsPerSample)))p->BitsPerSample = 1;
585 if(!(TIFFGetField(p->tiff, TIFFTAG_ORIENTATION, &p->Orientation)))
586 p->Orientation = ORIENTATION_TOPLEFT;
587
588 if(!(TIFFGetField(p->tiff, TIFFTAG_SAMPLEFORMAT, &p->SampleFormat)))
589 p->SampleFormat = SAMPLEFORMAT_UINT;
590
591 if(!(TIFFGetField(p->tiff, TIFFTAG_PLANARCONFIG, &tmp_16)) || (tmp_16 == 1))
592 p->is_planar = 0;
593 else
594 p->is_planar = 1;
595
596 format->frame_width = p->Width;
597 format->frame_height = p->Height;
598
599 format->image_width = format->frame_width;
600 format->image_height = format->frame_height;
601 format->pixel_width = 1;
602 format->pixel_height = 1;
603 /* Check for format */
604
605 if(p->BitsPerSample <= 8)
606 {
607 if(p->SamplesPerPixel == 4)
608 format->pixelformat = GAVL_RGBA_32;
609 else
610 format->pixelformat = GAVL_RGB_24;
611 }
612 else if((p->Photometric == PHOTOMETRIC_LOGL) || (p->Photometric == PHOTOMETRIC_LOGLUV))
613 {
614 if((p->Compression != COMPRESSION_SGILOG) && (p->Compression != COMPRESSION_SGILOG24))
615 {
616 bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Unsupported compression for LOGL/LOGLUV");
617 return 0;
618 }
619 TIFFSetField(p->tiff, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT);
620 format->pixelformat = GAVL_RGB_FLOAT;
621 if(p->Photometric == PHOTOMETRIC_LOGL)
622 p->convert_scanline = convert_scanline_logl;
623 else
624 p->convert_scanline = convert_scanline_logluv;
625 }
626 else /* High Precision (> 8 bits) */
627 {
628 switch(p->SampleFormat)
629 {
630 case SAMPLEFORMAT_UINT:
631 switch(p->BitsPerSample)
632 {
633 case 16:
634 if(p->SamplesPerPixel == 1)
635 {
636 p->convert_scanline = convert_scanline_gray_16;
637 format->pixelformat = GAVL_GRAY_16;
638 }
639 /* GAVL_RGB_48 */
640 else if(p->SamplesPerPixel == 3)
641 {
642 if(p->is_planar)
643 p->convert_scanline = convert_scanline_RGB_16_planar;
644 else
645 p->convert_scanline = convert_scanline_RGB_16;
646
647 format->pixelformat = GAVL_RGB_48;
648 }
649 /* GAVL_RGB_64 */
650 else if(p->SamplesPerPixel == 4)
651 {
652 if(p->is_planar)
653 p->convert_scanline = convert_scanline_RGBA_16_planar;
654 else
655 p->convert_scanline = convert_scanline_RGBA_16;
656 format->pixelformat = GAVL_RGBA_64;
657 }
658 else
659 {
660 bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Unsupported samples per pixel");
661 return 0;
662 }
663 break;
664 case 32:
665 if(p->SamplesPerPixel == 1)
666 {
667 p->convert_scanline = convert_scanline_gray_32;
668 format->pixelformat = GAVL_RGB_FLOAT;
669 }
670 else if(p->SamplesPerPixel == 3)
671 {
672 if(p->is_planar)
673 p->convert_scanline = convert_scanline_RGB_32_planar;
674 else
675 p->convert_scanline = convert_scanline_RGB_32;
676
677 format->pixelformat = GAVL_RGB_FLOAT;
678 }
679 else if(p->SamplesPerPixel == 4)
680 {
681 if(p->is_planar)
682 p->convert_scanline = convert_scanline_RGBA_32_planar;
683 else
684 p->convert_scanline = convert_scanline_RGBA_32;
685 format->pixelformat = GAVL_RGBA_FLOAT;
686 }
687 else
688 {
689 bg_log(BG_LOG_ERROR, LOG_DOMAIN,
690 "Unsupported samples per pixel");
691 return 0;
692 }
693 break;
694 default:
695 bg_log(BG_LOG_ERROR, LOG_DOMAIN,
696 "Unsupported bits per sample (%d) for UINT",
697 p->BitsPerSample);
698 return 0;
699 }
700 break;
701 case SAMPLEFORMAT_IEEEFP:
702 if(!(TIFFGetField(p->tiff, TIFFTAG_SMAXSAMPLEVALUE, minmax_d)))
703 bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Didn't get max sample value");
704
705 if(!(TIFFGetField(p->tiff, TIFFTAG_SMINSAMPLEVALUE, minmax_d)))
706 bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Didn't get min sample value");
707
708 switch(p->BitsPerSample)
709 {
710 case 64:
711 if(p->SamplesPerPixel == 3)
712 {
713 if(p->is_planar)
714 p->convert_scanline = convert_scanline_RGB_float_64_planar;
715 else
716 p->convert_scanline = convert_scanline_RGB_float_64;
717 format->pixelformat = GAVL_RGB_FLOAT;
718 }
719 else
720 {
721 bg_log(BG_LOG_ERROR, LOG_DOMAIN,
722 "Unsupported samples per pixel");
723 return 0;
724 }
725 break;
726 default:
727 bg_log(BG_LOG_ERROR, LOG_DOMAIN,
728 "Unsupported depth %d for IEEE float",
729 p->BitsPerSample);
730 return 0;
731 }
732
733 break;
734 case SAMPLEFORMAT_INT:
735 case SAMPLEFORMAT_VOID:
736 case SAMPLEFORMAT_COMPLEXINT:
737 case SAMPLEFORMAT_COMPLEXIEEEFP:
738 bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Unsupported sampleformat");
739 return 0;
740 break;
741 default:
742 bg_log(BG_LOG_ERROR, LOG_DOMAIN,
743 "Unknown sampleformat %d",
744 p->SampleFormat);
745 return 0;
746
747 }
748 }
749
750 gavl_metadata_set(&p->m, GAVL_META_FORMAT, "TIFF");
751 return 1;
752 }
753
754 #if 0
755 static uint32_t * transpose(uint32_t * raster, int width, int height)
756 {
757 int i, j;
758 uint32_t * ret;
759
760 ret = malloc(width * height * sizeof(*ret));
761
762 for(i = 0; i < height; i++)
763 {
764 for(j = 0; j < width; j++)
765 {
766 ret[i * width + j] = raster[j * height + i];
767 }
768 }
769 free(raster);
770 return ret;
771 }
772 #endif
773
774 #define GET_RGBA(fp, rp) \
775 fp[0]=TIFFGetR(*rp); \
776 fp[1]=TIFFGetG(*rp); \
777 fp[2]=TIFFGetB(*rp); \
778 fp[3]=TIFFGetA(*rp); \
779 fp += 4;
780
781 #define GET_RGB(fp, rp) \
782 fp[0]=TIFFGetR(*rp); \
783 fp[1]=TIFFGetG(*rp); \
784 fp[2]=TIFFGetB(*rp); \
785 fp += 3;
786
read_image_tiff(void * priv,gavl_video_frame_t * frame)787 static int read_image_tiff(void *priv, gavl_video_frame_t *frame)
788 {
789 int i, j;
790 uint32_t *raster;
791 tiff_t *p = priv;
792 uint32_t * raster_ptr;
793 uint8_t * frame_ptr;
794 uint8_t * frame_ptr_start;
795 tdata_t buf;
796 int num_planes;
797
798 if(!frame)
799 {
800 TIFFClose( p->tiff );
801 return 1;
802 }
803
804 num_planes = p->is_planar ? p->SamplesPerPixel : 1;
805
806 p->buffer_position =0;
807
808 if(p->BitsPerSample <= 8)
809 {
810 raster = (uint32_t*)_TIFFmalloc(p->Height * p->Width * sizeof(uint32_t));
811
812 if(!TIFFReadRGBAImage(p->tiff, p->Width, p->Height, (uint32*)raster, 0))
813 return 0;
814
815 #if 0
816 if((p->Orientation == ORIENTATION_LEFTTOP) ||
817 (p->Orientation == ORIENTATION_RIGHTTOP) ||
818 (p->Orientation == ORIENTATION_LEFTBOT) ||
819 (p->Orientation == ORIENTATION_RIGHTBOT))
820 raster = transpose(raster, p->Width, p->Height);
821 #endif
822
823
824 if(p->SamplesPerPixel == 4)
825 {
826 frame_ptr_start = frame->planes[0];
827
828 for (i=0;i<p->Height; i++)
829 {
830 frame_ptr = frame_ptr_start;
831
832 raster_ptr = raster + (p->Height - 1 - i) * p->Width;
833
834 for(j=0;j<p->Width; j++)
835 {
836 GET_RGBA(frame_ptr, raster_ptr);
837 raster_ptr++;
838 }
839 frame_ptr_start += frame->strides[0];
840 }
841 }
842 else
843 {
844 frame_ptr_start = frame->planes[0];
845
846 for (i=0;i<p->Height; i++)
847 {
848 frame_ptr = frame_ptr_start;
849
850 raster_ptr = raster + (p->Height - 1 - i) * p->Width;
851
852 for(j=0;j<p->Width; j++)
853 {
854 GET_RGB(frame_ptr, raster_ptr);
855 raster_ptr++;
856 }
857 frame_ptr_start += frame->strides[0];
858 }
859 }
860 if (raster) _TIFFfree(raster);
861 }
862 else
863 {
864
865 buf = _TIFFmalloc(TIFFScanlineSize(p->tiff));
866
867 if(!p->convert_scanline)
868 {
869 bg_log(BG_LOG_ERROR, LOG_DOMAIN, "BUG!!! convert_func == 0x0");
870 return 0;
871 }
872
873 for(j = 0; j < num_planes; j++)
874 {
875 frame_ptr = frame->planes[0];
876 for (i=0;i<p->Height; i++)
877 {
878 TIFFReadScanline(p->tiff, buf, i, j);
879
880 p->convert_scanline(frame_ptr, buf, p->Width, j);
881 frame_ptr += frame->strides[0];
882 }
883 }
884 if (buf) _TIFFfree(buf);
885
886 }
887
888
889 TIFFClose( p->tiff );
890 return 1;
891 }
892
get_metadata_tiff(void * priv)893 static const gavl_metadata_t * get_metadata_tiff(void * priv)
894 {
895 tiff_t * t = priv;
896 return &t->m;
897 }
898
899 const bg_image_reader_plugin_t the_plugin =
900 {
901 .common =
902 {
903 BG_LOCALE,
904 .name = "ir_tiff",
905 .long_name = TRS("TIFF reader"),
906 .description = TRS("Reader for TIFF images"),
907 .type = BG_PLUGIN_IMAGE_READER,
908 .flags = BG_PLUGIN_FILE,
909 .priority = BG_PLUGIN_PRIORITY_MAX,
910 .create = create_tiff,
911 .destroy = destroy_tiff,
912 },
913 .extensions = "tif tiff",
914 .read_header = read_header_tiff,
915 .get_metadata = get_metadata_tiff,
916 .read_image = read_image_tiff,
917 };
918
919 /* Include this into all plugin modules exactly once
920 to let the plugin loader obtain the API version */
921 BG_GET_PLUGIN_API_VERSION;
922
923