Autor Beitrag
Logikmensch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 390

Win XP
Delphi 2007 Prof., XE2, XE5
BeitragVerfasst: So 03.04.11 14:02 
Ziel ist es, in eine 8 x 8 Pixels große zweifarbige Bitmap ein beliebiges Punkteraster reinzuzeichnen. Ich habe die folgende, gut funktionierende Variante, die allerdings mit der Pixels-Eigenschaft arbeitet:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
procedure drawsinclairblock(b:TBitmap; cset:PChar; xoffset,yoffset:integer; brushcolor,pencolor:TColor);
var
  x,y,c:integer;
begin
  b.canvas.brush.color:=brushcolor;
  b.canvas.fillrect(rect(xoffset,yoffset,xoffset+8,yoffset+8));
  for y:=yoffset to yoffset+7 do begin
    c:=ord(cset^);
    if c<>0 then
      for x:=xoffset to xoffset+7 do begin
        if c and 128<>0 then b.canvas.Pixels[x,y]:=pencolor;
        c:=c shl 1;
      end{for}
    inc(cset);
  end{for}
end;


Dabei übergebe ich der Routine über die Variablen Xoffset und Yoffset die Position des 8x8-Punkterasters, welches in die bestehende, viel größere Bitmap B reingemalt werden soll. Das binäre Punkteraster ist in dem 8-Byte-Feld CSET übergeben worden.
Die Hintergrundfarbe übergebe ich über BRUSHCOLOR, die Vordergrund-Farbe übergebe ich mittels PENCOLOR. Um z.B. ein "A" als Punkteraster zu zeichnen, übergebe ich in dem CSET-Feld die Bytesequenz 0,60,66,66,124,66,66,0.

Nun dachte ich, es sei doch bestimmt viel effizienter (und schneller), wenn ich das ganze statt der Bitbehandlung und statt dem Zugriff mit Pixels die wohlweislich schnellere variante über ScanLine verwende. Dazu, so dachte ich, nehme ich einach eine zweifarbige Bitmap, erstelle die Palette mit den beiden zu verwendenden Farben und kopiere das via BitBlt in die Zielbitmap rein, somit ergab sich folgender Code (auch mit Unterstützung aus diesem Forum, weil ich vorher noch nicht mit HPALETTE gearbeitet hatte):

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
procedure drawsinclairblock(b:TBitmap; cset:PChar; xoffset,yoffset:integer; brushcolor,pencolor:TColor);
var
  b8x8:TBitmap;
  palette:PLOGPALETTE;
  hpal:HPALETTE;
  c,y,i:integer;
  byt:PByte;
begin
  b8x8:=TBitmap.Create;
  try
    b8x8.PixelFormat:=pf1bit;
    b8x8.SetSize(8,8);
    getmem(palette,sizeof(TLogPalette)+sizeof(TPaletteEntry)*2);
    try
      palette.palVersion:=$300;
      palette.palNumEntries:=2;
      with palette.palPalEntry[0do begin
        peRed:=  byte(brushcolor and $FF);
        peGreen:=byte(brushcolor and $FF00 shr 8);
        peBlue:= byte(brushcolor and $FF0000 shr 16);
        peFlags:=0;
      end{with}
      i:=1;
      with palette.palPalEntry[i] do begin
        peRed:=  byte(pencolor and $FF);
        peGreen:=byte(pencolor and $FF00 shr 8);
        peBlue:= byte(pencolor and $FF0000 shr 16);
        peFlags:=0;
      end{with}
      hpal:=CreatePalette(palette^);
      if hpal<>0 then b8x8.Palette:=hpal;
      for y := 0 to 7 do begin
        byt:=b8x8.ScanLine[y];
        c:=ord(cset^);
        byt^:=c;
        inc(cset);
      end;
      bitblt(b.Canvas.Handle,xoffset,yoffset,8,8,b8x8.Canvas.Handle,0,0,SRCCOPY);
    finally
      freemem(palette);
    end;
  finally
    b8x8.Free;
  end{try}
end;


Also, um es gleich vorweg zu nehmen: Beide Routinen erzeugen exakt dasselbe Ergebnis. Das mit der Palette funzt gut und die zweifarbige Bitmap klappt wohl auch.

Was ich nicht kapiere ist, dass beim Zeichnen von einer ganzen Fläche mit diesen 8x8-Rastern die erste Routine um den Faktor 10 schneller ist. Ich weiß jetzt aber überhaupt nicht, wo der große Zeitunterschied genau herkommt. Der Zugriff auf die 8x8-Bitmap über Scanline dürfte es nicht sein, aber was sonst?

Für Tipps und Hinweise bin ich wie immer sehr dankbar!

_________________
Es gibt keine Probleme - nur Lösungen!
HenryHux
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: So 03.04.11 14:11 
Hi, ich selber habe mich mit dem Thema noch nicht viel beschäftigt, aber ich habe mal einen Vergleich zwischen GetDIBits, Pixels und Scanline gelesen.
Demnach sollte Scanline eig um einiges schneller sein.
Vielleicht hilft es dir ja -> ksymeon.blogspot.com...ne-vs-pixels-in.html

Lg
FrEaKY
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 235


D7
BeitragVerfasst: Mo 04.04.11 20:21 
Niemals ist Pixels schneller. ;) Vergiss es.
Ich hab ein Programm gemacht, das ein 1000x700 Bitmap mit Zufallsfarben füllt (Rauschen). Pixels braucht 250-260ms.
Scanline: 6 Millisekunden. Mit QueryPerformanceCounter gemessen. Also wenn bei dir Pixels schneller ist machst du eindeutig was falsch.

PS: Was du da mit BitBlt rummachst ist mir auch nicht ganz klar. TBitmap hat doch die praktische Funktion Assign;