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?

Tom
  • 2,962
  • 3
  • 39
  • 69

1 Answers1

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.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • 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. – Deanna Mar 26 '13 at 15:30
  • No way to create somehow a 2d array that occupies a single block of memory? – Tom Mar 26 '13 at 15:30
  • @Deanna I know about the row-padding in bitmaps (that's why I use 32bit to avoid it), but thanks! – Tom Mar 26 '13 at 15:31
  • 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. – TLama Mar 26 '13 at 15:35
  • @Tom 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. – David Heffernan Mar 26 '13 at 15:37
  • @DavidHeffernan I know I can make a wrapper but I love short code and without any wrappers my code is shorter, nicer to read :) – Tom Mar 26 '13 at 15:38
  • @TLama I am perfectly fine with BGRA quads. – Tom Mar 26 '13 at 15:39
  • @Tom 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. – Deanna Mar 26 '13 at 15:40
  • 1
    Anyway, if you want a 2D array, the only way to do it is `array [0..127] of array [0..63] of Cardinal` – David Heffernan Mar 26 '13 at 15:41
  • @TLama It's an array of array of cardinals, 32bit (most of the time) ints. – Deanna Mar 26 '13 at 15:41