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 

A fast way to draw a bitmap
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Graphics
View previous topic :: View next topic  
Author Message
Marko Binic
Guest





PostPosted: Thu Mar 03, 2005 1:03 pm    Post subject: A fast way to draw a bitmap Reply with quote



I've got some color picker components I made recently (free), they look
great and work good, but I'm having a problem with performance. That is, I
paint the gradient bitmap whenever the Hue is changed and OnPaint I just
StretchDraw it to the canvas. There's no flickering and the stretching
doesn't appear to affect the quality. In my demo I put a slider beside the
component and programmed it so when it changes the Hue of the picker gets
changed, thus the bitmap gets recreated. Now the problem is when you use the
slider (drag, not just click) the component doesn't react right away, it
takes a bit of time to redraw pixel-by-pixel (about 1second - very
noticable), so it doesn't look smooth like in e.g. Photoshop. Here's the
code I use to create the bitmap, note that the bitmap is redrawn every time
the Hue changes. I need a faster way to create the gradient so everything
looks smooth.

functionCreateSatLumGradient: TBitmap;
var
x, y, SrcGap: integer;
SrcLine: pRGBTripleArray;
begin
Result := TBitmap.Create;
Result.Width := 256;
Result.Height := 256;
Result.PixelFormat := pf24bit;
SrcLine := Result.ScanLine[0];
SrcGap := Integer(Result.ScanLine[1]) - Integer(SrcLine);
for y := 0 to Result.Height - 1 do
begin
for x := 0 to Result.Width - 1 do
SrcLine[x] := HSLToRGBTriple(FHue, MulDiv(255, x, Result.Width),
MulDiv(255, Result.Width - y, Result.Width));
SrcLine := pRGBTripleArray(Integer(SrcLine) + SrcGap);
end;
end;

Can anyone help me do this, there are other components that use code very
similar to this one? :(

Marko


Back to top
Marko Binic
Guest





PostPosted: Thu Mar 03, 2005 1:15 pm    Post subject: Re: A fast way to draw a bitmap Reply with quote



By the way I uploaded an Exe-Demo showing the problem just use your mouse to
slide the hue trackbar - drag, don't just click - and you'll see what I
mean. You can download the file from http://mxs.bergsoft.net/Demo.zip it's
about 155KB.

Marko


Back to top
Heinrich Wolf
Guest





PostPosted: Thu Mar 03, 2005 1:40 pm    Post subject: Re: A fast way to draw a bitmap Reply with quote



The fastest way to show instant changes,
even on a slow machine,
is to switch the whole desktop to palette mode
(256 colors only, I do not know the API call).
Your internal bitmap of course keeps 24bit pixel format.
Then you only animate the palette.
After the user visually applied the modification,
you finally apply the modification internally in 24 bit mode.


Back to top
Andrew Jameson
Guest





PostPosted: Thu Mar 03, 2005 1:45 pm    Post subject: Re: A fast way to draw a bitmap Reply with quote

Hi,
Yes it does have a lengthy delay ... and the preview panels flicker a lot
but that's easily fixed ... I can't comment on your code but you're welcome
to look over a similar component that I wrote some years ago now ... can't
recollect the detail of how I generated the gradients but it's well
documented :

http://www.softspotsoftware.com/pages/downloads/TajColorPicker.zip

(I suspect that I avoided the problem by using a small selection image)

Andrew Jameson

"Marko Binic" <marko_binic (AT) yahoo (DOT) com> wrote

Quote:
By the way I uploaded an Exe-Demo showing the problem just use your mouse
to slide the hue trackbar - drag, don't just click - and you'll see what I
mean. You can download the file from http://mxs.bergsoft.net/Demo.zip it's
about 155KB.

Marko




Back to top
Andrew Jameson
Guest





PostPosted: Thu Mar 03, 2005 2:00 pm    Post subject: Re: A fast way to draw a bitmap Reply with quote

Hi Marko,

Hmm...just checked and your code and mine are very similar ... almost
identical so I don't think that looking at my code will help !

Andrew


Back to top
Jens Gruschel
Guest





PostPosted: Thu Mar 03, 2005 5:40 pm    Post subject: Re: A fast way to draw a bitmap Reply with quote

Quote:
Can anyone help me do this, there are other components that use code very
similar to this one? Sad

I don't think I can help you only seeing such a small code snippet. But
I wrote such a component, too. You can download it (with source) at
http://www.pegtop.net/delphi/files/pegtopcommon.zip (see
PegtopColorDialogs.pas, you can also find a compiled demo at
[url]http://www.pegtop.net/delphi/files/pegtopdemos.zip)[/url]. Maybe looking at
the source code you'll find some ways to optimize it.

I have tried your demo, mine is much faster, although I don't know why,
might be the HSL->RGB conversion, might be the fact that I'm using 32
bit pixelformat, might be something completely different (the loop
itself seems to be very similar).

Jens

P.S. Note that there are some small bugs in my component (mainly when
entering color values manually). But this doesn't affect speed. I will
upload a fixed version, soon, as well as a homepage with some help, just
in case you (or someone else) decides to use my component.

Back to top
Marko Binic
Guest





PostPosted: Thu Mar 03, 2005 6:00 pm    Post subject: Re: A fast way to draw a bitmap Reply with quote

Quote:
Hmm...just checked and your code and mine are very similar ... almost
identical so I don't think that looking at my code will help !

I haven't yet downloaded your component, but I don't think that making the
selection image smaller would fix anything, cause I'm sure programmers would
want the ability to resize the component. I'm not surprised about the code -
it's a nightmare, it took me an hour just to figure out which color model to
use, how to use it and how to make it resizable :(

Cheers
Marko



Back to top
Marko Binic
Guest





PostPosted: Thu Mar 03, 2005 6:48 pm    Post subject: Re: A fast way to draw a bitmap Reply with quote

Jens, I downloaded your components and I have to say - good work! I looked
at the picker source and I didn't understand a thing Sad This is way too
complicated for me, I know how to use the vcl and the provided methods, I
even know asm, but I have no idea about pointers. I don't bother them and
they don't bother me. I know thay're the fastest way to do something, but
I've never figured out how to work with 'em. So, can you please give me a
simpler example, cause I'm lost...

Cheers
Marko


Back to top
Marko Binic
Guest





PostPosted: Thu Mar 03, 2005 6:49 pm    Post subject: Re: A fast way to draw a bitmap Reply with quote

I uploaded a new demo with all color pickers I made recently, the url is the
same ( http://mxs.bergsoft.net/Demo.zip ) and the file size is about 180KB.
So if you're in a helping mood or would just like to see more...

Cheers
Marko


Back to top
Jens Gruschel
Guest





PostPosted: Thu Mar 03, 2005 7:14 pm    Post subject: Re: A fast way to draw a bitmap Reply with quote

Quote:
I uploaded a new demo with all color pickers I made recently, the url is the
same ( http://mxs.bergsoft.net/Demo.zip ) and the file size is about 180KB.
So if you're in a helping mood or would just like to see more...

Good work, too (except that refreshing takes too long)! I always wanted
to make such a "ring picker". I don't know whether I can help, but you
could try to replace your HSL->RGB routine with mine (see below, it's a
fixed version of the one you can find in PegtopColorUtils.pas). No
floating point arithmetic is involved (only integers), what makes it
quite fast (although I'm sure it could be made faster). The only thing
you have to take care about is that hue, saturation, and brightness (bad
name, I know) are values between 0 and 65535. Sorry, I'm leaving for 2
or 3 days, and I can only give you further assistance when I'm back.

type
TPegtopColor = packed record
case Integer of
0: (Def: Longword);
1: (R, G, B, A: Byte);
2: (Channel: packed array[0..3] of Byte);
end;
PPegtopColor = ^TPegtopColor;

const
Hue000 = 0;
Hue360 = 65536;
Hue060 = Hue360 div 6;
Hue120 = Hue360 div 3;
Hue180 = Hue360 div 2;
Hue240 = Hue360 * 2 div 3;
Hue300 = Hue360 * 5 div 6;
HueMask = 65535;

Sat100 = 65536;
SatMask = 65535;

Bri100 = 65536;
BriMask = 65535;

function GetSaturatedColor(const Hue: Integer): TPegtopColor;
const
AddTab: array[0..2] of Word = (Hue120, Hue000, Hue240);
HueMul = 255 * 6;
var
I: Integer;
S: Integer;
F: Integer;
begin
for I := 0 to 2 do begin
S := (Hue + AddTab[I]) and HueMask;
if S < Hue060 then begin
F := (S * HueMul) shr 16;
end
else if S <= Hue180 then begin
F := 255;
end
else if S < Hue240 then begin
F := ((Hue240 - S) * HueMul) shr 16;
end
else begin
F := 0;
end;
Result.Channel[I] := F;
end;
Result.A := 0;
end;

function ConvertHSBToColor(const Hue, Sat, Bri: Integer): TPegtopColor;
begin
Result := GetSaturatedColor(Hue);
Result.R := ((255 * 16) - ((255 - Result.R) * Sat shr 12)) * Bri shr 20;
Result.G := ((255 * 16) - ((255 - Result.G) * Sat shr 12)) * Bri shr 20;
Result.B := ((255 * 16) - ((255 - Result.B) * Sat shr 12)) * Bri shr 20;
Result.A := 0;
end;

procedure ConvertColorToHSB(const Color: TPegtopColor; out Hue, Sat,
Bri: Integer);
const
PureHues: array[0..2] of Word = (Hue000, Hue120, Hue240);
NextChannels: array[0..2] of Integer = (1, 2, 0);
var
StrongestChannel, WeakestChannel, MediumChannel: Integer;
WeakestValue, MediumValue: Word;
Diff: LongInt;
begin
if (Color.R = Color.G)
and (Color.R = Color.B) then begin // gray
Hue := 0;
Sat := 0;
Bri := Color.R shl 8;
end

else begin // not gray
if (Color.R >= Color.G)
and (Color.R >= Color.B) then begin
StrongestChannel := 0; // red dominates
if (Color.G <= Color.B) then WeakestChannel := 1 else
WeakestChannel := 2;
end
else if (Color.G >= Color.B) then begin
StrongestChannel := 1; // green dominates
if (Color.R <= Color.B) then WeakestChannel := 0 else
WeakestChannel := 2;
end
else begin
StrongestChannel := 2; // blue dominates
if (Color.R <= Color.G) then WeakestChannel := 0 else
WeakestChannel := 1;
end;
Bri := Color.Channel[StrongestChannel] * $10000 div 255;

if Bri = 0 then begin // black
Sat := 0;
Hue := 0;
end

else begin // not black: "normal" color
MediumChannel := 3 - WeakestChannel - StrongestChannel;
WeakestValue := Color.Channel[WeakestChannel] shl 8;
MediumValue := Color.Channel[MediumChannel] shl 8;
Sat := $10000 - ((WeakestValue * 256) div
Color.Channel[StrongestChannel]);
Hue := PureHues[StrongestChannel];
Diff := (((((MediumValue - WeakestValue) * 256) div
Color.Channel[StrongestChannel]) * Hue060)) div Sat;
if MediumChannel = NextChannels[StrongestChannel] then
Hue := (Hue + Diff) and HueMask
else
Hue := (Hue - Diff) and HueMask;
end;
end;
end;

Jens

Back to top
Jens Gruschel
Guest





PostPosted: Thu Mar 03, 2005 8:25 pm    Post subject: Re: A fast way to draw a bitmap Reply with quote

Quote:
Jens, I downloaded your components and I have to say - good work! I looked
at the picker source and I didn't understand a thing Sad This is way too
complicated for me, I know how to use the vcl and the provided methods, I
even know asm, but I have no idea about pointers. I don't bother them and
they don't bother me.

Well, I don't use many pointer, do I? Just for direct pixel access, just
like you...

for y := 0 to Result.Height - 1 do
begin
for x := 0 to Result.Width - 1 do
SrcLine[x] := HSLToRGBTriple(FHue, MulDiv(255, x, Result.Width),
MulDiv(255, Result.Width - y, Result.Width));
SrcLine := pRGBTripleArray(Integer(SrcLine) + SrcGap);
end;

SrcLine[x] really is SrcLine^[x], but the compiler is smart enough to
add the ^ silently if you are using a pointer of an array type.

Quote:
I know thay're the fastest way to do something

Why should pointers be faster than any other memory access? Any variable
is a "pointer" to some memory location. The only difference: using
pointers you can change the location. But of course for most things you
don't need pointers (except to access raw data like image pixels or
sound samples). But then again... any object is accessed by a pointer,
even if you don't see it at first glance (again the compiler silently
adds a ^, but this time you are not allowed to use the ^ optionally).

Jens

Back to top
Marko Binic
Guest





PostPosted: Sun Mar 06, 2005 3:30 pm    Post subject: Re: A fast way to draw a bitmap Reply with quote

I've posted a zipped copy of the color conversion units I'm using in this
component as well as others to the attachments group. I found the RGB-HSV
utility unit at efg2 Lab and the RGB-HSL unit at UNDU.
I'd be very grateful if you can help me optimize this code and fix some
incorrect parts, cause lately I've been getting 0 both for hue and
saturation when I try to convert a color using HSV utils, but in the
component it seems to work fine. It's strange, but I think I made a mistake
while trying to optimize it myself, and as you might have suspected - I
didn't make any backups :(

Cheers
Marko


Back to top
Jens Gruschel
Guest





PostPosted: Mon Mar 07, 2005 5:02 pm    Post subject: Re: A fast way to draw a bitmap Reply with quote

Quote:
I've posted a zipped copy of the color conversion units I'm using in this
component as well as others to the attachments group.

I didn't look at it very closely, but I have seen it (or a very similar
one) before. It uses floating point arithmetic. I have done some speed
tests (see "Fast HLS <-> RGB conversion" on January the 19th) and
noticed that using integer arithmetics can be up to 3 times faster. Try
using the code I've posted.

Maybe you can optimize other things, too, but it's impossible to help
without knowing more. How exactly do you react to changes (for my
component I'm using Invalidate of the control)? Maybe this sounds
stupid, but make sure the color control isn't rendered more than once
when hue changes.

Also try using 32 bit pixelformat. 24 bit is dword aligned, which can
slow down memory access a lot.

There really must be something significant. Your control is bigger, but
that cannot be the only reason. I can even apply filters (dithering for
16 bit output or websafe colors) without any noticable delay.

Jens

Back to top
Marko Binic
Guest





PostPosted: Mon Mar 07, 2005 8:23 pm    Post subject: Re: A fast way to draw a bitmap Reply with quote

Quote:
I didn't look at it very closely, but I have seen it (or a very similar
one) before. It uses floating point arithmetic. I have done some speed
tests (see "Fast HLS <-> RGB conversion" on January the 19th) and noticed
that using integer arithmetics can be up to 3 times faster. Try using the
code I've posted.

I remember that post, but unfortunately after my OS breakown I redownloaded
the posts and got everything after 23rd of January, so I can't see the post.
Can you please repost it or send it to my e-mail.

Quote:
Maybe you can optimize other things, too, but it's impossible to help
without knowing more. How exactly do you react to changes (for my
component I'm using Invalidate of the control)? Maybe this sounds stupid,
but make sure the color control isn't rendered more than once when hue
changes.

With this picker I create a bitmap on Create, CreateWnd and on hue change
and just StretchDraw it to the canvas, then I draw the selection circle.
This is just a brief description, but if you give me your e-mail I can send
you the complete source. To avoid spam you can just send a blank e-mail to
mine...yes, it's genuine, I'm crazy - I know ;)

Quote:
Also try using 32 bit pixelformat. 24 bit is dword aligned, which can slow
down memory access a lot.
There really must be something significant. Your control is bigger, but
that cannot be the only reason. I can even apply filters (dithering for 16
bit output or websafe colors) without any noticable delay.

This must sound sooo stupid, but here it goes: When I use pf32bit instead of
pf24bit I just get loads of black and white lines instead of colors, I have
no idea what I'm doing wrong. Is there any kind of a tutorial or something
where I can learn about graphic programming in Delphi, bitmaps & similar?

Anyway, if you can just give me your e-mail address I'll send you the
complete source, and we can even discuss it tomorrow during the day. See,
cause tomorrow is the 8th of March my school will be working shorter and the
classes will begin at 12h instead of 14h, so I'll be home before 17h and we
can talk about this using an instant msgr (I have Yahoo IM) or on a chat
site (yahoo.com or similar)...

Cheers
Marko



Back to top
Jens Gruschel
Guest





PostPosted: Tue Mar 08, 2005 12:00 am    Post subject: Re: A fast way to draw a bitmap Reply with quote

Quote:
I remember that post, but unfortunately after my OS breakown I redownloaded
the posts and got everything after 23rd of January, so I can't see the post.
Can you please repost it or send it to my e-mail.

Doesn't matter. It doesn't provide more information than I already told you.

Quote:
With this picker I create a bitmap on Create, CreateWnd and on hue change
and just StretchDraw it to the canvas, then I draw the selection circle.

StretchDraw makes me wonder. Usually it's quite fast (hardware bltting
is used if possible), but it's another approach than mine. Could be even
faster than mine, but since it's different, maybe one should take a
closer look at it.

Quote:
This must sound sooo stupid, but here it goes: When I use pf32bit instead of
pf24bit I just get loads of black and white lines instead of colors, I have
no idea what I'm doing wrong. Is there any kind of a tutorial or something
where I can learn about graphic programming in Delphi, bitmaps & similar?

Simple. If you are using 32 bit, you have to change your memory access
as well. You see lines, because you fill 3 bytes with color values when
you have to fill 4 bytes (one is unused). Take a look at this:

BGRBGRBGRBGR
BGRABGRABGRA

As you can see, the blue channel of the second pixel (32 bit) is where
you expect the green channel of the second pixel. Just replace
pRGBTripleArray by another type, which takes 4 bytes instead of 3.

Quote:
Anyway, if you can just give me your e-mail address I'll send you the
complete source, and we can even discuss it tomorrow during the day.

Unfortunatelly I don't have much time tomorrow. Anyway my email address
is [email]jg (AT) pegtopa (DOT) net[/email] without the a.

Jens

Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Graphics All times are GMT
Goto page 1, 2, 3  Next
Page 1 of 3

 
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.