Board index » cppbuilder » Refreshing parts of a BMP image?

Refreshing parts of a BMP image?

Hi,

I'm wondering if it's possible to have one large bitmap image (say
1024x768), just update small parts of it, and get bcb to refresh only
those parts?

The reason I need this is speed. I'm basicaly trying to create an app
that displays a screen image, and receives small updates to that
screen over the network. I want the program to just refresh those
small changes instead of the whole bitmap.

Is this possible at all? I'm new to bcb and have never used the
graphics package before, so I'm slightly lost.

Thanks,
Andreas Lundin

 

Re:Refreshing parts of a BMP image?


Quote
Andreas Lundin <Andreas.Lun...@compaq.com> wrote in message

news:380b743c.0107131425.473260d9@posting.google.com...

Quote
> Hi,

> I'm wondering if it's possible to have one large bitmap image (say
> 1024x768), just update small parts of it, and get bcb to refresh only
> those parts?

Yep.  (ok, not very informative, but read on...)

Quote
> The reason I need this is speed. I'm basicaly trying to create an app
> that displays a screen image, and receives small updates to that
> screen over the network. I want the program to just refresh those
> small changes instead of the whole bitmap.

> Is this possible at all? I'm new to bcb and have never used the
> graphics package before, so I'm slightly lost.

I've done something similar to this a few times, and found that the best way
to do it is to use a Graphics::TBitmap to store your image, and a TPaintBox
to display it.  The OnPaint event of the paint box will tell you when you
need to update a section of the on-screen image - usually when it has been
uncovered, etc - and you can find out which part to update by looking at the
TPaintBox::Canvas->ClipRect.

Unfortunately TPaintBox doesn't let you specify a section of the image to
invalidate - it's either all or nothing.  We can get around this by going
direct to the Win32 API call InvalidateRect().

Because TPaintBox descends from TGraphicControl rather than TWinControl, it
does not have a window handle of its own, but uses the one belonging to the
parent.  So to invalidate a section of the paint box you have to adjust your
ClipRect to parent coordinates, then call InvalidateRect() with the parent's
handle.

Here's a bit of code using a TPaintBox and a TButton on a form, with a
Graphics::TBitmap as the source for the image:

--

void __fastcall TForm1::Button1Click(
    TObject* Sender)
{
// the section to update
TRect r(10, 10, 20, 20);
// adjusted for control position on parent
  r.Left += PaintBox1->Left;
  r.Right += PaintBox1->Left;
  r.Top += PaintBox1->Top;
  r.Bottom += PaintBox1->Top;
// invalidate it
  ::InvalidateRect(PaintBox1->Parent->Handle,
                   &r,
                   false);

Quote
}

void __fastcall TForm1::PaintBox1Paint(
    TObject* Sender)
{
// get update area
TRect r = PaintBox1->Canvas->ClipRect;
// copy data from a back buffer
  PaintBox1->Canvas->CopyRect(r,
                   backbfr->Canvas,
                   r);

Quote
}

--

Of course you'll have to adjust that to fit your code, add error checking,
etc, but it's quite simple stuff.  Hope it helps.

--
Corey Murtagh
The Electric Monk
"Quidquid latine dictum sit, altum viditur."

Re:Refreshing parts of a BMP image?


Thanks for the input about how to deal with clipping of the image, but
I think I was a bit unclear in my question.
The thing is, I don't care (at the moment) about what happens to my
image locally, all I worry about is the data I get over the network.
This means I'll never get an OnPaint event, I think. Basically what I
want to happen is:

Recv graphic package  
   |
   V
write that package to memory  
   |
   V
update only that part of the image

So, what I would like is to write the 16x16 pixel package I get over
the network to it's correct location in memory (preferrably by jst
writing directly to memory), and then tell the program to just update
that small part of the image.

Can I just write to memory, without having to read that part of the
image first and without storing it in some buffer?

The I would be able to first invalidate that area, write the new
sauare to memory and just update that part.

//Andreas

Quote
"Corey Murtagh" <em...@ihug.co.nz> wrote in message <news:9iq3br$eqs$1@lust.ihug.co.nz>...
> I've done something similar to this a few times, and found that the best way
> to do it is to use a Graphics::TBitmap to store your image, and a TPaintBox
> to display it.  The OnPaint event of the paint box will tell you when you
> need to update a section of the on-screen image - usually when it has been
> uncovered, etc - and you can find out which part to update by looking at the
> TPaintBox::Canvas->ClipRect.

> Unfortunately TPaintBox doesn't let you specify a section of the image to
> invalidate - it's either all or nothing.  We can get around this by going
> direct to the Win32 API call InvalidateRect().

> Because TPaintBox descends from TGraphicControl rather than TWinControl, it
> does not have a window handle of its own, but uses the one belonging to the
> parent.  So to invalidate a section of the paint box you have to adjust your
> ClipRect to parent coordinates, then call InvalidateRect() with the parent's
> handle.

> Here's a bit of code using a TPaintBox and a TButton on a form, with a
> Graphics::TBitmap as the source for the image:

> --

> void __fastcall TForm1::Button1Click(
>     TObject* Sender)
> {
> // the section to update
> TRect r(10, 10, 20, 20);
> // adjusted for control position on parent
>   r.Left += PaintBox1->Left;
>   r.Right += PaintBox1->Left;
>   r.Top += PaintBox1->Top;
>   r.Bottom += PaintBox1->Top;
> // invalidate it
>   ::InvalidateRect(PaintBox1->Parent->Handle,
>                    &r,
>                    false);
> }

> void __fastcall TForm1::PaintBox1Paint(
>     TObject* Sender)
> {
> // get update area
> TRect r = PaintBox1->Canvas->ClipRect;
> // copy data from a back buffer
>   PaintBox1->Canvas->CopyRect(r,
>                    backbfr->Canvas,
>                    r);
> }

> --

> Of course you'll have to adjust that to fit your code, add error checking,
> etc, but it's quite simple stuff.  Hope it helps.

Re:Refreshing parts of a BMP image?


Quote
Andreas Lundin <Andreas.Lun...@compaq.com> wrote in message

news:380b743c.0107161004.6634878a@posting.google.com...

Quote
> Thanks for the input about how to deal with clipping of the image, but
> I think I was a bit unclear in my question.

More likely I was unclear about my answer :>

Quote
> The thing is, I don't care (at the moment) about what happens to my
> image locally, all I worry about is the data I get over the network.
> This means I'll never get an OnPaint event, I think. Basically what I
> want to happen is:

> Recv graphic package
>    |
>    V
> write that package to memory
>    |
>    V
> update only that part of the image

> So, what I would like is to write the 16x16 pixel package I get over
> the network to it's correct location in memory (preferrably by jst
> writing directly to memory), and then tell the program to just update
> that small part of the image.

Ok, writing to the bitmap's memory is (quite) simple.  Check out the
ScanLines property of Graphics::TBitmap.  This won't help you for the
on-screen image, but handy for an off-screen one.

Quote
> Can I just write to memory, without having to read that part of the
> image first and without storing it in some buffer?

You mean go direct to on-screen?  Well... unless you want to mess around
with DirectDraw (which, IMO, is completely unnecessary here) then you're
better off drawing to a back buffer and doing block transfers from there.
You COULD use a TImage, and write direct to its Picture property (which is a
bitmap), but that would be a lot slower as each write would be drawn
immediately.  Even then I'd use an off-screen bitmap as the draw buffer and
CopyRect to get the data to the screen.

Quote
> The I would be able to first invalidate that area, write the new
> sauare to memory and just update that part.

Which is what I discussed in the first message.  Unless you're using a
TImage (or similar persistent canvas) to display you'll get the odd request
to refresh the whole image, or parts of the image that have nothing to do
with the packet(s) you just received.

So, for speed and control I stand by my original suggestion: a TBitmap for a
buffer and a TPaintBox for visualisation.

--
Corey Murtagh
The Electric Monk
"Quidquid latine dictum sit, altum viditur."

Re:Refreshing parts of a BMP image?


Quote
"Corey Murtagh" <em...@ihug.co.nz> wrote in message <news:9j0orf$328$1@lust.ihug.co.nz>...
> Ok, writing to the bitmap's memory is (quite) simple.  Check out the
> ScanLines property of Graphics::TBitmap.  This won't help you for the
> on-screen image, but handy for an off-screen one.

But won't using scanline mean that I'll have to first read out the
lines of the image before I write to it? There is no way of doing
"blind" writes to the bitmap, ie without caring what's in that part of
the image right now?

Quote
> You mean go direct to on-screen?  Well... unless you want to mess around
> with DirectDraw (which, IMO, is completely unnecessary here) then you're
> better off drawing to a back buffer and doing block transfers from there.
> You COULD use a TImage, and write direct to its Picture property (which is a
> bitmap), but that would be a lot slower as each write would be drawn
> immediately.  Even then I'd use an off-screen bitmap as the draw buffer and
> CopyRect to get the data to the screen.

Excuse me for asking a pehaps obvious question, but what is an
backbuffer? And how do I write to it with raw image data?

//Andreas Lundin

Other Threads