0

Assuming I have a TImage component placed on a form along with a TButton. When I click the button I run the code that follows. Ignoring the palette (I know how to create a grayscale palette and assign it) the following code works:

BYTE bBits[] = { 0x00, 0x22, 0x44, 0x88, 0x00, 0x22, 0x44, 0x88,
         0x22, 0x44, 0x88, 0x00, 0x22, 0x44, 0x88, 0x00,
         0x44, 0x88, 0x00, 0x22, 0x44, 0x88, 0x00, 0x22,
         0x88, 0x00, 0x22, 0x44, 0x88, 0x00, 0x22, 0x44 };

Image1->Picture->Bitmap->Width=32;
Image1->Picture->Bitmap->Height=32;
Image1->Picture->Bitmap->PixelFormat = pf8bit;
SetBitmapBits(Image1->Picture->Bitmap->Handle,32*32,&bBits);

Now if I try this:

BYTE bBits[] = { 0x00, 0x22, 0x44, 0x88, 0x00, 0x22, 0x44, 0x88,
         0x22, 0x44, 0x88, 0x00, 0x22, 0x44, 0x88, 0x00,
         0x44, 0x88, 0x00, 0x22, 0x44, 0x88, 0x00, 0x22,
         0x88, 0x00, 0x22, 0x44, 0x88, 0x00, 0x22, 0x44 };


HBITMAP HBmp = CreateBitmap(32, 32, 1, 8, bBits);
Image1->Picture->Bitmap->Handle=HBmp;

It does not work - it displays nothing. But if I change the CreateBitmap code to:

HBITMAP HBmp = CreateBitmap(32, 32, 1, 8, bBits);

it displays however a monochrome image which is incorrect anyway.

The real "weirdness" though is this:

BYTE bBits[] = { 0x00, 0x22, 0x44, 0x88, 0x00, 0x22, 0x44, 0x88,
         0x22, 0x44, 0x88, 0x00, 0x22, 0x44, 0x88, 0x00,
         0x44, 0x88, 0x00, 0x22, 0x44, 0x88, 0x00, 0x22,
         0x88, 0x00, 0x22, 0x44, 0x88, 0x00, 0x22, 0x44 };
Image1->Picture->Bitmap->Width=32;
Image1->Picture->Bitmap->Height=32;
Image1->Picture->Bitmap->PixelFormat = pf8bit;
HBITMAP HBmp = CreateBitmap(32, 32, 1, 8, bBits);
Image1->Picture->Bitmap->Handle=HBmp;

Again nothing displays but if I click the button twice, I get an out of resources exception so it appears there is a memory leak.

Finally if I change the order:

HBITMAP HBmp = CreateBitmap(32, 32, 1, 8, bBits);
Image1->Picture->Bitmap->Handle=HBmp;
Image1->Picture->Bitmap->Width=32;
Image1->Picture->Bitmap->Height=32;
Image1->Picture->Bitmap->PixelFormat = pf8bit;

results in an instant exception (i.e. only need click the button once).

Note this memory leak has nothing to do with the original bitmap handle of the TImage i.e. Image1->Picture->Bitmap->Handle is NULL to begin with so there is no exisitng HBITMAP to release and DeleteObject etc. I am assuming when HBITMAP is assigned to TImage1's handle that TImage takes ownership.

Any explanation? Thank you in advance.

P.S: For reference sake this is how I did it with SetBitmapBits which worked:

BYTE bBits[] = { 128, 128, 128, 128, 0x00, 0x22, 0x44, 0x88,
         0x22, 0x44, 0x88, 0x00, 0x22, 0x44, 0x88, 0x00,
         0x44, 0x88, 0x00, 0x22, 0x44, 0x88, 0x00, 0x22,
         0x88, 0x00, 0x22, 0x44, 0x88, 0x00, 0x22, 0x44 };

TMaxLogPalette lp;
lp.palVersion = 0x0300;
lp.palNumEntries = 256;

for (int i = 0; i < 256; i++) {
    lp.palPalEntry[i].peRed   = i;
    lp.palPalEntry[i].peGreen = i;
    lp.palPalEntry[i].peBlue  = i;
    lp.palPalEntry[i].peFlags = PC_RESERVED;
}

HPALETTE pal= CreatePalette((LOGPALETTE*)&lp);

Image1->Picture->Bitmap->Width=32;
Image1->Picture->Bitmap->Height=32;
Image1->Picture->Bitmap->PixelFormat = pf8bit;
Image1->Picture->Bitmap->Palette = pal;
SetBitmapBits(Image1->Picture->Bitmap->Handle,32*32,&bBits);
JamesA
  • 1
  • 3

1 Answers1

0

Ok figured part of it out:

As soon as you do this:

Image1->Picture->Bitmap->Width=32;
Image1->Picture->Bitmap->Height=32;
Image1->Picture->Bitmap->PixelFormat = pf8bit;

Image1 creates a new HBITMAP so the reference to the bitmap:

HBITMAP HBmp = CreateBitmap(32, 32, 1, 8, bBits);

gets lost without memory cleanup - hence a memory leak.

However I still don't get why:

HBITMAP HBmp = CreateBitmap(32, 32, 1, 8, bBits);
Image1->Picture->Bitmap->Handle=HBmp;

doesn't work.

To clarify the following code works without leaking:

BYTE bBits[] = { 0x00, 0x22, 0x44, 0x88, 0x00, 0x22, 0x44, 0x88,
     0x22, 0x44, 0x88, 0x00, 0x22, 0x44, 0x88, 0x00,
     0x44, 0x88, 0x00, 0x22, 0x44, 0x88, 0x00, 0x22,
     0x88, 0x00, 0x22, 0x44, 0x88, 0x00, 0x22, 0x44 };


HBITMAP h= Image1->Picture->Bitmap->Handle;

if (h) {
Image1->Picture->Bitmap->ReleaseHandle();
DeleteObject(h);
}
Image1->Picture->Bitmap->Width=32;
Image1->Picture->Bitmap->Height=32;
Image1->Picture->Bitmap->PixelFormat = pf8bit;
h= Image1->Picture->Bitmap->Handle;
Image1->Picture->Bitmap->ReleaseHandle();
DeleteObject(h);

HBITMAP HBmp = CreateBitmap(32, 32, 1, 8, bBits);
Image1->Picture->Bitmap->Handle=HBmp;

Note that

Image1->Picture->Bitmap->ReleaseHandle();
DeleteObject(h);

is necessary before and after. The first time the button is clicked the before is unnecessary since h will be null, however on subsequent clicks it is.

JamesA
  • 1
  • 3
  • Most likely because `Image1->Picture->Bitmap` is not GDI/Winapi `HBITMAP` but VCLs `Graphicss::TBitmap` instead... Why you are not using that? its easy to use and better ... you can use its `ScanLine[y]` to access the pixels directly (fast) ... see bullet #4 in [Display an array of color in C](https://stackoverflow.com/a/21699076/2521214). Such bitmap has also Canvas so you can still use all that GDI stuff in it too ... also copying Handle is not good way (that is the memory leak source) use `Image1->Picture->Bitmap->Assign(bmp);` instead or free the Handle before overwriting it ... – Spektre Aug 11 '19 at 06:25
  • Thank you @Spektre. I understand the source of the memory leak and edited my answer to demonstrate. Thanks for your insight regarding why the CreateBitmap doesn't work. I find the SetBitmapBits is the fastest way to go and works. I like finding other ways to do stuff so I was frustrated at not understanding why the CreateBitmap would not work properly when assigned to the TImage bitmap's handle. – JamesA Aug 11 '19 at 07:53
  • The `Graphics::TBitmap` is much more than just handle to Winapi object so if you force change its hnd you are corrupting its properties ... on winapi the `bitblt` is fastest (you need o lock/unlock it) but VCL's `ScanLine` is much more faster than that (not sure why if on the background its also GDI bitmap) without any interlocking.. – Spektre Aug 11 '19 at 07:56
  • Thanks very much, I appreciate your response - I'll look into it. – JamesA Aug 11 '19 at 08:09