aimsdata 6.0.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>
40#include <cartobase/exception/file.h>
41#include <cartobase/exception/format.h>
42#include <cartobase/stream/fileutil.h>
44#include <stdio.h>
45extern "C"
46{
47#include <tiffio.h>
48}
49
50
51namespace aims
52{
53
54 template<class T>
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> &
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_t * rgba_data = (uint32_t *)&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
void setSizeY(float sizey)
const carto::AllocatorContext & allocator() const
void setSizeT(float sizet)
void setHeader(aims::Header *hdr)
int dimY() const
int dimX() const
int dimZ() const
void setSizeZ(float sizez)
void setSizeX(float sizex)
virtual std::vector< std::string > inputFilenames()
The descriptor class of the .dim GIS header.
Definition tiffheader.h:49
int dimT() const
Definition tiffheader.h:63
float sizeZ() const
Definition tiffheader.h:67
void setType(const std::string &t)
float sizeT() const
Definition tiffheader.h:68
int dimY() const
Definition tiffheader.h:61
int dimZ() const
Definition tiffheader.h:62
float sizeY() const
Definition tiffheader.h:66
float sizeX() const
Definition tiffheader.h:65
int dimX() const
Definition tiffheader.h:60
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
void read(AimsData< T > &thing, const carto::AllocatorContext &context, carto::Object options)
Definition tiffR.h:85
TiffReader(const std::string &name)
Definition tiffR.h:58
std::string dataType()
static char separator()
static std::string dirname(const std::string &)
static std::string fileStat(const std::string &)
Object value(const Object &value)
virtual bool getProperty(const std::string &, Object &) const
virtual bool removeProperty(const std::string &)
virtual void setProperty(const std::string &, Object)
virtual bool hasProperty(const std::string &) const
The class for EcatSino data write operation.
GenesisReader< T > & operator>>(GenesisReader< T > &reader, AimsData< T > &thing)
Definition genesisR.h:70
carto::VoxelRGBA AimsRGBA
Definition rgb.h:44
carto::VoxelRGB AimsRGB
Definition rgb.h:43
unsigned int uint
unsigned short ushort