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

用 libtiff 进行图形编程-2

用 libtiff 进行图形编程-2

读 TIFF 文件可靠地读 TIFF 文件比起写它们要困难得多。 遗憾的是,本文篇幅有限,无法讨论所有的重要问题,所以一些问题需要留到以后的文章中讨论。Web 上也有大量讨论有关问题的页面。我所喜爱的一些页面包括在本文末尾的 一节中。      
使读取黑白 TIFF 图像变得最复杂的问题是 TIFF 文件本身中可能存在的几种不同存储模式。Libtiff 不阻止您使用这些模式,所以您必须能够自己处理它们。TIFF 支持的三种模式是单条图像、条纹图像和平铺图像:
单条图像
象它的名称表述的那样,这是条纹图像的特例。在这种情况中,所有位图都存储在一个大的块中。 我在 Windows 机器上体验过单条图像的可靠性问题。通常建议一个未压缩的条不要占据 8 K 字节以上, 黑白图像限制为单条中最多为 65536 个像素。
条纹(或多条)图像
图像的水平块存储在一起。多个条垂直地连接以形成完整的位图。 演示了这个概念。      
图 2. 悉尼港大桥的条纹图像平铺图像
象盥洗室墙壁那样,它是由瓷砖组成的。 演示了这种表示法, 它可用于非常大的图像。当您想在任何时候只操纵图像的一小部分时,平铺特别有用。      
图 3. 悉尼港大桥的平铺图像平铺图像不太常见,所以在本文中我将集中讨论条纹图像。请记住,单条图像只是多条图像的子集。
读操作的基础设施读入 TIFF 图像时要记住的最重要的事情是要灵活。读操作示例(下面的清单 3)的基本概念与写操作示例(上面的清单 2) 相同,主要区别在于读操作示例需要处理许多可能的输入图像。除了条纹和平铺之外, 灵活性的最重要事情是光度解释(photometric interpretation)。幸运的是,对于黑白图像,只要考虑两种光度解释; 而对于彩色及某种程度的灰度级图像,则有更多的光度解释。
什么是        光度解释?缓冲区中图像的表示法确实是一件很随意的事情。 我可能对位图进行编码,让 0 表示黑色(         TIFFTAG_MINISBLACK ), 而您可能喜欢用 1 表示黑色(         TIFFTAG_MINISWHITE )。TIFF 允许这两种表示, 所以代码必须能够处理这两种情况。 在下面的示例中,我假设了内部缓冲区必需是         MINISWHITE 形式, 所以我们要转换         MINISBLACK 形式的图像。      
另一件要记住的大事情是        填充次序,即字节中的第一位是最高位的值还是最低位的值。 清单 3 也正确地处理了这两种情况。我假设了缓冲区的第一位是最高位的值。TIFF 图像可以是大尾数法也可以是小尾数法,但 libtiff 会为我们处理。 感到欣慰的是,libtiff 还支持各种压缩算法,所以您不必担心它们。目前为止, 这些都是 TIFF 的最令人头疼之处,所以仍值得花时间来使用 libtiff。清单 3 是可下载的 read.c(请参阅 )。      
清单 3. 读操作的代码(read.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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <stdio.h>
#include <tiffio.h>
int main(int argc, char *argv[]){
  TIFF *image;
  uint16 photo, bps, spp, fillorder;
  uint32 width;
  tsize_t stripSize;
  unsigned long imageOffset, result;
  int stripMax, stripCount;
  char *buffer, tempbyte;
  unsigned long bufferSize, count;
  // Open the TIFF image
  if((image = TIFFOpen(argv[1], "r")) == NULL){
    fprintf(stderr, "Could not open incoming image\n");
    exit(42);
  }
  // Check that it is of a type that we support
  if((TIFFGetField(image, TIFFTAG_BITSPERSAMPLE, &bps) == 0) || (bps != 1)){
    fprintf(stderr, "Either undefined or unsupported number of bits per sample\n");
    exit(42);
  }
  if((TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp) == 0) || (spp != 1)){
    fprintf(stderr, "Either undefined or unsupported number of samples per pixel\n");
    exit(42);
  }
  // Read in the possibly multiple strips
  stripSize = TIFFStripSize (image);
  stripMax = TIFFNumberOfStrips (image);
  imageOffset = 0;
   
  bufferSize = TIFFNumberOfStrips (image) * stripSize;
  if((buffer = (char *) malloc(bufferSize)) == NULL){
    fprintf(stderr, "Could not allocate enough memory for the uncompressed image\n");
    exit(42);
  }
   
  for (stripCount = 0; stripCount < stripMax; stripCount++){
    if((result = TIFFReadEncodedStrip (image, stripCount,
                      buffer + imageOffset,
                      stripSize)) == -1){
      fprintf(stderr, "Read error on input strip number %d\n", stripCount);
      exit(42);
    }
    imageOffset += result;
  }
  // Deal with photometric interpretations
  if(TIFFGetField(image, TIFFTAG_PHOTOMETRIC, &photo) == 0){
    fprintf(stderr, "Image has an undefined photometric interpretation\n");
    exit(42);
  }
   
  if(photo != PHOTOMETRIC_MINISWHITE){
    // Flip bits
    printf("Fixing the photometric interpretation\n");
    for(count = 0; count < bufferSize; count++)
      buffer[count] = ~buffer[count];
  }
  // Deal with fillorder
  if(TIFFGetField(image, TIFFTAG_FILLORDER, &fillorder) == 0){
    fprintf(stderr, "Image has an undefined fillorder\n");
    exit(42);
  }
   
  if(fillorder != FILLORDER_MSB2LSB){
    // We need to swap bits -- ABCDEFGH becomes HGFEDCBA
    printf("Fixing the fillorder\n");
    for(count = 0; count < bufferSize; count++){
      tempbyte = 0;
      if(buffer[count] & 128) tempbyte += 1;
      if(buffer[count] & 64) tempbyte += 2;
      if(buffer[count] & 32) tempbyte += 4;
      if(buffer[count] & 16) tempbyte += 8;
      if(buffer[count] & 8) tempbyte += 16;
      if(buffer[count] & 4) tempbyte += 32;
      if(buffer[count] & 2) tempbyte += 64;
      if(buffer[count] & 1) tempbyte += 128;
      buffer[count] = tempbyte;
    }
  }
      
  // Do whatever it is we do with the buffer -- we dump it in hex
  if(TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width) == 0){
    fprintf(stderr, "Image does not define its width\n");
    exit(42);
  }
   
  for(count = 0; count < bufferSize; count++){
    printf("%02x", (unsigned char) buffer[count]);
    if((count + 1) % (width / 8) == 0) printf("\n");
    else printf(" ");
  }
  TIFFClose(image);
}




这段代码先打开图像并检查我们是否可以处理它。然后,它读入图像的所有条并将它们一起附加到一个大的内存块中。 如果需要,它还翻转位,直到光度解释是我们可以处理的那个, 而且如果填充次序不对,它还进行必要的位交换处理。 最后,我们的样本将图像输出为由十六进制值组成的一系列行。请记住,每个值都表示实际图像中的 8 个像素。
结束语在本文中, 我向您演示了如何使用 libtiff 来读写一些简单的黑白图像,并介绍了一些您要知道的关键问题。 在开始用 libtiff 编码之前,请记住要考虑应该对您的图像使用什么压缩算法 ― 对于黑白色,group 4 fax 很合适, 但对于彩色使用什么压缩算法确实取决于您的需要。
返回列表