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:
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; inc(cset); end; 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):
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[0] do begin peRed:= byte(brushcolor and $FF); peGreen:=byte(brushcolor and $FF00 shr 8); peBlue:= byte(brushcolor and $FF0000 shr 16); peFlags:=0; end; 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; 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; 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!