ATL CImage class (Attach)

Hi Leute,
Ich versuche verzweifelt, ohne Load Bilddaten in ein CImage-Objekt zu bekommen.
Eigentlich sollte das Ganze mit folgendem Code gegessen sein.

CClientDC (this);
HDC hdc= dc.m_hDC;
CImage I;
CBitmap B;
B.Create (320,240,1,24,lpBits);
I.Attach(B,CImage::smiley:IBOR_TOPDOWN ); // bis hierher soweit ok
I.Draw (hdc,rc); // das geht daneben.

Beim Debugen hab ich herausgefunden, dass SelectObject NULL liefert.
Arbeite ich mit einer dc compatiblen Bitmap gehts bis auf eine falsche Darstellung, da dann 32 BPP verlangt werden.
Ich hab aber nur 24-Bit Daten zur Verfügung.
Vielleicht kann mir da jemand helfen.
Ciao, Norbert

Beim Debugen hab ich herausgefunden, dass SelectObject NULL
liefert.
Arbeite ich mit einer dc compatiblen Bitmap gehts bis auf eine
falsche Darstellung, da dann 32 BPP verlangt werden.
Ich hab aber nur 24-Bit Daten zur Verfügung.
Vielleicht kann mir da jemand helfen.
Ciao, Norbert

Also 'ne kompatible Bitmap musst du schon machen! sonst ist nix mit schreiben (So ist es zumindest bei mir wenn ich das nur mit Standard-Windows-GDI-Funktionen mache). Die 24-Bit Daten kannst du ja ohne weiteres umwandeln und auf das Fenster (vermute ich mal) schreiben. Mit Draw/BitBlt kommste nur weg wenn du die Daten zuerst umwandelst und dann das fertige Bild auf den DC kopierst/malst.

KIM

Also 'ne kompatible Bitmap musst du schon machen! sonst ist
nix mit schreiben (So ist es zumindest bei mir wenn ich das
nur mit Standard-Windows-GDI-Funktionen mache). Die 24-Bit
Daten kannst du ja ohne weiteres umwandeln und auf das Fenster
(vermute ich mal) schreiben. Mit Draw/BitBlt kommste nur weg
wenn du die Daten zuerst umwandelst und dann das fertige Bild
auf den DC kopierst/malst.

KIM

Hi Kim,
vielen Dank für deine Antwort.
Natürlich gehts auch mit Umwandeln. Aber das Ganzte ist wie gesagt verdammt zeitkritisch. Ich bin jetzt nach einigem Suchen selber draufgekommen, woran
es liegt:
Die ATL-Klasse CImage arbeitet intern bereits mit GDI+ und damit mit
anderen Datenstrukturen.
Irgendwie kam mir das ja beim Debuggen schon komisch vor mit Namespace und
so. (eigentl. .NET C#)
Es reicht aber nicht, nur die die entsprechenden Header einzubinden,auch
der entsprechende Startup-Code muss deine Anweisungen einkapseln. Dann
funktionierts.

#include
using namespace Gdiplus;
#pragma comment(lib, „gdiplus.lib“)


GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); {

HBITMAP h;
CImage I;
Bitmap B(320,240,960,PixelFormat24bppRGB,lp);//lp=vorhandene 24 Bit Bilddaten
B.GetHBITMAP (0,&h);
I.Attach (h,CImage::smiley:IBOR_TOPDOWN);
I.Draw (hdc,rc);

} GdiplusShutdown(gdiplusToken); …

Mitlerweile hab ich noch was viel schnelleres gefunden, was vielleicht sogar ohne Gdiplus geht (weiss noch nicht)

CImage I;
I.Create (320,240,24);
HBITMAP h= J.Detach();;
I.Attach(h,CImage::smiley:IBOR_TOPDOWN);
memcpy (I.GetBits(),lp,320*240*3);

Das Detachen und Attachen ist notwendig, um alles umzudrehen, da Create einen negavtiven Pitch von -960 erzeugt (BOTTOMUP)und GetBits() den falschen Pointer liefert.(Wert einfach abziehen hat aus irgendwelchen Gründen nicht geklappt)Blöde Methode, aber funktioniert und zwar sehr schnell.

Aber trotzdem nochmal vielen Dank.
Tschau, Norbert

Na siehste. Geht auch so…
Ich hab mir mal 'ne C+±Puffer-Klasse geschrieben die ein 32-Bit Bitmap der gewünschten Grösse erzeugt. Man hat einen Pointer auf die Bilddaten und kann sie ganz genau wie ein Array benutzen, andererseits kann man auch mit dem zugehörigen DC Windows Blit/AlphaBlend/… -Funktionen benutzen (schneller gehts ja kaum noch, ausser mit DirectX). Ausserdem hat man dann sozusagen einen Hintergrund-Puffer zur Verfügung.

Die Innereien sehen grundsätzlich so aus :

int \* colorBuffer; //a 32Bit color-buffer (the image)
BITMAPINFO bitmapinfo;
HBITMAP bitmap;
HDC dc;

//Set up windows bitmap stuff
 this-\>bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 this-\>bitmapinfo.bmiHeader.biWidth = width;
 this-\>bitmapinfo.bmiHeader.biHeight = -height; /\* top-down \*/
 this-\>bitmapinfo.bmiHeader.biPlanes = 1;
 this-\>bitmapinfo.bmiHeader.biBitCount = 32;
 this-\>bitmapinfo.bmiHeader.biCompression = BI\_RGB;
 this-\>bitmapinfo.bmiHeader.biSizeImage = width \* height \* sizeof(int);
 this-\>bitmapinfo.bmiHeader.biXPelsPerMeter = 0;
 this-\>bitmapinfo.bmiHeader.biYPelsPerMeter = 0;
 this-\>bitmapinfo.bmiHeader.biClrUsed = 0;
 this-\>bitmapinfo.bmiHeader.biClrImportant = 0;

 this-\>dc = CreateCompatibleDC(NULL); //sollte danach != NULL sein...
 this-\>bitmap = CreateDIBSection(this-\>dc, &bitmapinfo, DIB\_RGB\_COLORS, reinterpret\_cast (&colorBuffer), 0, 0);
 SelectObject(this-\>dc, this-\>bitmap);

Windows besorgt sogar die Speicherreservierung für uns…
Jetzt kann man z.B. mit :

void blitTo(HDC hDC, DWORD operation)
{
 BitBlt(hDC, 0, 0, width, height, dc, 0, 0, operation);
}
//oder
void stretchAlphaBlendTo(HDC hDC, bool perPixelAlpha, unsigned char sourceAlpha, int hwidth, int hheight)
{
 //define constants for ALPHABLEND
 BLENDFUNCTION bf;
 bf.AlphaFormat = AC\_SRC\_OVER;
 bf.BlendFlags = 0;
 if (perPixelAlpha) {
 bf.BlendOp = AC\_SRC\_ALPHA; //possible values are : AC\_SRC\_ALPHA or AC\_SRC\_OVER
 bf.SourceConstantAlpha = 255; //if AC\_SRC\_ALPHA, we need to set this to 255 to get per-pixel-alpha
 }
 else {
 bf.BlendOp = AC\_SRC\_OVER;
 bf.SourceConstantAlpha = sourceAlpha;
 }
 int oldMode = SetStretchBltMode(hDC, COLORONCOLOR);
 AlphaBlend(hDC, 0, 0, hwidth, hheight, dc, 0, 0, width, height, bf);
 SetStretchBltMode(hDC, oldMode);
}

arbeiten. auch alle Funktionen die für Bitmaps funktionieren können über „bitmap“ verwendet werden…
Am ende :

DeleteDC(dc);
DeleteObject(bitmap);

Falls jemand sowas mal brauchen sollte… :wink:

KIM