libtiff的使用

最近的一个项目用到tif图片格式读写。tif是一种图像文件格式,最初用于黑白传真,后来也支持彩色。相对于其他图像格式,tif有点像容器,支持多页不同尺寸、不同的压缩格式。黑白的压缩算法常见为CCITT 4/6,无损压缩,不支持灰度和彩色;彩色的常见压缩算法为LZW无损压缩,对文字和矢量图形的效果不错,但对于照片的压缩率很差。最新的tif格式也支持jpeg有损压缩和zip压缩,不过很多旧版软件不支持,如XP图片查看器等。

最初为了图方便,我使用了windows自带的gdi+来读写tif,但后来发现几个无法解决的问题

1.在32位系统上,打开2G以上的tif文件失败;

2.被某些应用(如splwow64)调用时,总是失败;

无奈之下只好换方案,使用libtiff库。本来想下载编译好的dll文件,不过都没64位的,干脆自己编一下吧。

【编译】

libtiff引用了jpeg,zip库,一开始我用不着这两个,就把他们去掉了:

1.libtiff\makefile.vc 注释tif_jpeg/pixarlog/zip三行

2.tiffconf.h 注释 JPEG_SUPPORT,PIXARLOG,ZIP三行

编译64位版本是我用了VS2008 x64 win64 command prompt tools,运行 nmake /f makefile.vc 但编译出来的dll依赖mfc90.dll等文件,最好改为静态链接: nmake.opt OPTFLAGS, MD->MT 另外可以不生成pdb: nmake.opt- LD=link /nologo 加上 /pdb:none

32位也可以用VC6编译:VC6\VC98\Bin\VCVARS32.bat 命令同上

编译生成libtiff.dll, libtif_i.lib(dynamic), libtiff.lib(static) 不过我还是建了一个VC工程来编译,更方便一些。 ==========================================================

如果要支持jpeg编码,请到http://www.ijg.org/ 下载源码包jpegsrxc

copy jconfig.vc jconfig.h ; nmake /f makefile.vc libjpeg.lib ; 默认生成libjpeg.lib静态库 在libtiff\makefile.vc,tiffconf.h开启jpeg行,nmake.opt中打开jpeg项目并写入路径 64位编译时,要在makefile.vc CFLAGS=..加上/Ox /MT /GX /W3 静态链接MFC.

==========================================================

用VC编译应用程序没问题,但在WDK编译驱动时遇到错误[unresolved external symbol [email protected] referenced].这里TIFFOpen后面为什么有个@4?看了下Lib文件里有这些函数但没有@序号。这是因为libtiff都是c函数,默认是cdecl调用方式,dll输出函数不带@序号。而WDK编译驱动时默认是stdcall(/Gz)编译方式,链接时就找不到了。这里需要把libtiff里的函数都加上__stdcall修饰再重编译,不过改动比较多,也可以加上/Gz编译选项,或在VC的Code Generation/Advanced - calling convention 选为stdcall(/Gz)编译,注意libjpeg也要重新编译。如果以stdcall编译后,头文件tiffio.h中的函数也必须加上__stdcall修饰。

【使用】

#include "tiffio.h"
int main()
{
  int i,nret,nw,nh,nbpp,npage=1;
  TIFF* pTif = TIFFOpen("d:\\1.tif", "r");
  TIFFSetDirectory(pTif, 1); // 跳到指定的页数1
  nret = TIFFGetField(pTif, TIFFTAG_IMAGEWIDTH, &nw); // 获取图像长、宽
  nret = TIFFGetField(pTif, TIFFTAG_IMAGELENGTH, &nh);
  npage = TIFFNumberOfDirectories(pTif); // 读取页数
  TIFFClose(pTif);
}

 错误和警告信息

libtiff使用CallBack方式显示错误和警告。定义如下函数

void TIFFErrorProc(const char* pModule, const char* pFormat, va_list pArg)
{
    char szMsg[512];
    vsprintf(szMsg, pFormat, pArg);
    printf("tifferr-%s: %s", pModule, szMsg);
}//然后设置为错误和警告处理函数,最好分开两个。TIFFSetWarningHandler(TIFFWarnProc);TIFFSetErrorHandler(TIFFErrorProc);//其中pModule是函数模块,如TiffEncode; pFormat是带参数的信息如"height should be %d", pArg是可变参数表

Directories 多页

一个tif文件可以包含多页,每页的宽高大小都可以不同,在libtiff中称为Directories.

获取页数 npage = TIFFNumberOfDirectories(TIFF*);

跳到指定页数 TIFFSetDirectory(TIFF*, tdir_t);

写入一页 TIFFWriteDirectory(TIFF*);

tif图像的三种压缩和组织形式scanline,strip,tile

scanline:每行图像压缩,只支持ccitt等算法,不支持lzw,jpeg等

strip:图像分为几个横条压缩,

tile: 图像分为若干个正方形块进行压缩

与其他图像格式转换的问题

彩色tif内的颜色顺序为rgb,在bmp内的顺序为bgr,两者需要翻转

黑白tif可调用TIFFSetField(pTif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK/WHITE)来指定0-1为黑、白,不过有些软件不支持。

tif内的每行数据为1字节对齐,bmp为4字节对齐 使用jpeg算法压缩时,strip的高度必须为8的倍数

最后附上tif-bmp转换的代码例子

void SaveBmpFile(LPTSTR pszBmp, int nW, int nH, int nBpp, LPBYTE pBuf)
{
	BITMAPFILEHEADER bfh={0};
	BITMAPINFOHEADER bih={0};
	DWORD pal[256]={0,0XFFFFFF};
	int nLineByte,nwb,y;

	bfh.bfType = ‘MB‘;
	bfh.bfSize = sizeof bfh;
	bfh.bfOffBits = sizeof(bfh)+sizeof(bih);
	if(nBpp == 1)
		bfh.bfOffBits += 8;
	bih.biSize = sizeof bih;
	bih.biWidth = nW;
	bih.biHeight = nH;
	bih.biBitCount = nBpp;
	bih.biPlanes = 1;
	nwb = (nW*nBpp+31)/32*4; //bmp 4 bytes align
	bih.biSizeImage = nwb*nH;

	CFile fBmp(pszBmp, CFile::modeCreate|CFile::modeWrite);
	fBmp.Write(&bfh, sizeof bfh);
	fBmp.Write(&bih, sizeof bih);
	if(nBpp == 1)
		fBmp.Write(pal, 8);

	nLineByte = (nW*nBpp+7)/8; //tif 1 bytes align
	LPBYTE pLine = pBuf+nLineByte*(nH-1);
	for(y=0; y<nH; y++)
	{
		fBmp.Write(pLine, nLineByte);
		if(nwb > nLineByte)
			fBmp.Write(pal, nwb-nLineByte);
		pLine -= nLineByte;
	}
	fBmp.Close();
}
void SaveTif2Bmp(LPTSTR pszTif, LPTSTR pszBmp)
{
	TIFF* pTif = TIFFOpen(pszTif, "r");
	if(!pTif)
		return;
	int i,nret,nw,nh,npage,nrps;
	unsigned short nComp, nPho, nBps,nSpp;
	TIFFSetErrorHandler(TIFFErrorHandler);
	nret = TIFFGetField(pTif, TIFFTAG_IMAGEWIDTH, &nw);
	nret = TIFFGetField(pTif, TIFFTAG_IMAGELENGTH, &nh);
	nret = TIFFGetField(pTif, TIFFTAG_COMPRESSION, &nComp);
	nret = TIFFGetField(pTif, TIFFTAG_PHOTOMETRIC, &nPho);
	nret = TIFFGetField(pTif, TIFFTAG_BITSPERSAMPLE, &nBps);
	nret = TIFFGetField(pTif, TIFFTAG_SAMPLESPERPIXEL, &nSpp);
	nret = TIFFGetField(pTif, TIFFTAG_ROWSPERSTRIP, &nrps);
	npage = TIFFNumberOfDirectories(pTif);
	int nSize = TIFFStripSize(pTif);
	int nStrip = TIFFNumberOfStrips(pTif);
	uint32* bc; // wrong size??
	nret = TIFFGetField(pTif, TIFFTAG_STRIPBYTECOUNTS, &bc);

	int nwb = (nw*nBps*nSpp+31)/32*4; // 4-byte align for bmp
	LPBYTE pBufBmp = new BYTE[nwb*nh];
	//uint32 stripsize = bc[0];
	//tdata_t buf = _TIFFmalloc(nSize);//stripsize);
	LPBYTE pStripBmp = pBufBmp;
	for (i=0; i<nStrip; i++)
	{
		nret = TIFFReadEncodedStrip(pTif, i, pStripBmp, nSize);
		int nHStrip = nret/(nw*nBps*nSpp/8);
		pStripBmp += nHStrip * nwb;
	}
	//uint32* raster = (uint32*) _TIFFmalloc(nw*nh*sizeof(uint32));
	//TIFFReadRGBAImage(tif, nw, nh, raster, 0);
	SaveBmpFile(pszBmp, nw,nh, nBps*nSpp, (LPBYTE)pBufBmp);
	//_TIFFfree(buf);
	delete [] pBufBmp;
	TIFFClose(pTif);
}

// pszBmp: d:\1.bmp|d:\2.bmp
void SaveBmp2Tif(LPTSTR pszBmp, LPTSTR pszTif)
{
	BITMAPFILEHEADER bfh;
	BITMAPINFOHEADER bih;
	DWORD pal[256];
	int i,x,nwb;
	LPBYTE pBuf,pLine;
	//LPDWORD pdw;
	LPTSTR pBmpFile = pszBmp, pc;

	TIFF *pTif = TIFFOpen(pszTif, "w+");
	if(!pTif)	return;

	pc = strchr(pszBmp, ‘|‘);
	while (pBmpFile)
	{
		if(pc)	*pc = 0;
		CFile fBmp(pBmpFile, CFile::modeRead);
		fBmp.Read(&bfh, sizeof(bfh));
		fBmp.Read(&bih, sizeof(bih));
		if (bih.biBitCount == 1)
		{
			fBmp.Read(pal, 2*4);
			nwb = (bih.biWidth+31)/32 * 4;
		} else if (bih.biBitCount == 24)
		{
			nwb = (bih.biWidth*3+3)/4*4;
		}
		pBuf = (LPBYTE)malloc(nwb*bih.biHeight);
		fBmp.Read(pBuf, nwb*bih.biHeight);
		fBmp.Close();

		TIFFSetField(pTif, TIFFTAG_IMAGEWIDTH, bih.biWidth);
		TIFFSetField(pTif, TIFFTAG_IMAGELENGTH, bih.biHeight);
		//TIFFSetField(pTif, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
		TIFFSetField(pTif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); //single image plane
		TIFFSetField(pTif, TIFFTAG_XRESOLUTION, 300.0); // must be double
		TIFFSetField(pTif, TIFFTAG_YRESOLUTION, 300.0);
		TIFFSetField(pTif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
		TIFFSetField(pTif, TIFFTAG_IMAGEDESCRIPTION, "PaperSize=2100x2970;");
		TIFFSetField(pTif, TIFFTAG_DOCUMENTNAME, "tif-test by chaos;");
		if (bih.biBitCount == 1)
		{
			TIFFSetField(pTif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); // 0=black
			TIFFSetField(pTif, TIFFTAG_COMPRESSION, COMPRESSION_CCITT_T6);//
			TIFFSetField(pTif, TIFFTAG_BITSPERSAMPLE, 1);
			TIFFSetField(pTif, TIFFTAG_SAMPLESPERPIXEL, 1);
			TIFFSetField(pTif, TIFFTAG_ROWSPERSTRIP, bih.biHeight);
			pLine = pBuf + nwb*(bih.biHeight-1);
			for (i=0; i<bih.biHeight; i++)
			{
				//pdw = (LPDWORD)pLine; // invert color
				//for(x=0; x<nwb/4; x++)
				//{
				//	*pdw = ~(*pdw);
				//	pdw++;
				//}
				TIFFWriteScanline(pTif, pLine, i);
				pLine -= nwb;
			}
		} else if (bih.biBitCount == 24)
		{
			TIFFSetField(pTif, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);//LZW);//
			TIFFSetField(pTif, TIFFTAG_BITSPERSAMPLE, 8);
			TIFFSetField(pTif, TIFFTAG_SAMPLESPERPIXEL, 3);
			TIFFSetField(pTif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
			int nJpegQuality = 75;
			TIFFSetField(pTif, TIFFTAG_JPEGQUALITY, nJpegQuality);
			TIFFSetField(pTif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
			// bgr->rgb
			BYTE btmp, *pDot;
			pLine = pBuf + nwb*(bih.biHeight-1);
			for (i=0; i<bih.biHeight; i++)
			{
				pDot = pLine;
				for (x=0; x<bih.biWidth; x++)
				{
					btmp = *pDot;
					*pDot = pDot[2];
					pDot[2] = btmp;
					pDot += 3;
				}
				pLine -= nwb;
			}
			TIFFSetField(pTif, TIFFTAG_ROWSPERSTRIP, bih.biHeight);
			TIFFWriteEncodedStrip(pTif, 0, pBuf, nwb*bih.biHeight);
			//Sleep(100);
			//TIFFWriteEncodedStrip(pTif, 1, pBuf+nwb*(bih.biHeight/2), nwb*(bih.biHeight/2));
		}
		TIFFWriteDirectory(pTif);
		free(pBuf);

		if(pc)
		{
			pBmpFile = pc+1;
			pc = strchr(pBmpFile, ‘|‘);
		} else
			pBmpFile = NULL;
	}
	TIFFClose(pTif);
}
时间: 2024-10-05 16:09:46

libtiff的使用的相关文章

Mac10.9下的libtiff编译

libtiff介绍 libtiff下载 libtiff编译 libtiff介绍? 参考:http://en.wikipedia.org/wiki/Tiff libtiff下载 直接到官网下载:http://download.osgeo.org/libtiff/,目前最新版本4.0.3 libtiff编译 1.解压libtiff   2. 进入 libtiff 目录: cd tiff-4.0.3/ 3. 配置编译完成后的install文件夹,就是最后你的库跟头文件放在哪里,一般可以放到/usr/l

使用libtiff读取tif/tiff图像

这几天在写tif图像的程序,需要用libtiff读取tif图像(当然用OpenCV的imread和GDAL会更加方便),Demo程序如下: int TestTIFFDemo() { //打开图像 char* fileName = "D:/Image/Color/Beauty.tif"; //char* fileName = "D:/Image/Projects/ShipImage/01001.tif"; //char *fileName = "D:/Ima

Anaconda中安装了Libtiff模块,但运行程序显示ModuleNotFoundError: No module named &#39;libtiff&#39;

出现问题:Anaconda中已经用[conda install libtiff]命令安装了libtiff,并且利用命令[conda list]发现libtiff确实存在,但在pip中却不存在[pip list] 解决办法: 1. 下载anaconda中当前虚拟环境下对应版本的libtiff的whl文件,并用pip安装,我的是TensorFlow36虚拟环境,python版本是3.6 libtiff下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/ c

centos下载安装libgcc 和 libtiff

1. 查看libtiff 可安装列表: [[email protected] lib]# yum list | grep "libtiff" libtiff.i686 4.0.9-13.el8 AppStream libtiff.x86_64 4.0.9-13.el8 AppStream libtiff-devel.i686 4.0.9-13.el8 AppStream libtiff-devel.x86_64 4.0.9-13.el8 AppStream 查看libgcc可安装列表:

libtiff 生成48位色tif图片

BOOL CTifImage_48Bits::BitmapConvertTo48BitsTif(CString strImagePath, int nWidth, int nHeight, int nBpp, BYTE* pData) { if (nBpp != 24) { AfxMessageBox(L"只支持24位真彩图!"); return FALSE; } if (pData == NULL) { AfxMessageBox(L"内存段为空!"); retu

mac下编译 boost编译工具b2

cd boost_1_64_0/tools/build ./bootstrap.sh --with-toolset=gcc 输出: -n Bootstrapping the build engine with toolset gcc... engine/bin.macosxx86_64/b2 Bootstrapping is done. To build and install, run: ./b2 install --prefix=<DIR> ./b2 install --prefix=/u

【Tesseract】Tesseract API在VS 2013中的配置以及调用

想要在VS中使用Tesseract库,必须使用经过相对应的VS版本编译过的dll以及lib.比如在VS 2013中,就必须使用在VS 2013中编译过的Tesseract库. 这里我给出经过VS 2013编译的Tesseract库, 下载地址: http://pan.baidu.com/s/1o7JqXmU 解压后内容如下图, 有了Tesseract库之后,我们便在VS 2013中配置环境以及包含库了. 引入头文件 在“解决方案管理器”窗口–>右键“photo”工程–>“属性(R)”–>

macos或类linux 系统安装ettercap + gtk3 抓取并分析邻居数据包

最近邻居夜生活猖獗,打游戏"砸键盘".搞直播弹琴唱歌以及各种与人视频聊天,每天半夜十二点以后,笑声.骂声.弹琴声.唱歌声轮番上阵,先前公用路由是我控制的,密码只有我一人知道,还能限个速.这两天这哥们找个了人把路由器初始化,然后自己设置了管理密码,更疯狂的猖獗的闹腾了.好吧,你有张良计,我有过墙梯. "Ettercap是一款强大的可以被称为神器的工具,同类型软件中的佼佼者.Ettercap是开源企且跨平台 的,Ettercap在某些方面和dsniff有相似之处,同样可以很方便的

opencv中的子库

1 FLANN 近似最近邻库,NN就是nearest neighbor的缩写. 2 IlmImf Ilm是Industrial light & magic公司的缩写. Imf是image format的缩写吗? 3 libjasper Jasper是JPEG2000的一个非官方实现,由一个国外的一个大学教师实现,还算是个好用的LIB,你可以从http://www.ece.uvic.ca/~mdadams/jasper/地址下在,里面有VC的工程文件.Jpeg60是JPEG的官方实现:其编译只提供