BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

AV in Graphics Routine

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Graphics
View previous topic :: View next topic  
Author Message
Jim
Guest





PostPosted: Thu Apr 26, 2007 6:14 pm    Post subject: AV in Graphics Routine Reply with quote



Can someone who is more versed in graphics then I look at this and tell
me where I went wrong? I have been getting a large number of reports
on the last line shown

LongColor := PDWORD( PMask)^;

I am clearly not accounting for something in this routine.

Thanks,
Jim


exception class : EAccessViolation
exception message : Access violation at address 004F67CC in module
'UltraExplorer.exe'. Read of address 055E8E80.


**********************************************


procedure ConvertBitmapEx(Image32: TBitmap; var OutImage: TBitmap;
const BackGndColor: TColor);

var
I, N: Integer;
PImage, PTarget, PMask: PByte;
LongColor: DWORD;
SourceRed, SourceGreen, SourceBlue, BkGndRed, BkGndGreen, BkGndBlue,
RedTarget, GreenTarget, BlueTarget, Alpha: Byte;
Target, Mask: TBitmap;
PImageDelta, PBitmapDelta, PMaskDelta: Integer;
begin
// Algorithm only works for bitmaps with a height > 1 pixel, should
not be a limitation
// as it would then be a line!
if (Image32.PixelFormat = pf32Bit) and (Image32.Height > 1) then
begin
Target := TBitmap.Create;
Mask := TBitmap.Create;
try
Target.Width := Image32.Width;
Target.Height := Image32.Height;
Target.Assign(Image32);

Mask.Width := Image32.Width;
Mask.Height := Image32.Height;
Mask.Canvas.Brush.Color := BackGndColor;
Mask.Canvas.FillRect(Mask.Canvas.ClipRect);

// initialize the bitmaps
PImage := Image32.ScanLine[0];
PTarget := Target.ScanLine[0];
PMask := Mask.ScanLine[0];

// Calculate the number of bytes in a row to do the direct
calculation
// of the pixel index address, note for a "bottom up" storage
this will
// these will be negative numbers
PImageDelta := Integer( Image32.ScanLine[1]) - Integer(PImage);
PBitmapDelta := Integer( Target.ScanLine[1]) - Integer( PTarget);
PMaskDelta := Integer( Mask.ScanLine[1]) - Integer( PMask);

// If the Deltas are postive then it is a "top down" bitmap and
easier
// to calculate then next rows address, just add one
if PImageDelta > 0 then
PImageDelta := 1;
if PBitmapDelta > 0 then
PBitmapDelta := 1;
if PMaskDelta > 0 then
PMaskDelta := 1;

for I := 0 to Image32.Height - 1 do
begin
for N := 0 to Image32.Width -1 do
begin
// Pixel encoded:

// Source GetColorValues ; Profiled = ~24-30% of time
LongColor := PDWORD( PImage)^;
SourceBlue := LongColor and $000000FF;
SourceGreen := (LongColor and $0000FF00) shr 8;
SourceRed := (LongColor and $00FF0000) shr 16;
Alpha := (LongColor and $FF000000) shr 24;
Inc(PImage, 4);

// Mask GetColorValues ; Profiled = ~24-30% of time
LongColor := PDWORD( PMask)^; <<<<<<< AV Right Here.
......


--
www.mustangpeak.net
Back to top
David Ninnes
Guest





PostPosted: Thu Apr 26, 2007 6:28 pm    Post subject: Re: AV in Graphics Routine Reply with quote



Jim wrote:
Quote:

// Mask GetColorValues ; Profiled = ~24-30% of time
LongColor := PDWORD( PMask)^; <<<<<<< AV Right Here.
......


Target := TBitmap.Create;

Mask := TBitmap.Create;

These create bitmaps in device format Bitmap.pixelformat := pfdevice;

If so the bitmap is in the screen pixel depth, which may not be 32 bit
and your pointer's overrunning the bitmap, should use
Target.pixelformat := pf32bit;
Mask.pixelformat := pf32bit;

hth,
Dave
Back to top
Anders Isaksson
Guest





PostPosted: Thu Apr 26, 2007 10:52 pm    Post subject: Re: AV in Graphics Routine Reply with quote



"Jim" <jimdk (AT) mindspring00 (DOT) com> skrev i meddelandet
news:4630a5bd$1 (AT) newsgroups (DOT) borland.com...

Quote:
// Calculate the number of bytes in a row to do the direct
calculation
// of the pixel index address, note for a "bottom up" storage
this will
// these will be negative numbers
PImageDelta := Integer( Image32.ScanLine[1]) - Integer(PImage);
PBitmapDelta := Integer( Target.ScanLine[1]) - Integer( PTarget);
PMaskDelta := Integer( Mask.ScanLine[1]) - Integer( PMask);

// If the Deltas are postive then it is a "top down" bitmap and
easier
// to calculate then next rows address, just add one
if PImageDelta > 0 then
PImageDelta := 1;
if PBitmapDelta > 0 then
PBitmapDelta := 1;
if PMaskDelta > 0 then
PMaskDelta := 1;

As you don't show the incrementing parts of your loops, this might not be a
problem, but the above code looks very suspicious to me! For a bottom-up
image, you calculate a Delta that is the number of bytes to add to get to
the next scan line, for a top-down image you set the Delta to 1 byte!?

As the Delta is a signed value, calculated as the difference ScanLine[1] -
ScanLine[0] it will work equally well for both kinds of storage.

--
Anders Isaksson, Sweden
BlockCAD: http://web.telia.com/~u16122508/proglego.htm
Gallery: http://web.telia.com/~u16122508/gallery/index.htm
Back to top
Jim
Guest





PostPosted: Fri Apr 27, 2007 6:46 am    Post subject: Re: AV in Graphics Routine Reply with quote

Quote:
As you don't show the incrementing parts of your loops, this might
not be a problem, but the above code looks very suspicious to me! For
a bottom-up image, you calculate a Delta that is the number of bytes
to add to get to the next scan line, for a top-down image you set the
Delta to 1 byte!?

Trust me I am not proud of these and to be honest I don't recall all
the details of why I did what. Here is the entire thing.

Jim

procedure ConvertBitmapEx(Image32: TBitmap; var OutImage: TBitmap;
const BackGndColor: TColor);

var
I, N: Integer;
PImage, PTarget, PMask: PByte;
LongColor: DWORD;
SourceRed, SourceGreen, SourceBlue, BkGndRed, BkGndGreen, BkGndBlue,
RedTarget, GreenTarget, BlueTarget, Alpha: Byte;
Target, Mask: TBitmap;
PImageDelta, PBitmapDelta, PMaskDelta: Integer;
begin
// Algorithm only works for bitmaps with a height > 1 pixel, should
not be a limitation
// as it would then be a line!
if (Image32.PixelFormat = pf32Bit) and (Image32.Height > 1) then
begin
Target := TBitmap.Create;
Mask := TBitmap.Create;
try
Target.Width := Image32.Width;
Target.Height := Image32.Height;
Target.Assign(Image32);

Mask.Width := Image32.Width;
Mask.Height := Image32.Height;
Mask.Canvas.Brush.Color := BackGndColor;
Mask.Canvas.FillRect(Mask.Canvas.ClipRect);

// initialize the bitmaps
PImage := Image32.ScanLine[0];
PTarget := Target.ScanLine[0];
PMask := Mask.ScanLine[0];

// Calculate the number of bytes in a row to do the direct
calculation
// of the pixel index address, note for a "bottom up" storage
this will
// these will be negative numbers
PImageDelta := Integer( Image32.ScanLine[1]) - Integer(PImage);
PBitmapDelta := Integer( Target.ScanLine[1]) - Integer( PTarget);
PMaskDelta := Integer( Mask.ScanLine[1]) - Integer( PMask);

// If the Deltas are postive then it is a "top down" bitmap and
easier
// to calculate then next rows address, just add one
if PImageDelta > 0 then
PImageDelta := 1;
if PBitmapDelta > 0 then
PBitmapDelta := 1;
if PMaskDelta > 0 then
PMaskDelta := 1;

for I := 0 to Image32.Height - 1 do
begin
for N := 0 to Image32.Width -1 do
begin
// Pixel encoded:

// Source GetColorValues ; Profiled = ~24-30% of time
LongColor := PDWORD( PImage)^;
SourceBlue := LongColor and $000000FF;
SourceGreen := (LongColor and $0000FF00) shr 8;
SourceRed := (LongColor and $00FF0000) shr 16;
Alpha := (LongColor and $FF000000) shr 24;
Inc(PImage, 4);

// Mask GetColorValues ; Profiled = ~24-30% of time
LongColor := PDWORD( PMask)^;
BkGndBlue := LongColor and $000000FF;
BkGndGreen := (LongColor and $0000FF00) shr 8;
BkGndRed := (LongColor and $00FF0000) shr 16;
Inc(PMask, 4);

if Alpha < High(Byte) then
begin
// displayColor = sourceColor?alpha / 255 +
backgroundColor?(255 - alpha) / 255
// Profiled = ~15-24% of time
RedTarget := SourceRed*Alpha shr 8 + BkGndRed*(255-Alpha)
shr 8;
GreenTarget := SourceGreen*Alpha shr 8 +
BkGndGreen*(255-Alpha) shr 8;
BlueTarget := SourceBlue*Alpha shr 8 +
BkGndBlue*(255-Alpha) shr 8;
end else
begin
// skip non-blended pixels
RedTarget := SourceRed;
GreenTarget := SourceGreen;
BlueTarget := SourceBlue;
end;

// Create the RGB DWORD color ; Profiled = ~8%-9%% of time
// Mask out all but the alpha channel then build the
backwards stored RGB preserving the alpha channel bits
PDWORD(PTarget)^ := ((BlueTarget) or (GreenTarget shl 8)or
(RedTarget shl 16));
Inc(PTarget, 4);
end;
Inc(PImage, PImageDelta*2);
Inc(PMask, PMaskDelta*2);
Inc(PTarget, PBitmapDelta*2);
end;
OutImage.Assign(Target);
finally
FreeAndNil(Target);
FreeAndNil(Mask);
end;
end else
OutImage.Assign(Image32)
end;


--
www.mustangpeak.net
Back to top
Anders Isaksson
Guest





PostPosted: Fri Apr 27, 2007 8:00 pm    Post subject: Re: AV in Graphics Routine Reply with quote

Jim wrote [slightly edited]:

Quote:
PImageDelta := Integer( Image32.ScanLine[1]) - Integer(PImage);
PBitmapDelta := Integer( Target.ScanLine[1]) - Integer( PTarget);
PMaskDelta := Integer( Mask.ScanLine[1]) - Integer( PMask);
if PImageDelta > 0 then
PImageDelta := 1;
if PBitmapDelta > 0 then
PBitmapDelta := 1;
if PMaskDelta > 0 then
PMaskDelta := 1;
for I := 0 to Image32.Height - 1 do
begin
for N := 0 to Image32.Width -1 do
begin
work
Inc(PImage, 4);
Inc(PMask, 4);
Inc(PTarget, 4);
end;
Inc(PImage, PImageDelta*2);
Inc(PMask, PMaskDelta*2);
Inc(PTarget, PBitmapDelta*2);
end;

So, for bottom-up, you do one line pixelwise forward, and then a double line
leap backwards, seems OK.

But for top-down you do one line pixelwise forward, then skip half a pixel
and think you are at the beginning of the next line... I'd assume the Deltas
should be zero for top-down, as you have Inc'ed your way through the whole
line and are already standing at the beginning of the next.

For both approaches, you have also made the assumption that the memory
layout doesn't contain any non-pixel filler bytes. I'm not sure that's a
safe assumption.

I would have coded it something like (newsreader code, no promises):

LineDelta := ScanLine[1] - ScanLine[0];
if (LineDelta > 0) then PixelDelta := SizeOf(TRGBQuad) else PixelDelta
:= -SizeOf(TRGBQuad);
PLine := ScanLine[0];
for I := 0 to Height - 1 do
begin
PPixel := PLine;
for N := 0 to Width - 1 do
begin
< work with PPixel^ >
Inc(PPixel, PixelDelta);
end;
Inc(PLine, LineDelta);
end;

Also note that if the pointers are instead declared as pointers to the
actual data type, you don't have to fiddle with SizeOf(TRGBQuad), the value
would have been +-1 instead. But the pointer arithmetic lines would need
some more typecasts.

There's also (I believe) a problem zone where the image begins at an address
< PositiveMaxInt and extends into the negative range of an Integer (or vice
versa). Unsigned integers, or longint, would probably be better.

Another beware for the future: Integer will not be able to contain a Pointer
when Delphi for Win64 finally arrives, AFAIK.

--
Anders Isaksson, Sweden
BlockCAD: http://web.telia.com/~u16122508/proglego.htm
Gallery: http://web.telia.com/~u16122508/gallery/index.htm
Back to top
Jim
Guest





PostPosted: Fri Apr 27, 2007 10:55 pm    Post subject: Re: AV in Graphics Routine Reply with quote

Quote:
For both approaches, you have also made the assumption that the
memory layout doesn't contain any non-pixel filler bytes. I'm not
sure that's a safe assumption.

I would have coded it something like (newsreader code, no promises):


Thanks, much clearer but....

I uploaded a demo to the attachements. If I set the first loop to what
is should be

for I := 0 to Image32.Height - 1 do

it AV when access the last (top row). If I do this:

for I := 0 to Image32.Height - 2 do

Then it works... but it does not run the top line. You can't see the
effect in the demo but in my real app there is a black line across the
top where the algrothim does not touch those pixels.

If you could take a quick look I would appreciate it.

Jim


--
www.mustangpeak.net
Back to top
Anders Isaksson
Guest





PostPosted: Fri Apr 27, 2007 11:16 pm    Post subject: Re: AV in Graphics Routine Reply with quote

Jim wrote:

Quote:
If you could take a quick look I would appreciate it.


I haven't taken a look yet, but have you given thought to the other thing I
mentioned in the previous post:

Quote:

But for top-down you do one line pixelwise forward, then skip half a pixel

and think you are at the beginning of the next line... I'd assume the Deltas
should be zero for top-down, as you have Inc'ed your way through the whole
line and are already standing at the beginning of the next.
<<<

If I'm understanding your code right, it will Inc the pointers a bit too far
for each line, meaning that it will AV if you try to go through them all (as
it seems you go a bit farther), while it would still 'work' if you skip
enough lines.

Why not test it on a bitmap that is only 1 pixel wide, and with very
distinct color variations for each line?

--
Anders Isaksson, Sweden
BlockCAD: http://web.telia.com/~u16122508/proglego.htm
Gallery: http://web.telia.com/~u16122508/gallery/index.htm
Back to top
Anders Isaksson
Guest





PostPosted: Fri Apr 27, 2007 11:57 pm    Post subject: Re: AV in Graphics Routine Reply with quote

Jim wrote:

Quote:
If you could take a quick look I would appreciate it.

OK, now I have taken a look. Jim, we are both a little stupid :-)

The [newsreader] code I wrote places the line pointer at the *beginning* of
each line, irrespective of the direction of Delta.

Of course, if PixelDelta is negative, we should start at the *end* of the
line , or (the easier way) we should always go *forward* inside the line -
PixelDelta is always = SizeOf(TRGBQuad). Save a bit on the if:s too :-)

After changing this, it works as expected (at least in D5).

As a side note, I tried to compile with OVERFLOW and RANGE on, but then I
get exceptions on the pointer arthmetic lines. Sometimes I feel like having
these tests on, as they *can* show me problems with the code. To make that
possible here, you'd have to go through some more type casting, probably up
to a longer integer type which would take more time, so I'm not sure which
way I'd go...

--
Anders Isaksson, Sweden
BlockCAD: http://web.telia.com/~u16122508/proglego.htm
Gallery: http://web.telia.com/~u16122508/gallery/index.htm
Back to top
Anders Isaksson
Guest





PostPosted: Sat Apr 28, 2007 12:20 am    Post subject: Re: AV in Graphics Routine Reply with quote

BTW, did you know that by setting

GroupBoxDest.DoubleBuffered := True;

in the FormCreate() event, you will get very smooth, flicker-free drawing of
the blended image? Probably takes a bit more time, but the user experience
is so much better :-)

--
Anders Isaksson, Sweden
BlockCAD: http://web.telia.com/~u16122508/proglego.htm
Gallery: http://web.telia.com/~u16122508/gallery/index.htm
Back to top
Anders Isaksson
Guest





PostPosted: Sat Apr 28, 2007 12:25 am    Post subject: Re: AV in Graphics Routine Reply with quote

Anders Isaksson wrote:

Quote:
GroupBoxDest.DoubleBuffered := True;

GroupBoxDest.ControlStyle := GroupBoxDest.ControlStyle + [csOpaque];

seems to give as good results, but takes less time. That assumes that the
control is redrawing the full canvas though (as this example project is
doing).

--
Anders Isaksson, Sweden
BlockCAD: http://web.telia.com/~u16122508/proglego.htm
Gallery: http://web.telia.com/~u16122508/gallery/index.htm
Back to top
Jim
Guest





PostPosted: Sat Apr 28, 2007 2:08 am    Post subject: Re: AV in Graphics Routine Reply with quote

Quote:
OK, now I have taken a look. Jim, we are both a little stupid :-)

The [newsreader] code I wrote places the line pointer at the
beginning of each line, irrespective of the direction of Delta.

Uh..... stepped through that at least 50 times and did not even think
about that...... Thanks.

Jim
--
www.mustangpeak.net
Back to top
Jim
Guest





PostPosted: Sat Apr 28, 2007 2:11 am    Post subject: Re: AV in Graphics Routine Reply with quote

Quote:
GroupBoxDest.ControlStyle := GroupBoxDest.ControlStyle + [csOpaque];

seems to give as good results, but takes less time. That assumes that
the control is redrawing the full canvas though (as this example
project is doing).

This example is not being used for anything. Someone wanted me to do
that type of blending for the images in my EasyListview component so
all that is was a test bed they developed. I did a bit of profiling
and got it about 300% faster with that code. All I use out of it is
the graphics routines in my common library.

Thanks for all your help.
Jim
--
www.mustangpeak.net
Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Graphics All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.