1 ## Copyright (C) 2010 Carnë Draug
3 ## This program is free software; you can redistribute it and/or modify
4 ## it under the terms of the GNU General Public License as published by
5 ## the Free Software Foundation; either version 3 of the License, or
6 ## (at your option) any later version.
8 ## This program is distributed in the hope that it will be useful,
9 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 ## GNU General Public License for more details.
13 ## You should have received a copy of the GNU General Public License
14 ## along with this program; If not, see <http://www.gnu.org/licenses/>.
16 ## Based on the documentation at
17 ## * http://en.wikipedia.org/wiki/Tagged_Image_File_Format
18 ## * http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
19 ## * http://ibb.gsf.de/homepage/karsten.rodenacker/IDL/Lsmfile.doc
20 ## * http://www.awaresystems.be/imaging/tiff/faq.html
22 ## and the function tiff_read by F. Nedelec, EMBL (www.cytosim.org)
23 ## * http://www.cytosim.org/misc/index.html
26 ## @deftypefn {Function File} [@var{value}, @var{offset}] = tiff_tag_read (@var{file}, @var{tag}, @var{ifd})
27 ## Reads the values of TIFF file tags.
29 ## @var{file} is a TIFF file and @var{tag} is the tag number to read. If
30 ## @var{ifd} is given, only the tag value from that IFD (Image File Directory)
31 ## will be read. By default, reads only the first IFD.
33 ## @var{value} is the read value from @var{tag}. @var{offset} will be @code{1}
34 ## if @var{value} is a file offset.
36 ## @seealso{imread, imfinfo, readexif}
39 ## * On the TIFF image file header:
40 ## bytes 00-01 --> byte order used within the file: "II" for little endian
41 ## and "MM" for big endian byte ordering.
42 ## bytes 02-03 --> number 42 that identifies the file as TIFF
43 ## bytes 04-07 --> file offset (in bytes) of the first IFD (Image File Directory)
45 ## Note: offset is always from the start of the file ("bof" in fread) and first
46 ## byte has an offset of zero.
48 ## * On a TIFF's IFD structure:
49 ## bytes 00-01 --> number of entries (or tags or fields or directories)
50 ## bytes 02-13 --> the entry (the tag is repeated the number of times
51 ## specified at the start of the IFD, but always takes
53 ## bytes XX-XX --> file offset for next IFD (last 4 bytes of the IFD)
55 ## Note: there must be always one IFD and each IFD must have at least one entry
57 ## * On an IFD entry (or TIFF's field) structure:
58 ## bytes 00-01 --> tag that identifies the entry
59 ## bytes 02-03 --> entry type
62 ## 3 --> SHORT (uint16)
63 ## 4 --> LONG (uint32)
64 ## 5 --> RATIONAL (two LONGS)
66 ## 7 --> UNDEFINED (8 bit)
67 ## 8 --> SSHORT (int16)
68 ## 9 --> SLONG (int32)
69 ## 10 --> FLOAT (single IEEE precision)
70 ## 11 --> DOUBLE (double IEEE precision)
71 ## bytes 04-07 --> number of values (count)
72 ## bytes 08-11 --> file offset to the value or value (only if it fits in 4 bytes)
74 ## Note: file offset of the value may point anywhere in the file, even after the image.
76 function [value, offset] = tiff_tag_read (file, tag, ifd)
78 [FID, msg] = fopen (file, "r", "native");
80 error ("Unable to fopen '%s': %s.", file, msg);
84 byte_order = fread(FID, 2, "char=>char");
85 if ( strcmp(byte_order', "II") )
86 arch = "ieee-le"; # IEEE little endian format
87 elseif ( strcmp(byte_order',"MM") )
88 arch = "ieee-be"; # IEEE big endian format
90 error("First 2 bytes of header returned '%s'. TIFF file expects either 'II' or 'MM'.", byte_order');
94 nTIFF = fread(FID, 1, "uint16", arch);
96 error("This is not a TIFF file (missing 42 on header at offset 2. Instead got '%g').", tiff_id);
99 # Read offset and move for the first IFD
100 offset_IFD = fread(FID, 1, "uint32", arch);
101 status = fseek(FID, offset_IFD, "bof");
103 error("Error on fseek when moving to first IFD.");
106 # Read number of entries (nTag) and look for the desired tag ID
107 nTag = fread(FID, 1, "uint16", arch);
108 iTag = 0; # Tag index
109 while (1) # Control is made inside the loop
111 cTag = fread(FID, 1, "uint16", arch); # Tag ID
112 if (cTag == tag) # Tag ID was found
113 value = read_value (FID, arch, tag); # Read tag value
115 elseif (iTag == nTag || cTag > tag) # All tags have been read (tags are in ascendent order)
116 error ("Unable to find tag %g.", tag)
118 status = fseek(FID, 10, "cof"); # Move to the next tag
120 error("Error on fseek when moving to tag %g of %g. Last tag read had value of %g", rTag, nTag, tag);
129 function [value, offset] = read_value (FID, arch, tag)
131 tiff_type = fread(FID, 1, "uint16", arch);
132 count = fread(FID, 1, "uint32", arch);
135 case 1 # BYTE = 8-bit unsigned integer
138 case 2 # ASCII = 8-bit byte that contains a 7-bit ASCII code; the last byte must be NUL (binary zero)
141 case 3 # SHORT = 16-bit (2-byte) unsigned integer
143 precision = "uint16";
144 case 4 # LONG = 32-bit (4-byte) unsigned integer
146 precision = "uint32";
147 case 5 # RATIONAL = Two LONGs: the first represents the numerator of a fraction; the second, the denominator
149 precision = "uint32";
150 case 6 # SBYTE = An 8-bit signed (twos-complement) integer
153 case 7 # UNDEFINED = An 8-bit byte that may contain anything, depending on the definition of the field
156 case 8 # SSHORT = A 16-bit (2-byte) signed (twos-complement) integer
159 case 9 # SLONG = A 32-bit (4-byte) signed (twos-complement) integer
162 case 10 # SRATIONAL = Two SLONG’s: the first represents the numerator of a fraction, the second the denominator
165 case 11 # FLOAT = Single precision (4-byte) IEEE format
167 precision = "float32";
168 case 12 # DOUBLE = Double precision (8-byte) IEEE format
170 precision = "float64";
171 otherwise # Warning (from TIFF file specifications): It is possible that other TIFF field types will be added in the future
172 error("TIFF type %i not supported", tiff_type)
175 if ( (nBytes*count) > 4 ) # If it doesn't fit in 4 bytes, it's an offset
177 value = fread(FID, 1, "uint32", arch);
178 ## The file offset must be an even number
179 if ( rem(value,2) != 0 )
180 error("Couldn't find correct value offset for tag %g", tag);
187 value = fread(FID, 2*count, precision, arch);
189 value = fread(FID, count, precision, arch);
192 value = char(value');