1. 程式人生 > >關於libtiff庫函式的一些解釋

關於libtiff庫函式的一些解釋

(1)下載tiff庫檔案
http://www.libtiff.org/
無法下載,映象下載處http://libtiff.maptools.org/dl/可以,目前版本3.8.2
可以處理5.0或6.0標準的TIFF檔案
(2)第1次編譯tiff庫
按說明(http://www.libtiff.org/build.html#PC)需要使用命令列
nmake /f makefile.vc
cd ..\tools
nmake /f makefile.vc
原文如下
Building the Software under Windows 95/98/NT/2000 with MS VC++ With Microsoft Visual C++ installed, and properly configured for commandline use (you will likely need to source VCVARS32.BAT in AUTOEXEC.bAT or somewhere similar) you should be able to use the provided makefile.vc.

C:\LIBTIFF\LIBTIFF> nmake /f makefile.vc
C:\LIBTIFF\LIBTIFF> cd ..\tools
C:\LIBTIFF\TOOLS> nmake /f makefile.vc

This will build the library file LIBTIFF\LIBTIFF\LIBTIFF.LIB. This can be used in Win32 programs. If used in a project using the /MD compiler switch (using the runtime C library), it may be necessary to modify the CFLAGS macro in makefile.vc to correspond.
The makefile also builds a DLL (libtiff.dll) with an associated import library (libtiff_i.lib). Any builds using libtiff will need to include the LIBTIFF\LIBTIFF directory in the include path.
The libtiff\tools\makefile.vc should build .exe's for all the standard TIFF tool programs.
NOTE: The contents of the contrib/win32 directory should no longer be needed, and are kept in the distribution temporarily.

編譯提示
tif_jpeg.c(87) : fatal error C1083: Cannot open include file: 'jpeglib.h': No such file or directory
NMAKE : fatal error U1077: 'cl' : return code '0x2'
(3)下載並編譯jpeg庫檔案
看原始檔中讓去ftp.uu.net:/graphics/jpeg/下載,但是沒有使用者名稱和密碼進不去,去http://www.ijg.org/下載jpegsr8c.zip
解壓jpeg檔案後執行命令列
nmake /f makefile.vc setup-vc6 這是準備工作,makefile裡有但是文件沒寫
nmake /f makefile.vc
如果不放心再來一個
nmake /f makefile.vc test
比較無誤後可以使用了
(4)第2次編譯tiff庫檔案
把jpeg目錄加入lib和include環境變數
nmake /f makefile.vc
提示需要zlib.h
tif_pixarlog.c(90) : fatal error C1083: Cannot open include file: 'zlib.h': No s
uch file or directory
NMAKE : fatal error U1077: 'cl' : return code '0x2'
(5)zlib庫
這次原始檔中沒有提示下載位置,搜尋到主頁http://zlib.net/無法開啟
去http://gnuwin32.sourceforge.net/packages/zlib.htm下載個不帶原始檔的安裝包,這回省得編譯了。
安裝後加入include和lib環境變數
***\psoftware\lib\zconf.h(289) : fatal error C1083: Cannot open include file:
'unistd.h': No such file or directory
去檔案中把那裡的#if 1改為#if 0重新編譯(unistd表示unix standard)
(6)第3次編譯tiff庫檔案
連結時提示
tif_jpeg.obj : error LNK2001: unresolved external symbol _jpeg_read_header
tif_jpeg.obj : error LNK2001: unresolved external symbol _jpeg_resync_to_restart
...
反正很多沒找到就是了
用 dumpbin /linkermember libjpeg.lib 可以找到對應函式,看來是路徑問題
查詢makefile.vc,發現引用nmake.opt
nmake.opt裡預設把jpeg和zlib取消了(靠,編譯時需要,輸出庫檔案不用?),修改其路徑
(7)第4次編譯tiff庫檔案
出現很多警告,但是lib和dll檔案生成了,tools下部分工具沒有生成,不管了,現在tiff庫可以使用了

使用VC編譯時自己的程式時需要修改編譯選項中的/MLd改為/MDd(/MDd link with MSVCRTD.LIB debug lib, /MLd link with LIBCD.LIB debug lib),這樣會產生程式庫連結衝突的警告,可能由於除錯庫和編譯的libTIFF庫不相容引起,目前來看可以忽略。

-----------------------------------------------
tiff庫使用方式(來自幫助文件,後面涉及到檔案格式部分可能理解錯誤)
1、開啟檔案
#include "tiffio.h"
main()
{
    TIFF* tif = TIFFOpen("foo.tif", "r"); // 開啟,關閉
    // TIFF* tif = TIFFOpen("foo.tif", "w"); // 寫入方式,不能像stdio那樣同時為rw方式
    ... do stuff ...
    TIFFClose(tif);
}
2、TIFF Directories
TIFF檔案每個影象都有相關的資料結構,稱為directory儲存圖形資訊,不同圖形的directory可以無關。
通常不需要讀取directory,庫函式在開啟和寫入檔案時會自動處理(呼叫TIFFClose或TIFFFlush時)。
讀取檔案時TIFFSetDirectory可以用從0開始的序號選擇任意directory,TIFFReadDirectory和TIFFWriteDirectory可以用於順序讀寫directory。
計算檔案中的directory數:
#include "tiffio.h"
main(int argc, char* argv[])
{
    TIFF* tif = TIFFOpen(argv[1], "r");
    if (tif) {
      int dircount = 0;
      do {
        dircount++;
      } while (TIFFReadDirectory(tif)); // 讀入每個Directory
      printf("%d directories in %s\n", dircount, argv[1]);
      TIFFClose(tif);
    }
  exit(0);
}
TIFFCurrentDirectory返回當前directory的序號,TIFFLastDirectory返回當前directory是否為最後一個directory,TIFFPrintDirectory可以顯示當前directory的格式化資訊。
3、TIFF Tags
影象資訊如寬度和高度、取樣數、方向、色度資訊等儲存在每個影象directory的tags中,tags用數字表示,Adobe有相關說明,但是部分公司的TIFF檔案使用自定義的tags沒有說明。
TIFFGetField and TIFFSetField 是針對tag操作的
uint32 w, h;
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);

位元組順序:big-endian and little-endian

資料位置
TIFF標準除了對前8位元組的檔案頭資料有要求外,其他資料位置均沒有要求,因此可以在影象資料後放一些資訊。

libtiff提供了讀取TIFF檔案的介面,預設使用32bit形式的ABGR畫素,也可以以其他格式讀入,然後對資料進行解釋。有兩種方式讀入影象資料,一次讀入所有資料用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);
}
另一函式可以代替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);
}
tools/*.c中有使用TIFFRGBAImage的例子程式。

Scanline-based影象IO
libtiff提供的最簡單的介面是scanline方式的介面,用於讀取條狀或塊狀的影象,scanline是一個畫素高度×影象寬度的影象,這種方式只能用於非壓縮格式影象。函式為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 < imagelength; row++)
            tiffreadscanline(tif, buf, row);
        _tifffree(buf);
        tiffclose(tif);
    }
}
TIFFScanlineSize可以返回解碼後的scanline大小,類似TIFFReadScanline返回的資料。
如果影象中存在多個圖形資料,上面程式只返回第一個圖形,需要用下面程式代替
#include "tiffio.h"
main()
{
    TIFF* tif = TIFFOpen("myfile.tif", "r");
    if (tif) {
        uint32 imagelength;
        tdata_t buf;
        uint32 row;
       
        TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imagelength);
        TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config);
        buf = _TIFFmalloc(TIFFScanlineSize(tif)); // 呼叫TIFFScanlineSize
        if (config == PLANARCONFIG_CONTIG) {
            for (row = 0; row < imagelength; row++)
                tiffreadscanline(tif, buf, row);
        } else if (config == planarconfig_separate) {
            uint16 s, nsamples;
           
            tiffgetfield(tif, tifftag_samplesperpixel, &nsamples);
            for (s = 0; s < nsamples; s++)
                for (row = 0; row < imagelength; row++)
                    tiffreadscanline(tif, buf, row, s);
        }
        _tifffree(buf);
        tiffclose(tif);
    }
}

Strip-oriented影象處理
可以處理壓縮或非壓縮資料
#include "tiffio.h"
main()
{
    TIFF* tif = TIFFOpen("myfile.tif", "r");
    if (tif) {
        tdata_t buf;
        tstrip_t strip;
       
        buf = _TIFFmalloc(TIFFStripSize(tif));
        for (strip = 0; strip < tiffnumberofstrips(tif); strip++)
            tiffreadencodedstrip(tif, strip, buf, (tsize_t) -1); // -1表示自動計算strip大小
        _tifffree(buf);
        tiffclose(tif);
    }
}
最後一個strip的資料可能少於RowsPerStrip tag的數,因此讀入時不能對讀入的資料數進行假定。
#include "tiffio.h"
main()
{
    TIFF* tif = TIFFOpen("myfile.tif", "r");
    if (tif) {
        tdata_t buf;
        tstrip_t strip;
        uint32* bc;
        uint32 stripsize;
       
        TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &bc);
        stripsize = bc[0];
        buf = _TIFFmalloc(stripsize);
        for (strip = 0; strip < tiffnumberofstrips(tif); strip++) {
            if (bc[strip] > stripsize) {
                buf = _TIFFrealloc(buf, bc[strip]);
                stripsize = bc[strip];
            }
            TIFFReadRawStrip(tif, strip, buf, bc[strip]);
        }
        _TIFFfree(buf);
        TIFFClose(tif);
    }
}
上述例子中的strip是按物理儲存的順序讀入的,可能與邏輯順序不同。
其他略,前面有很多不理解地方,後面無法繼續了。

-----------------------------------------------

有時程式輸出時出現類似下面的警告:

TIFFReadDirectory: Warning, ***.tif: unknown field with tag 33550 (0x830e) encountered.
TIFFReadDirectory: Warning, ***.tif: invalid TIFF directory; tags are not sorted in ascending order.
要抑制程式的警告輸出,根據幫助檔案使用TIFFWarningHandler出錯,解決問題方法如下
http://www.asmail.be/msg0055340520.html
1994.12.06 08:41 "TIFFWarningHandler doesn't exist", by Glenn Herteg
Documentation bug:

In the man/man3/TIFFWarning.3t file from the 3.3beta021 release, all
references to TIFFWarningHandler should be changed to TIFFErrorHandler,
to match tiff/libtiff/tiffio.h (or perhaps the latter file should be
changed to match the documentation, though this would make it difficult
to use one handler for both warnings and errors, if the compiler runs
strong type checks).

Glenn Herteg
[email protected]

http://hi.baidu.com/necrohan/item/580ebe4a612b4408e9350464