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
- 6.1. Press-Papiers (3)
- Comment charger une image sur une fenêtre dans un projet Visual C++ ?
- Comment remplir une zone rectangle avec un dégradé de 2 ou 3 couleurs ?
- Comment extraire des Icônes dans un fichier externe ?
- Comment retrouver l'icône d'un fichier ?
- Comment obtenir la taille en pixels de l'écran ?
- Comment afficher un bitmap depuis une ressource ?
- Comment dilater/rétrécir un bitmap ?
- Comment déterminer les dimensions d'une chaîne de caractères en pixels ?
- Comment régler l'imprimante en mode paysage ?
- Comme lire une icône au format 16x16 ?
- Comment convertir un DDB (Device Dependant Bitmap) en DIB (Device Independant Bitmap) ?
- Comment écrire sur le disque un DIB (ou un Bitmap en passant au préalable par DDBToDIB) ?
- Comment obtenir un pointeur sur les Bytes d'une resource binaire ?
- Comment transformer un Buffer RGB sur 24 bits (TrueColor) en Buffer RGB 16 bits (HiColor ou HighColor) ?
- Comment attacher un bitmap à une CImageList ?
- Comment changer le contenu d'un Bitmap ?
- Comment écrire le contenu d'une fenêtre (boîte de dialogue, bouton...) dans un Bitmap ?
- Comment savoir si un CBitmap est initialisé ?
(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.
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)); } } |
Sur MSDN il y a un exemple complet traitant ce sujet : http://msdn.microsoft.com/library/de...msdn_icons.asp
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; } |
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 |
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); } |
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 .
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 ); |
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); } |
Code c++ : | Sélectionner tout |
1 2 | pDC->SetStretchBltMode( COLORONCOLOR ); |
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; |
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); |
Après il est facile de calculer un rectangle d'occupation à partir d'une position x,y.
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); } } |
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; |
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 ); |
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); |
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; } |
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; } |
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!"); } |
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.
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))); |
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)); } |
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; } |
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() ); |
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 çaLes 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.