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