Entwickler-Ecke

Multimedia / Grafik - TBitmap: 24Bit --> 8Bit


MKehrer - Di 11.11.03 09:05
Titel: TBitmap: 24Bit --> 8Bit
Hi Delphianer,

Ich hab ein Bitmap (24Bit) welches aber eigentlich nur ca. 20 unterschiedliche Farben hat. Umkopieren in ein 8Bit-Bitmap mit der entsprechenden Palette dauert sehr lange, obwohl ich bereits mit TBitmap.ScanLine arbeite.

Wenn man dann noch einen AVI-Film aus vielen Bitmaps basteln will und jedes Bild erst in ein 8Bit-Bitmap umkopiert dauert das ewig.

Kennt da jemand schnelle Routinen für das umwandeln 24Bit --> 8Bit ?

Manfred


Andreas Pfau - Di 11.11.03 19:58

Hallo,

das kommt drauf an... ist die Plaette bekannt oder muss die jedesmal neu berechnet werden? Wenn du weißt, welche Farben es sein sollen, verwende doch diese Prozedur:

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:
{ Erzeugt eine 4Bit-Palette mit den in Colors angegeben Farben
  Wenn Colors weniger als 16 Farben enthält, werden die restlichen Farben
  auf schwarz gesetzt }

procedure CreatePalette4Bit(Bitmap: TBitmap; Colors: array of TColor);
var
  I: Integer;
  Palette: HPalette;
  LogPalette: PLogPalette;
begin
  // Bitmap auf 4Bit setzen
  Bitmap.PixelFormat := pf4Bit;

  // Speicher für Palette reservieren
  GetMem(LogPalette, SizeOf(TLogPalette) + 15 * (SizeOf(TPaletteEntry)));

  // Einstellungen setzen
  LogPalette^.palVersion := $300
  LogPalette^.palNumEntries := 16;

  // Alle Paletteneinträge auf 0 (schwarz) setzen
  ZeroMemory(@LogPalette^.palPalEntry[0], 16 * SizeOf(TPaletteEntry));

  // Farben setzen
  for I := 0 To High(Colors) do
  begin
    Colors[I] := ColorToRgb(Colors[I]);
    LogPalette^.palPalEntry[I].peRed   := Colors[I] and $FF;
    LogPalette^.palPalEntry[I].peGreen := Colors[I] and $FF00 shr 8;
    LogPalette^.palPalEntry[I].peBlue  := Colors[I] and $FF0000 shr 16;
    LogPalette^.palPalEntry[I].peFlags := 0;
  end;

  // Palette erzeugen
  Palette := CreatePalette(LogPalette^);

  // Bei Erfolg Palette zuweisen
  if (Palette <> 0then
    Bitmap.Palette := Palette;

  // Speicher freigeben
  FreeMem(LogPalette);
end;

Kannst das ganze noch in 8 Bit umschreiben.


MKehrer - Mi 12.11.03 08:10

Die Palette wird zu Beginn einmalig berechnet, dass dauert ca. ein paar ms.
Aber dann muß ich bei jedem Bild durch alle Pixel [ca. 600x600] durchrödeln.

Manfred


Andreas Pfau - Mi 12.11.03 13:42

Hallo,

ja, dann passt mein code ja wie die faust auf's Auge - denn die Übernahme der Palette macht Windows in ein paar Millisekunden. Du übergisbt halt jedesmal die Palette, die du anfangs berechnet hast.


MKehrer - Mi 12.11.03 13:47

Danke,

ich probier´s mal
morgen geb ich bescheid

Manfred


MKehrer - Do 13.11.03 08:34

Andreas Pfau hat folgendes geschrieben:
Hallo,

ja, dann passt mein code ja wie die faust auf's Auge - denn die Übernahme der Palette macht Windows in ein paar Millisekunden. Du übergisbt halt jedesmal die Palette, die du anfangs berechnet hast.


Windows verwendet aber nur ähnliche Farben!!

Also ich hab folgendes Vorgehen:
- erstellen einer Palette aus dem Quell-Bmp (24Bit aber nur ca. 20 Farben)
- erstellen eines Ziel-bmp (8Bit)
- Setzen der Palette des ZielBmp.
- Pixelweise umkopieren.

Beim letzen Punkt hab ich bemerkt, dass ich immer noch lesend auf Canvas.Pixels zugegriffen habe. Jetzt (über .ScanLine) geht´s schnell Genug.

Wenn ich den letzen Punkt ersetze durch bmp8Bit.Assign(bmp24Bit),
dann hab ich eben das Problem, dass Windows nur ähnliche Farben verwendet.

Weißt Du hier Abhilfe ?

Manfred


Currywurst - Do 13.11.03 08:53

auf den efg seiten gibs reichlich infos zu sowas, evtl. hilft dir ja sogar das hier schon http://www.efg2.com/Lab/Graphics/Colors/ShowDemoOne.htm


Andreas Pfau - Do 13.11.03 16:04

Hallo,

warum Pixelweise umnkopieren? Canvas.Draw()!!! Einhundertmillionenmal schneller...