[Gdal-dev] Writing bit interleaved datawith GDALRasterBand::RasterIO

Alain Rist ar at navpoch.com
Wed Jul 7 13:11:23 EDT 2004


Hi Martin,
This is what I wrote for GDALView.
Hope it helps.

Alain

----- Original Message ----- 
From: "Chapman, Martin" <MChapman at sanz.com>
To: "Frank Warmerdam" <warmerdam at pobox.com>
Cc: "gdal-dev" <gdal-dev at remotesensing.org>
Sent: Wednesday, July 07, 2004 6:35 PM
Subject: RE: [Gdal-dev] Writing bit interleaved datawith
GDALRasterBand::RasterIO


Frank,

I'm not sure if I mean byte or pixel interleave.  I want to save data
the I have in a windows DIB.  When I create the DIB from a gdal dataset
I interleave the bits into the following structure something like
this...

unsigned char* pCombinedBytes = (unsigned char*)
CPLMalloc(sizeof(unsigned char) * nWidth * nHeight * nSize);
//Where nSize is the number of bands and nWidth and nHeight is the aoi w
and h...

//then I retrieve the bytes for each band something like this...

void** pBandBuffer = (void**) new unsigned char*[nSize];
//for each band
pBandBytes = (unsigned char*) CPLMalloc(sizeof(unsigned char) *
nWidth * nHeight);
pBand->RasterIO(GF_Read, nXOffset, nYOffset, nWidth, nHeight,
pBandBytes, nWidth , nHeight, GDT_Byte, 0, 0);
pBandBuffer[n] = pBandBytes;
//end if

// then I interleave the bytes into one array...

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

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);
}
}

// then I realign the bytes for a windows DIB...

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);
}

So I think I am pixel interleaving then?  Anyway, I think the example
you sent me will work if I undo the windows DIB realignment, (which
would be really cool).  I'll let you know if it works.

Thanks for the quick response.

Martin

-----Original Message-----
From: Frank Warmerdam [mailto:warmerdam at pobox.com]
Sent: Wednesday, July 07, 2004 10:02 AM
To: Chapman, Martin
Cc: gdal-dev
Subject: Re: [Gdal-dev] Writing bit interleaved data with
GDALRasterBand::RasterIO


Chapman, Martin wrote:
> All,
>
> If I have raster data stored as bit interleaved
> (r,g,b,r,g,b,r,g,b...),
> can I use the GDALRasterBand::RasterIO function to write this data to
> disc?  I read that the nPixelSpace and nLineSpace parameters allow
> reading into or writing from unusually organized buffers.  If this is
> possible, could someone please provide me a brief example of how to
use
> these parameters with this type of data structure?

Martin,

Do you literally mean bit interleaved?  Or pixel interleaved?

I'll assume you mean pixel interleaved.   To write from a pixel
interleaved
1 line buffer of 8bit data you might use:

poBandRed->RasterIO( GF_Write, 0, line, xsize, 1,
                      pabyRGB + 0, xsize, 1, GDT_Byte,
                      3, xsize * 3 );

poBandGreen->RasterIO( GF_Write, 0, line, xsize, 1,
                      pabyRGB + 1, xsize, 1, GDT_Byte,
                      3, xsize * 3 );
poBandBlue->RasterIO( GF_Write, 0, line, xsize, 1,
                      pabyRGB + 2, xsize, 1, GDT_Byte,
                      3, xsize * 3 );

Note that the buffer pointer you pass in needs to point to the beginning
of the data to be written (hence the +1 and +2 offsets on pabyRGB for
green and blue).  The nPixelSpace is the number of bytes from the
beginning of one pixel to the beginning of the next.  3 in this case
since there are 3 bytes of data for for each pixel written.  The
linespacing is the offset from the beginning of one line to the next, so
xsize * 3 in this case.

I hope this helps. If your data is really "bit" interleaved you will
need to repack stuff before writing.

Best regards,

-- 
---------------------------------------+--------------------------------
---------------------------------------+------
I set the clouds in motion - turn up   | Frank Warmerdam,
warmerdam at pobox.com
light and sound - activate the windows | http://pobox.com/~warmerdam
and watch the world go round - Rush    | Geospatial Programmer for Rent

_______________________________________________
Gdal-dev mailing list
Gdal-dev at xserve.flids.com
http://xserve.flids.com/mailman/listinfo/gdal-dev
-------------- next part --------------
/******************************************************************************
 * Purpose:  Create a Windows bitmap from a GDALDataSet.  
 *	
 * Author:   Alain Rist, ar at navpoch.com
 *
 ******************************************************************************
 * Copyright (c) 2004, Alain Rist
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 ******************************************************************************
 */

#pragma once

#include <windows.h>
#include <gdal_priv.h>
/*
	GDALCreateDib returns a HBITMAP from a RGB, grayscale, or 8bits paletted GDALDataset. 
	Returns NULL if fails.
	If the failure comes from Windows(r) ( file too big for this system ) GetLastError() will
	return ERROR_NO_SYSTEM_RESOURCES .
	Otherwise the format is not implemented.
*/


HBITMAP GDALCreateDib( GDALDataset * poDataset)
{
	struct DIBINFO : public BITMAPINFO
	{
		RGBQUAD	 arColors[255];    // Color table info - adds an extra 255 entries to palette
		DIBINFO(BITMAPINFO bm) : BITMAPINFO(bm) {}
		operator LPBITMAPINFO()          { return (LPBITMAPINFO) this; }
		RGBQUAD* ColorTable( int i=0 )   { return bmiColors + i ; }
	};

	BITMAPINFO bm = { sizeof(BITMAPINFOHEADER), 
		poDataset->GetRasterXSize(), - poDataset->GetRasterYSize(), 1, 24, BI_RGB };
	DIBINFO bmi(bm);

	int nBands = poDataset->GetRasterCount();

	if ( nBands == 1 )
	{
		bmi.bmiHeader.biBitCount = 8 ;

		switch ( poDataset->GetRasterBand(1)->GetColorInterpretation())
		{
		case GCI_PaletteIndex :
			{
				GDALColorTable * pgdColorTable = poDataset->GetRasterBand(1)->GetColorTable();
				bmi.bmiHeader.biClrUsed = pgdColorTable->GetColorEntryCount();
				if ( ( bmi.bmiHeader.biClrUsed > 256 ) || 
					( pgdColorTable->GetPaletteInterpretation() != GPI_RGB ))
					return NULL; // unsupported image format
				// Fill the color table
				for ( UINT i=0 ; i < bmi.bmiHeader.biClrUsed ; i++ )
				{
					bmi.ColorTable(i)->rgbBlue =(BYTE) pgdColorTable->GetColorEntry(i)->c3;
					bmi.ColorTable(i)->rgbGreen =(BYTE) pgdColorTable->GetColorEntry(i)->c2;
					bmi.ColorTable(i)->rgbRed =(BYTE) pgdColorTable->GetColorEntry(i)->c1;
					bmi.ColorTable(i)->rgbReserved = 0;
				}
				break;
			}
		case GCI_GrayIndex :
			bmi.bmiHeader.biClrUsed = 256 ;
			// Fill the color table
			for ( UINT i=0 ; i < bmi.bmiHeader.biClrUsed ; i++ )
			{
				RGBQUAD q = {i,i,i,0} ;
				*bmi.ColorTable(i) = q ;
			}
			break;
		default : 
			return NULL ;
		}
	}
	// Create the DIB
	HDC dc = CreateCompatibleDC( NULL );
	LPVOID pBits;
	HBITMAP hbm = CreateDIBSection( dc, bmi, DIB_RGB_COLORS, &pBits, NULL, NULL );
	DeleteDC(dc);
	if ( ! hbm )
	{
		SetLastError( ERROR_NO_SYSTEM_RESOURCES );
		LocalFree(pBits);
		return hbm;
	}
	// Fill the Bits
	CPLErr gdErr = CE_Failure;
	int nScanSize = ((bmi.bmiHeader.biWidth  * bmi.bmiHeader.biBitCount + 31) & (~31) ) / 8;
	int nBandsRead = 1 ;
	
	if ( bmi.bmiHeader.biBitCount == 8 ) // Paletted or Gray
		gdErr = poDataset->GetRasterBand(1)->RasterIO( 
			GF_Read , 0 ,0 , poDataset->GetRasterXSize(), poDataset->GetRasterYSize(),
			pBits,bmi.bmiHeader.biWidth,-bmi.bmiHeader.biHeight,GDT_Byte, 
			1, nScanSize );
	else
		for ( int iBand = 1 ,nBandsRead = 0 ; iBand <= nBands ; iBand ++ )
		{
			int iColorOffset;
			switch( poDataset->GetRasterBand(iBand)->GetColorInterpretation() )
			{	// BGR 
				case GCI_RedBand : iColorOffset = 2; 
					break;
				case GCI_GreenBand : iColorOffset = 1;
					break;
				case GCI_BlueBand : iColorOffset = 0;
					break;
				default : continue ;
			}
			gdErr = poDataset->GetRasterBand(iBand)->RasterIO( 
				GF_Read , 0 ,0 , poDataset->GetRasterXSize(), poDataset->GetRasterYSize(),
				 ((LPBYTE)pBits) + iColorOffset ,bmi.bmiHeader.biWidth,-bmi.bmiHeader.biHeight,
				GDT_Byte, 3, nScanSize );
			nBandsRead ++;
	}
	if  (( gdErr != CE_None ) || !nBandsRead )
	{
		::DeleteObject(hbm);
		hbm=NULL;
	}
	return hbm ;
};


More information about the Gdal-dev mailing list