[Gdal-dev] how to draw images on Windows

Chapman, Martin MChapman at sanz.com
Fri Mar 5 17:05:16 EST 2004


All,

1. First of all you need the attached helper class which represents a windows DIB Section, add this class to your application.  

2. You need to open the image with GDAL and get the 3 bands you want to use as rgb (three pointers, or an array of pointers to the band buffers).  There is good sample code out there to open a file with GDAL and get a pointer to each band buffer.

3. You need to bit interleave each raster band buffer.  That basically means that instead of having each band buffer contain all values for a band, such as red, green or blue, you need one big band buffer that contains the the the rgb as interleaved, ie... Bit format = r,g,b,r,g,b,r,g,b,r,g,b.... And so on rather than band1 = r,r,r,r,r,r,r,r,r, band 2 = g,g,g,g,g,g,g,g,g, band 3 = b,b,b,b,b,b,b,b,b,b.  The following code snippet shows how to do it fast (I use memcpy because arrays and vectors are way to slow for this operation).  Notice also, that it does it differently depending on whether it's raster data or elevation data.  File tye 2 = raster (unsigned char raster data), and file type 3 = elevation data (short and float raster data).  The pCombinedBytes pointer holds all three bands after they are interleaved.  File type 2 also uses the GDAL color table for unsigned char raster data to get it's color values.  nSize is how many bands, which will always be 3 for windows (rgb).  nWidth and nHeight are the width and height of the image (or area of interest within the image that you want, get this from GDALRasterBand->GetBandX(), ...->GetBandY() ...or some method like that).  pBandBuffer is an array of pointers to the raster band data retrieved from GDALRasterBand->RasterIO().  m_DataType is the image data type, obtained from GDALRasterBand->->GetRasterDataType().


unsigned char* pCombinedBytes = (unsigned char*) CPLMalloc(sizeof(unsigned char) * nWidth * nHeight * nSize);

for (long i = 0, long j = 0; i < (nWidth * nHeight * nSize); i += nSize, j++)
{
	int k = i;

	if (m_nFileType == 2)
	{
		for (int m = nSize - 1; m >= 0; m--, k++)
		{
			unsigned char* pBytes = (unsigned char*) pBandBuffer[m];
			ptr_dest = pCombinedBytes + k;
			unsigned char b = pBytes[j];

			if (pCT != NULL)
			{
				GDALColorEntry ce;
				unsigned int c = (unsigned int) b;
				c = pCT->GetColorEntryAsRGB(c, &ce);
				if (m == 0) c = ce.c1;
				if (m == 1) c = ce.c2;
				if (m == 2) c = ce.c3;
				b = (unsigned char) c;
			}

			ptr_src = &b;
			memcpy(ptr_dest, ptr_src, 1);
		}
	}
	else
	{
		if (m_DataType == GDT_Int16 || m_DataType == GDT_Byte)
		{
			for (int m = nSize - 1; m >= 0; m--, k++)
			{
				short* pBytes = (short*) pBandBuffer[m];
				ptr_dest = pCombinedBytes + k;
				short nVal = pBytes[j];
				unsigned char uc = (nVal & 0xffff) >> 4;
				ptr_src = &uc;
				memcpy(ptr_dest, ptr_src, 1);
			}
		}
		else
		{
			for (int m = nSize - 1; m >= 0; m--, k++)
			{
				float* pBytes = (float*) pBandBuffer[m];
				ptr_dest = pCombinedBytes + k;
				float nVal = pBytes[j];
				unsigned char uc = (unsigned char) nVal >> 8;
				ptr_src = &uc;
				memcpy(ptr_dest, ptr_src, 1);
			}
		}
	}
}


4. Then you need to realign the bytes for the windows DIB Section.  This code, uses the CDIBSection class and loads it's byte array (the image data) by re-aligning the bytes to the windows width restriction.  Note, the issue of flipping the y value that Frank mentioned is taken care of in the CDIBSection class by multiplying the y value by negative one.  You can refer to the CDIBSection class to see the implementation of that.

if ((nWidth > 0) && (nHeight > 0))
{
	if (m_pDIBSection) delete m_pDIBSection;
		m_pDIBSection = new CDIBSection;

	if (m_pDIBSection)
	{
		m_pDIBSection->Create(nWidth ,nHeight, 24);
		unsigned int dibwidth = m_pDIBSection->GetTotalWidth();

		GByte* dest = (GByte*) m_pDIBSection->GetBits();
		GByte* src = (GByte*) pCombinedBytes;

		for (int row = 0; row < nHeight; row++)
		{
			ptr_dest = dest + row * dibwidth * nSize;
			ptr_src = src + row * nWidth * nSize;
					memcpy(ptr_dest, ptr_src, nWidth * nSize);
		}
	}
}

5.  Lastly, you need to display the m_pDIBSection in your Cview window.  To do this override the CView's OnPaint() function and call the CDIBSection's Draw() method like so:

void CMyView::OnPaint() 
{
	try
	{
		CPaintDC dc(this);
		CMemDC pDC(&dc);

		if (m_pDIBSection)
		{
			m_pDIBSection->Draw(&pDC, 0, 0);	
		}
	}
	catch(...)
	{
		//
	}
}

Thi works great for me on all rasters that GDAL supports.  Plus it can be used for any other raster not obtained from GDAL.  Just need to remove the GDAL specific stuff like the color table.  Let me know whether you have problems or questions.

Martin Chapman

P.S.  I hope this will work for anyone interested in using GDAL on windows.  Maybe I will post a sample MFC app in the future so you can see the whole thing in action.


-----Original Message-----
From: dacianliu at hotmail.com [mailto:dacianliu at hotmail.com] 
Sent: Friday, March 05, 2004 10:21 AM
To: gdal-dev at remotesensing.org
Subject: [Gdal-dev] how to draw images on Windows


hi, all
i am new to GDAL. it is great. and i would like to know how to visualize 
the images on Windows with Windows GDI.
any suggestions would be very appreciated.
thanks in advance

_________________________________________________________________
Ãâ·ÑÏÂÔØ MSN Explorer:   http://explorer.msn.com/lccn  

_______________________________________________
Gdal-dev mailing list
Gdal-dev at remotesensing.org http://remotesensing.org/mailman/listinfo/gdal-dev
-------------- next part --------------
A non-text attachment was scrubbed...
Name: CDIBSection.zip
Type: application/x-zip-compressed
Size: 1712 bytes
Desc: CDIBSection.zip
Url : http://lists.osgeo.org/pipermail/gdal-dev/attachments/20040305/59876418/CDIBSection.bin


More information about the Gdal-dev mailing list