一 介绍
TIFF(标记图像文件格式(Tag Image File Format))是一种最初由 Adobe 提出的光栅图像格式。 光栅图像格式将图片存储为描述像素状态的位图,而不是记录图元(譬如,线和曲线)的长度和位置。Libtiff 是 TIFF 规范的标准实现之一,目前它因其速度、强大的功能和源代码的易于获取而被广泛使用。
二. TIFF 挑战
大多数文件格式规范定义文件表示的一些基本规则。 例如,PNG 文档(TIFF 的一个竞争者)始终使用大尾数法。然而,TIFF 没有这种规定。下面的示例列出了某些看起来很基本而 TIFF 并未定义的内容:
- 字节次序:大尾数法还是小尾数法
- 图像字节内的位填充次序:最高位首先填充还是最低位首先填充
- 给定的黑白象素值的含义:0 代表黑还是白?
创建 TIFF 文件很容易,因为几乎不需要对您已有的数据进行任何转换。 另一方面,它也意味着读入其它应用程序创建的随机 TIFF 会很困难 ― 所以您必须编码所有可能的组合,以确信得到可靠的产品。
那么,如何编写一个应用程序来读入 TIFF 格式的所有可能的不同排列呢? 最重要的是要记住 决不要假设正在读入的图像数据的格式。
三.写TIFF文件
具体见如下代码
1 #include <stdio.h>
2 #include <tiffio.h>
3 int main(int argc, char *argv[]){
4 // Define an image
5 char buffer[25 * 144] = { /* 省略了16进制的图像值 */ };
6 TIFF *image;
7 // Open the TIFF file
8 if((image = TIFFOpen("output.tif", "w")) == NULL){
9 printf("Could not open output.tif for writing
");
10 exit(42);
11 }
12 // We need to set some values for basic tags before we can add any data
13 TIFFSetField(image, TIFFTAG_IMAGEWIDTH, 25 * 8); //图像的宽度
14 TIFFSetField(image, TIFFTAG_IMAGELENGTH, 144); //图像长度
15 TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 1); //每个像素点位数
16 TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, 1);//每像素样本数
17 TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, 144); //每个条的行数
18 TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4); //压缩算法
19 TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE); //
20 TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB); //图像排列方式
21 TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
22 TIFFSetField(image, TIFFTAG_XRESOLUTION, 150.0); //X分辨率
23 TIFFSetField(image, TIFFTAG_YRESOLUTION, 150.0); //Y分辨率
24 TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); //分辨率单位 英寸
25
26 // Write the information to the file
27 TIFFWriteEncodedStrip(image, 0, buffer, 25 * 144); //写文件
28 // Close the file
29 TIFFClose(image); //关闭文件
30 }
四 读TIFF文件
1 void testReadGrayTiff()
2 {
3 TIFF* image;
4 uint16 photo, bps, spp, fillorder;
5 uint32 width;
6 tsize_t stripSize;
7 unsigned long imageOffset, result;
8 int stripMax, stripCount;
9 char* buffer, tempbyte;
10 unsigned long bufferSize, count;
11
12 // Open the TIFF image
13 if ((image = TIFFOpen("output.tif", "r")) == NULL) {
14 fprintf(stderr, "Could not open incoming image
");
15 exit(42);
16 }
17
18 // Check that it is of a type that we support
19 if ((TIFFGetField(image, TIFFTAG_BITSPERSAMPLE, &bps) == 0) || (bps != 1)) {
20 fprintf(stderr, "Either undefined or unsupported number of bits per sample
");
21 exit(42);
22 }
23
24 if ((TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp) == 0) || (spp != 1)) {
25 fprintf(stderr, "Either undefined or unsupported number of samples per pixel
");
26 exit(42);
27 }
28
29 // Read in the possibly multiple strips
30 stripSize = TIFFStripSize(image);
31 stripMax = TIFFNumberOfStrips(image);
32 imageOffset = 0;
33
34 bufferSize = TIFFNumberOfStrips(image) * stripSize;
35 if ((buffer = (char*)malloc(bufferSize)) == NULL) {
36 fprintf(stderr, "Could not allocate enough memory for the uncompressed image
");
37 exit(42);
38 }
39
40 for (stripCount = 0; stripCount < stripMax; stripCount++) {
41 if ((result = TIFFReadEncodedStrip(image, stripCount,
42 buffer + imageOffset,
43 stripSize)) == -1) {
44 fprintf(stderr, "Read error on input strip number %d
", stripCount);
45 exit(42);
46 }
47
48 imageOffset += result;
49 }
50
51 // Deal with photometric interpretations
52 if (TIFFGetField(image, TIFFTAG_PHOTOMETRIC, &photo) == 0) {
53 fprintf(stderr, "Image has an undefined photometric interpretation
");
54 exit(42);
55 }
56
57 if (photo != PHOTOMETRIC_MINISWHITE) {
58 // Flip bits
59 printf("Fixing the photometric interpretation
");
60
61 for (count = 0; count < bufferSize; count++)
62 buffer[count] = ~buffer[count];
63 }
64
65 // Deal with fillorder
66 if (TIFFGetField(image, TIFFTAG_FILLORDER, &fillorder) == 0) {
67 fprintf(stderr, "Image has an undefined fillorder
");
68 exit(42);
69 }
70
71 if (fillorder != FILLORDER_MSB2LSB) {
72 // We need to swap bits -- ABCDEFGH becomes HGFEDCBA
73 printf("Fixing the fillorder
");
74
75 for (count = 0; count < bufferSize; count++) {
76 tempbyte = 0;
77 if (buffer[count] & 128) tempbyte += 1;
78 if (buffer[count] & 64) tempbyte += 2;
79 if (buffer[count] & 32) tempbyte += 4;
80 if (buffer[count] & 16) tempbyte += 8;
81 if (buffer[count] & 8) tempbyte += 16;
82 if (buffer[count] & 4) tempbyte += 32;
83 if (buffer[count] & 2) tempbyte += 64;
84 if (buffer[count] & 1) tempbyte += 128;
85 buffer[count] = tempbyte;
86 }
87 }
88
89 // Do whatever it is we do with the buffer -- we dump it in hex
90 if (TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width) == 0) {
91 fprintf(stderr, "Image does not define its width
");
92 exit(42);
93 }
94
95 for (count = 0; count < bufferSize; count++) {
96 printf("%02x", (unsigned char)buffer[count]);
97 if ((count + 1) % (width / 8) == 0) printf("
");
98 else printf(" ");
99 }
100
101 TIFFClose(image);
102 }
五. TIFF图像的几种类型
1.单条格式
象它的名称表述的那样,这是条纹图像的特例。在这种情况中,所有位图都存储在一个大的块中。 我在 Windows 机器上体验过单条图像的可靠性问题。通常建议一个未压缩的条不要占据 8 K 字节以上, 黑白图像限制为单条中最多为 65536 个像素。
条纹(或多条)图像
图像的水平块存储在一起。多个条垂直地连接以形成完整的位图。
2.瓦片格式
象盥洗室墙壁那样,它是由瓷砖组成的。 下图演示了这种表示法, 它可用于非常大的图像。当您想在任何时候只操纵图像的一小部分时,平铺特别有用。