Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Impression d'un BITMAP

10 réponses
Avatar
atoub.michel
Bonjour,

Je suis en train de d=E9velopper un Driver pour une imprimante. Et, je
souhaite imprimer une BITMAP.

Mais, je n'arrive pas =E0 imprimer la BITMAP en couleur, la seule chose
qui s'imprime est un rectangle noir de la taille de l'image.

Ce que je fais :
1: je charge l'image avec LoadImage pour avoir un Handle de la Bitmap
2: je fais un GetObject pour obtenir la Bitmap
3: je cr=E9e ma structure BITMAPINFO
4: je cr=E9e mon compatibleDC pour l'=E9cran en lui passant NULL comme
param=E8tre
5: je s=E9lectionne mon objet SelectObject
6: je fais ma DIBColorTable
7: je r=E9tablis le Bitmap d'origine avec SelectObject
8: je fais un StretchDIBits ou SetDIBitsToDevice pour afficher et
imprimer

/----------- DEBUT CODE ------------/
_DrawImage(std::string sImageFile, uint uiX, uint uiY, uint uiW /*=3D0*/,
uint uiH /*=3D0*/)
{
HBITMAP hbmpImage, hbmpMemOld;
BITMAP bmp; HDC hdcMem; // about the bitmap (size, color depth...)
PBITMAPINFO info; // Structure for storing the DIB information, it will
be used by 'StretchDIBits()'
int nColors =3D 0; // Used to store the number of colors the DIB has
RGBQUAD rgb[256]; // Used to store the DIB color table

/* Etape 1 */
// The following line loads the bitmap from a file
hbmpImage =3D (HBITMAP) ::LoadImageA(NULL, sImageFile.c_str(),
IMAGE_BITMAP, 0, 0,
LR_CREATEDIBSECTION|LR_LOADMAP3DCOLORS|LR_LOADFROMFILE);

if( ! hbmpImage)
return PRN_FRESULT(ERROR_BADPARAMETER, 1);

/* Etape 2 */
// Obtain information about 'hbmpImage' and store it in 'bmp'
::GetObject(hbmpImage, sizeof(BITMAP), (LPVOID) &bmp);
nColors =3D (1 << bmp.bmBitsPixel);
if(nColors > 256) nColors =3D 0; // This is when DIB is 24 bit.
// In this case there is not any color table information

/* Etape 3 */
// Now we need to know how much size we have to give for storing "info"
in memory.
// This involves the proper BITMAPINFO size and the color table size.
// Color table is only needed when the DIB has 256 colors or less.
info =3D CreateBitmapInfoStruct(hbmpImage);

// Now for 256 or less color DIB we have to fill the "info" color table
parameter
if(nColors >=3D 0 && nColors <=3D 256)
{
/* Etape 4 */
hdcMem =3D ::CreateCompatibleDC(NULL); // Creating an auxiliary
device context with screen

/* Etape 5*/
hbmpMemOld =3D (HBITMAP) ::SelectObject(hdcMem, hbmpImage); //
Select this bitmap in this DC:

/* Etape 6*/
::GetDIBColorTable(hdcMem, 0, nColors, rgb); // Obtaining the
color table information

// Now we pass this color information to "info"
for(int iCnt =3D 0; iCnt < nColors; ++iCnt)
{
info->bmiColors[iCnt].rgbRed =3D rgb[iCnt].rgbRed;
info->bmiColors[iCnt].rgbGreen =3D
rgb[iCnt].rgbGreen;
info->bmiColors[iCnt].rgbBlue =3D rgb[iCnt].rgbBlue;

}

/* Etape 7*/
// R=E9tablir le bitmap d'origine:
::SelectObject(hdcMem, hbmpMemOld);
}

/* Etape 8 */
// Stretching all the bitmap on a destination rectangle of size
(size_x, size_y)
// and upper left corner at (uiX, uiY)
if( (uiW =3D=3D 0) && (uiH =3D=3D 0) )
// To printer device
// m_hdcCurrent est le HDC de l'imprimante
::SetDIBitsToDevice(m_hdcCurrent,
uiX,
uiY,
info->bmiHeader.biWidth,
info->bmiHeader.biHeight,
0,
0,
0,
info->bmiHeader.biHeight,
bmp.bmBits,
info,
DIB_RGB_COLORS);
else
// To printer device
::StretchDIBits(m_hdcCurrent,
uiX,
uiY,
uiW,
uiH,
0,
0,
bmp.bmWidth,
bmp.bmHeight,
bmp.bmBits,
info,
DIB_RGB_COLORS,
SRCCOPY);
// This mode, DIB_RGB_COLORS indicate the color table are pure RGB
values
// The mode DIB_PAL_COLORS indicate the color table items are index to
the local palette items
//..... Delete les differents objets
}

/----------- FIN CODE ------------/

Je ne vois pas o=F9 le probl=E8me viendrait mais j'ai une piste sur le
fait qu'il faudrait deux HDC (un pour l'=E9cran et un pour
l'imprimante), mais je ne suis pas s=FBr.

Le probl=E8me aussi est que j'ai fait un programme de tests et dans ce
programme simule une impression. Avec cette simulation, j'obtiens la
m=EAme chose que si j'imprime (un rectangle noir).

Merci de pouvoir m'aider
@+

10 réponses

Avatar
Arnold McDonald \(AMcD\)
Il te faut bien évidemment créer un DC sur ton imprimante.

Les deux fonctions de base sont EnumPrinters() puis CreateDC().

--
Arnold McDonald (AMcD) - Help #49/2006

http://arnold.mcdonald.free.fr/
Avatar
Christian ASTOR
wrote:

Mais, je n'arrive pas à imprimer la BITMAP en couleur, la seule chose
qui s'imprime est un rectangle noir de la taille de l'image.



Une de mes vieilles fonctions, basée à 98% sur la KB186736 =>

BOOL PrintBitmap(HBITMAP hBitmap, int iWidth , int iHeight, int
nOrientation)
{
HBITMAP hbm, hBitmapOld;
HDC hdcPrinter;
HDC hdcMemory, hdcMem;
HDC hdcScreen;
DOCINFO di;
RECT rc;
DIBSECTION ds;
HPALETTE hPal;
BITMAP bmp;
GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bmp);

PRINTDLG pd;
ZeroMemory(&pd, sizeof(PRINTDLG));
pd.lStructSize = sizeof(PRINTDLG);
pd.Flags = PD_RETURNDEFAULT | PD_RETURNDC;
PrintDlg(&pd);
hdcPrinter=pd.hDC;

DEVMODE *dm=(DEVMODE *)GlobalLock(pd.hDevMode);
dm->dmOrientation=nOrientation;
ResetDC(pd.hDC,dm);
GlobalUnlock(pd.hDevMode);

if (!hdcPrinter) return FALSE;
hdcScreen = GetDC(NULL);
hdcMem = CreateCompatibleDC(hdcScreen);
hBitmapOld = (HBITMAP)SelectObject(hdcMem, hBitmap);
hbm = Create24BPPDIBSection(hdcMem, bmp.bmWidth, bmp.bmHeight);
if (!hbm)
{
DeleteDC(hdcPrinter);
ReleaseDC(NULL, hdcScreen);
SelectObject(hdcMem, hBitmapOld);
DeleteDC(hdcMem);
MessageBox(NULL, "Error Creating DIB Section", "Error", MB_OK |
MB_ICONSTOP);
return FALSE;
}
hdcMemory = CreateCompatibleDC(hdcScreen);
SelectObject(hdcMemory, hbm);
hPal = GetSystemPalette();
if (hPal)
{
SelectPalette(hdcMem, hPal, FALSE);
RealizePalette(hdcMem);
SelectPalette(hdcMemory, hPal, FALSE);
RealizePalette(hdcMemory);
}
BitBlt(hdcMemory, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcMem, 0, 0,
SRCCOPY);
ZeroMemory(&di, sizeof(di));
di.cbSize = sizeof(di);
di.lpszDocName = "Bitmap Printing";
if (StartDoc(hdcPrinter, &di))
{
if (StartPage(hdcPrinter))
{
GetObject(hbm, sizeof(DIBSECTION), &ds);
StretchDIBits(hdcPrinter,
0, 0, iWidth, iHeight,
0, 0, bmp.bmWidth, bmp.bmHeight,
ds.dsBm.bmBits,
(LPBITMAPINFO)&ds.dsBmih,
DIB_RGB_COLORS,
SRCCOPY);
EndPage(hdcPrinter);
}
EndDoc(hdcPrinter);
}
DeleteDC(hdcPrinter);
DeleteDC(hdcMemory);
SelectObject(hdcMem, hBitmapOld);
DeleteDC(hdcMem);
ReleaseDC(NULL, hdcScreen);
DeleteObject(hbm);
if (hPal) DeleteObject(hPal);
}
Avatar
atoub.michel
Merci pour vos réponses,

Mais mon DC sur mon imprimante existe bien c'est "m_hdcCurrent". Il
n'est pas null pourtant, je ne comprends pas mais je recherche
toujours.

@+
Michel
Avatar
Arnold McDonald \(AMcD\)
wrote:
Merci pour vos réponses,

Mais mon DC sur mon imprimante existe bien c'est "m_hdcCurrent". Il
n'est pas null pourtant, je ne comprends pas mais je recherche
toujours.

@+
Michel



Et tu le crées où et comment ce DC ?

--
Arnold McDonald (AMcD)

http://arnold.mcdonald.free.fr/
Avatar
atoub.michel
> Et tu le crées où et comment ce DC ?



En fait, j'ai fais une fonciton NewPage où je le crée ainsi :
// internal printer variables
HDC m_hdcCurrent; // dans le Header

//---------- dans la fonction NewPage, cette fonction me permet en mode
simuler de faire une fenetre
// avec un "page" blanche (comme dans Paint) qui représente ma feuille
de papier.
m_hdcCurrent = ::CreateCompatibleDC(NULL);
// create the bitmap that will store the "page"
m_hbmpCurrent = ::CreateCompatibleBitmap(m_hdcCurrent, m_uiPageW,
m_uiPageH);


et en mode réel dans ma fonction PrintPage je fais :
// create a printer DC to spool
hdcPrinter = ::CreateDC(NULL, sDeviceName.c_str(), NULL, pdm);
// actually print
BitBlt(hdcPrinter, 0, -int(uiH), uiW, uiH, m_hdcCurrent, 0, -int(uiH),
SRCCOPY);

Voilà, je sais que c'est un peu compliqué mais je suis obligé de
suivre cette voie.
@+
Avatar
atoub.michel
Ah oui !! Je voulais dire aussi que si je mets juste avant l'étape 8
dans le code du 1er post :
m_hdcCurrent = ::GetDC((HWND) // de la fenetre général);

J'arrive à afficher mon bitmap mais avec le bureau. C'est un premier
pas mais avec une partie du bureau de windows sur la page d'impression
ça le fait moyen. C'est comme si je faisait un ScreenShot.

Mais, je souhaiterai avoir juste mon bitmap.

@+
Avatar
Arnold McDonald \(AMcD\)
> m_hdcCurrent = ::CreateCompatibleDC(NULL);



Non. Il te faut créer un DC sur ton imprimante. Par exemple, pour
l'imprimante par défaut :

DWORD dwNeeded,dwReturn;
PRINTER_INFO_5 pinfo5[3];

if (
EnumPrinters(PRINTER_ENUM_DEFAULT,NULL,5,(LPBYTE)pinfo5,sizeof(pinfo5),&dwNeeded,&dwReturn)
)
return CreateDC(NULL,pinfo5[0].pPrinterName,NULL,NULL);

else return 0;

--
Arnold McDonald (AMcD) - Help #50/2006

http://arnold.mcdonald.free.fr/
Avatar
atoub.michel
Oki, merci, mais si je souhaite faire un preview. Il faudra mettre quel
HDC ? celui de l'écran ou celui de l'imprimante ?

Et est-ce que les fonctions stretchDIBits et SetDIBitsToDevice sont
toujours approprié ?

@+
Avatar
Bertrand Lenoir-Welter
> Oki, merci, mais si je souhaite faire un preview. Il faudra mettre quel
HDC ? celui de l'écran ou celui de l'imprimante ?



Si tu veux faire un preview, il te faut un handle sur un DC
correspondant à ta zone d'affichage. Si tu veux imprimer, il te faut un
autre handle sur un autre DC correspondant à ton imprimante.


Et est-ce que les fonctions stretchDIBits et SetDIBitsToDevice sont
toujours approprié ?



Windows a été fait entre autres pour que tu puisse utiliser de la même
façon un DC correspondant à l'écran, la mémoire, l'imprimante, etc. Du
moment que ton hDC est valide, les fonctions qui en ont besoin sont
contentes.
Avatar
atoub.michel
Oki, merci à Bertrand Lenoir-Welter, je vais voir cela !!!

@+