首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

用 libtiff 进行图形编程-1

用 libtiff 进行图形编程-1

TIFF(标记图像文件格式(Tag Image File Format))是一种最初由 Adobe 提出的光栅图像格式。 光栅图像格式将图片存储为描述像素状态的位图,而不是记录图元(譬如,线和曲线)的长度和位置。Libtiff 是 TIFF 规范的标准实现之一,目前它因其速度、强大的功能和源代码的易于获取而被广泛使用。
本文专注于黑白 TIFF 图像;以后可能会有文章讨论彩色图像。
TIFF 挑战大多数文件格式规范定义文件表示的一些基本规则。 例如,PNG 文档(TIFF 的一个竞争者)始终使用大尾数法。然而,TIFF 没有这种规定。下面的示例列出了某些看起来很基本而 TIFF 并未定义的内容:
  • 字节次序:大尾数法还是小尾数法
  • 图像字节内的位填充次序:最高位首先填充还是最低位首先填充
  • 给定的黑白象素值的含义:0 代表黑还是白?
创建 TIFF 文件很容易,因为几乎不需要对您已有的数据进行任何转换。 另一方面,它也意味着读入其它应用程序创建的随机 TIFF 会很困难 ― 所以您必须编码所有可能的组合,以确信得到可靠的产品。
那么,如何编写一个应用程序来读入 TIFF 格式的所有可能的不同排列呢? 最重要的是要记住        决不要假设正在读入的图像数据的格式。
写 TIFF 文件首先,我将向您演示如何写出 TIFF 文件。然后,我将演示如何将 TIFF 文件读回程序中。
写操作的基础设施传统上, 位图在代码内由一个字符数组表示。这是因为在大多数操作系统上,一个字符能很好地映射成一个字节。 在清单 1 中,我设置了 libtiff 并创建一个简单的缓冲区,使之包含我稍后可以写到磁盘上的图像。 您可以下载该代码,作为 write-infrastructure.c(请参阅本文后面的 )。      
清单 1. 设置基础设施(write-infrastructure.c)
1
2
3
4
5
6
7
#include <stdio.h>
#include <tiffio.h>
int
main (int argc, char *argv[])
{
  char buffer[32 * 9];
}




上面的代码相当简单。要使用 libtiff,只需要包含 tiffio.h 头文件。要编译它, 请使用命令         gcc foo.c -o foo -ltiff -lm 。         -ltiff 是包含名为 libtiff 的库的命令,该库必需在库路径中。一旦开始显式地指定库, 还必需添加         -lm ,它是数学库。这里定义的 char buffer 将是黑白图像, 所以我们接下来定义其中的一个。      
写图像为了凑足那个令人生厌的示例, 我现在很乐意向您提供迄今为止可能是画得最差的悉尼港大桥的图片。在清单 2 中,图像已经在图像缓冲区中,我们只需将它保存到磁盘上的文件中。 该示例先以写方式打开一个 TIFF 图像,然后将该图像放到该文件中。
请注意,为了清晰起见,我省略了该图像的实际十六进制值;如果对它们感兴趣, 可以从这段代码的可下载版本 write.c(请参阅 )中获得它们。      
清单 2. 写操作的代码(write.c)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <tiffio.h>
int main(int argc, char *argv[]){
  // Define an image
  char buffer[25 * 144] = { /* boring hex omitted */ };
  TIFF *image;
  // Open the TIFF file
  if((image = TIFFOpen("output.tif", "w")) == NULL){
    printf("Could not open output.tif for writing\n");
    exit(42);
  }
  // We need to set some values for basic tags before we can add any data
  TIFFSetField(image, TIFFTAG_IMAGEWIDTH, 25 * 8);
  TIFFSetField(image, TIFFTAG_IMAGELENGTH, 144);
  TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 1);
  TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, 1);
  TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, 144);
  TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
  TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
  TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
  TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  TIFFSetField(image, TIFFTAG_XRESOLUTION, 150.0);
  TIFFSetField(image, TIFFTAG_YRESOLUTION, 150.0);
  TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
   
  // Write the information to the file
  TIFFWriteEncodedStrip(image, 0, buffer, 25 * 144);
  // Close the file
  TIFFClose(image);
}




(在我的 Linux 机器上使用         xview 命令将不能显示输出图像。事实上, 我还没发现哪一个以 group 4 fax 方式压缩的黑白图像可以使用那个程序显示出来。 在发表本文时,我仍无法找到这个程序的修正。)      
无论如何,样本代码演示了使用 libtiff API 的基本要素。值得注意的几点是:
  • 提供给 libtiff 和从 libtiff 返回的缓冲区都是每个字节中包含 8 个像素。 因而,您必须能够抽取您所感兴趣的像素。在这里使用掩码、右移和左移运算符很方便。
  • TIFFOpen 函数与您熟悉的           fopen 函数非常相似。
  • 在开始将图像写出之前,我们需要为相当多的字段设置值。 这些字段为 libtiff 提供有关图像大小和形状的信息,以及在图像内压缩数据的方法。 在开始将图像数据交给 libtiff 之前,需要设置这些字段。还可以为许多其它字段设置值; 在本示例中,我使用了接近最少数量的字段。
  • TIFFWriteEncodedStrip 是实际将图像插入文件的函数调用。这个调用将未压缩的图像数据插入文件。 这意味着在将图像数据写入文件之前,libtiff 将先对它进行压缩。 如果您已经对数据进行压缩,那么可以看一看           TIFFWriteRawStrip 。
  • 最后,用           TIFFClose 关闭文件。
如果您对悉尼港大桥的外观感到好奇,可以看一下 ,它是该图片的副本。 (我不得不作弊并将它转换成 JPEG,因为大多数 Web 浏览器不支持 TIFF。)      
有关 libtiff 函数调用的更多信息如果您需要有关本文中提到的任何 libtiff 函数调用的更多信息,请参阅与该库一起提供的详尽的帮助页。
         请记住,帮助手册页面中的大小写很重要,所以需要正确拼写函数名中的字母大小写。 例如,它是           TIFFOpen ,而不是           tiffopen 。        

图 1. Michael Still 绘制的悉尼港大桥
返回列表