Entwickler-Ecke

Multimedia / Grafik - Bitmap in Graustufen umwandeln


maxk - Sa 02.11.02 17:55
Titel: Bitmap in Graustufen umwandeln
Hilfe,
wie kann ich ein Bitmap in Graustufen konvertieren? Egal wie,
hauptsache ohne auf die Festplatte zu speichern... (Vom virtuellen Speicher mal abgesehen)

maxk


OregonGhost - Sa 02.11.02 18:36

Eine Möglichkeit ist, mit CreateBitmap oder CreateDIBSection eine Graustufen-Bitmap zu erstellen von derselben Größe wie die Quellbitmap, und dann einfach mit BitBlt die Quellbitmap auf die neue Bitmap zu blitten. Windows übernimmt dann glaub ich das Farbmanagement automatisch, naja, jedenfalls sieht das Graustufenergebnis ganz gut aus ;c)


maxk - Sa 02.11.02 20:13

:?: :?: :?: Kannst du mit da mal ein Beispiel coden?


OregonGhost - So 03.11.02 17:29

Nein, aber ich gebe dir den Quellcode aus einem meiner Programme. Ich habe das Problem wie folgt gelöst, da ich schnellen Zugriff auf die Pixeldaten brauchte. Vielleicht ist das für dein Programm etwas überdimensioniert, aber es wird funktionieren. Ist in C geschrieben, wenn du damit nicht klarkommst, kann ich dir noch beim Übersetzen helfen.

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:
BYTE* g_GrayBits = NULL;

// Quellbitmap laden und Größe abfragen
HBITMAP g_hSource = (HBITMAP) LoadImage(NULL, szFilename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
BITMAP bm;
GetObject(g_hSource, sizeof(BITMAP), &bm);

// Graustufenbitmap erzeugen
BITMAPINFO * bmi = (BITMAPINFO*)malloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi->bmiHeader.biWidth = bm.bmWidth;
bmi->bmiHeader.biHeight = bm.bmHeight;
bmi->bmiHeader.biPlanes = 1;
bmi->bmiHeader.biBitCount = 8;
bmi->bmiHeader.biCompression = BI_RGB;
bmi->bmiHeader.biSizeImage = 0;
bmi->bmiHeader.biXPelsPerMeter = 72000;
bmi->bmiHeader.biYPelsPerMeter = 72000;
bmi->bmiHeader.biClrUsed = 0;
bmi->bmiHeader.biClrImportant = 0;
for (int i = 0; i < 256; i++) {
    bmi->bmiColors[i].rgbRed = i;
    bmi->bmiColors[i].rgbGreen = i;
    bmi->bmiColors[i].rgbBlue = i;
    bmi->bmiColors[i].rgbReserved = 0;
}
HBITMAP g_hGrayscale = CreateDIBSection(NULL, bmi, DIB_RGB_COLORS, (void**)&g_GrayBits, NULL, 0);

// Quellbitmap auf Graustufenbitmap kopieren
HDC cdc = GetDC(NULL), dcs = CreateCompatibleDC(cdc), dct = CreateCompatibleDC(cdc);
ReleaseDC(NULL, cdc);
HBITMAP hbmOlds = (HBITMAP)SelectObject(dcs, g_hSource);
HBITMAP hbmOldt = (HBITMAP)SelectObject(dct, g_hGrayscale);
BitBlt(dct, 0, 0, bm.bmWidth, bm.bmHeight, dcs, 0, 0, SRCCOPY);
SelectObject(dcs, hbmOlds);
SelectObject(dct, hbmOldt);
DeleteDC(dct);
DeleteDC(dcs);

// Naja, hier könntest du die Quellbitmap mit
DeleteObject(g_hSource);
// freigeben.

Achtung, g_hGrayscale ist hier ein lokaler Handle, vielleicht solltest du eine Funktion schreiben die ihn zurückliefert. In meinem Programm ist g_hGrayscale global, auch wenn das nicht wirklich schicklich ist ;c)
Ich weiß nicht genau, wie man CreateBitmap() oder CreateCompatibleBitmap() zu diesem Zwecke verwenden kann, das wäre um einiges kürzer als CreateDIBSection() ;c)


Tomac - So 03.11.02 20:05
Titel: hier in Delphi
Und hier mal das Ganze in Delphi- Code:


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:
procedure TForm1.RGBtoGray;
type
  Pixelarray = array[1..3] of Byte;
var
  PPixels:    ^Pixelarray;
  i,u:           Integer;
  Newcolor:  Byte
begin
  with image1.picture.bitmap do begin
      for i:= 0 to height-1 do begin
          PPixels := Scanline[i];
      for u:=0 to width-1 do begin
           Newcolor:= HiByte (PPixels^[1]*76
                                     +PPixels^[2]*149
                                     +PPixels^[3]*28);
         PPixels^[1]:=Newcolor;
         PPixels^[2]:=Newcolor;
         PPixels^[3]:=Newcolor;
        inc(PPixels);
   end;
 end;
end;
image1.refresh;
end;


sollte funktionieren

mfG
Tomac


maxk - Di 05.11.02 18:22

Yoh,so viel Code - und so wenig Zeit...
Aber erstmal Danke für die schnellen Antworten, ich werd's probieren.

maxk


maxk - So 10.11.02 21:32

Sorry, der Code klappt bei mir nicht. Habs mit den Splashbildern von Borland ausprobiert.

Was kann ich noch tun :?:


Tomac - Mo 11.11.02 15:00

Der Code von mir müsste funktionieren.
Woran scheiterts?


Tomac - Mo 11.11.02 15:02

edit: Sorry, Doppelpost.


maxk - Sa 16.11.02 12:54

04.02.2003 - Bilder entfernt

Ich habe den oben genannten Code benutzt.

Quelle: Borland Delphi Splash Screens

maxk


Aya - Sa 16.11.02 19:58

Hi,

hier die funktion die ich in meinem GrafikProg dafür benutze:


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
function Grayscale(Bitmap: TBitmap; Rect: TRect): Boolean;
var
  x, y: Integer;
  P: PByteArray;
  res: Byte;
begin
  for y:=Rect.Top to Rect.Bottom-1 do begin
    P:=Bitmap.ScanLine[y];
    for x:=Rect.Left to Rect.Right-1 do begin
      res:=Round((P^[x*3]+P^[x*3+1]+P^[x*3+2])/3);
      P^[x*3]:=res;
      P^[x*3+1]:=res;
      P^[x*3+2]:=res;
    end;
  end;
  Result:=True;
end;


Bitmap ist einfach das Bitmap das in Graufstufen umgewandelt werden soll.
Rect ist der Teil vom Bitmap der in Graufstufen umgewandelt werden soll.

Aufruf wenn das gesammte Bitmap grau sein soll:

Quelltext
1:
function Grayscale(Image1.Picture.Bitmap,Rect(0,0,Image1.Picture.Bitmap.Width,Image1.Picture.Bitmap.Height)):                    


Au'revoir,
Aya[/b]


OregonGhost - So 17.11.02 17:49

Die beiden zuletzt genannten Codes funktionieren nur, wenn die Quellgrafik RGB, um genau zu sein R8G8B8 ist. Die Borland Splash Screens haben 16 bzw. 256 Farben. Der Code, den ich oben gepostet habe, funktioniert mit allen Farbtiefen.


maxk - Sa 12.04.03 15:49

Nagut, ums abzuschließen:

1. BMP nach JPEG konvertieren
2. JPEG in Stream speichern
3. JPEG aus Stream laden
4. JPEG nach BMP konvertieren

Nach etwa 3 Stunden steht der Rechner nach Aufruf wieder zur Verfügung :wink:

maxk