]> Creatis software - CreaPhase.git/blob - octave_packages/image-1.0.15/tiff_tag_read.m
Add a useful package (from Source forge) for octave
[CreaPhase.git] / octave_packages / image-1.0.15 / tiff_tag_read.m
1 ## Copyright (C) 2010 Carnë Draug
2 ## 
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.
7 ## 
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.
12 ## 
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/>.
15 ##
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
21 ##
22 ## and the function tiff_read by F. Nedelec, EMBL (www.cytosim.org)
23 ##  * http://www.cytosim.org/misc/index.html
24
25 ## -*- texinfo -*-
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.
28 ##
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.
32 ##
33 ## @var{value} is the read value from @var{tag}. @var{offset} will be @code{1}
34 ## if @var{value} is a file offset. 
35 ##
36 ## @seealso{imread, imfinfo, readexif}
37 ## @end deftypefn
38
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)
44 ##
45 ##   Note: offset is always from the start of the file ("bof" in fread) and first
46 ##   byte has an offset of zero.
47 ##
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
52 ##                     12 bytes of size)
53 ##     bytes XX-XX --> file offset for next IFD (last 4 bytes of the IFD)
54 ##
55 ##   Note: there must be always one IFD and each IFD must have at least one entry
56 ##
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
60 ##                      1  --> BYTE (uint8)
61 ##                      2  --> ASCII
62 ##                      3  --> SHORT (uint16)
63 ##                      4  --> LONG (uint32)
64 ##                      5  --> RATIONAL (two LONGS)
65 ##                      6  --> SBYTE (int8)
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)
73 ##
74 ##   Note: file offset of the value may point anywhere in the file, even after the image.
75
76 function [value, offset] = tiff_tag_read (file, tag, ifd)
77
78   [FID, msg] = fopen (file, "r", "native");
79   if (msg != 0)
80     error ("Unable to fopen '%s': %s.", file, msg);
81   endif
82
83   # Read byte order
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
89   else
90     error("First 2 bytes of header returned '%s'. TIFF file expects either 'II' or 'MM'.", byte_order');
91   endif
92
93   # Read number 42
94   nTIFF = fread(FID, 1, "uint16", arch);
95   if (nTIFF != 42)
96     error("This is not a TIFF file (missing 42 on header at offset 2. Instead got '%g').", tiff_id);
97   endif
98
99   # Read offset and move for the first IFD
100   offset_IFD = fread(FID, 1, "uint32", arch);
101   status = fseek(FID, offset_IFD, "bof");
102   if (status != 0)
103       error("Error on fseek when moving to first IFD.");
104   endif
105
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
110     iTag++;
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
114       break
115     elseif (iTag == nTag || cTag > tag)           # All tags have been read (tags are in ascendent order)
116       error ("Unable to find tag %g.", tag)
117     endif
118     status = fseek(FID, 10, "cof");               # Move to the next tag
119     if (status != 0)
120       error("Error on fseek when moving to tag %g of %g. Last tag read had value of %g", rTag, nTag, tag);
121     endif
122   endwhile
123
124   fclose (FID);
125
126 endfunction
127
128 #####
129 function [value, offset] = read_value (FID, arch, tag)
130
131   tiff_type = fread(FID, 1, "uint16", arch);
132   count     = fread(FID, 1, "uint32", arch);
133
134   switch (tiff_type)
135     case 1      # BYTE      = 8-bit unsigned integer
136       nBytes    = 1;
137       precision = "uint8";
138     case 2      # ASCII     = 8-bit byte that contains a 7-bit ASCII code; the last byte must be NUL (binary zero)
139       nBytes    = 1;
140       precision = "uchar";
141     case 3      # SHORT     = 16-bit (2-byte) unsigned integer
142       nBytes    = 2;
143       precision = "uint16";
144     case 4      # LONG      = 32-bit (4-byte) unsigned integer
145       nBytes    = 4;
146       precision = "uint32";
147     case 5      # RATIONAL  = Two LONGs: the first represents the numerator of a fraction; the second, the denominator
148       nBytes    = 8;
149       precision = "uint32";
150     case 6      # SBYTE     = An 8-bit signed (twos-complement) integer
151       nBytes    = 1;
152       precision = "int8";
153     case 7      # UNDEFINED = An 8-bit byte that may contain anything, depending on the definition of the field
154       nBytes    = 1;
155       precision = "uchar";
156     case 8      # SSHORT    = A 16-bit (2-byte) signed (twos-complement) integer
157       nBytes    = 2;
158       precision = "int16";
159     case 9      # SLONG     = A 32-bit (4-byte) signed (twos-complement) integer
160       nBytes    = 4;
161       precision = "int32";
162     case 10     # SRATIONAL = Two SLONG’s: the first represents the numerator of a fraction, the second the denominator
163       nBytes    = 8;
164       precision = "int32";
165     case 11     # FLOAT     = Single precision (4-byte) IEEE format
166       nBytes    = 4;
167       precision = "float32";
168     case 12     # DOUBLE    = Double precision (8-byte) IEEE format
169       nBytes   = 8;
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)
173   endswitch
174
175   if ( (nBytes*count) > 4 )    # If it doesn't fit in 4 bytes, it's an offset
176     offset = 1;
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);
181     endif
182   else
183     offset = 0;
184     ## read here
185     switch precision
186       case { 5, 10 }
187         value = fread(FID, 2*count, precision, arch);
188       otherwise
189         value = fread(FID, count, precision, arch);
190     endswitch
191     if (precision == 2)
192         value = char(value');
193     endif
194   endif
195
196 endfunction