2010-06-29 4 views
0

J'ai essayé de dessiner sur un bitmap en niveaux de gris 8bpp sans succès. Voici certaines de mes tentatives. Peut-être que quelqu'un peut signaler ce que je fais mal.Dessin sur bitmap en niveaux de gris 8bpp (C++ non géré)

============================================== =====

Tentative 1: Créer, sélectionnez et dessiner:

dans le constructeur:

CBitmap bm; 
bm.CreateBitmap (200, 200, 1, 8, NULL); 

En OnDraw:

CDC *mdc=new CDC(); 
HGDIOBJ tmp = mdc->SelectObject(bm); 

Résultat: tmp est NULL, ce qui indique échec.

============================================== =====

Tentative 2: CreateDIBSection

dans le constructeur:

HBITMAP hbm; 
BITMAPINFOHEADER bih; 
BITMAPINFO bi; 
HANDLE hb; 
CDC* myDc = new CDC(); 
HDC hdc = myDc->GetSafeHdc(); 
void* bits; 
RGBQUAD rq [256]; 

initBi(); 
hbm = CreateDIBSection (hdc, &bi, DIB_RGB_COLORS, &bits, NULL, 0); 

... 

void CEightBitDrawingView::initBi() 
{ 
bih.biSize = sizeof (BITMAPINFOHEADER); 
bih.biWidth = 200; 
bih.biHeight = -200; 
bih.biPlanes = 1; 
bih.biBitCount = 8; 
bih.biCompression = BI_RGB; 
bih.biSizeImage = 0; 
bih.biXPelsPerMeter = 14173; 
bih.biYPelsPerMeter = 14173; 
bih.biClrUsed = 0; 
bih.biClrImportant = 0; 

memset ((void *) rq, 0, 256 * sizeof (RGBQUAD)); 

bi.bmiHeader = bih; 
bi.bmiColors = rq; 
} 

Résultat: Cela ne compile même pas parce que le membre BITMAPINFO bmiColors est défini comme: RGBQUAD bmiColors [1] ;

n'acceptera donc pas plus d'une couleur RVB. En fait, rien que j'assigne à ce membre ne se compile! (Pourraient-ils éventuellement le rendre plus complexe!?)

Toutes les suggestions seraient appréciées! Merci!

============================================== =====

+1

Avez-vous essayé GDI +? Ou est-ce que toute entreprise n'a pas besoin de le faire? –

+0

Je convertis mon exemple de travail en GDI + en C++/GDI non géré pour la vitesse. Il s'avère extrêmement difficile d'obtenir un bitmap 8bpp à utiliser dans GDI. – user20493

+0

GDI + n'est pas géré. C'est une bibliothèque C++ construite sur win32. Géré serait WinForms ou WPF. – Cogwheel

Répondre

0

Votre bitmap doit être compatible (même couleur-profondeur) que le contexte d'affichage sur lequel vous allez le rendre. De plus, les bitmaps 8 bits/pixel ne sont pas nécessairement en niveaux de gris - c'est une fonction de la palette que vous utilisez.

+0

Les bitmaps 8bpp vont contenir les composants d'un bitmap CYMK pour une autre application, donc je ne veux pas qu'ils soient compatibles avec l'affichage. Je ne me soucie pas de la palette, mais Windows me force à la traiter pour obtenir un bitmap 8bpp. – user20493

4

Ici. Code qui montre comment - dans un monde non géré - allouer une structure de taille dynamique sur la pile, le remplir et le passer à CreateDIBSection.

#include <malloc.h> 

HBITMAP CreateGreyscaleBitmap(int cx, int cy) 
{ 
    BITMAPINFO* pbmi = (BITMAPINFO*)alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256); 
    pbmi->bmiHeader.biSize = sizeof (pbmi->bmiHeader); 
    pbmi->bmiHeader.biWidth = cx; 
    pbmi->bmiHeader.biHeight = cy; 
    pbmi->bmiHeader.biPlanes = 1; 
    pbmi->bmiHeader.biBitCount = 8; 
    pbmi->bmiHeader.biCompression = BI_RGB; 
    pbmi->bmiHeader.biSizeImage = 0; 
    pbmi->bmiHeader.biXPelsPerMeter = 14173; 
    pbmi->bmiHeader.biYPelsPerMeter = 14173; 
    pbmi->bmiHeader.biClrUsed = 0; 
    pbmi->bmiHeader.biClrImportant = 0; 

    for(int i=0; i<256; i++) 
    { 
    pbmi->bmiColors[i].rgbRed = i; 
    pbmi->bmiColors[i].rgbGreen = i; 
    pbmi->bmiColors[i].rgbBlue = i; 
    pbmi->bmiColors[i].rgbReserved = 0; 
    } 

    PVOID pv; 
    return CreateDIBSection(NULL,pbmi,DIB_RGB_COLORS,&pv,NULL,0); 
} 
+0

Le calcul de la taille de la structure 'BITMAPINFO' est incorrect. Il ne tient pas compte du remplissage en raison des règles d'alignement pour une plate-forme/architecture particulière. Le compilateur peut calculer la taille correcte, en utilisant la macro [offsetof] (https://msdn.microsoft.com/en-us/library/dz4y9b9a.aspx): 'alloca (offsetof (BITMAPINFO, bmiColors [256])); '. Les principes sous-jacents sont expliqués dans cette entrée de blog: [Pourquoi certaines structures se terminent par un tableau de taille 1?] (Https://blogs.msdn.microsoft.com/oldnewthing/20040826-00/?p=38043). – IInspectable

2

Dans vos deux exemples, vous avez créé un nouveau CDC avec la ligne suivante:

CDC* pDC = new CDC(); 

Mais il y a quelque chose qui manque: Cela suffit de créer un nouvel objet CDC, mais sans une poignée HDC valide attaché à lui. Vous devez d'abord appeler CDC :: CreateCompatibleDC, sinon essayer de sélectionner un objet dans ce DC échouera. En ce qui concerne les bmiColors: Ce membre est défini comme un tableau de taille 1 car les données qui le sous-tend dépendent de la profondeur de couleur et du type de bitmap. Cela est documenté dans le MSDN. Par exemple, si vous aviez un 128x128 pixels 8bit Bitmap, vous devez allouer la somme suivante de mem: pour créer une image bitmap 8bpp

128 * 128 * sizeof(WORD) + sizeof(BITMAPINFOHEADER) 
0

J'ai finalement eu recours à l'aide d'un outil graphique .NET (Aurigma), et passé son handle au C++ non managé.

Puis, en C++:

HDC memDc = CreateCompatibleDC (NULL);  
HGDIOBJ Obmp = ::SelectObject(memDc, varLayer); // Handle to 8-bit bitmap. 

j'ai pu sélectionner le bitmap dans un CDC et d'en tirer dessus. Non 100% non géré, mais cela m'a permis de faire le dessin en code non managé, ce qui donne une vitesse acceptable.

Questions connexes