1. 程式人生 > >心如止水-GISer的成長之路

心如止水-GISer的成長之路

以下是VC下讀取TIFF檔案的程式碼

char* szFileName = "K:\\地圖\\fujian-DEM\\fujian1.tif";
	TIFF* tiff = TIFFOpen(szFileName, "r");//開啟Tiff檔案,得到指標,以後所有的操作都通過指標進行

	int nTotalFrame = TIFFNumberOfDirectories(tiff);	//得到影象的總幀數

	//TIFFSetDirectory(tiff,0);
	//我們開啟第一幅圖,也就是第0幀,如果是第1幀,第二個引數寫1,由此類推。因為Windows下影象基本
	//操作都是以BMP格式進行,我們讀出該幀並轉成BMP格式。

	char *dtitle;
	TIFFGetField(tiff,TIFFTAG_PAGENAME,&dtitle);
	//得到該幀的名字,存放在dtitle中。

	int width,height;
	TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width);  //得到寬度
	TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height);//得到高度

	float resolution = max(width,height);

	uint16 bitspersample = 1;
	uint16 samplesperpixel = 1;

	TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
	//每個畫素佔多少機器字,24點陣圖samplesperpixel應該等於3。
	TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitspersample);
	//每一個機器字長,這裡應為8。

	uint16 bitsperpixel = bitspersample * samplesperpixel;
	//算出每個畫素佔多少bit,24點陣圖,值為24
	DWORD dwBytePerLine = (width*bitsperpixel+31)/32 *4;
	//由上面幾個引數算出影象每行所佔位元組(BYTE)數。


	DWORD64 dwLeng = height*dwBytePerLine;//在記憶體裡存放這幀影象資料所需要的長度
	BYTE* pData = new BYTE[dwLeng];    //為存放資料分配記憶體空間


	uint32* raster;        
	uint32 *row;
	raster = (uint32*)malloc(width * height * sizeof (uint32));
	TIFFReadRGBAImage(tiff, width, height, (uint32*)pData, 1); 
	//以上幾行讀出該幀資料,儲存到raster中。

	row = &raster[0];
	LPBYTE bits2 = pData;
	for (int y = 0; y < height; y++) 
	{

		LPBYTE bits = bits2;
		for (int x = 0; x < width; x++) 
		{
			*bits++ = (BYTE)TIFFGetB(row[x]);
			*bits++ = (BYTE)TIFFGetG(row[x]);
			*bits++ = (BYTE)TIFFGetR(row[x]);
		}
		row += width;
		bits2 += dwBytePerLine;
	}
	_TIFFfree(raster);

	//因為Tif的資料存放順序和Windows下的BMP相反,上面這幾句進行轉換。
	//轉換結束後,資料存在pData裡,釋放raster所用記憶體。



	LPBITMAPINFO pInfo = new BITMAPINFO;
	pInfo->bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
	pInfo->bmiHeader.biWidth        = width;
	pInfo->bmiHeader.biHeight        = width;
	pInfo->bmiHeader.biCompression    = BI_RGB;

	pInfo->bmiHeader.biClrUsed        = 0;
	pInfo->bmiHeader.biClrImportant    = 0;
	pInfo->bmiHeader.biPlanes        = 1;
	pInfo->bmiHeader.biBitCount = 24;
	pInfo->bmiHeader.biSizeImage        = dwLeng;

	float xres,yres;
	uint16 res_unit; 
	//解析度單位:如是英寸,釐米
	TIFFGetFieldDefaulted(tiff, TIFFTAG_RESOLUTIONUNIT, &res_unit);

	if(TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &xres) == 0)
	{
		pInfo->bmiHeader.biXPelsPerMeter = 0;
	}
	else
	{
		if(res_unit == 2)    //英寸
		{
			pInfo->bmiHeader.biXPelsPerMeter = xres * 10000 / 254;
		}
		else if(res_unit == 3)    //釐米
		{
			pInfo->bmiHeader.biXPelsPerMeter = xres * 100;
		}
		else
		{
			pInfo->bmiHeader.biXPelsPerMeter = 0;
		}
	}
	//得到該幀TIFF橫向解析度,並計算出m_pInfo->bmiHeader.biXPelsPerMeter

	if(TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &yres) == 0)
	{
		pInfo->bmiHeader.biYPelsPerMeter = 0;
	}
	else
	{
		if(res_unit == 2)    //英寸
		{
			pInfo->bmiHeader.biYPelsPerMeter = yres * 10000 / 254;
		}
		else if(res_unit == 3)    //釐米
		{
			pInfo->bmiHeader.biYPelsPerMeter = yres * 100;
		}
		else
		{
			pInfo->bmiHeader.biYPelsPerMeter = 0;
		}
	}
	//得到該幀TIFF縱向解析度,並計算出m_pInfo->bmiHeader.biYPelsPerMeter


	BITMAPFILEHEADER bmheader;
	bmheader.bfType=0x4d42;
	bmheader.bfSize=0;
	bmheader.bfReserved1=0;
	bmheader.bfReserved2=0;
	bmheader.bfOffBits=54;
	//這幾句是生成bmp檔案的頭結構

	CFile bmpFile;
	bmpFile.Open(_T("c://test.bmp"),CFile::modeCreate|CFile::modeWrite);
	bmpFile.Write(&bmheader,sizeof(BITMAPFILEHEADER));
	bmpFile.Write(&(pInfo->bmiHeader),sizeof(BITMAPINFOHEADER));
	bmpFile.Write(pData,dwLeng);
	bmpFile.Close();

	//這裡,把該幀TIFF儲存到了C盤的test.bmp中,可以用看圖軟體開啟瀏覽一下。

	//記得釋放記憶體空間
	delete pInfo;
	pInfo = NULL;
	delete pData;
	pData = NULL;
	//如果想直接顯示,就不需要釋放,呼叫StretchDIBits在客戶區的DC上就可以顯示了。


	//如果再開啟其他幀的話,從TIFFSetDirectory開始迴圈執行,比如取下一幀就是
	TIFFSetDirectory(tiff,1);
	//記得儲存時另換一個bmp檔名。
	//最後,對這個TIFF檔案全部操作結束,記得呼叫
	TIFFClose(tiff);

下面的程式碼是用GDAL開啟的

char* szFileName = "K:\\地圖\\fujian-DEM\\fujian1.tif";
	GDALDataset *poDataset;   //GDAL資料集
	GDALAllRegister();

	poDataset = (GDALDataset*)GDALOpen(szFileName,GA_ReadOnly);
	if( poDataset == NULL )
	{
		AfxMessageBox(_T("檔案開啟失敗!!!"));
		return;
	} 

	GDALRasterBand *poBand;   //遙感的一個波段
	int nBandCount = poDataset->GetRasterCount();
	poBand = poDataset->GetRasterBand(1);   //和陣列下標有點不同

	//獲得影象顯示視窗的尺寸
	GetClientRect(&m_ViewRect);

	int nImgSizeX = poDataset->GetRasterXSize();
	int nImgSizeY = poDataset->GetRasterYSize();

	double adfGeoTransform[6];
	poDataset->GetGeoTransform( adfGeoTransform );

	double right  = adfGeoTransform[0] + nImgSizeX*adfGeoTransform[1];
	double bottom  = adfGeoTransform[3] + nImgSizeY*adfGeoTransform[5];

	int nBufferSizeX,nBufferSizeY;

	nBufferSizeX = nImgSizeX;
	nBufferSizeY = nImgSizeY;

	int nScrrenWidth = m_ViewRect.Width();
	int nScrrenHeight= m_ViewRect.Height();

	BYTE *pafScanblock1,*TempLock1;
	pafScanblock1 = (BYTE *) CPLMalloc((nScrrenWidth)*(nScrrenHeight));
	TempLock1 = pafScanblock1;

	poBand->RasterIO( GF_Read, 0, 0,nBufferSizeX,nBufferSizeY, 
		pafScanblock1,nScrrenWidth,nScrrenHeight, GDT_Byte,0, 0 );

	//在View逐點顯示影象
	DWORD dwBytes = (nScrrenWidth * 24) / 8;
	while(((DWORD) dwBytes) % 4) 
	{
		dwBytes++;
	}

	BYTE *szBuffer = new BYTE[nScrrenHeight*dwBytes];
	memset(szBuffer,0,nScrrenHeight*dwBytes);
	BYTE *pTemp = szBuffer;
	CClientDC dc(this);
	int nIndex = 0;
	for (int i=0;i<nScrrenHeight;i++)
	{
		for (int j=0;j<nScrrenWidth;j++)
		{

			BYTE dn1 = *pafScanblock1;

			memcpy(szBuffer,(char*)(&dn1),1);
			szBuffer += 1;

			pafScanblock1 ++;

		}

		szBuffer = pTemp+dwBytes*i;

	}
	CPLFree(TempLock1);

	BITMAPINFOHEADER bmiHdr;
	BITMAPINFO MapInfo;
	memset(&bmiHdr, 0, sizeof(BITMAPINFOHEADER));
	bmiHdr.biBitCount = 3*8;
	bmiHdr.biClrImportant = 0;
	bmiHdr.biClrUsed = 0;
	bmiHdr.biCompression = BI_RGB;
	bmiHdr.biHeight = -nScrrenHeight;
	bmiHdr.biPlanes = 1;
	bmiHdr.biSize = sizeof(BITMAPINFOHEADER);
	bmiHdr.biSizeImage = 0;
	bmiHdr.biWidth = nScrrenWidth;

	bmiHdr.biXPelsPerMeter = 0;
	bmiHdr.biYPelsPerMeter = 0;

	MapInfo.bmiHeader = bmiHdr;
	MapInfo.bmiColors[0].rgbBlue = 0;
	MapInfo.bmiColors[0].rgbGreen = 0;
	MapInfo.bmiColors[0].rgbRed = 0;
	MapInfo.bmiColors[0].rgbReserved = 0;

	dc.SetStretchBltMode(MAXSTRETCHBLTMODE);
	::StretchDIBits(dc.GetSafeHdc(), 0, 0, nScrrenWidth, nScrrenHeight,
		0, 0, bmiHdr.biWidth, -bmiHdr.biHeight,
		pTemp, (LPBITMAPINFO)(&MapInfo), DIB_RGB_COLORS, SRCCOPY);

	GDALClose(poDataset);
	delete []pTemp;