Bilddaten aus einem CStatic
-
Hallo zusammen,
ich habe ein CStatic, auf dem ich ein Bild darstelle(ich bastele mir das aus einen Datenarray zusammen und zeichne es dann mit der Funktion StretchDIBits.
Nun habe ich aber das Problem, dass ich es nicht hinbekomme, diese Daten dann wieder aus dem CStatic auszulesen, also quasi mir in ein Bitmap-Daten-Array zu holen, um dann evtl. vom User vorgenommene Änderungen zu finden.
CStatic::GetBitmap() liefert mir immer 0 zurück.
Hat evtl. schonmal jemand sowas in der Art gemacht?
Viele Grüsse,
Pommes
-
ich hab das damals quasi als "screenshot" realisiert und dann das entsprechende teilbild anhand der bekannten koordinaten ausgeschnitten.
hab den code jetzt nicht bei der hand, aber so in etwa hat das ausgesehen:
https://stackoverflow.com/questions/3291167/how-to-make-screen-screenshot-with-win32-in-c
-
Hi,
danke für den Tip. Das würde funktionieren.
Nur leider habe ich dann ein Problem, wenn die Applikation in den Hintergrund gerät, bzw. ein anderes Fenster in den Bildbereich verschoben wird.
Da ich die Bilder zyklisch wegspeichere, komme ich leider so nicht weiter.
Ist es nicht möglich, sich direkt den Device Kontext von dem CStatic zu holen, und dann die Bitmapdaten auszulesen?
Ich probiere da gerade ein wenig herum, bin aber noch nicht zu einem Ergebnis gekommen...
-
Es gibt keinen DC des CStatic, wenn es eben keinen privaten DC hat.
Man kann keinen "Fensterinhalt" auslesen. Schon garnicht von Controls die nicht gezeichnet werden... weil sie z.B. im Hintergeund sindoder minimiert sind.
Erzeuge intern eine Btmap und lass das static diese doch selbst zeichnen. Dann könntest Du die Bitmap selbst aus dem Control holen. Ob dies aber über Prozesse hinweg geht habe ich noch nie probiert.
Aber wenn es Deine Anwednung ist, warum baust Du nicht ein besseres Interface mit dem Du die die Bitmaps ausliest?
-
Hallo Martin,
das Problem ist, dass sich eine Änderung ergeben hat. Jetzt werden die Bilder nicht mehr eingelesen und gezeichnet, sondern als Video mit Hilfe des IMFPMediaPlayer in dem PictureControl angezeigt. Ich benutze dazu die Funktion MFPCreateMediaPlayer(...), der ich als Parameter ein HWND auf meine Zeichenfläche mitgebe.
Da war meine Idee, einfach die angezeigten Bilder irgendwie wieder aus dem Picture Control auszulesen, und zu speichern.Evtl. muss ich mir mal anschauen, wie ich aus dem IMFPMediaPlayer die Bilddaten herausbekomme.
mfg
-
Ich würde in dem Fall davon ausgehen, dass hier kein "Static-Control" mehr vorliegt und dass es hier ein subclassing gibt, bei dem der Mediaplayer die Kontrolle über das Fenster übernimmt.
-
Hier hast Du es mit Dependent und Independent Maps zu tun, wenn dein Video
ein 2 Farben -Bild zeichnet macht es das mit der über HAL verkapselten
Fähigkeit deiner Grafikkarte.Diese Fähigkeiten werden durch Dibsektionen verkapselt.
Wenn du nur mit CreateBitmap und GetBitmap handelst wirst du immer
andere Pixelformate erlangen als Du möchtest.Das beste ist Du erstellst eine Dibsektion deiner Wunschformatierung:
Pseudeo:
::DrawDibOpen(); m_hBmp = ::CreateDIBSection(m_hDC, m_pBitmapInfo, DIB_RGB_COLORS, (void**)&m_pDat, NULL, NULL); if(!(m_hDC = ::CreateCompatibleDC(0))) //Dc erzeugen ; //dc mit compatible bitmap verbinden m_hOldBitmap = (HBITMAP)::SelectObject (m_hDC, m_hBmp);
Ein Wunschvorlage für dein Zielformat legst Du in einer Bitmapinfo an:
Pseudo:
bool CDib::AllocBitmapInfo(BITMAPINFO **ppBitmapInfo, int Width, int Height, int Bpp) { *ppBitmapInfo = (BITMAPINFO*)(new char[sizeof(BITMAPINFOHEADER) + ((Bpp == 8 ? 256 : 1)*sizeof(RGBQUAD))]); if (!*ppBitmapInfo) return FALSE; (*ppBitmapInfo)->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); (*ppBitmapInfo)->bmiHeader.biWidth = Width; (*ppBitmapInfo)->bmiHeader.biHeight = Height;//Bpp==8|Bpp==24?-Height:Height;//botomup (*ppBitmapInfo)->bmiHeader.biPlanes = 1; (*ppBitmapInfo)->bmiHeader.biBitCount = Bpp; (*ppBitmapInfo)->bmiHeader.biCompression = BI_RGB; (*ppBitmapInfo)->bmiHeader.biSizeImage = Width*abs(Height)*(Bpp >> 3); (*ppBitmapInfo)->bmiHeader.biXPelsPerMeter = 0; (*ppBitmapInfo)->bmiHeader.biYPelsPerMeter = 0; (*ppBitmapInfo)->bmiHeader.biClrUsed = Bpp == 8 ? 256 : 0; (*ppBitmapInfo)->bmiHeader.biClrImportant = 0; if ((*ppBitmapInfo)->bmiHeader.biClrUsed) SetColorbasis(*ppBitmapInfo, RGB(255, 255, 255), 1); return true; } //ist dein Wuschziel ein 256 Farben Bild musst Du die indizierten Farben //anhängen hier Grau natürlich. void CDib::SetColorbasis(BITMAPINFO *pBmi, COLORREF basecol, BYTE chanels, bool setgraymap/*= true*/) { if(!pBmi) { if(!m_pBitmapInfo) return; pBmi = m_pBitmapInfo; } int step = max((chanels/8)*8,1); int loops = pBmi->bmiHeader.biClrUsed-(step>1?step:0); for(int i = 0; i < loops; i+=step) for(int n = 0; n < step; n++) { float r((GetRValue(basecol)/255.0f)*i), g((GetGValue(basecol)/255.0f)*i), b((GetBValue(basecol)/255.0f)*i); pBmi->bmiColors[i+n].rgbRed = r; pBmi->bmiColors[i+n].rgbGreen = g; pBmi->bmiColors[i+n].rgbBlue = b; pBmi->bmiColors[i+n].rgbReserved = 0; if(setgraymap) m_GrayMap[i+n] = (r+g+b)/3; } }
Pseudo:
//Dann blittest Du dein Fenster in die Dibsection dabei wird sie per HArdware in unter [1ms] auf dein Zielformat gewandelt: //hier compatible HDC aus Dibsection verwenden ::SetStretchBltMode( m_hDC ,STRETCH_DELETESCANS); ::StretchBlt( m_hDC , 0,0, rc.Width(), rc.Height(),clientDC, bw, th+bw,rcClient.Width()-bw,rcClient.Height(),SRCCOPY);
Danach hast Du unmittelbar den Zugriff auf den Bildspeicher den Du bei
CreateDIBSection angegeben hast.Das Prinzip nutzt also die Hardware und frisst null Brot.
Wenn Du mehr Code brauchst forsche nach DibSectionen.Grüße
Karsten