The
following demonstrates how
to
create 24 bit
colour RGB
TIFF (Tagged
Image FIle Format)
files. That is,
how to
create images
from your own software that
can be then opened and
manipulated with image
handling software, for
example: GIMP, PhotoShop,
etc. Given this aim, this
document illustrates the
"minimal" requirements
necessary to
create a TIFF file,
it does not provide enough
information for
writing a TIFF file
reader. For more
information on the full
TIFF
specification the following
postscript and pdf files
describe the
TIFF version 6.
The
basic structure of a
TIFF file is as
follows:
The
first 8 bytes forms the
header. The
first two bytes of which is
either "II" for little
endian byte ordering or "MM"
for big endian byte
ordering. In what follows
we'll be assuming little
endian ordering. Note: any
true
TIFF reading
software is supposed to be
handle both types. The next
two bytes of the header
should be 0 and 42dec
(2ahex). The
remaining 4 bytes of the
header is the offset from
the start of the file to the
first "Image
File Directory"
(IFD), this normally follows
the image data it applies
to. In the
example below
there is only one
image and one
IFD.
An
IFD
consists of two bytes
indicating the number of
entries followed by the
entries themselves. The IFD
is terminated with 4 byte
offset to the next IFD or 0
if there are none. A
TIFF file must
contain at least one IFD!
Each
IFD entry
consists of 12 bytes. The
first two bytes identifies
the tag type (as in
Tagged
Image File Format).
The next two bytes are the
field type (byte, ASCII,
short int, long int, ...).
The next four bytes indicate
the number of values. The
last four bytes is either
the value itself or an
offset to the values.
Considering the first IFD
entry from the example gievn
below:
Collapse
Copy Code
0100 0003 0000 0001 0064 0000
| | | |
tag --+ | | |
short int -----+ | |
one value ----------+ |
value of 100 -----------------+
Example
The
following is an
example using the
TIFF file shown
on the right, namely a black
image with a single white
pixel at the top left and
the bottom right position.
The image is 100 pixels wide
by 200 pixels high.
A hex
dump is given below along
with matching pointers and
locations marked in matching
colours, these colours
further match the
appropriate parts of the
source code gievn later. The
tags are underlined.
Collapse
Copy Code
4d4d 002a 0000 ea68 ffff ff00 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
.... .... black 0's deleted .... ....
0000 0000 00ff ffff 000e 0100 0003 0000
0001 0064 0000 0101 0003 0000 0001 00c8
0000 0102 0003 0000 0003 0000 eb16 0103
0003 0000 0001 0001 0000 0106 0003 0000
0001 0002 0000 0111 0004 0000 0001 0000
0008 0112 0003 0000 0001 0001 0000 0115
0003 0000 0001 0003 0000 0116 0003 0000
0001 00c8 0000 0117 0004 0000 0001 0000
ea60 0118 0003 0000 0003 0000 eb1c 0119
0003 0000 0003 0000 eb22 011c 0003 0000
0001 0001 0000 0153 0003 0000 0003 0000
eb28 0000 0000 0008 0008 0008 0000 0000
0000 00ff 00ff 00ff 0001 0001 0001
|
|
The
above example uses 14dec
(000eihex)
directory entries.
0100 - Image width
0101 - Image height
0102 - Bits per sample (8)
0103 - Compression method (1
= uncompressed)
0106 - Photometric
Interpretation (2 = RGB)
0111 - Strip Offsets
0112 - Orientation (1 = 0
top, 0 left hand side) 0115
- Samples per pixel (1)
0116 - Rows per strip (200 =
image height)
0117 - Strip Byte Counts
(60000 = 100 x 200 x 3)
0118 - Minimum sample value
(0,0,0)
0119 - Maximum sample value
(255,255,255)
011c - Planar configuration
(1 = single image plane)
0153 - Sample format
Source code example
The
following is the guts of a C
program to
create a
TIFF file of
width nx, height ny. Each
pixel is made up of 3 bytes,
one byte for each of Red,
Green, Blue. Each colour
component ranges from 0
(black) to 255 (white).
Collapse
Copy Code
WriteHexString(fptr,"4d4d002a");
offset = nx * ny * 3 + 8;
putc((offset & 0xff000000) / 16777216,fptr);
putc((offset & 0x00ff0000) / 65536,fptr);
putc((offset & 0x0000ff00) / 256,fptr);
putc((offset & 0x000000ff),fptr);
for (j=0;j<ny;j++) {
for (i=0;i<nx;i++) {
... calculate the RGB value between 0 and 255 ...
fputc(red,fptr);
fputc(green,fptr);
fputc(blue,fptr);
}
}
WriteHexString(fptr,"000e");
WriteHexString(fptr,"0100000300000001");
fputc((nx & 0xff00) / 256,fptr);
fputc((nx & 0x00ff),fptr);
WriteHexString(fptr,"0000");
WriteHexString(fptr,"0101000300000001");
fputc((ny & 0xff00) / 256,fptr);
fputc((ny & 0x00ff),fptr);
WriteHexString(fptr,"0000");
"#ff0000">
WriteHexString(fptr,"0102000300000003");
offset = nx * ny * 3 + 182;
putc((offset & 0xff000000) / 16777216,fptr);
putc((offset & 0x00ff0000) / 65536,fptr);
putc((offset & 0x0000ff00) / 256,fptr);
putc((offset & 0x000000ff),fptr);
WriteHexString(fptr,"010300030000000100010000");
WriteHexString(fptr,"010600030000000100020000");
WriteHexString(fptr,"011100040000000100000008");
WriteHexString(fptr,"011200030000000100010000");
WriteHexString(fptr,"011500030000000100030000");
WriteHexString(fptr,"0116000300000001");
fputc((ny & 0xff00) / 256,fptr);
fputc((ny & 0x00ff),fptr);
WriteHexString(fptr,"0000");
WriteHexString(fptr,"0117000400000001");
offset = nx * ny * 3;
putc((offset & 0xff000000) / 16777216,fptr);
putc((offset & 0x00ff0000) / 65536,fptr);
putc((offset & 0x0000ff00) / 256,fptr);
putc((offset & 0x000000ff),fptr);
"#00ff00">
WriteHexString(fptr,"0118000300000003");
offset = nx * ny * 3 + 188;
putc((offset & 0xff000000) / 16777216,fptr);
putc((offset & 0x00ff0000) / 65536,fptr);
putc((offset & 0x0000ff00) / 256,fptr);
putc((offset & 0x000000ff),fptr);
"#ffff00">
WriteHexString(fptr,"0119000300000003");
offset = nx * ny * 3 + 194;
putc((offset & 0xff000000) / 16777216,fptr);
putc((offset & 0x00ff0000) / 65536,fptr);
putc((offset & 0x0000ff00) / 256,fptr);
putc((offset & 0x000000ff),fptr);
WriteHexString(fptr,"011c00030000000100010000");
"#0000ff">
WriteHexString(fptr,"0153000300000003");
offset = nx * ny * 3 + 200;
putc((offset & 0xff000000) / 16777216,fptr);
putc((offset & 0x00ff0000) / 65536,fptr);
putc((offset & 0x0000ff00) / 256,fptr);
putc((offset & 0x000000ff),fptr);
WriteHexString(fptr,"00000000");
WriteHexString(fptr,"000800080008");
WriteHexString(fptr,"000000000000");
WriteHexString(fptr,"00ff00ff00ff");
WriteHexString(fptr,"000100010001");