IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo

FAQ VC++ et MFCConsultez toutes les FAQ

Nombre d'auteurs : 20, nombre de questions : 545, dernière mise à jour : 5 avril 2013  Ajouter une question

 

Cette faq a été réalisée pour répondre aux questions les plus fréquement posées sur le forum Développement Visual C++

Je tiens à souligner que cette faq ne garantit en aucun cas que les informations qu'elle contient sont correctes ; Les auteurs font le maximum, mais l'erreur est humaine. Si vous trouvez une erreur, ou si vous souhaitez devenir redacteur, lisez ceci.

Sur ce, je vous souhaite une bonne lecture. Farscape

SommaireGDI (21)
précédent sommaire suivant
 

(MFC ou non ,Win32,voire d'autres environnements de développements.)
C'est vrai que le gros problème de Visual C++ et classes associées (dont MFC) c'est de ne pas gérer les images ou "bitmaps".
Il faut tout faire par soi-même.

Basiquement pour afficher une bitmap sur une fenêtre il faut obtenir un contexte de périphérique ou HDC de la fenêtre sur laquelle on affiche la bitmap.

Le MSDN décrit largement tout cela :

Faire une copie d'écran
http://msdn.microsoft.com/library/de...tmaps_5a5h.asp

Sauvegarder des contextes graphiques ( HDC) et écrans en fichier .BMP
http://msdn.microsoft.com/library/de...maps_7zfp.asp3
Noter qu'il faut ajuster éventuellement la profondeur de pixels
Description des formats de fichiers images
http://www.wotsit.org

Exemples assez simples. Je préfère ceux cités ci-dessous car facilement adaptable à n'importe quel projet

http://www.cplusplus.com/src/#win32
Pour charger une BMP
http://www.cplusplus.com/src/winbmp.zip

Pour charger une image GIF http://www.cplusplus.com/src/wingif.zip

Pour charger une JPEG :
http://www.smalleranimals.com/jpegfile.htm
Fonctionne parfaitement j'ai utilisé et adopté le code source pour un projet personnel.

Exemples plus évolués et complets :

http://www.codeguru.com/cpp/g-m/bitm...ictureShow.htm

À noter qu'il y a l'interface COM IPicture :
http://msdn.microsoft.com/library/de...tin_p_482t.asp

Librairie payante mais très complète :
http://www.leadtools.com

Voilà à vous de jouer maintenant.

Mis à jour le 5 avril 2013 Mat.M

Code C++ : Sélectionner tout
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//***************************************************************************** 
// rempli le rectangle donné avec un dégradé de 3 couleurs : Haut, milieu, bas 
//***************************************************************************** 
void RempliDegradeRectHautBas(CDC* pDC,CRect rect 
,short RedHaut,short GrHaut,short BlHaut // couleur de départ du haut 
,short RedMilieu,short GrMilieu,short BlMilieu // couleur du milieu 
,short RedBas,short GrBas,short BlBas) // couleur du bas 
{ 
    short ColorR, ColorG, ColorB; 
  
    int nWidth = rect.Width (); 
    int nHeight = rect.Height (); 
  
    // calcul de constantes intermédiaires 
    short ColorRinterm = RedHaut - RedMilieu; 
    short ColorGinterm = GrHaut - GrMilieu; 
    short ColorBinterm = BlHaut - BlMilieu; 
  
    // remplissage d'une premiere moitiée de rectangle (haut) avec 1er dégradé 
    for(int i = 0; i < nHeight/2; ++i)  
    { 
        rect.SetRect(0, i, nWidth, nHeight/2 + 1); 
        ColorR = RedHaut  - MulDiv(i,ColorRinterm, nHeight/2); 
        ColorG = GrHaut - MulDiv(i,ColorGinterm, nHeight/2); 
        ColorB = BlHaut - MulDiv(i,ColorBinterm, nHeight/2); 
        pDC->FillSolidRect(&rect, RGB(ColorR ,ColorG,ColorB)); 
    } 
  
    // calcul de constantes intermédiaires 
    ColorRinterm = RedMilieu - RedBas; 
    ColorGinterm = GrMilieu - GrBas; 
    ColorBinterm = BlMilieu - BlBas; 
  
    // remplissage de la deuxieme moitiée de rectangle (bas) avec 2eme dégradé 
    for( i = nHeight/2; i < nHeight; ++i)  
    { 
        rect.SetRect(0, i, nWidth, nHeight + 1); 
        ColorR = RedMilieu - MulDiv(i-nHeight/2,ColorRinterm/*70*/, nHeight/2); 
        ColorG = GrMilieu - MulDiv(i-nHeight/2,ColorGinterm/*10*/, nHeight/2); 
        ColorB = BlMilieu - MulDiv(i-nHeight/2,ColorBinterm/*10*/, nHeight/2); 
        pDC->FillSolidRect(&rect, RGB(ColorR ,ColorG,ColorB)); 
    } 
  
} 
  
//******************************************************************************** 
// rempli le rectangle donné avec un dégradé de 3 couleurs : Gauche, milieu, Droit 
//******************************************************************************** 
void RempliDegradeRectGaucheDroite(CDC* pDC,CRect rect 
   ,short RedGauche,short GrGauche,short BlGauche // couleur de départ de gauche 
   ,short RedMilieu,short GrMilieu,short BlMilieu // couleur du milieu 
   ,short RedDroit,short GrDroit,short BlDroit)  // couleur de droite 
{ 
    short ColorR, ColorG, ColorB; 
  
    int nWidth = rect.Width (); 
    int nHeight = rect.Height (); 
  
    // calcul de constantes intermédiaires 
    short ColorRinterm = RedGauche - RedMilieu; 
    short ColorGinterm = GrGauche - GrMilieu; 
    short ColorBinterm = BlGauche - BlMilieu; 
  
    // remplissage d'une premiere moitiée de rectangle (haut) avec 1er dégradé 
    for(int i = 0; i < nWidth/2; ++i)  
    { 
        rect.SetRect(i, 0, nWidth/2 + 1, nHeight); 
        ColorR = RedGauche  - MulDiv(i,ColorRinterm, nWidth/2); 
        ColorG = GrGauche - MulDiv(i,ColorGinterm, nWidth/2); 
        ColorB = BlGauche - MulDiv(i,ColorBinterm, nWidth/2); 
        pDC->FillSolidRect(&rect, RGB(ColorR ,ColorG,ColorB)); 
    } 
  
    // calcul de constantes intermédiaires 
    ColorRinterm = RedMilieu - RedDroit; 
    ColorGinterm = GrMilieu - GrDroit; 
    ColorBinterm = BlMilieu - BlDroit; 
  
    // remplissage de la deuxieme moitiée de rectangle (bas) avec 2eme dégradé 
    for( i = nWidth/2; i < nWidth; ++i)  
    { 
        rect.SetRect(i, 0, nWidth + 1, nHeight); 
        ColorR = RedMilieu - MulDiv(i-nWidth/2,ColorRinterm/*70*/, nWidth/2); 
        ColorG = GrMilieu - MulDiv(i-nWidth/2,ColorGinterm/*10*/, nWidth/2); 
        ColorB = BlMilieu - MulDiv(i-nWidth/2,ColorBinterm/*10*/, nWidth/2); 
        pDC->FillSolidRect(&rect, RGB(ColorR ,ColorG,ColorB)); 
    } 
  
} 
  
//********************************************************************* 
// rempli le rectangle donné avec un dégradé de 2 couleurs : Haut, bas 
//********************************************************************* 
void RempliDegradeSimpleHautBas(CDC* pDC,CRect rect 
,short RedHaut,short GrHaut,short BlHaut // couleur de départ du haut 
,short RedBas,short GrBas,short BlBas) // couleur du bas 
{ 
    short ColorR, ColorG, ColorB; 
  
    int nWidth = rect.Width (); 
    int nHeight = rect.Height (); 
  
    // remplissage du rectangle avec dégradé 
    for(int i = 0; i < nHeight; ++i)  
    { 
        rect.SetRect(0, i, nWidth, nHeight + 1); 
        ColorR = RedHaut  - MulDiv(i,RedHaut - RedBas, nHeight); 
        ColorG = GrHaut - MulDiv(i,GrHaut - GrBas, nHeight); 
        ColorB = BlHaut - MulDiv(i,BlHaut - BlBas, nHeight); 
        pDC->FillSolidRect(&rect, RGB(ColorR ,ColorG,ColorB)); 
    } 
  
} 
  
//************************************************************************ 
// rempli le rectangle donné avec un dégradé de 2 couleurs : Gauche, droit 
//************************************************************************ 
void RempliDegradeSimpleGaucheDroit(CDC* pDC,CRect rect 
,short RedGauche,short GrGauche,short BlGauche // couleur de départ de gauche 
,short RedDroit,short GrDroit,short BlDroit)  // couleur de droite 
{ 
    short ColorR, ColorG, ColorB; 
  
    int nWidth = rect.Width (); 
    int nHeight = rect.Height (); 
  
    // remplissage du rectangle avec dégradé 
    for(int i = 0; i < nWidth; ++i)  
    { 
        rect.SetRect(i, 0, nWidth + 1, nHeight); 
        ColorR = RedGauche  - MulDiv(i,RedGauche - RedDroit, nWidth); 
        ColorG = GrGauche - MulDiv(i,GrGauche - GrDroit, nWidth); 
        ColorB = BlGauche - MulDiv(i,BlGauche - BlDroit, nWidth); 
        pDC->FillSolidRect(&rect, RGB(ColorR ,ColorG,ColorB)); 
    } 
  
}

Mis à jour le 5 avril 2013 lucky

Sur MSDN il y a un exemple complet traitant ce sujet : http://msdn.microsoft.com/library/de...msdn_icons.asp

Mis à jour le 5 avril 2013 farscape

en utilisant la fonction SHGetFileInfo comme dans l'exemple ci dessous :

Code c++ : Sélectionner tout
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
43
  
HICON GetIconFromFile(LPCTSTR sz) 
{ 
    CString key,ret; 
    char drive[_MAX_DRIVE]; 
    char dir[_MAX_DIR]; 
    char fname[_MAX_FNAME]; 
    char ext[_MAX_EXT]; 
  
    CString szpath,szext; 
    HIMAGELIST hSysImageList; 
    SHFILEINFO shfi; 
  
    int nic; 
    HICON hicon=NULL; 
  
    _splitpath(sz,drive,dir,fname,ext); 
    szext=ext; 
    szpath=sz; 
    if(!(szext.Find(".exe")!=-1 ||  
            szext.Find(".pif")!=-1 || 
            szext.IsEmpty() || 
            strlen(szext)<4 || 
            szext.Find(".lnk")!=-1) && 
            SHGetFileInfo(szext,FILE_ATTRIBUTE_NORMAL,&shfi,sizeof(shfi), 
            SHGFI_USEFILEATTRIBUTES|SHGFI_ICON|SHGFI_SMALLICON)) 
    { 
  
        hicon=shfi.hIcon; 
    } 
    if(!hicon) 
    { 
        hSysImageList=(HIMAGELIST) SHGetFileInfo(szpath,0,&shfi,sizeof(SHFILEINFO), 
                        SHGFI_SYSICONINDEX | SHGFI_SMALLICON); 
  
        if(hSysImageList) 
        { 
            nic=shfi.iIcon; 
            hicon=ImageList_GetIcon(hSysImageList,nic,ILD_NORMAL); 
        } 
    } 
    return hicon; 
}

Mis à jour le 5 avril 2013 farscape

On obtient la taille de l'écran avec la fonction GetSystemMetrics:

Code c++ : Sélectionner tout
1
2
3
  
int nResolx=GetSystemMetrics(SM_CXSCREEN); // resolution sur les X 
int nResoly=GetSystemMetrics(SM_CYSCREEN); // resolution sur les Y

Mis à jour le 5 avril 2013 farscape

L'exemple ci-dessous montre les étapes nécessaires pour lire et afficher un bitmap provenant des ressources (IDB_BMPESSAI) .

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  
CMyView::OnDraw(CDC *pDC) 
{ 
    CBitmap Bitmap; 
    CDC MemDC; 
  
    Bitmap.LoadBitmap(IDB_BMPESSAI); // lecture bitmap dans les ressources 
    BITMAP InfosBmp; // structure d'informations. 
    Bitmap.GetBitmap(&InfosBmp); 
    MemDC.CreateCompatibleDC(pDC);// creation d'un DC en memoire 
    MemDC.SelectObject(&Bitmap); // selection du bitmap dans le DC en memoire 
    // transfert final du bitmap dans le dc de la view. 
    pDC->BitBlt( 0,0,InfosBmp.bmWidth, InfosBmp.bmHeight, 
                     &MemDC, 
                     0,0, 
                     SRCCOPY); 
}
Note: l'exemple ci-dessus fonctionne très bien à l'écran.
dans le cas d'une édition sur imprimante ce bitmap ne sera pas compatible, il faudra disposer d'un bitmap DIB: device-independent bitmap au lieu d'un DDB: device-dependent bitmap .

Mis à jour le 5 avril 2013 farscape

Il faut utiliser la fonction StretchBlt à la place de BitBlt

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
  
CDC::StretchBlt 
BOOL StretchBlt (  
int x,  
int y,  
int nWidth,  
int nHeight,  
CDC* pSrcDC,  
int xSrc,  
int ySrc,  
int nSrcWidth,  
int nSrcHeight,  
DWORD dwRop );
Exemple d'affichage avec un bitmap appartenant aux ressources.

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  
CMyView::OnDraw(CDC *pDC) 
{ 
    CBitmap Bitmap; 
    CDC MemDC; 
  
    Bitmap.LoadBitmap(IDB_BMPESSAI); // lecture bitmap dans les ressources 
    BITMAP InfosBmp; // structure d'informations. 
    Bitmap.GetBitmap(&InfosBmp); 
    MemDC.CreateCompatibleDC(pDC);// creation d'un DC en memoire 
    MemDC.SelectObject(&Bitmap); // selection du bitmap dans le DC en memoire 
    // transfert final du bitmap dans le dc de la view. 
    // zoom x 2 
    CSize Size(InfosBmp.bmWidth *2 , InfosBmp.bmHeight *2); 
    pDC->DPtoLP(&Size);// si le systeme de coordonnées n'est pas MM_TEXT 
    pDC->StretchBlt( 0, 0, 
                     Size.cx,-Size.cy, 
                     &MemDC, 
                     0, 0, 
                     InfosBmp.bmWidth, InfosBmp.bmHeight, 
                     SRCCOPY);  
}
Note:Pour la réduction d'un bitmap il est conseillé d'appliquer un :

Code c++ : Sélectionner tout
1
2
  
    pDC->SetStretchBltMode( COLORONCOLOR );
Avant le StretchBlt,COLORONCOLOR donne un meilleur aspect aux bitmaps rétrécis.

Mis à jour le 5 avril 2013 farscape

En utilisant la fonction :

Code c++ : Sélectionner tout
1
2
3
4
  
CDC::GetTextExtent 
CSize GetTextExtent( LPCTSTR lpszString, int nCount ) const; 
CSize GetTextExtent( const CString& str ) const;
Exemple d'utilisation :

Code c++ : Sélectionner tout
1
2
3
4
  
CClientDC dc(this); 
CFont* pFont = dc.SelectObject(m_pMyFont); // sélection d'une fonte . 
CSize size=dc.GetTextExtent(string);
La variable size contiendra la hauteur (size.cy) et largeur (size.cx) de la chaîne pour la fonte en cours.
Après il est facile de calculer un rectangle d'occupation à partir d'une position x,y.

Mis à jour le 5 avril 2013 farscape

Pour spécifier le mode d'impression portrait ou paysage sur une imprimante il faut disposer d'un pointeur sur la structure DEVMODE qui contient les données liées à l'imprimante.
Le code ci-dessous commence par récupérer l'imprimante par défaut pour utiliser le pointeur m_hDevMode qui est une donnée membre de la classe CWinApp.

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  
void CMyApp::SetLandscapeMode()  
{  
   PRINTDLG pd;  
   pd.lStructSize=(DWORD)sizeof(PRINTDLG);  
   BOOL bRet=GetPrinterDeviceDefaults(&pd);  
   if(bRet)  
   {  
      // protect memory handle with ::GlobalLock and ::GlobalUnlock  
      DEVMODE FAR *pDevMode=(DEVMODE FAR *)::GlobalLock(m_hDevMode);  
      // set orientation to landscape  
      pDevMode->dmOrientation=DMORIENT_LANDSCAPE;  
      ::GlobalUnlock(m_hDevMode);  
   }  
}

Mis à jour le 5 avril 2013 farscape

Dans Visual Studio on peut définir pour le même identifiant de ressource une icône au format 32x32 et 16x16 pixels.
la fonction

Code c++ : Sélectionner tout
1
2
  
HICON CWinApp::LoadIcon( UINT nIDResource ) const;
Lit par défaut l'icône au format 32x32 .
pour la lecture du format 16x16 on procédera comme suit:

Code c++ : Sélectionner tout
1
2
3
4
5
6
  
HICON hIcon = (HICON)::LoadImage(   AfxFindResourceHandle(MAKEINTRESOURCE(IDI_MYICONE),RT_GROUP_ICON), 
                                    MAKEINTRESOURCE(IDI_MYICONE), 
                                    IMAGE_ICON, 
                                    16,16,LR_DEFAULTSIZE); 
/*CStatic */m_MyStatic.SetIcon( hIcon );
IDI_MYICONE représente l'identifiant de l'icône à lire.
Note: l'icône devra étre libérée par un DestroyIcon

Code c++ : Sélectionner tout
1
2
3
  
HICON hIcon =m_MyStatic.GetIcon(); 
if(hIcon) ::DestroyIcon(hIcon);

Mis à jour le 17 septembre 2007 farscape

Code c++ : Sélectionner tout
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  
/*******************************************************************************/ 
// DDBToDIB- Creates a DIB from a DDB 
// bitmap- Device dependent bitmap 
// dwCompression- Type of compression - see BITMAPINFOHEADER 
// pPal- Logical palette 
/*******************************************************************************/ 
HANDLE DDBToDIB( CBitmap& bitmap, DWORD dwCompression, CPalette* pPal ) 
{ 
    BITMAPbm; 
    BITMAPINFOHEADERbi; 
    LPBITMAPINFOHEADER lpbi; 
    DWORDdwLen; 
    HANDLEhDIB; 
    HANDLEhandle; 
    HDC hDC; 
    HPALETTEhPal; 
  
  
    ASSERT( bitmap.GetSafeHandle() ); 
  
    // The function has no arg for bitfields 
    if( dwCompression == BI_BITFIELDS ) 
        return NULL; 
  
    // If a palette has not been supplied use defaul palette 
    hPal = (HPALETTE) pPal->GetSafeHandle(); 
    if (hPal==NULL) 
        hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE); 
  
    // Get bitmap information 
    bitmap.GetObject(sizeof(bm),(LPSTR)&bm); 
  
    // Initialize the bitmapinfoheader 
    bi.biSize= sizeof(BITMAPINFOHEADER); 
    bi.biWidth= bm.bmWidth; 
    bi.biHeight = bm.bmHeight; 
    bi.biPlanes = 1; 
    bi.biBitCount= bm.bmPlanes * bm.bmBitsPixel; 
    bi.biCompression= dwCompression; 
    bi.biSizeImage= 0; 
    bi.biXPelsPerMeter= 0; 
    bi.biYPelsPerMeter= 0; 
    bi.biClrUsed= 0; 
    bi.biClrImportant= 0; 
  
    // Compute the size of the  infoheader and the color table 
    int nColors = (1 << bi.biBitCount); 
    if( nColors > 256 ) 
        nColors = 0; 
    dwLen  = bi.biSize + nColors * sizeof(RGBQUAD); 
  
    // We need a device context to get the DIB from 
    hDC = GetDC(NULL); 
    hPal = SelectPalette(hDC,hPal,FALSE); 
    RealizePalette(hDC); 
  
    // Allocate enough memory to hold bitmapinfoheader and color table 
    hDIB = GlobalAlloc(GMEM_FIXED,dwLen); 
  
    if (!hDIB) 
    { 
        SelectPalette(hDC,hPal,FALSE); 
        ReleaseDC(NULL,hDC); 
        return NULL; 
    } 
  
    lpbi = (LPBITMAPINFOHEADER)hDIB; 
  
    *lpbi = bi; 
  
    // Call GetDIBits with a NULL lpBits param, so the device driver  
    // will calculate the biSizeImage field  
    GetDIBits(hDC, (HBITMAP)bitmap.GetSafeHandle(), 0L, (DWORD)bi.biHeight, 
        (LPBYTE)NULL, (LPBITMAPINFO)lpbi, (DWORD)DIB_RGB_COLORS); 
  
    bi = *lpbi; 
  
    // If the driver did not fill in the biSizeImage field, then compute it 
    // Each scan line of the image is aligned on a DWORD (32bit) boundary 
    if (bi.biSizeImage == 0){ 
        bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) 
            * bi.biHeight; 
  
        // If a compression scheme is used the result may infact be larger 
        // Increase the size to account for this. 
        if (dwCompression != BI_RGB) 
            bi.biSizeImage = (bi.biSizeImage * 3) / 2; 
    } 
  
    // Realloc the buffer so that it can hold all the bits 
    dwLen += bi.biSizeImage; 
    if (handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE)) 
        hDIB = handle; 
    else{ 
        GlobalFree(hDIB); 
  
        // Reselect the original palette 
        SelectPalette(hDC,hPal,FALSE); 
        ReleaseDC(NULL,hDC); 
        return NULL; 
    } 
  
    // Get the bitmap bits 
    lpbi = (LPBITMAPINFOHEADER)hDIB; 
  
    // FINALLY get the DIB 
    BOOL bGotBits = GetDIBits( hDC, (HBITMAP)bitmap.GetSafeHandle(), 
        0L,// Start scan line 
        (DWORD)bi.biHeight,// # of scan lines 
        (LPBYTE)lpbi // address for bitmap bits 
        + (bi.biSize + nColors * sizeof(RGBQUAD)), 
        (LPBITMAPINFO)lpbi,// address of bitmapinfo 
        (DWORD)DIB_RGB_COLORS);// Use RGB for color table 
  
    if( !bGotBits ) 
    { 
        GlobalFree(hDIB); 
  
        SelectPalette(hDC,hPal,FALSE); 
        ReleaseDC(NULL,hDC); 
        return NULL; 
    }    
    SelectPalette(hDC,hPal,FALSE); 
    ReleaseDC(NULL,hDC); 
    return hDIB; 
}

Mis à jour le 27 novembre 2005 matazz

Code c++ : Sélectionner tout
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
  
/*******************************************************************************/ 
//LPTSTR szFile : DestFile 
//HANDLE hDIB  : Handle sur un DIB (convertis depuis un CBitmap par DDBToDIB) 
/*******************************************************************************/ 
BOOL WriteDIB( LPTSTR szFile, HANDLE hDIB) 
{ 
BITMAPFILEHEADERhdr; 
LPBITMAPINFOHEADERlpbi; 
  
if (!hDIB) 
return FALSE; 
  
CFile file; 
if( !file.Open( szFile, CFile::modeWrite|CFile::modeCreate) ) 
return FALSE; 
  
lpbi = (LPBITMAPINFOHEADER)hDIB; 
  
int nColors = 1 << lpbi->biBitCount; 
  
// Fill in the fields of the file header  
hdr.bfType= ((WORD) ('M' << 8) | 'B');// is always "BM" 
hdr.bfSize= GlobalSize (hDIB) + sizeof( hdr ); 
hdr.bfReserved1 = 0; 
hdr.bfReserved2 = 0; 
hdr.bfOffBits= (DWORD) (sizeof( hdr ) + lpbi->biSize + 
nColors * sizeof(RGBQUAD)); 
  
// Write the file header  
file.Write( &hdr, sizeof(hdr) ); 
  
// Write the DIB header and the bits  
file.Write( lpbi, GlobalSize(hDIB) ); 
  
file.Close(); 
  
return TRUE; 
}

Mis à jour le 27 novembre 2005 matazz

Code c++ : Sélectionner tout
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
  
HINSTANCEhIn= NULL; 
HRSRCSrc= NULL; 
HGLOBAL hMem= NULL; 
DWORD rsize= NULL; 
CStringRSNumb; 
  
RSNumb.Format("#%d",IDR_RESOURCE_BINAIRE); 
  
hIn= ::AfxGetResourceHandle(); 
//ou BINARY est un Dossier dans l'onglet resource (Comme Dilalog) 
//à l'import d'une resource binaire, il demande le resource Type 
//c'est en fait le nom qu'il va donner au dossier 
tSrc= ::FindResource(hIn,RSNumb.GetBuffer(0),"BINARY"); 
rsize= ::SizeofResource(hModule,hRes); 
hMem= ::LoadResource(hModule,hRes); 
if (hMem) 
{ 
    BYTE *pData = (BYTE *) ::LockResource(hMem); 
    if (pData) 
    { 
        //travaille avec la resource 
    } 
} 
else  
{ 
    AfxmessageBox("Unable to load resource!"); 
}

Mis à jour le 27 novembre 2005 matazz

Une couleur RGB en 24bits est codée sur 3 octets (1 par composante soit 8 bits).
Une couleur RGB en 16bits est codée sur 2 octets (soit 5 bits par composantes voire 6 pour le Vert (couleur plus visible par l'oeil humain)).

Tout d'abord voici deux liens concernant le codage des images RGB sur 15 et 16 bits :



Définitions :
  • RGB555 : Codage d'une couleur d'un pixel sur 15 bits (5 pour le R, 5 pour le G et 5 pour le B).
    Le tout tiens sur 2 octets, 1 bit étant inutilisé.
  • RGB565 : Codage d'une couleur d'un pixel sur 16 bits (5 pour le R, 6 pour le G et 5 pour le B).
    Le tout tiens sur 2 octets.


En fait il faut distinguer RGB555(15 bits) et RGB565(16 bits).
En théorie il est possible de toujours coder en RGB565puisque si le décodeur ne gère que le RGB555par le jeu des masques, vous perdez l'information supplémentaire sur la composante Verte, mais la couleur restera proche de celle que vous avez codé.

Le principe de ce codage, utilisé dans le format BMP et d'enlever les 3 bits de poids Faible de chaque composante (R,G et B) afin d'économiser un octet par pixel.
Ceci permet de créer des paliers de valeurs :
Par exemple si une des composantes vaut 0xFF (1111 1111) , 0xFE (1111 1110), 0xFD(1111 1101)....jusqu'a 0xF8 (1111 1000) toutes ces valeurs auront pour équivalant en codage 15 bits 0x1F (1111 1) soit 0xF8 (1111 1000) dont les 3 bits de poids faible ont été enlevés par décalage à droite.

Donc en fait il suffit de travailler avec des WORD pour chaque composante (R,G et B) et d'assembler le tout par décalage.
Donc en gros par un masque 0xF8 (1111 1000) et un ET logique les 3 bits de poids faible sont enlevés, ensuite il faut faire un décalage à droite de 3 bits.
Mais comme il faut redécaler à gauche pour assembler les composantes (10 pour le R(11 en 16 bits), 5 pour le G, et 0 pour le B) les valeurs du décalage sont 3 à droite pour le Bleu, 2 (3-5) à gauche pour le G et 7(3-7) à gauche pour le R.
Enfin il faut faire un swap du byte de poids fort avec celui de poids faible (en tout cas sous Windows et en mémoire, je n'ai pas essayé d'écrire un fichier) en fonction de mode d'écriture LittleEndian ou BigEndian...

Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
WORD   B,G,R; 
     //Application du masque pour retirer les 3 bits de poids faible 
     //Dans le cas du 16 bits le masque pour le vert est 0xFC 
   B = BuffBGR[Ind  ] & 0xF8; 
   G = BuffBGR[Ind+1] & 0xF8; 
   R = BuffBGR[Ind+2] & 0xF8; 
  
    //application des décalages 
   B = (B>>3); 
   G = (G<<2); 
   R = (R<<7); 
  
    //composition des valeurs 
   WORD BGR16Bit = (R + G + B); 
  
    //Et swap entre le byte de poids fort et de poids faible. 
   BGR16Bit = (BGR16Bit << 8) + (BGR16Bit >> 8);

Exemple: Prenons une couleur verte (94, 228, 94)
Prenons sa valeur hexa et binaire sur 24 bits :

5E (01011110) E4(11100100) 5E(01011110)
En appliquant le masque 0xF8 (11111000) à chaque composante on obtient 58 (01011000) E0 (11100000) 58 (01011000) soit la couleur (88, 224, 88 ).

Vous pouvez faire le test dans Photoshop et la différence à l'œil est minime.

Ensuite il suffit d'enlever les 3 bits de poids faible (en gras)et d' assembler le reste sur 2 octets.

Mis à jour le 27 novembre 2005 matazz

L'exemple ci-dessous attache directement une ressource Bitmap (IDB_BITMAP1) à l'objet ImageList.

Code C++ : Sélectionner tout
1
2
CImageList ImageList;// attention l'objet ne doit pas etre locale a une fonction 
ImageList.Attach(ImageList_LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP1), 35, 1, RGB(255, 0, 255)));

Mis à jour le 27 novembre 2005 farscape

Depuis Visual.Net nous disposons de la classe CImage permettant des manipulations sur les bitmaps, notamment la fonction SetPixel.
Exemple:

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
  
CBitmap Bmp;  
CImage Image;  
int         i;  
  
Bmp.LoadBitmap(IDB_MON_IMAGE); // image 100x16 en couleur vraie Windows  
Image.Attach(Bmp, Image.DIBOR_DEFAULT);  
  
for(int i=0; i<16;i++)  
{  
  Image.SetPixel(99,i,RGB(0,0,0));  
}

Mis à jour le 20 mai 2006 farscape

En utilisant les 2 fonctions précédentes :

Code c++ : Sélectionner tout
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
43
44
45
46
47
48
49
50
  
/*******************************************************************************/ 
// par Zafir Anjum  http://www.codeguru.com/Cpp/G-M/bitmap/article.php/c1741 
// WriteWindowToDIB par Zafir Anjum  
// LPTSTR DestFile 
// Pointeur sur un CWnd 
/*******************************************************************************/ 
BOOL WriteWindowToDIB( LPTSTR szFile, CWnd *pWnd ) 
{ 
    CBitmap bitmap; 
    CWindowDCdc(pWnd); 
    CDC memDC; 
    CRectrect; 
  
    memDC.CreateCompatibleDC(&dc); 
    pWnd->GetWindowRect(rect); 
  
    bitmap.CreateCompatibleBitmap(&dc, rect.Width(),rect.Height() ); 
  
    CBitmap* pOldBitmap = memDC.SelectObject(&bitmap); 
    memDC.BitBlt(0, 0, rect.Width(),rect.Height(), &dc, 0, 0, SRCCOPY); 
  
    // Create logical palette if device support a palette 
    CPalette pal; 
    if( dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE ) 
    { 
        UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256); 
        LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize]; 
        pLP->palVersion = 0x300; 
  
        pLP->palNumEntries = 
            GetSystemPaletteEntries( dc, 0, 255, pLP->palPalEntry ); 
  
        // Create the palette 
        pal.CreatePalette( pLP ); 
  
        delete[] pLP; 
    } 
    memDC.SelectObject(pOldBitmap); 
  
    // Convert the bitmap to a DIB 
    HANDLE hDIB = DDBToDIB( bitmap, BI_RGB, &pal );     
    if( hDIB == NULL )return FALSE; 
  
    // Write it to file 
    WriteDIB( szFile, hDIB );    
    // Free the memory allocated by DDBToDIB for the DIB 
    GlobalFree( hDIB ); 
    return TRUE; 
}

Mis à jour le 20 mai 2006 matazz

Pour savoir si un CBitmap est déjà initialisé, on testera la valeur du handle GDI attaché, ici un HBITMAP.

Code C++ : Sélectionner tout
1
2
if(!static_cast<HBITMAP>(m_bitmap)) 
     m_bitmap.CreateCompatibleBitmap( dc, rcClient.Width(), rcClient.Height() );

Mis à jour le 22 janvier 2007 farscape

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.