您当前的位置: 首页 >  c++

插件开发

暂无认证

  • 0浏览

    0关注

    492博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

LibTiff-C++-基本用法-条带块-读取保存数据

插件开发 发布时间:2022-05-08 08:15:00 ,浏览量:0

文章目录
    • 1.如何分辨你拥有的是哪个版本
    • 2.库数据类型
    • 3.内存管理
    • 4.错误处理
    • 5.基本的文件处理
    • 6.TIFF目录
    • 7.TIFF标签
    • 8.TIFF压缩方案
    • 9.字节顺序
    • 10.数据放置
    • 11.TIFFRGBAImage支持
    • 12.Scanline-based图像I / O
    • 13.Strip-oriented图像I / O
    • 14.Tile-oriented图像I / O
  Libtiff提供了多个抽象层(和花销)的图像数据接口。在最高级别上,可以将图像数据读入8位/样本、ABGR像素光栅格式,而不考虑底层数据组织、颜色空间或压缩方案。在这个高级接口之下,库提供了面向扫描线、条带和平铺的接口,这些接口返回解压缩但未转换的数据。这些接口要求应用程序首先识别存储数据的组织,并选择基于条带或基于平铺的API来操作数据。在最低级别上,库提供了对未压缩的原始条带或贴图的访问,返回的数据与文件中显示的数据完全相同。

1.如何分辨你拥有的是哪个版本

  在使用libtiff的应用程序中,TIFFGetVersion例程将返回一个指向包含软件版本信息的字符串的指针。包含文件的库包含一个C预处理器定义的TIFFLIB_VERSION,可用于在编译时检查库版本兼容性。

2.库数据类型

  libtiff通过使用一组C类型概念定义了一个可移植的编程接口。在文件tiffo.h和tiffio.h中定义的这些定义将libtiff API与底层机器的特征隔离开来。为了确保可移植的代码和正确的操作,使用libtiff的应用程序应该使用typedefs,并遵循库API的函数原型。

3.内存管理

  Libtiff使用一组特定于机器的例程来管理动态分配的内存。_TIFFmalloc、_TIFFrealloc和_TIFFfree模拟普通的ANSI C例程。任何要传递到库中的动态分配内存都应该使用这些接口进行分配,以确保具有分段体系结构的机器的指针兼容性。(在32位UNIX系统中,这些例程只调用C库中的普通malloc、realloc和自由例程。)   为了处理分段指针问题,libtiff还提供了_TIFFmemcpy、_TIFFmemset和_TIFFmemmove例程,这些例程模拟等效的ANSI C例程,但它们是用于通过_TIFFmalloc和_TIFFrealloc分配的内存。

4.错误处理

  Libtiff在从函数调用返回时,通过返回一个无效/错误的值来处理大多数错误。库还可以生成各种诊断消息。所有错误消息都被定向到单个全局错误处理程序例程,该例程可以通过调用TIFFSetErrorHandler来指定。同样,警告消息被定向到单个处理程序例程,该例程可以通过调用TIFFSetWarningHandler来指定。

5.基本的文件处理

  这个库是仿照普通的UNIX stdio库创建的。例如,要从现有的TIFF图像中读取文件,必须先打开:

#include "tiffio.h"
main()
{
    TIFF* tif = TIFFOpen("foo.tif", "r");
    ... do stuff ...
    TIFFClose(tif);
}

  TIFFOpen返回的句柄是不透明的,即应用程序不允许知道它的内容。对该文件的所有后续库调用都必须将句柄作为参数传递。要创建或覆盖一个TIFF图像,也要打开文件,但带有一个“w”参数:

#include "tiffio.h"
main()
{
    TIFF* tif = TIFFOpen("foo.tif", "w");
    ... do stuff ...
    TIFFClose(tif);
}

  如果文件已经存在,则首先将其截断为零长度。   注意,不像stdio库TIFF图像文件可能不能同时打开读写;不支持更改TIFF文件的内容。libtiff缓冲与写入有效TIFF图像相关的许多信息。因此,在写入TIFF图像时,必须始终调用TIFFClose或TIFFFlush将任何缓冲信息刷新到文件中。注意,如果调用TIFFClose,则不需要调用TIFFFlush。

6.TIFF目录

  TIFF支持在一个文件中存储多个图像。每个图像都有一个关联的数据结构,称为目录,其中包含有关图像数据格式和内容的所有信息。一个文件中的图像通常是相关的,但他们不需要;将彩色图像与黑白图像存储在一起是完全可以的。但是请注意,虽然图像可能是相关的,但它们的目录不是。也就是说,每个目录都是独立的;它们不需要读取不相关的目录来正确解释图像的内容。   Libtiff提供了几个读写目录的例程。在正常使用中,不需要显式地读或写一个目录:库在打开并读取文件时自动读取第一个目录,并且在写入时自动累积并写入要写入的目录信息(假设调用了TIFFClose或TIFFFlush)。   对于打开供读取的文件,TIFFSetDirectory例程可用于选择任意目录;目录通过编号引用,编号从0开始。否则,TIFFReadDirectory和TIFFWriteDirectory例程可以用于对目录的顺序访问。例如,要计算一个文件中的目录数,可以使用以下代码:

#include "tiffio.h"
main(int argc, char* argv[])
{
    TIFF* tif = TIFFOpen(argv[1], "r");
    if (tif) {
        int dircount = 0;
        do {
            dircount++;
        } while (TIFFReadDirectory(tif));
        printf("%d directories in %s\n", dircount, argv[1]);
        TIFFClose(tif);
    }
    exit(0);
}

  最后,请注意有几个用于查询打开文件的目录状态的例程:TIFFCurrentDirectory返回当前目录的索引,而TIFFLastDirectory返回当前目录是否是文件中的最后一个目录的指示。还有一个例程TIFFPrintDirectory,可以调用它来打印当前目录内容的格式化描述;详细信息请参阅手册页。

7.TIFF标签

  与图像相关的信息,如图像的宽度和高度,样本数量,方向,色度信息等存储在每个图像目录的字段或标签中。标签由一个数字标识,这个数字通常是在Aldus(现在是Adobe)公司注册的值。但是要注意,有些供应商使用未注册的标签编写TIFF图像;在这种情况下,解释它们的内容通常是浪费时间。

  Libtiff一次性读取目录的所有内容,并将磁盘上的信息转换为适当的内存形式。虽然TIFF规范允许在文件中定义和使用任意一组标记,但库只理解有限的一组标记。文件中遇到的任何未知标记都将被忽略。有一种机制可以在不修改库本身的情况下扩展库处理的标记集;这在别处有描述。

  libtiff提供了两个获取和设置标记值的接口:TIFFGetField和TIFFSetField。这些例程使用变量参数列表样式的接口,通过单个函数接口传递不同类型的参数。get接口接受一个或多个指向将要返回标记值的内存位置的指针,并根据所请求的标记是否在目录中定义返回1或0。set接口按引用或按值接受标记值。TIFF规范定义了一些标记的默认值。要获取标签的值,或者它的默认值(如果它未定义的话),可以使用tiffgetfielddefaults接口。

  标记get和set例程的手册页指定了库支持的每个标记所需的确切数据类型和调用约定。

8.TIFF压缩方案

  Libtiff支持多种数据压缩方案。在正常操作中,当设置TIFF compression标签时,通过打开文件进行读取或在写入时设置标签,自动使用压缩方案。压缩方案由称为编解码器的软件模块实现,编解码器和编码器例程挂钩到核心库的i/o支持。除与库绑定的编解码器外,还可以注册用于TIFFRegisterCODEC例程。此接口还可用于覆盖压缩方案的核心库实现。

9.字节顺序

  TIFF规范指出,并且总是指出,正确的TIFF阅读器必须以大端字节顺序和小端字节顺序处理图像。Libtiff符合这一点。因此没有意味着迫使一个特定字节顺序的数据写入一个TIFF图像文件(数据写在本机的主机CPU除非附加到现有文件,在这种情况下,它被写在文件)中指定的字节顺序。

10.数据放置

  TIFF规范要求除了8字节的头之外的所有信息都可以放在文件的任何地方。特别是,在图像数据本身之后写入目录信息是完全合法的。因此,TIFF本质上不适合通过面向流的机制(如UNIX管道)。要求数据以特定顺序组织在文件中的软件(例如,目录信息先于图像数据)不正确地支持TIFF。Libtiff没有提供控制文件中数据位置的机制;图像数据通常在目录信息之前写入。

11.TIFFRGBAImage支持

  libtiff提供了从TIFF文件读取图像数据的高级接口。该接口处理各种TIFF文件的数据组织和格式的细节;至少是人们通常会遇到的大部分文件。默认情况下,图像数据返回为打包成32位字的ABGR像素(每个样本8位)。可以读取矩形光栅或在中间水平上截取数据,并以更适合该应用程序的格式装入存储器。这个库处理存储在磁盘上的数据格式的所有细节,在大多数情况下,如果需要任何颜色空间转换:二层到RGB,灰度到RGB, CMYK到RGB, YCbCr到RGB, 16位采样到8位采样,关联/不关联alpha,等等。

  有两种方法可以使用这个接口读取图像数据。如果所有的数据都存储在内存中,并且一次操作,那么例程TIFFReadRGBAImage可以使用:

#include "tiffio.h"
main(int argc, char* argv[])
{
    TIFF* tif = TIFFOpen(argv[1], "r");
    if (tif) {
        uint32 w, h;
        size_t npixels;
        uint32* raster;
        
        TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
        TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
        npixels = w * h;
        raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
        if (raster != NULL) {
            if (TIFFReadRGBAImage(tif, w, h, raster, 0)) {
                ...process raster data...
            }
            _TIFFfree(raster);
        }
        TIFFClose(tif);
    }
    exit(0);
}

  注意上面的_TIFFmalloc是用来为传递给TIFFReadRGBAImage的光栅分配内存的;这对于确保在具有分段架构的机器上传递“适当类型的内存”是很重要的。或者,TIFFReadRGBAImage可以用一个更低级的接口替换,该接口允许应用程序对这个读取过程有更多的控制。与上述等价的是:

#include "tiffio.h"
main(int argc, char* argv[])
{
    TIFF* tif = TIFFOpen(argv[1], "r");
    if (tif) {
        TIFFRGBAImage img;
        char emsg[1024];
        
        if (TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
            size_t npixels;
            uint32* raster;
            
            npixels = img.width * img.height;
            raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
            if (raster != NULL) {
                if (TIFFRGBAImageGet(&img, raster, img.width, img.height)) {
                    ...process raster data...
                }
                _TIFFfree(raster);
            }
            TIFFRGBAImageEnd(&img);
        } else
            TIFFError(argv[1], emsg);
        TIFFClose(tif);
    }
    exit(0);
}

  然而,这种用法并没有利用更细粒度的控制。也就是说,通过使用这个接口,可以:   重复获取(和操作)图像而不打开和关闭文件   根据特定应用程序的需要(或直接写入数据)插入一种打包光栅像素数据的方法   处理核心库尚未处理的TIFF格式的插入方法   第一项意味着,例如,希望处理多个文件的图像查看器可以缓存解码信息,以加快显示TIFF图像所需的工作。   第二项是这个接口的主要原因。通过插入一个“put方法”(用于在光栅中打包像素数据的例程),可以共享理解如何处理TIFF的核心逻辑,同时将生成的像素打包成适合应用程序的格式。这种替代格式可能与库默认写的每个示例8位ABGR格式非常不同。例如,如果应用程序要在一个8位颜色地图显示上显示图像,那么put例程可能会获取数据并将其实时转换为显示的最佳颜色地图索引。   最后一项允许应用程序在不修改核心代码的情况下扩展库。通过覆盖所提供的代码,应用程序可能会添加对它所   需要的某些神秘的TIFF风格的支持,或者它可能会替换能够使用特定于应用程序/环境的信息进行优化的打包例程。在tools/sgigt.c中找到的TIFF图像查看器是一个使用TIFFRGBAImage支持的应用程序示例。

12.Scanline-based图像I / O

  libtiff提供的最简单的接口是面向扫描线的接口,可用于读取以条带组织图像数据的TIFF图像(尝试使用此接口读取以块形式写入的数据将会产生错误)。扫描线是图像数据的一个高像素行,其宽度为图像的宽度。如果图像数据与打包在一起的样本一起存储,则返回数据;如果数据与分离的样本一起存储,则返回数据为独立样本的数组。scanline-oriented接口的主要限制,除了需要首先识别现有文件有一个合适的组织,是随机存取个人对线只能提供数据没有存储在一个压缩格式时,或者当地带的图像数据的行数设置为1 (RowsPerStrip是其中之一)。   为基于扫描线的i/o提供了两个例程:TIFFReadScanline和TIFFWriteScanline。例如,要读取一个假定以条带组织的文件的内容,可以使用以下方法:

#include "tiffio.h"
main()
{
    TIFF* tif = TIFFOpen("myfile.tif", "r");
    if (tif) {
        uint32 imagelength;
        tdata_t buf;
        uint32 row;
        
        TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imagelength);
        buf = _TIFFmalloc(TIFFScanlineSize(tif));
        for (row = 0; row             
关注
打赏
1665481431
查看更多评论
0.0444s