1 /*=========================================================================
2 *
3 * Copyright Insight Software Consortium
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0.txt
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *=========================================================================*/
18
19 #include "itkMacro.h"
20 #include "itkTIFFReaderInternal.h"
21 #include <sys/stat.h>
22
23 namespace itk
24 {
25
Open(const char * filename)26 int TIFFReaderInternal::Open(const char *filename)
27 {
28 this->Clean();
29 struct stat fs;
30 if ( stat(filename, &fs) )
31 {
32 #if defined(_WIN32) && ! defined(__MINGW32_VERSION)
33 struct _stat64 fs64;
34 if ( _stat64(filename, &fs64) )
35 {
36 // Both stat() and _stat64() return != 0
37 return 0;
38 }
39 #else
40 return 0;
41 #endif
42 }
43
44 this->m_Image = TIFFOpen(filename, "r");
45 if ( !this->m_Image )
46 {
47 this->Clean();
48 return 0;
49 }
50 if ( !this->Initialize() )
51 {
52 this->Clean();
53 return 0;
54 }
55
56 this->m_IsOpen = true;
57 return 1;
58 }
59
Clean()60 void TIFFReaderInternal::Clean()
61 {
62 if ( this->m_Image )
63 {
64 TIFFClose(this->m_Image);
65 }
66 this->m_Image = nullptr;
67 this->m_Width = 0;
68 this->m_Height = 0;
69 this->m_SamplesPerPixel = 0;
70 this->m_Compression = 0;
71 this->m_BitsPerSample = 0;
72 this->m_Photometrics = 0;
73 this->m_HasValidPhotometricInterpretation = false;
74 this->m_PlanarConfig = 0;
75 this->m_CurrentPage = 0;
76 this->m_NumberOfPages = 0;
77 this->m_NumberOfTiles = 0;
78 this->m_Orientation = ORIENTATION_TOPLEFT;
79 this->m_TileRows = 0;
80 this->m_TileColumns = 0;
81 this->m_TileWidth = 0;
82 this->m_TileHeight = 0;
83 this->m_XResolution = 1;
84 this->m_YResolution = 1;
85 this->m_SubFiles = 0;
86 this->m_IgnoredSubFiles = 0;
87 this->m_SampleFormat = 1;
88 this->m_ResolutionUnit = 1; // none
89 this->m_IsOpen = false;
90 }
91
92
TIFFReaderInternal()93 TIFFReaderInternal::TIFFReaderInternal()
94 {
95 this->m_Image = nullptr;
96 this->Clean();
97 }
98
Initialize()99 int TIFFReaderInternal::Initialize()
100 {
101 if ( this->m_Image )
102 {
103 if ( !TIFFGetField(this->m_Image, TIFFTAG_IMAGEWIDTH, &this->m_Width)
104 || !TIFFGetField(this->m_Image, TIFFTAG_IMAGELENGTH, &this->m_Height) )
105 {
106 return 0;
107 }
108
109 // Get the resolution in each direction
110 TIFFGetField(this->m_Image,
111 TIFFTAG_XRESOLUTION, &this->m_XResolution);
112 TIFFGetField(this->m_Image,
113 TIFFTAG_YRESOLUTION, &this->m_YResolution);
114 TIFFGetField(this->m_Image,
115 TIFFTAG_RESOLUTIONUNIT, &this->m_ResolutionUnit);
116
117 // Check the number of pages. First by looking at the number of directories
118 this->m_NumberOfPages = TIFFNumberOfDirectories(this->m_Image);
119
120 if ( this->m_NumberOfPages == 0 )
121 {
122 itkGenericExceptionMacro("No directories found in TIFF file.");
123 }
124
125 if ( TIFFIsTiled(this->m_Image) )
126 {
127 this->m_NumberOfTiles = TIFFNumberOfTiles(this->m_Image);
128
129 if ( !TIFFGetField(this->m_Image, TIFFTAG_TILEWIDTH, &this->m_TileWidth)
130 || !TIFFGetField(this->m_Image, TIFFTAG_TILELENGTH, &this->m_TileHeight) )
131 {
132 itkGenericExceptionMacro(
133 << "Cannot read tile width and tile length from file");
134 }
135 else
136 {
137 this->m_TileRows = this->m_Height / this->m_TileHeight;
138 this->m_TileColumns = this->m_Width / this->m_TileWidth;
139 }
140 }
141
142 // Checking if the TIFF contains subfiles
143 if ( this->m_NumberOfPages > 1 )
144 {
145 this->m_SubFiles = 0;
146 this->m_IgnoredSubFiles = 0;
147
148 for ( unsigned int page = 0; page < this->m_NumberOfPages; page++ )
149 {
150 int32 subfiletype = 6;
151 if ( TIFFGetField(this->m_Image, TIFFTAG_SUBFILETYPE, &subfiletype) )
152 {
153 if ( subfiletype == 0 )
154 {
155 this->m_SubFiles += 1;
156 }
157 // ignored flags
158 else if ( subfiletype & FILETYPE_REDUCEDIMAGE
159 || subfiletype & FILETYPE_MASK )
160 {
161 ++this->m_IgnoredSubFiles;
162 }
163
164 }
165 TIFFReadDirectory(this->m_Image);
166 }
167
168 // Set the directory to the first image, and reads it
169 TIFFSetDirectory(this->m_Image, 0);
170 }
171
172 TIFFGetFieldDefaulted(this->m_Image, TIFFTAG_ORIENTATION,
173 &this->m_Orientation);
174 TIFFGetFieldDefaulted(this->m_Image, TIFFTAG_SAMPLESPERPIXEL,
175 &this->m_SamplesPerPixel);
176 TIFFGetFieldDefaulted(this->m_Image, TIFFTAG_COMPRESSION, &this->m_Compression);
177 TIFFGetFieldDefaulted(this->m_Image, TIFFTAG_BITSPERSAMPLE,
178 &this->m_BitsPerSample);
179 TIFFGetFieldDefaulted(this->m_Image, TIFFTAG_PLANARCONFIG, &this->m_PlanarConfig);
180 TIFFGetFieldDefaulted(this->m_Image, TIFFTAG_SAMPLEFORMAT, &this->m_SampleFormat);
181
182 // If TIFFGetField returns false, there's no Photometric Interpretation
183 // set for this image, but that's a required field so we set a warning flag.
184 // (Because the "Photometrics" field is an enum, we can't rely on setting
185 // this->m_Photometrics to some signal value.)
186 if ( TIFFGetField(this->m_Image, TIFFTAG_PHOTOMETRIC, &this->m_Photometrics) )
187 {
188 this->m_HasValidPhotometricInterpretation = true;
189 }
190 else
191 {
192 this->m_HasValidPhotometricInterpretation = false;
193 }
194 }
195
196 return 1;
197 }
198
CanRead()199 int TIFFReaderInternal::CanRead()
200 {
201 const bool compressionSupported = ( TIFFIsCODECConfigured(this->m_Compression) == 1 );
202 return ( this->m_Image && ( this->m_Width > 0 ) && ( this->m_Height > 0 )
203 && ( this->m_SamplesPerPixel > 0 )
204 && compressionSupported
205 && ( m_NumberOfTiles == 0 ) // just use TIFFReadRGBAImage, an
206 // native optimized version would be nice
207 && ( this->m_HasValidPhotometricInterpretation )
208 && ( this->m_Photometrics == PHOTOMETRIC_RGB
209 || this->m_Photometrics == PHOTOMETRIC_MINISWHITE
210 || this->m_Photometrics == PHOTOMETRIC_MINISBLACK
211 || ( this->m_Photometrics == PHOTOMETRIC_PALETTE
212 && this->m_BitsPerSample != 32 )
213 )
214 && ( this->m_PlanarConfig == PLANARCONFIG_CONTIG
215 || this->m_SamplesPerPixel == 1 )
216 && ( this->m_Orientation == ORIENTATION_TOPLEFT
217 || this->m_Orientation == ORIENTATION_BOTLEFT )
218 && ( this->m_BitsPerSample == 8 || this->m_BitsPerSample == 16 || this->m_BitsPerSample == 32 ) );
219 }
220
221 }
222