aimsdata  4.7.0
Neuroimaging data handling
tiffR.h
Go to the documentation of this file.
1 /* This software and supporting documentation are distributed by
2  * Institut Federatif de Recherche 49
3  * CEA/NeuroSpin, Batiment 145,
4  * 91191 Gif-sur-Yvette cedex
5  * France
6  *
7  * This software is governed by the CeCILL-B license under
8  * French law and abiding by the rules of distribution of free software.
9  * You can use, modify and/or redistribute the software under the
10  * terms of the CeCILL-B license as circulated by CEA, CNRS
11  * and INRIA at the following URL "http://www.cecill.info".
12  *
13  * As a counterpart to the access to the source code and rights to copy,
14  * modify and redistribute granted by the license, users are provided only
15  * with a limited warranty and the software's author, the holder of the
16  * economic rights, and the successive licensors have only limited
17  * liability.
18  *
19  * In this respect, the user's attention is drawn to the risks associated
20  * with loading, using, modifying and/or developing or reproducing the
21  * software by the user in light of its specific status of free software,
22  * that may mean that it is complicated to manipulate, and that also
23  * therefore means that it is reserved for developers and experienced
24  * professionals having in-depth computer knowledge. Users are therefore
25  * encouraged to load and test the software's suitability as regards their
26  * requirements in conditions enabling the security of their systems and/or
27  * data to be ensured and, more generally, to use and operate it in the
28  * same conditions as regards security.
29  *
30  * The fact that you are presently reading this means that you have had
31  * knowledge of the CeCILL-B license and that you accept its terms.
32  */
33 
34 #ifndef AIMS_IO_TIFFR_H
35 #define AIMS_IO_TIFFR_H
36 
37 #include <aims/data/data.h>
38 #include <aims/io/tiffheader.h>
39 #include <aims/io/datatypecode.h>
44 #include <stdio.h>
45 extern "C"
46 {
47 #include <tiffio.h>
48 }
49 
50 
51 namespace aims
52 {
53 
54  template<class T>
55  class TiffReader
56  {
57  public:
58  TiffReader( const std::string& name ) : _name( name ) {}
60 
61  void read( AimsData<T>& thing, const carto::AllocatorContext & context,
62  carto::Object options );
65  void readFrame( AimsData<T> & thing, const std::string & filename,
66  int zframe, unsigned tframe );
67 
68  private:
69  std::string _name;
70  };
71 
72 
73  template <class T>
74  inline TiffReader<T> &
75  operator >> ( TiffReader<T> & reader, AimsData<T> & thing )
76  {
77  reader.read( thing, thing.allocator(),
79  return reader;
80  }
81 
82 
83  template <class T>
84  inline
86  const carto::AllocatorContext & context,
87  carto::Object options )
88  {
89  TiffHeader *hdr = new TiffHeader( _name );
90  try
91  {
92  hdr->read();
93  }
94  catch( std::exception & e )
95  {
96  delete hdr;
97  throw;
98  }
99 
100  int frame = -1, border = 0;
101  options->getProperty( "frame", frame );
102  options->getProperty( "border", border );
103 
104  std::vector<std::string> files = hdr->inputFilenames();
105  std::vector<int> dims;
106  hdr->getProperty( "volume_dimension", dims );
107 
108  if( dims.size() < 1 )
109  dims.push_back( hdr->dimX() );
110  if( dims.size() < 2 )
111  dims.push_back( hdr->dimY() );
112  if( dims.size() < 3 )
113  dims.push_back( hdr->dimZ() );
114  if( dims.size() < 4 )
115  dims.push_back( hdr->dimT() );
116 
117  unsigned tmin = 0, tmax = dims[3] - 1;
118  if( frame >= 0 )
119  {
120  if( tmax < (unsigned) frame )
121  {
122  delete hdr;
123  throw std::domain_error( "frame higher than file dimT" );
124  }
125  if( (unsigned) frame < tmax )
126  files.erase( files.begin() + ( frame + 1 ) * hdr->dimZ(),
127  files.end() );
128  if( frame > 0 )
129  files.erase( files.begin(), files.begin() + frame * hdr->dimZ() );
130  tmin = frame;
131  tmax = frame;
132  }
133 
134  carto::AllocatorContext al
135  ( context.accessMode(),
137  ( new carto::FileDataSource( *files.begin(), 0,
138  carto::DataSource::Read ) ),
139  false, context.useFactor() );
140 
141 // std::cout << "TiffReader allocate data " << carto::DataTypeCode<T>::dataType()
142 // << "[ " << hdr->dimX()
143 // << ", " << hdr->dimY()
144 // << ", " << hdr->dimZ()
145 // << ", " << tmax - tmin + 1 << " ]"
146 // << " border size " << carto::toString(border)
147 // << std::endl << std::flush;
148 
149  AimsData<T> data( hdr->dimX(),
150  hdr->dimY(),
151  hdr->dimZ(),
152  tmax - tmin + 1,
153  border, al );
154  data.setSizeX( hdr->sizeX() );
155  data.setSizeY( hdr->sizeY() );
156  data.setSizeZ( hdr->sizeZ() );
157  data.setSizeT( hdr->sizeT() );
158 
159  dims[3] = tmax - tmin + 1;
160  hdr->setProperty( "volume_dimension", dims );
161 
162  // force data type into header
164  hdr->setType( dtc.dataType() );
165  std::string dir = carto::FileUtil::dirname( _name );
166  if( !dir.empty() )
168 
169  unsigned i = 0, s, t, ns = (unsigned) data.dimZ(), nt = tmax - tmin + 1;
170 
171  if ( files.size() == ns * nt )
172  {
173  // Each file contain 1 slice and 1 frame
174  for( t=0; t<nt; ++t ) {
175  for( s=0; s<ns; ++s, ++i ) {
176  if ( ! carto::FileUtil::fileStat( dir + files[i] ).empty() ) {
177  readFrame( data, dir + files[i], s, t );
178  }
179  }
180  }
181  } else if ( files.size() == nt )
182  {
183  // Each file contain z slices and 1 frame
184  for( t=0; t<nt; ++t ) {
185  if ( ! carto::FileUtil::fileStat( dir + files[t] ).empty() ) {
186  readFrame( data, dir + files[t], -1, t );
187  }
188  }
189  }
190 
191  thing = data;
192  if( hdr->hasProperty( "filenames" ) )
193  hdr->removeProperty( "filenames" );
194  thing.setHeader( hdr );
195  }
196 
197  namespace
198  {
199  template <typename T, typename U> inline
200  T tiff_scaled_value_single( const U* buffer )
201  {
202  T item;
203  int shift = sizeof(U) <= sizeof(T) ?
204  0 : ((sizeof(U) - sizeof(T)) * 8);
205  item = *buffer >> shift;
206  return item;
207  }
208 
209  template <typename T, typename U> inline
210  T tiff_scaled_value_items( const U* buffer, uint16_t nitems )
211  {
212  T item;
213  int shift = sizeof(U) * nitems <= sizeof(T) ?
214  0 : ((sizeof(U) - sizeof(T) / nitems) * 8);
215  for( uint16_t i=0; i<nitems; ++i )
216  {
217  item[i] = *buffer++ >> shift;
218  }
219  return item;
220  }
221 
222  template <typename T, typename U>
223  class tiff_scaled_value_u
224  {
225  public:
226  static inline T scale( const U* buffer )
227  {
228  return tiff_scaled_value_single<T, U>( buffer );
229  }
230  };
231 
232  template <typename U>
233  class tiff_scaled_value_u<AimsRGB, U>
234  {
235  public:
236  static inline AimsRGB scale( const U* buffer )
237  {
238  return tiff_scaled_value_items<AimsRGB, U>( buffer, 3 );
239  }
240  };
241 
242  template <typename U>
243  class tiff_scaled_value_u<AimsRGBA, U>
244  {
245  public:
246  static inline AimsRGBA scale( const U* buffer )
247  {
248  return tiff_scaled_value_items<AimsRGBA, U>( buffer, 4 );
249  }
250  };
251 
252  template <typename T> inline
253  T tiff_scaled_value( const char *buffer, uint16_t bits )
254  {
255  if( bits == 8 )
256  return tiff_scaled_value_u<T, uint8_t>::scale(
257  (const uint8_t *) buffer );
258  else if( bits == 16 )
259  return tiff_scaled_value_u<T, uint16_t>::scale(
260  (const uint16_t *) buffer );
261  else // if( bits == 32 )
262  return tiff_scaled_value_u<T, uint32_t>::scale(
263  (const uint32_t *) buffer );
264  }
265 
266  }
267 
268  template<class T>
269  inline
271  const std::string & name, int zframe,
272  unsigned tframe )
273  {
274  int tiled, stripSize, rowsPerStrip;
275  uint i, s, zmin, zmax, dx = data.dimX(), dy = data.dimY();
276  ushort photometric;
277 
278  TIFFSetWarningHandler( 0 );
279  TIFF* tif = TIFFOpen(name.c_str(), "r");
280 
281  if( !tif )
282  throw carto::wrong_format_error( _name );
283 
284  if (tif)
285  {
286  tiled = TIFFIsTiled(tif);
287  if (tiled)
288  {
290  "Not a tiled TIFF image : can't read" );
291  }
292  else
293  {
294  if ( zframe == -1 )
295  {
296  // Process all Tiff directories
297  zmin = 0;
298  zmax = data.dimZ();
299  }
300  else
301  {
302  // Process only the matching z slice
303  zmin = (uint)zframe;
304  zmax = (uint)zframe + 1;
305  }
306 
307  for ( uint z = zmin; z < zmax; z++ )
308  {
309  TIFFSetDirectory(tif, z );
310  stripSize = TIFFStripSize(tif);
311  uint16_t bits, samplesize/*, items*/;
312 
313  // Read tif frame properties
314  TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsPerStrip);
315  TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &photometric);
316  TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bits);
317  samplesize = stripSize / dx / rowsPerStrip;
318  //items = samplesize / (bits >> 3);
319 // std::cout << "tiff rowsPerStrip: " << rowsPerStrip << ", photometric: " << photometric << ", t: " << tframe << ", z: " << z << ", stripsize: " << stripSize << ", bits: " << bits << ", samplesize: " << samplesize << ", items: " << items << std::endl;
320  if( photometric != PHOTOMETRIC_PALETTE )
321  {
322  std::vector<char> buffer( stripSize, 0 );
323  for(s=0, i=0; s < dy; s += rowsPerStrip, ++i)
324  {
325  TIFFReadEncodedStrip(tif, i, &buffer[0], stripSize);
326  if( samplesize == sizeof(T) )
327  for( uint y=s; y<std::min(s+rowsPerStrip, dy); ++y )
328  memcpy( &data(0, y, z, tframe),
329  &buffer[(y-s) * dx * samplesize],
330  dx * sizeof(T) );
331  else
332  for( uint y=s; y<std::min(s+rowsPerStrip, dy); ++y )
333  {
334  T* ibuf = &data( 0, y, z, tframe );
335  for( uint x=0; x<dx; ++x, ++ibuf )
336  *ibuf = tiff_scaled_value<T>(
337  &buffer[((y-s) * dx + x) * samplesize], bits );
338  }
339  }
340 
341  if(photometric == PHOTOMETRIC_MINISWHITE)
342  {
343  // Flip bits
344  byte* buffer;
345 
346  for(int y = 0; y < data.dimY(); ++y) {
347  buffer = (byte*)&data(0, y, z, tframe);
348  for( unsigned index=0; index<(dx * sizeof(T)); index++ )
349  {
350  buffer[index] =~ buffer[index];
351  }
352  }
353  }
354  }
355  else if( carto::DataTypeCode<T>().dataType()
356  == carto::DataTypeCode<AimsRGBA>().dataType() )
357  {
358  // Indexed images can only be read as RGBA data
359  uint32 * rgba_data = (uint32 *)&data(0, 0, z, tframe);
360  TIFFReadRGBAImageOriented(tif, dx, data.dimY(),
361  rgba_data, ORIENTATION_TOPLEFT);
362  }
363  }
364  }
365  TIFFClose(tif);
366  }
367  }
368 }
369 
370 #endif
The descriptor class of the .dim GIS header.
Definition: tiffheader.h:48
float sizeY() const
Definition: tiffheader.h:66
GenesisReader< T > & operator>>(GenesisReader< T > &reader, AimsData< T > &thing)
Definition: genesisR.h:70
std::string dataType()
int dimZ() const
virtual bool getProperty(const std::string &, Object &) const
int dimX() const
Definition: tiffheader.h:60
int nt
float sizeZ() const
Definition: tiffheader.h:67
TiffReader(const std::string &name)
Definition: tiffR.h:58
int dimY() const
The class for EcatSino data write operation.
Definition: border.h:42
static std::string fileStat(const std::string &)
void setSizeX(float sizex)
virtual bool removeProperty(const std::string &)
void setHeader(aims::Header *hdr)
static char separator()
int dimT() const
Definition: tiffheader.h:63
float sizeT() const
Definition: tiffheader.h:68
static std::string dirname(const std::string &)
void readFrame(AimsData< T > &thing, const std::string &filename, int zframe, unsigned tframe)
called by read(), but you can call it for single frame reading (axial slice)
Definition: tiffR.h:270
int dimY() const
Definition: tiffheader.h:61
static Object value()
void setType(const std::string &t)
virtual std::vector< std::string > inputFilenames()
unsigned int uint
int dimZ() const
Definition: tiffheader.h:62
const carto::AllocatorContext & allocator() const
virtual void setProperty(const std::string &, Object)
uint8_t byte
void read(AimsData< T > &thing, const carto::AllocatorContext &context, carto::Object options)
Definition: tiffR.h:85
virtual bool hasProperty(const std::string &) const
float sizeX() const
Definition: tiffheader.h:65
unsigned short ushort
int dimX() const