10 public static final int NEW_SUBFILE_TYPE = 254;
11 public static final int IMAGE_WIDTH = 256;
12 public static final int IMAGE_LENGTH = 257;
13 public static final int BITS_PER_SAMPLE = 258;
14 public static final int COMPRESSION = 259;
15 public static final int PHOTO_INTERP = 262;
16 public static final int IMAGE_DESCRIPTION = 270;
17 public static final int STRIP_OFFSETS = 273;
18 public static final int SAMPLES_PER_PIXEL = 277;
19 public static final int ROWS_PER_STRIP = 278;
20 public static final int STRIP_BYTE_COUNT = 279;
21 public static final int X_RESOLUTION = 282;
22 public static final int Y_RESOLUTION = 283;
23 public static final int PLANAR_CONFIGURATION = 284;
24 public static final int RESOLUTION_UNIT = 296;
25 public static final int SOFTWARE = 305;
26 public static final int DATE_TIME = 306;
27 public static final int COLOR_MAP = 320;
28 public static final int SAMPLE_FORMAT = 339;
29 public static final int METAMORPH1 = 33628;
30 public static final int METAMORPH2 = 33629;
31 public static final int IPLAB = 34122;
32 public static final int NIH_IMAGE_HDR = 43314;
35 static final int UNSIGNED = 1;
36 static final int SIGNED = 2;
37 static final int FLOATING_POINT = 3;
40 static final int SHORT = 3;
41 static final int LONG = 4;
43 private String directory;
47 protected boolean debugMode;
48 private boolean littleEndian;
53 this.directory = directory;
64 final int getInt()
throws IOException {
70 return ((b4 << 24) + (b3 << 16) + (b2 << 8) + (b1 << 0));
72 return ((b1 << 24) + (b2 << 16) + (b3 << 8) + b4);
75 int getShort()
throws IOException {
79 return ((b2 << 8) + b1);
81 return ((b1 << 8) + b2);
84 int OpenImageFileHeader()
throws IOException {
88 int byteOrder = in.readShort();
89 if (byteOrder==0x4949)
91 else if (byteOrder==0x4d4d)
97 int magicNumber = getShort();
98 int offset = getInt();
102 int getValue(
int fieldType,
int count)
throws IOException {
105 if (fieldType==SHORT && count==1) {
114 void getColorMap(
int offset,
FileInfo fi)
throws IOException {
115 byte[] colorTable16 =
new byte[768*2];
116 int saveLoc = in.getFilePointer();
118 in.readFully(colorTable16);
121 fi.reds =
new byte[256];
122 fi.greens =
new byte[256];
123 fi.blues =
new byte[256];
127 for (
int i=0; i<256; i++) {
128 fi.reds[i] = colorTable16[j];
129 fi.greens[i] = colorTable16[512+j];
130 fi.blues[i] = colorTable16[1024+j];
136 byte[] getString(
int count,
int offset)
throws IOException {
140 byte[] bytes =
new byte[count];
141 int saveLoc = in.getFilePointer();
153 if (description.length<7)
156 ij.IJ.log(
"Image Description: " +
new String(description).replace(
'\n',
' '));
157 if (!
new String(description,0,6).equals(
"ImageJ"))
159 fi.description =
new String(description);
162 void decodeNIHImageHeader(
int offset,
FileInfo fi)
throws IOException {
163 int saveLoc = in.getFilePointer();
166 int version = in.readShort();
169 double scale = in.readDouble();
170 if (version>106 && scale!=0.0) {
171 fi.pixelWidth = 1.0/scale;
172 fi.pixelHeight = fi.pixelWidth;
177 int units = in.readShort();
178 if (version<=153) units += 5;
180 case 5: fi.unit =
"nanometer";
break;
181 case 6: fi.unit =
"micrometer";
break;
182 case 7: fi.unit =
"mm";
break;
183 case 8: fi.unit =
"cm";
break;
184 case 9: fi.unit =
"meter";
break;
185 case 10: fi.unit =
"km";
break;
186 case 11: fi.unit =
"inch";
break;
187 case 12: fi.unit =
"ft";
break;
188 case 13: fi.unit =
"mi";
break;
193 int fitType = in.read();
194 int unused = in.read();
195 int nCoefficients = in.readShort();
197 fi.calibrationFunction = 21;
198 fi.valueUnit =
"U. OD";
199 }
else if (fitType>=0 && fitType<=8 && nCoefficients>=1 && nCoefficients<=5) {
201 case 0: fi.calibrationFunction = 0;
break;
202 case 1: fi.calibrationFunction = 1;
break;
203 case 2: fi.calibrationFunction = 2;
break;
204 case 3: fi.calibrationFunction = 3;
break;
205 case 5: fi.calibrationFunction = 4;
break;
206 case 6: fi.calibrationFunction = 5;
break;
207 case 7: fi.calibrationFunction = 6;
break;
208 case 8: fi.calibrationFunction = 7;
break;
210 fi.coefficients =
new double[nCoefficients];
211 for (
int i=0; i<nCoefficients; i++) {
212 fi.coefficients[i] = in.readDouble();
215 int size = in.read();
216 StringBuffer sb =
new StringBuffer();
217 if (size>=1 && size<=16) {
218 for (
int i=0; i<size; i++)
219 sb.append((
char)(in.read()));
220 fi.valueUnit =
new String(sb);
226 int nImages = in.readShort();
227 if(nImages>=2 && (fi.fileType==FileInfo.GRAY8||fi.fileType==FileInfo.COLOR8)) {
228 fi.nImages = nImages;
229 fi.pixelDepth = in.readFloat();
230 int skip = in.readShort();
231 fi.frameInterval = in.readFloat();
236 float aspectRatio = in.readFloat();
237 if (version>140 && aspectRatio!=0.0)
238 fi.pixelHeight = fi.pixelWidth/aspectRatio;
243 void dumpTag(
int tag,
int count,
int value, FileInfo fi) {
246 case NEW_SUBFILE_TYPE: name=
"NewSubfileType";
break;
247 case IMAGE_WIDTH: name=
"ImageWidth";
break;
248 case IMAGE_LENGTH: name=
"ImageLength";
break;
249 case STRIP_OFFSETS: name=
"StripOffsets";
break;
250 case PHOTO_INTERP: name=
"PhotoInterp";
break;
251 case IMAGE_DESCRIPTION: name=
"ImageDescription";
break;
252 case BITS_PER_SAMPLE: name=
"BitsPerSample";
break;
253 case SAMPLES_PER_PIXEL: name=
"SamplesPerPixel";
break;
254 case ROWS_PER_STRIP: name=
"RowsPerStrip";
break;
255 case STRIP_BYTE_COUNT: name=
"StripByteCount";
break;
256 case X_RESOLUTION: name=
"XResolution";
break;
257 case Y_RESOLUTION: name=
"YResolution";
break;
258 case RESOLUTION_UNIT: name=
"ResolutionUnit";
break;
259 case SOFTWARE: name=
"Software";
break;
260 case DATE_TIME: name=
"DateTime";
break;
261 case PLANAR_CONFIGURATION: name=
"PlanarConfiguration";
break;
262 case COMPRESSION: name=
"Compression";
break;
263 case COLOR_MAP: name=
"ColorMap";
break;
264 case SAMPLE_FORMAT: name=
"SampleFormat";
break;
265 case NIH_IMAGE_HDR: name=
"NIHImageHeader";
break;
266 default: name=
"???";
break;
268 String cs = (count==1)?
"":
", count=" + count;
269 dInfo +=
" " + tag +
", \"" + name +
"\", value=" + value + cs +
"\n";
273 double getRational(
int loc)
throws IOException {
274 int saveLoc = in.getFilePointer();
276 int numerator = getInt();
277 int denominator = getInt();
280 return (
double)numerator/denominator;
285 FileInfo OpenIFD() throws IOException {
288 int tag, fieldType, count, value;
289 int nEntries = getShort();
293 FileInfo fi =
new FileInfo();
294 for (
int i=0; i<nEntries; i++) {
296 fieldType = getShort();
298 value = getValue(fieldType, count);
299 if (debugMode) dumpTag(tag, count, value, fi);
313 int saveLoc = in.getFilePointer();
315 fi.offset = getInt();
320 fi.whiteIsZero = value==0;
322 case BITS_PER_SAMPLE:
325 fi.fileType = FileInfo.GRAY8;
326 else if (value==16) {
327 fi.fileType = FileInfo.GRAY16_UNSIGNED;
328 fi.intelByteOrder = littleEndian;
330 else if (value==32) {
331 fi.fileType = FileInfo.GRAY32_INT;
332 fi.intelByteOrder = littleEndian;
334 fi.fileType = FileInfo.BITMAP;
336 throw new IOException(
"Unsupported BitsPerSample: " + value);
337 }
else if (count==3) {
338 int saveLoc = in.getFilePointer();
340 int bitDepth = getShort();
341 if (!(bitDepth==8||bitDepth==16))
342 throw new IOException(
"ImageJ can only open 8 and 16 bit/channel RGB images");
344 fi.intelByteOrder = littleEndian;
345 fi.fileType = FileInfo.RGB48;
350 case SAMPLES_PER_PIXEL:
351 if (value==3 && fi.fileType!=FileInfo.RGB48)
352 fi.fileType = FileInfo.RGB;
353 else if (!(value==1||value==3)) {
354 String msg =
"Unsupported SamplesPerPixel: " + value;
356 msg +=
" \n \n" +
"ImageJ cannot open CMYK and RGB+alpha TIFFs";
357 throw new IOException(msg);
361 double xScale = getRational(value);
362 if (xScale!=0.0) fi.pixelWidth = 1.0/xScale;
365 double yScale = getRational(value);
366 if (yScale!=0.0) fi.pixelHeight = 1.0/yScale;
368 case RESOLUTION_UNIT:
369 if (value==1&&fi.unit==null)
376 case PLANAR_CONFIGURATION:
377 if (value==2 && fi.fileType==FileInfo.RGB48)
378 throw new IOException(
"ImageJ cannot open planar 48-bit RGB images");
379 if (value==2 && fi.fileType==FileInfo.RGB)
380 fi.fileType = FileInfo.RGB_PLANAR;
383 if (value!=1 && value!=7)
384 throw new IOException(
"ImageJ cannot open compressed TIFF files ("+value+
")");
387 if (count==768 && fi.fileType==fi.GRAY8)
388 getColorMap(value, fi);
391 if (fi.fileType==FileInfo.GRAY32_INT && value==FLOATING_POINT)
392 fi.fileType = FileInfo.GRAY32_FLOAT;
393 if (fi.fileType==FileInfo.GRAY16_UNSIGNED && value==SIGNED)
394 fi.fileType = FileInfo.GRAY16_SIGNED;
396 case IMAGE_DESCRIPTION:
398 byte[] s = getString(count,value);
402 case METAMORPH1:
case METAMORPH2:
403 if (name.indexOf(
".STK")>0 || name.indexOf(
".stk")>0) {
415 decodeNIHImageHeader(value, fi);
420 fi.fileFormat = fi.TIFF;
422 fi.directory = directory;
425 if (debugMode) dInfo +=
" offset=" + fi.offset +
"\n";
430 public void enableDebugging() {
435 public FileInfo[] getTiffInfo() throws IOException {
440 in =
new RandomAccessStream(
new RandomAccessFile(directory + name,
"r"));
442 ifdOffset = OpenImageFileHeader();
447 if (debugMode) dInfo =
"\n " + name +
": opening\n";
448 while (ifdOffset>0) {
450 FileInfo fi = OpenIFD();
454 ifdOffset = getInt();
455 if (debugMode) dInfo +=
" nextIFD=" + ifdOffset +
"\n";
456 if (fi!=null && fi.nImages>1)
459 if (info.size()==0) {
463 FileInfo[] fi =
new FileInfo[info.size()];
464 info.copyInto((Object[])fi);
465 if (debugMode) fi[0].info = dInfo;
468 fi[0].inputStream = in;