Converting HBitmap into byte array in Delphi
Asked Answered
A

1

6

I am trying to convert hBitmap to array of bytes but I don't want to use TBitmap from unit Graphics. My input image is 128x64x32bit.

var TheBits: array of array of Cardinal;
begin   
  with info.bmiHeader do begin
    biWidth:=131;
    biHeight:=64;
    biSize:=SizeOf(TBITMAPINFOHEADER);
    biCompression:=BI_RGB;
    biBitCount:=32;
    biPlanes:=1;
    biSizeImage:=0;
  end; 

  DC := CreateCompatibleDC(0);    
  SetLength(TheBits, 128, 64);    
  GetDIBits(DC, BmpHandle, 0, 64,@TheBits[0][0],Info,DIB_RGB_COLORS);

This gives me a nice image (upside down, of course) but I had to put 131 into biWidth which doesn't really make sense to me. Why can't it be 128?

Agone answered 26/3, 2013 at 15:10 Comment(0)
D
7

You were extremely lucky. Your array is actually 128 entirely separate arrays. When you set the dimensions, Delphi happened to allocate each array very close to the previous one, with 12 bytes separating them, accounting for the various bookkeeping data in each dynamic array. Lying by telling the API that your bitmap was 131 pixels wide made it skip those bytes when copying data for a narrower bitmap.

The API expects a single contiguous block of bytes, which is not what a multidimensional dynamic array is. A multidimensional dynamic array is really just seen ordinary dynamic array whose element type happens to be another dynamic array.

To fix your code, you need a single-dimension array; set its length to the product of the bitmap height and width.

Derian answered 26/3, 2013 at 15:22 Comment(10)
Also make sure that the row width is a multiple of 4 bytes. In this case, it already is due to being a 32bpp image. If it was 24bpp, the width would need to be rounded up.Hovercraft
No way to create somehow a 2d array that occupies a single block of memory?Agone
@Hovercraft I know about the row-padding in bitmaps (that's why I use 32bit to avoid it), but thanks!Agone
But @Tom, you won't get array of pixels. You will get array of BGRA quads. That two dimensional array makes not much sense in my view.Warrant
@Agone The way to do that is to write a loose wrapper around the 1D array that presents a 2D view of the underlying data. That's the way numerical libraries like numpy operate.Kloof
@DavidHeffernan I know I can make a wrapper but I love short code and without any wrappers my code is shorter, nicer to read :)Agone
@Warrant I am perfectly fine with BGRA quads.Agone
@Agone There is a big difference between a 2 dimensional array and a 1 dimensional array of 1 dimensional arrays. In your case, you have the latter but wan't the former. I don't use delphi so don't know the syntax.Hovercraft
Anyway, if you want a 2D array, the only way to do it is array [0..127] of array [0..63] of CardinalKloof
@Warrant It's an array of array of cardinals, 32bit (most of the time) ints.Hovercraft

© 2022 - 2024 — McMap. All rights reserved.