source: libsrc/libbioimg/formats/tiff/dim_tiff_format_io.cpp @ 227:cc4c44695bb2

Last change on this file since 227:cc4c44695bb2 was 227:cc4c44695bb2, checked in by Dmitry Fedorov <fedorov@…>, 8 years ago

fix for not decoding all metadata in ome-bigtiff

File size: 33.2 KB
Line 
1/*****************************************************************************
2  TIFF IO
3  Copyright (c) 2004 by Dmitry V. Fedorov <www.dimin.net> <dima@dimin.net>
4
5  IMPLEMENTATION
6 
7  Programmer: Dima V. Fedorov <mailto:dima@dimin.net> <http://www.dimin.net/>
8   
9  TODO:
10    4) read preview image in RGB 8bit
11
12  History:
13    03/29/2004 22:23 - First creation
14       
15  Ver : 1
16*****************************************************************************/
17
18#include <cstdio>
19#include <cstdlib>
20#include <cmath>
21
22#include <limits>
23
24#include "memio.h"
25#include "bim_tiny_tiff.h"
26#include "dim_tiff_format.h"
27
28#ifndef MAX
29#  define MIN(a,b)      ((a<b) ? a : b)
30#  define MAX(a,b)      ((a>b) ? a : b)
31#endif
32
33// Disables Visual Studio 2005 warnings for deprecated code
34#if ( defined(_MSC_VER) && (_MSC_VER >= 1400) )
35  #pragma warning(disable:4996)
36#endif
37
38int invertImg(TDimImageBitmap *img);
39int invertSample(TDimImageBitmap *img, const int &sample);
40
41// must include these guys here if not no access to internal TIFF structs
42#include "dim_stk_format_io.cpp"
43#include "dim_psia_format_io.cpp"
44#include "dim_fluoview_format_io.cpp"
45#include "dim_cz_lsm_format_io.cpp"
46#include "dim_ometiff_format_io.cpp"
47
48//****************************************************************************
49// util procs
50//****************************************************************************
51
52template< typename T >
53void invert_buffer(void *buf, const unsigned int &size) {
54  T maxval = std::numeric_limits<T>::max();
55  T *p = (T *) buf; 
56  for (unsigned int i=0; i<size; i++)
57    p[i] = maxval - p[i];
58}
59
60void invert_buffer_1bit(void *buf, const unsigned int &size) {
61  int maxval = 1;
62  int rest = size%8;
63  unsigned int w = floor( size/8.0 );
64  unsigned char *p = (unsigned char *) buf; 
65  if (rest>0) ++w;
66
67  for (unsigned int x=0; x<w; ++x) {
68    unsigned char b[8];
69    b[0] = maxval - (p[x] >> 7);
70    b[1] = maxval - ((p[x] & 0x40) >> 6);
71    b[2] = maxval - ((p[x] & 0x20) >> 5);
72    b[3] = maxval - ((p[x] & 0x10) >> 4);
73    b[4] = maxval - ((p[x] & 0x08) >> 3);
74    b[5] = maxval - ((p[x] & 0x04) >> 2);
75    b[6] = maxval - ((p[x] & 0x02) >> 1);
76    b[7] = maxval - (p[x] & 0x01);
77    p[x] = (b[0]<<7) + (b[1]<<6) + (b[2]<<5) + (b[3]<<4) + (b[4]<<3) + (b[5]<<2) + (b[6]<<1) + b[7];
78  } // for x
79}
80
81void invert_buffer_4bit(void *buf, const unsigned int &size) {
82  int maxval = 15;
83  bool even = ( size%2 == 0 );
84  unsigned int w = floor( size/2.0 );
85  unsigned char *p = (unsigned char *) buf; 
86
87  for (unsigned int x=0; x<w; ++x) {
88    unsigned char b1 = maxval - (p[x] >> 4);
89    unsigned char b2 = maxval - (p[x] & 0x0F);
90    p[x] = (b1 << 4) + b2;
91  } // for x
92
93  // do the last pixel if the size is not even
94  if (!even) {
95    unsigned char b1 = maxval - (p[w] >> 4);
96    p[w] = (b1 << 4);
97  }
98}
99
100int invertSample(TDimImageBitmap *img, const int &sample) {
101  unsigned int size = img->i.width * img->i.height; 
102
103  // all typed will fall here
104  if (img->i.depth==8 && img->i.pixelType==D_FMT_UNSIGNED)
105    invert_buffer<DIM_UINT8>(img->bits[sample], size);
106  else
107  if (img->i.depth==8 && img->i.pixelType==D_FMT_SIGNED)
108    invert_buffer<DIM_INT8>(img->bits[sample], size);
109  else
110  if (img->i.depth==16 && img->i.pixelType==D_FMT_UNSIGNED)
111    invert_buffer<DIM_UINT16>(img->bits[sample], size);
112  else
113  if (img->i.depth==16 && img->i.pixelType==D_FMT_SIGNED)
114    invert_buffer<DIM_INT16>(img->bits[sample], size);
115  else
116  if (img->i.depth==32 && img->i.pixelType==D_FMT_UNSIGNED)
117    invert_buffer<DIM_UINT32>(img->bits[sample], size);
118  else
119  if (img->i.depth==32 && img->i.pixelType==D_FMT_SIGNED)
120    invert_buffer<DIM_INT32>(img->bits[sample], size);
121  else
122  if (img->i.depth==32 && img->i.pixelType==D_FMT_FLOAT)
123    invert_buffer<DIM_FLOAT32>(img->bits[sample], size);
124  else
125  if (img->i.depth==64 && img->i.pixelType==D_FMT_FLOAT)
126    invert_buffer<DIM_FLOAT64>(img->bits[sample], size);
127  else
128  // we still have 1 and 4 bits
129  if (img->i.depth==4 && img->i.pixelType==D_FMT_UNSIGNED)
130    invert_buffer_4bit(img->bits[sample], size);
131  else
132  if (img->i.depth==1 && img->i.pixelType==D_FMT_UNSIGNED)
133    invert_buffer_1bit(img->bits[sample], size);
134
135  return 0;
136}
137
138int invertImg(TDimImageBitmap *img) {
139  if (!img) return -1;
140  for (unsigned int sample=0; sample<img->i.samples; sample++)
141    invertSample(img, sample);
142  return 0;
143}
144
145//****************************************************************************
146// MISC
147//****************************************************************************
148
149bool areValidParams(TDimFormatHandle *fmtHndl, DTiffParams *tifParams)
150{
151  if (fmtHndl == NULL) return FALSE;
152  if (tifParams == NULL) return FALSE;
153  if (tifParams->dimTiff == NULL) return FALSE;
154  if (fmtHndl->image == NULL) return FALSE;
155
156  return TRUE;
157}
158
159void init_image_palette( TIFF *tif, TDimImageInfo *info ) {
160  if (tif == NULL) return;
161  if (info == NULL) return;
162  uint16 photometric = PHOTOMETRIC_MINISWHITE;
163  uint16 bitspersample = 1; 
164  TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric);
165  TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);
166
167  info->lut.count = 0;
168  for (DIM_UINT i=0; i<256; i++) 
169    info->lut.rgba[i] = dimRGB( i, i, i );
170 
171  if (photometric == PHOTOMETRIC_PALETTE) { // palette
172    uint16 *red, *green, *blue;
173    DIM_UINT num_colors = ( 1L << bitspersample );
174    if (num_colors > 256) num_colors = 256;   
175
176    TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue);
177    for (DIM_UINT i=0; i<num_colors; i++)
178      info->lut.rgba[i] = dimRGB( red[i]/256, green[i]/256, blue[i]/256 );
179
180    info->lut.count = num_colors;
181  } // if paletted
182}
183
184//****************************************************************************
185// META DATA
186//****************************************************************************
187
188DIM_UINT read_one_tag (TDimFormatHandle *fmtHndl, DTiffParams *tifParams, uint16 tag)
189{
190  if (!areValidParams(fmtHndl, tifParams)) return 1;
191  bim::TinyTiff::IFD *ifd = tifParams->ifds.getIfd(fmtHndl->pageNumber);
192  if (!ifd) return 1;
193
194  if (fmtHndl->pageNumber >= tifParams->ifds.count()) fmtHndl->pageNumber = 0;
195  TIFF *tif = tifParams->dimTiff;
196
197  DIM_UCHAR *buf=NULL; uint16 buf_type; uint64 buf_size;
198
199  if ( (tifParams->subType == tstStk) && (tag == 33629) ) {// stk 33629 got custom size 6*N
200    buf_type = DIM_TAG_LONG;
201    uint64 count = ifd->tagCount(tag);
202    buf_size = ( count * 6 ) * bim::TinyTiff::tag_size_bytes[buf_type];
203    ifd->readTagCustom(tag, buf_size, buf_type, (DIM_UCHAR **) &buf);
204  }
205  else
206    ifd->readTag(tag, buf_size, buf_type, (DIM_UCHAR **) &buf);
207
208
209
210  if (buf_size==0 || !buf) return 1;
211  else
212  {
213    // now add tag into structure
214    TDimTagItem item;
215
216    item.tagGroup  = DIM_META_TIFF_TAG;
217    item.tagId     = tag;
218    item.tagType   = buf_type;
219    item.tagLength = buf_size / bim::TinyTiff::tag_size_bytes[buf_type];
220    item.tagData   = buf;
221
222    addMetaTag( &fmtHndl->metaData, item);
223  }
224
225  return 0;
226}
227
228DIM_UINT read_tiff_metadata (TDimFormatHandle *fmtHndl, DTiffParams *tifParams, int group, int tag, int type)
229{
230  if (!areValidParams(fmtHndl, tifParams)) return 1;
231  if (group == DIM_META_BIORAD) return 1;
232  bim::TinyTiff::IFD *ifd = tifParams->ifds.getIfd(fmtHndl->pageNumber);
233  if (!ifd) return 1;
234
235  // first read custom formatted tags
236  if (tifParams->subType == tstStk)
237    stkReadMetaMeta (fmtHndl, group, tag, type);
238
239  if (tag != -1)
240    return read_one_tag ( fmtHndl, tifParams, tag );
241
242  if ( (group == -1) || (group == DIM_META_TIFF_TAG) ) {
243    for (uint64 i=0; i<ifd->size(); i++ ) {
244      bim::TinyTiff::Entry *entry = ifd->getEntry(i);
245      if (type == -1) {
246        if (entry->tag>532 && entry->tag!=50434) 
247            read_one_tag ( fmtHndl, tifParams, entry->tag );   
248   
249        switch( entry->tag ) 
250        {
251          case 269: //DocumentName
252          case 270: //ImageDescription
253          case 271: //Make
254          case 272: //Model
255          case 285: //PageName
256          case 305: //Software
257          case 306: //DateTime
258          case 315: //Artist
259          case 316: //HostComputer
260            read_one_tag ( fmtHndl, tifParams, entry->tag );
261            break;
262        } // switch
263      } // type == -1
264      else
265      {
266        if (entry->type == type)
267          read_one_tag ( fmtHndl, tifParams, entry->tag );
268
269      } // type != -1
270
271    } // for i<ifd count
272  } // if no group
273
274  return 0;
275}
276
277//----------------------------------------------------------------------------
278// Textual METADATA
279//----------------------------------------------------------------------------
280
281void change_0_to_n (char *str, long size) {
282  for (long i=0; i<size; i++)
283    if (str[i] == '\0') str[i] = '\n'; 
284}
285
286void write_title_text(const char *text, MemIOBuf *outIOBuf)
287{
288  char title[1024];
289  sprintf(title, "\n[%s]\n\n", text);
290  MemIO_WriteProc( (thandle_t) outIOBuf, title, strlen(title)-1 );
291}
292
293void read_text_tag(bim::TinyTiff::IFD *ifd, DIM_UINT tag, MemIOBuf *outIOBuf, const char *text) {
294    if (!ifd->tagPresent(tag)) return;
295
296    uint64 buf_size;
297    uint16 buf_type; 
298    DIM_UCHAR *buf = NULL;
299    write_title_text(text, outIOBuf);
300    ifd->readTag (tag, buf_size, buf_type, &buf);
301    change_0_to_n ((char *) buf, buf_size);
302    MemIO_WriteProc( (thandle_t) outIOBuf, buf, buf_size );
303    _TIFFfree( buf );
304}
305
306void read_text_tag(bim::TinyTiff::IFD *ifd, DIM_UINT tag, MemIOBuf *outIOBuf) {
307    if (!ifd->tagPresent(tag)) return;
308    uint64 buf_size;
309    uint16 buf_type; 
310    DIM_UCHAR *buf = NULL;
311 
312    ifd->readTag (tag, buf_size, buf_type, &buf);
313    change_0_to_n ((char *) buf, buf_size);
314    MemIO_WriteProc( (thandle_t) outIOBuf, buf, buf_size );
315    _TIFFfree( buf );
316}
317
318char* read_text_tiff_metadata ( TDimFormatHandle *fmtHndl, DTiffParams *tifParams ) {
319    return NULL;
320}
321
322//----------------------------------------------------------------------------
323// New METADATA
324//----------------------------------------------------------------------------
325
326DIM_UINT append_metadata_generic_tiff (TDimFormatHandle *fmtHndl, DTagMap *hash ) {
327  if (fmtHndl == NULL) return 1;
328  if (fmtHndl->internalParams == NULL) return 1;
329  if (!hash) return 1;
330
331  DTiffParams *par = (DTiffParams *) fmtHndl->internalParams;
332  bim::TinyTiff::IFD *ifd = par->ifds.firstIfd();
333  if (!ifd) return 1;
334
335  std::map< int, std::string > hash_tiff_tags;
336  hash_tiff_tags[269] = "Document Name";
337  hash_tiff_tags[270] = "Image Description";
338  hash_tiff_tags[285] = "Page Name";
339  hash_tiff_tags[271] = "Make";
340  hash_tiff_tags[272] = "Model";
341  hash_tiff_tags[305] = "Software";
342  hash_tiff_tags[306] = "Date Time";
343  hash_tiff_tags[315] = "Artist";
344  hash_tiff_tags[316] = "Host Computer";
345
346  std::map< int, std::string >::const_iterator it = hash_tiff_tags.begin();
347  while (it != hash_tiff_tags.end()) {
348    xstring tag_str = ifd->readTagString(it->first);
349    if (tag_str.size()>0) hash->append_tag( xstring("custom/") + it->second, tag_str );
350    it++;
351  }
352  return 0;
353}
354
355DIM_UINT append_metadata_qimaging_tiff (TDimFormatHandle *fmtHndl, DTagMap *hash ) {
356  if (fmtHndl == NULL) return 1;
357  if (fmtHndl->internalParams == NULL) return 1;
358  if (!hash) return 1;
359
360  DTiffParams *par = (DTiffParams *) fmtHndl->internalParams;
361  bim::TinyTiff::IFD *ifd = par->ifds.firstIfd();
362  if (!ifd) return 1;
363
364  /*
365[Image Description]
366Exposure: 000 : 00 : 00 . 300 : 000
367Binning: 2 x 2
368Gain: 2.000000
369%Accumulated%=0
370
371[Software]
372QCapture Pro
373
374[Date Time]
37508/28/2006 04:34:47.000 PM
376  */
377
378  // check if it's QImage tiff file
379  // should exist private tags 50288 and 50296
380  if (!ifd->tagPresent(50288)) return 0;
381  if (!ifd->tagPresent(50296)) return 0;
382
383  // tag 305 should be "QCapture Pro"
384  xstring tag_software = ifd->readTagString(305);
385  if ( tag_software != "QCapture Pro" ) return 0;
386 
387  // ok, we're sure it's QImaging
388  hash->append_tag( bim::CUSTOM_TAGS_PREFIX+"Software", tag_software );
389
390
391  xstring tag_description = ifd->readTagString(TIFFTAG_IMAGEDESCRIPTION);
392  if (tag_description.size()>0)
393    hash->parse_ini( tag_description, ":", bim::CUSTOM_TAGS_PREFIX );
394
395  // read tag 306 - Date/Time
396  xstring tag_datetime = ifd->readTagString(306);
397  if (tag_datetime.size()>0) {
398    int y=0, m=0, d=0, h=0, mi=0, s=0, ms=0;
399    char ampm=0;
400    //08/28/2006 04:34:47.000 PM
401    sscanf( (char *)tag_datetime.c_str(), "%d/%d/%d %d:%d:%d.%d %c", &m, &d, &y, &h, &mi, &s, &ms, &ampm );
402    if (ampm == 'P') h += 12;
403    tag_datetime.sprintf("%.4d-%.2d-%.2d %.2d:%.2d:%.2d", y, m, d, h, mi, s);
404    hash->append_tag( bim::IMAGE_DATE_TIME, tag_datetime );
405  }
406
407  //hash->append_tag( "pixel_resolution_x", par->pixel_size[0] );
408  //hash->append_tag( "pixel_resolution_y", par->pixel_size[1] );
409  //hash->append_tag( "pixel_resolution_z", par->pixel_size[2] );
410
411  return 0;
412}
413
414DIM_UINT tiff_append_metadata (TDimFormatHandle *fmtHndl, DTagMap *hash ) {
415  if (fmtHndl == NULL) return 1;
416  if (fmtHndl->internalParams == NULL) return 1;
417  if (!hash) return 1;
418  DTiffParams *tifParams = (DTiffParams *) fmtHndl->internalParams;
419
420  append_metadata_qimaging_tiff (fmtHndl, hash );
421
422  if (tifParams->subType == tstStk) 
423    append_metadata_stk(fmtHndl, hash);
424  else
425  if (tifParams->subType == tstPsia) 
426    append_metadata_psia(fmtHndl, hash);
427  else
428  if (tifParams->subType==tstFluoview || tifParams->subType==tstAndor)
429    append_metadata_fluoview(fmtHndl, hash);
430  else
431  if (tifParams->subType == tstCzLsm)
432    append_metadata_lsm(fmtHndl, hash);
433  else
434  if (tifParams->subType == tstOmeTiff || tifParams->subType == tstOmeBigTiff)
435    append_metadata_omeTiff (fmtHndl, hash);
436  else
437    append_metadata_generic_tiff(fmtHndl, hash);
438
439  return 0;
440}
441
442//----------------------------------------------------------------------------
443// Write METADATA
444//----------------------------------------------------------------------------
445
446
447DIM_UINT write_tiff_metadata (TDimFormatHandle *fmtHndl, DTiffParams *tifParams)
448{
449  if (!areValidParams(fmtHndl, tifParams)) return 1;
450
451  DIM_UINT i;
452  TDimTagList *tagList = &fmtHndl->metaData;
453  void  *t_list = NULL;
454  int16 t_list_count;
455  TIFF *tif = tifParams->dimTiff;
456
457  if (tagList->count == 0) return 1;
458  if (tagList->tags == NULL) return 1;
459
460  for (i=0; i<tagList->count; i++) {
461    TDimTagItem *tagItem = &tagList->tags[i];
462    if (tagItem->tagGroup == DIM_META_TIFF_TAG) {
463      t_list = tagItem->tagData;
464      t_list_count = tagItem->tagLength;
465
466      TIFFSetField( tif, tagItem->tagId, tagItem->tagLength, tagItem->tagData ); 
467    }
468  }
469
470  return 0;
471}
472
473
474//****************************************************************************
475// WRITING LINE SEGMENT FROM BUFFER
476//****************************************************************************
477
478template< typename T >
479void write_line_segment_t(void *po, void *bufo, TDimImageBitmap *img, DIM_UINT sample, DIM_ULONG w) {
480  T *p   = (T *) po;
481  T *buf = (T *) bufo; 
482  DIM_UINT nsamples = img->i.samples;
483  register DIM_UINT x, xi=0;
484  for (x=sample; x<w*nsamples; x+=nsamples) {
485    p[xi] = buf[x];
486    xi++;
487  }
488}
489
490void write_line_segment(void *po, void *bufo, TDimImageBitmap *img, DIM_UINT sample, DIM_ULONG w) {
491  if (img->i.depth==8)  write_line_segment_t<DIM_UINT8>  (po, bufo, img, sample, w);
492  else
493  if (img->i.depth==16) write_line_segment_t<DIM_UINT16> (po, bufo, img, sample, w);
494  else
495  if (img->i.depth==32) write_line_segment_t<DIM_UINT32> (po, bufo, img, sample, w);
496  else
497  if (img->i.depth==64) write_line_segment_t<DIM_FLOAT64>(po, bufo, img, sample, w);
498}
499
500
501//****************************************************************************
502// SCANLINE METHOD TIFF
503//****************************************************************************
504
505int read_scanline_tiff(TIFF *tif, TDimImageBitmap *img, TDimFormatHandle *fmtHndl)
506{
507  int result = -1;
508  register DIM_UINT y = 0;
509  uint16 planarConfig;
510
511  if (tif == NULL) return result;
512  if (img == NULL) return result;
513 
514  DIM_UINT sample;
515  DIM_UINT lineSize = getLineSizeInBytes( img );
516
517  TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planarConfig);
518
519  if ( (planarConfig == PLANARCONFIG_SEPARATE) || (img->i.samples == 1) ) {
520    for (sample=0; sample<img->i.samples; sample++) {
521      DIM_UCHAR *p = (DIM_UCHAR *) img->bits[sample];
522
523      for(y=0; y<img->i.height; y++) {
524
525        dimProgress( fmtHndl, y*(sample+1), img->i.height*img->i.samples, "Reading TIFF" );
526        if ( dimTestAbort( fmtHndl ) == 1) break; 
527
528        result = TIFFReadScanline(tif, p, y, sample);
529        p += lineSize;
530      } // for y
531
532    }  // for sample
533
534  } // if planar
535  else // if image contain several samples in one same plane ex: RGBRGBRGB...
536  {
537    DIM_UCHAR *buf = (DIM_UCHAR *) _TIFFmalloc( TIFFScanlineSize ( tif ) );
538    for(y=0; y<img->i.height; y++) {
539
540      dimProgress( fmtHndl, y, img->i.height, "Reading TIFF" );
541      if ( dimTestAbort( fmtHndl ) == 1) break; 
542
543      TIFFReadScanline(tif, buf, y, 0);
544
545      for (sample=0; sample<img->i.samples; ++sample) {
546        DIM_UCHAR *p = (DIM_UCHAR *) img->bits[sample] + (lineSize * y);
547        write_line_segment(p, buf, img, sample, img->i.width);
548      }  // for sample
549
550    } // for y
551    _TIFFfree( buf );
552  } 
553
554  return result;
555}
556
557//****************************************************************************
558// TILED METHOD TIFF
559//****************************************************************************
560
561int read_tiled_tiff(TIFF *tif, TDimImageBitmap *img, TDimFormatHandle *fmtHndl) {
562  uint16 planarConfig;
563  if (tif == NULL) return 1;
564  if (img == NULL) return 1;
565
566  // if tiff is not tiled get out and never come back :-)
567  if( !TIFFIsTiled(tif) ) return 1;
568 
569  uint32 columns, rows;
570  DIM_UCHAR *tile_buf;
571  register DIM_UINT x, y;
572
573  DIM_UINT sample;
574  DIM_UINT lineSize = getLineSizeInBytes( img );
575
576  TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planarConfig);
577  TIFFGetField(tif, TIFFTAG_TILEWIDTH,  &columns);
578  TIFFGetField(tif, TIFFTAG_TILELENGTH, &rows);
579
580
581  tile_buf = (DIM_UCHAR*) _TIFFmalloc( TIFFTileSize(tif) );
582  if (tile_buf == NULL) return 1;
583  uint32 tileW = columns, tileH = rows;
584
585
586  for (y=0; y<img->i.height; y+=rows) {
587    if (y > img->i.height) break;
588
589    // the tile height may vary
590    if (img->i.height-y < rows) tileH = img->i.height-y; 
591
592    dimProgress( fmtHndl, y, img->i.height, "Reading TIFF" );
593    if ( dimTestAbort( fmtHndl ) == 1) break; 
594
595    tileW = columns;
596    for (x=0; x<(DIM_UINT)img->i.width; x+=columns) {
597      register uint32 yi;
598      uint32 tW;
599 
600      // the tile size is now treated by libtiff guys the
601      // way that the size stay on unchanged     
602      if (img->i.width-x < columns) tW = img->i.width-x; else tW = tileW;
603
604
605      if ( (planarConfig == PLANARCONFIG_SEPARATE) || (img->i.samples == 1) ) {
606        for (sample=0; sample<img->i.samples; sample++) {
607          if (!TIFFReadTile(tif, tile_buf, x, y, 0, sample)) break;
608 
609          // now put tile into the image
610          for(yi = 0; yi < tileH; yi++) {
611            DIM_UCHAR *p = (DIM_UCHAR *) img->bits[sample] + (lineSize * (y+yi));
612            _TIFFmemcpy(p+x, tile_buf+yi*tileW, tW);
613          }
614        }  // for sample
615
616      } // if planar
617      else { // if image contain several samples in one same plane ex: RGBRGBRGB...
618        if (!TIFFReadTile(tif, tile_buf, x, y, 0, 0)) break;
619        for (sample=0; sample<img->i.samples; sample++) {
620          // now put tile into the image
621          for(yi = 0; yi < tileH; yi++) {
622            DIM_UCHAR *p = (DIM_UCHAR *) img->bits[sample] + (lineSize * (y+yi));
623            write_line_segment(p+x, tile_buf+(yi*tileW*img->i.samples), img, sample, tW);
624          }
625        }  // for sample
626      } // if not separate planes
627
628    } // for x
629  } // for y
630
631  _TIFFfree(tile_buf);
632
633  return 0;
634}
635
636
637
638//****************************************************************************
639//*** TIFF READER
640//****************************************************************************
641
642// if the file is LSM then the strip size given in the file is incorrect, fix that
643// by simply checking against the file size and adjusting if needed
644void lsmFixStripByteCounts ( TIFF *tif, uint32 row, tsample_t sample ) {
645
646  TIFFDirectory *td = &tif->tif_dir;
647  D_TIFF_STRP_TYPE strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip;
648  D_TIFF_BCNT_TYPE bytecount = td->td_stripbytecount[strip];
649  if (tif->tif_size <= 0) tif->tif_size = TIFFGetFileSize(tif);
650
651  if ( td->td_stripoffset[strip] + bytecount > tif->tif_size) {
652    bytecount = tif->tif_size - td->td_stripoffset[strip];
653    td->td_stripbytecount[strip] = bytecount;
654  }
655}
656
657int read_tiff_image(TDimFormatHandle *fmtHndl, DTiffParams *tifParams) {
658  if (!areValidParams(fmtHndl, tifParams)) return 1;
659
660  TIFF *tif = tifParams->dimTiff;
661  TDimImageBitmap *img = fmtHndl->image;
662
663  uint32 height = 0; 
664  uint32 width = 0; 
665  uint16 bitspersample = 1;
666  uint16 samplesperpixel = 1;
667  uint32 rowsperstrip; 
668  uint16 photometric = PHOTOMETRIC_MINISWHITE;
669  uint16 compression = COMPRESSION_NONE;
670  uint16 PlanarConfig;
671  unsigned int currentDir = 0;
672
673  currentDir = TIFFCurrentDirectory(tif);
674  int needed_page_num = fmtHndl->pageNumber;
675  if (tifParams->subType == tstCzLsm)
676    needed_page_num = fmtHndl->pageNumber*2;
677
678  // now must read correct page and set image parameters
679  if (currentDir != needed_page_num)
680  if (tifParams->subType != tstStk) {
681    TIFFSetDirectory(tif, needed_page_num);
682
683    currentDir = TIFFCurrentDirectory(tif);
684    if (currentDir != needed_page_num) return 1;
685
686    getCurrentPageInfo( tifParams );
687  }
688 
689  if (tifParams->subType != tstOmeTiff) img->i = tifParams->info;
690
691  TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression);
692  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
693  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
694  TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
695  TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);
696  TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);   
697  TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric);
698  TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &PlanarConfig);       // single image plane
699
700  // this is here due to some OME-TIFF do not conform with the standard and come with all channels in the same IFD
701  if (tifParams->subType == tstOmeTiff) {
702    int r = omeTiffReadPlane( fmtHndl, tifParams, fmtHndl->pageNumber );
703    if (r != 2) return r;
704    img->i = tifParams->info;
705  }
706
707  // if image is PSIA then read and init it here
708  if (tifParams->subType == tstPsia)
709    return psiaReadPlane(fmtHndl, tifParams, fmtHndl->pageNumber, img);
710
711  // if image is Fluoview and contains 1..4 channels
712  if ( (tifParams->subType==tstFluoview || tifParams->subType==tstAndor) && (tifParams->fluoviewInfo.ch > 1) )
713    return fluoviewReadPlane( fmtHndl, tifParams, fmtHndl->pageNumber );
714
715  // if the file is LSM then the strip size given in the file is incorrect, fix that
716  if (tifParams->subType == tstCzLsm)
717    for (unsigned int sample=0; sample < samplesperpixel; ++sample)
718      for (unsigned int y=0; y < height; ++y)
719        lsmFixStripByteCounts( tif, y, sample );
720
721  if ( allocImg( fmtHndl, &img->i, img) != 0 ) return 1;
722
723  // if image is STK
724  if (tifParams->subType == tstStk)
725    return stkReadPlane(tifParams, fmtHndl->pageNumber, img, fmtHndl);
726
727
728  if( !TIFFIsTiled(tif) )
729    read_scanline_tiff(tif, img, fmtHndl);
730  else
731    read_tiled_tiff(tif, img, fmtHndl);
732
733  // invert each pixel if PHOTOMETRIC_MINISWHITE
734  if (photometric == PHOTOMETRIC_MINISWHITE)
735    invertImg( img );
736
737
738  return 0;
739}
740
741//****************************************************************************
742// TIFF WRITER
743//****************************************************************************
744
745int write_tiff_image(TDimFormatHandle *fmtHndl, DTiffParams *tifParams) {
746  if (!areValidParams(fmtHndl, tifParams)) return 1;
747
748  if (tifParams->subType == tstOmeTiff)
749    return omeTiffWritePlane( fmtHndl, tifParams);
750
751  TIFF *out = tifParams->dimTiff;
752  TDimImageBitmap *img = fmtHndl->image;
753 
754  uint32 height;
755  uint32 width;
756  uint32 rowsperstrip = (uint32) -1;
757  uint16 bitspersample;
758  uint16 samplesperpixel;
759  uint16 photometric = PHOTOMETRIC_MINISBLACK;
760  uint16 compression;
761  uint16 planarConfig;
762
763  width = img->i.width;
764  height = img->i.height;
765  bitspersample = img->i.depth;
766  samplesperpixel = img->i.samples;
767  if (img->i.imageMode == DIM_RGB)   photometric = PHOTOMETRIC_RGB;
768  if (img->i.imageMode == DIM_MULTI) photometric = PHOTOMETRIC_RGB;
769  if (samplesperpixel >= 2)          photometric = PHOTOMETRIC_RGB;
770  if ( (img->i.imageMode == DIM_INDEXED) && (img->i.lut.count > 0) && (samplesperpixel==1) && (bitspersample<=8) )
771    photometric = PHOTOMETRIC_PALETTE;
772
773  if ( (bitspersample == 1) && (samplesperpixel == 1) ) photometric = PHOTOMETRIC_MINISWHITE;
774  // a failed attempt to force photoshop to load 2 channel image
775  //if (samplesperpixel == 2) photometric = PHOTOMETRIC_SEPARATED;
776
777  // handle standard width/height/bpp stuff
778  TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
779  TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
780  TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
781  TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, bitspersample);
782  TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
783  TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
784
785 
786  // set pixel format
787  uint16 sampleformat = SAMPLEFORMAT_UINT;
788  if (img->i.pixelType == D_FMT_SIGNED) sampleformat = SAMPLEFORMAT_INT;
789  if (img->i.pixelType == D_FMT_FLOAT)  sampleformat = SAMPLEFORMAT_IEEEFP;
790  TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, sampleformat);
791
792
793  // set planar config
794  planarConfig = PLANARCONFIG_SEPARATE; // separated planes
795  if (samplesperpixel==3 && bitspersample==8)
796    planarConfig = PLANARCONFIG_CONTIG;
797
798  /*
799  if (img->i.imageMode == DIM_MULTI)
800    planarConfig = PLANARCONFIG_SEPARATE;       // separated planes
801  else
802    planarConfig = PLANARCONFIG_CONTIG; // mixed planes
803
804  // now more tests for plane configuration
805  if (samplesperpixel > 3) planarConfig = PLANARCONFIG_SEPARATE;
806  if ( (samplesperpixel == 1) || (samplesperpixel == 3) )
807    planarConfig = PLANARCONFIG_CONTIG;
808  */
809 
810  TIFFSetField(out, TIFFTAG_PLANARCONFIG, planarConfig);        // separated planes
811
812
813  TIFFSetField(out, TIFFTAG_SOFTWARE, "DIMIN TIFF WRAPPER <www.dimin.net>");
814
815  //if( TIFFGetField( out, TIFFTAG_DOCUMENTNAME, &pszText ) )
816  //if( TIFFGetField( out, TIFFTAG_IMAGEDESCRIPTION, &pszText ) )
817  //if( TIFFGetField( out, TIFFTAG_DATETIME, &pszText ) )
818
819
820
821  //------------------------------------------------------------------------------ 
822  // compression
823  //------------------------------------------------------------------------------ 
824
825  compression = fmtHndl->compression;
826  if (compression == 0) compression = COMPRESSION_NONE; 
827
828  switch(bitspersample) {
829  case 1  :
830    if (compression != COMPRESSION_CCITTFAX4) compression = COMPRESSION_NONE;
831    break;
832
833  case 8  :
834  case 16 :
835  case 32 :
836  case 64 :
837    if ( (compression != COMPRESSION_LZW) && (compression != COMPRESSION_PACKBITS) )
838      compression = COMPRESSION_NONE; 
839    break;
840 
841  default :
842    compression = COMPRESSION_NONE;
843    break;
844  }
845
846  TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
847
848  unsigned long strip_size = (unsigned long) MAX( TIFFDefaultStripSize(out,-1), 1 );
849  switch ( compression ) {
850    case COMPRESSION_JPEG:
851    {
852      TIFFSetField( out, TIFFTAG_ROWSPERSTRIP, strip_size+(16-(strip_size % 16)) );
853      break;
854    }
855
856    case COMPRESSION_ADOBE_DEFLATE:
857    {
858      TIFFSetField( out, TIFFTAG_ROWSPERSTRIP, height );
859      if ( (photometric == PHOTOMETRIC_RGB) ||
860           ((photometric == PHOTOMETRIC_MINISBLACK) && (bitspersample >= 8)) )
861        TIFFSetField( out, TIFFTAG_PREDICTOR, 2 );
862      TIFFSetField( out, TIFFTAG_ZIPQUALITY, 9 );
863      break;
864    }
865
866    case COMPRESSION_CCITTFAX4:
867    {
868      TIFFSetField( out, TIFFTAG_ROWSPERSTRIP, height );
869      break;
870    }
871
872    case COMPRESSION_LZW:
873    {
874      TIFFSetField( out, TIFFTAG_ROWSPERSTRIP, strip_size );
875      if (planarConfig == PLANARCONFIG_SEPARATE)
876         TIFFSetField( out, TIFFTAG_PREDICTOR, PREDICTOR_NONE );
877      else
878         TIFFSetField( out, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL );
879      break;
880    }
881    default:
882    {
883      TIFFSetField( out, TIFFTAG_ROWSPERSTRIP, strip_size );
884      break;
885    }
886  }
887
888  //------------------------------------------------------------------------------ 
889  // Save resolution
890  //------------------------------------------------------------------------------
891
892  {
893    double rx = img->i.xRes, ry = img->i.yRes; 
894    uint16 units = img->i.resUnits;
895   
896    if ( (img->i.xRes == 0) && (img->i.yRes == 0) || (img->i.resUnits == 1) ) {
897      // Standard resolution some claim to be 72ppi... why not?
898      units = RESUNIT_INCH;
899      rx = 72.0; 
900      ry = 72.0;
901    }
902    else
903    if (img->i.resUnits != 2) {
904      if (img->i.resUnits == 0)  { rx = pow(rx, -2); ry = pow(ry, -2); }
905      if (img->i.resUnits == 4)  { rx = pow(rx, -1); ry = pow(ry, -1); }
906      if (img->i.resUnits == 5)  { rx = pow(rx, -4); ry = pow(ry, -4); }
907      if (img->i.resUnits == 6)  { rx = pow(rx, -7); ry = pow(ry, -7); }
908      if (img->i.resUnits == 7)  { rx = pow(rx, 11); ry = pow(ry, 11); }
909      if (img->i.resUnits == 8)  { rx = pow(rx, 8); ry = pow(ry, 8); }
910      if (img->i.resUnits == 9)  { rx = pow(rx, 5); ry = pow(ry, 5); }
911      if (img->i.resUnits == 10) { rx = pow(rx, 0); ry = pow(ry, 0); }
912    }
913
914    TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, units);
915    TIFFSetField(out, TIFFTAG_XRESOLUTION, rx);
916    TIFFSetField(out, TIFFTAG_YRESOLUTION, ry);
917  }
918 
919  //------------------------------------------------------------------------------ 
920  // palettes (image colormaps are automatically scaled to 16-bits)
921  //------------------------------------------------------------------------------
922  uint16 palr[256], palg[256], palb[256];
923  if ( (photometric == PHOTOMETRIC_PALETTE) && (img->i.lut.count > 0) ) {
924    uint16 nColors = img->i.lut.count;
925    for (int i=0; i<nColors; i++) {
926      palr[i] = (uint16) dimR( img->i.lut.rgba[i] ) * 256;
927      palg[i] = (uint16) dimG( img->i.lut.rgba[i] ) * 256;
928      palb[i] = (uint16) dimB( img->i.lut.rgba[i] ) * 256;
929    }
930    TIFFSetField(out, TIFFTAG_COLORMAP, palr, palg, palb);
931  }
932
933
934  //------------------------------------------------------------------------------
935  // writing meta data
936  //------------------------------------------------------------------------------
937
938  write_tiff_metadata (fmtHndl, tifParams);
939  //TIFFFlush(out); // error in doing this, due to additional checks to the libtiff 4.0.0
940
941
942  //------------------------------------------------------------------------------
943  // writing image
944  //------------------------------------------------------------------------------
945
946  // if separate palnes or only one sample
947  if ( (planarConfig == PLANARCONFIG_SEPARATE) || (samplesperpixel == 1) ) {
948    DIM_UINT sample;
949    DIM_UINT line_size = getLineSizeInBytes( img );
950
951    for (sample=0; sample<img->i.samples; sample++) {
952      DIM_UCHAR *bits = (DIM_UCHAR *) img->bits[sample];
953      register uint32 y;
954
955      for (y = 0; y <height; y++) {
956        dimProgress( fmtHndl, y*(sample+1), height*img->i.samples, "Writing TIFF" );
957        if ( dimTestAbort( fmtHndl ) == 1) break; 
958
959        TIFFWriteScanline(out, bits, y, sample);
960        bits += line_size;
961      } // for y
962    } // for samples
963
964  } // if separate planes
965  else
966  { // if RGB image
967    DIM_UINT Bpp = (unsigned int) ceil( ((double) bitspersample) / 8.0 );
968    DIM_UCHAR *buffer = (DIM_UCHAR *) _TIFFmalloc(width * 3 * Bpp);
969    register DIM_UINT x, y;
970    DIM_UCHAR *black_line = (DIM_UCHAR *) _TIFFmalloc(width * Bpp);
971    memset( black_line, 0, width * Bpp );
972   
973    for (y = 0; y < height; y++) {
974      dimProgress( fmtHndl, y, height, "Writing TIFF" );
975      if ( dimTestAbort( fmtHndl ) == 1) break; 
976
977      DIM_UCHAR *bufIn0 = ((DIM_UCHAR *) img->bits[0]) + y*width*Bpp;
978      DIM_UCHAR *bufIn1 = ((DIM_UCHAR *) img->bits[1]) + y*width*Bpp;
979      DIM_UCHAR *bufIn2 = NULL;
980      if (samplesperpixel > 2)
981        bufIn2 = ((DIM_UCHAR *) img->bits[2]) + y*width*Bpp;
982      else
983        bufIn2 = black_line;
984
985      if (img->i.depth <= 8) { // 8 bits
986        DIM_UCHAR *= (DIM_UCHAR *) buffer;
987       
988        for (x=0; x<width; x++) {
989          p[0] = *(bufIn0 + x);
990          p[1] = *(bufIn1 + x);
991          p[2] = *(bufIn2 + x);
992          p += 3;
993        }
994
995      } // if 8 bit
996      else  { // 16 bits
997        uint16 *= (uint16 *) buffer;
998        uint16 *p0 = (uint16 *) bufIn0;   
999        uint16 *p1 = (uint16 *) bufIn1; 
1000        uint16 *p2 = (uint16 *) bufIn2;
1001     
1002        for (x=0; x<width; x++) {
1003          p[0] = *(p0 + x);
1004          p[1] = *(p1 + x);
1005          p[2] = *(p2 + x);
1006          p += 3;
1007        }
1008      } // if 16 bit
1009
1010      // write the scanline to disc
1011      TIFFWriteScanline(out, buffer, y, 0);
1012    }
1013
1014    _TIFFfree(buffer);
1015    _TIFFfree(black_line);
1016  }
1017
1018  TIFFWriteDirectory( out );
1019  TIFFFlushData(out);
1020  TIFFFlush(out);
1021
1022  return 0;
1023}
1024
1025#ifdef MAX
1026#undef MAX
1027#endif
1028
1029#ifdef MIN
1030#undef MIN
1031#endif
1032
Note: See TracBrowser for help on using the repository browser.