Click to See Complete Forum and Search --> : Printing 2^8 (256 Color) Bitmaps - REWARD!:)


Fooo
May 15th, 1999, 05:09 PM
If someone can send me some code that will print
a 256 Color CBitmap to a monochrome device (like
a laser printer) and I can get it to work in my
project, I'll send you $20.

I've been stuck on this for way too long and can't figure out what's going on. I have a CBitmap
object that is 16 bit aligned than I need to print to a laser printer. I can print 1 bit images and 24 bit images just fine, but I can't print 8 bit images. I've tried building palletes, converting to DIBs, and other fun things, but I don't have a firm grasp on this.

So basically I have a 256 greyscale image (2^8) that I want to send to my printer in an optimal way. It's a 8.5 inchesX11inchesX400DPI greyscale image so printing it in a 24 bit method is not viable (would take way too many MB of ram).

Please help! - thanks in advance!

Lars Dirks
May 17th, 1999, 02:31 AM
Here is the code, and it works

Have fun

Lars Dirks ld@tr-partner.dk


BOOL GPrint::Bitmap(int iID, double dXPos, double dYPos, double dXSize, double dYSize, double xScale)
{
BITMAP bm;
CBitmap bitmap;
CBitmap* pOldBitmap = NULL;
CRect rcDest, rc_source;
CDC sourceDC;

if (!bitmap.LoadBitmap(iID))
return FALSE;

bitmap.GetObject(sizeof(BITMAP), &bm);

rc_source.bottom = bm.bmHeight;
rc_source.top = 0;
rc_source.left = 0;
rc_source.right = bm.bmWidth;

if (!sourceDC.CreateCompatibleDC(m_pDC))
return FALSE; // not enough memory

pOldBitmap = sourceDC.SelectObject(&bitmap);

bitmap.GetObject(sizeof(bm), &bm);

sourceDC.SelectObject(&bitmap);

rcDest = CRect(m_iPixLeftMargin + (int)(dXPos / 25.4 * m_iLogPixelsX),
m_iPixTopMargin + (int)(dYPos / 25.4 * m_iLogPixelsY),
m_iPixLeftMargin + (int)((dXPos + dXSize) / 25.4 * m_iLogPixelsX),
m_iPixTopMargin + (int)((dYPos + dYSize) / 25.4 * m_iLogPixelsY));

if (m_pDC->IsPrinting())
{
PaintDIB(m_pDC->GetSafeHdc(),&rcDest,BitmapToDIB(bitmap, NULL), &rc_source, NULL);
}
else
m_pDC->StretchBlt(m_iPixLeftMargin + (int)(dXPos / 25.4 * m_iLogPixelsX),
m_iPixTopMargin + (int)(dYPos / 25.4 * m_iLogPixelsY),
rcDest.Width(),
rcDest.Height(),
&sourceDC,
0,
0,
bm.bmWidth,
bm.bmHeight,
SRCCOPY);

sourceDC.SelectObject(pOldBitmap);

return TRUE;
}

HANDLE GPrint::BitmapToDIB(HBITMAP hBitmap, HPALETTE hPal)
{
BITMAP bm; // bitmap structure
BITMAPINFOHEADER bi; // bitmap header
BITMAPINFOHEADER FAR *lpbi; // pointer to BITMAPINFOHEADER
DWORD dwLen; // size of memory block
HANDLE hDIB, h; // handle to DIB, temp handle
HDC hDC; // handle to DC
WORD biBits; // bits per pixel

/* check if bitmap handle is valid */

if (!hBitmap)
return NULL;

/* fill in BITMAP structure, return NULL if it didn't work */
if (!GetObject(hBitmap, sizeof(bm), (LPSTR)&bm))
return NULL;

/* if no palette is specified, use default palette */
if (hPal == NULL)
hPal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);

/* calculate bits per pixel */
biBits = bm.bmPlanes * bm.bmBitsPixel;

/* make sure bits per pixel is valid */
if (biBits <= 1)
biBits = 1;
else if (biBits <= 4)
biBits = 4;
else if (biBits <= 8)
biBits = 8;
else /* if greater than 8-bit, force to 24-bit */
biBits = 24;

/* initialize BITMAPINFOHEADER */
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bm.bmWidth;
bi.biHeight = bm.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = biBits;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;

/* calculate size of memory block required to store BITMAPINFO */
dwLen = bi.biSize + PaletteSize((LPSTR)&bi);

/* get a DC */
hDC = GetDC(NULL);

/* select and realize our palette */
hPal = SelectPalette(hDC, hPal, FALSE);
RealizePalette(hDC);

/* alloc memory block to store our bitmap */
hDIB = GlobalAlloc(GHND, dwLen);

/* if we couldn't get memory block */
if (!hDIB)
{
/* clean up and return NULL */
SelectPalette(hDC, hPal, TRUE);
RealizePalette(hDC);
ReleaseDC(NULL, hDC);
return NULL;
}

/* lock memory and get pointer to it */
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);

/* use our bitmap info. to fill BITMAPINFOHEADER */
*lpbi = bi;

/* call GetDIBits with a NULL lpBits param, so it will calculate the
* biSizeImage field for us
*/
GetDIBits(hDC, hBitmap, 0, (WORD)bi.biHeight, NULL, (LPBITMAPINFO)lpbi,
DIB_RGB_COLORS);

/* get the info. returned by GetDIBits and unlock memory block */
bi = *lpbi;
GlobalUnlock(hDIB);

/* if the driver did not fill in the biSizeImage field, make one up */
if (bi.biSizeImage == 0)
bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight;

/* realloc the buffer big enough to hold all the bits */
dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + bi.biSizeImage;
if (h = GlobalReAlloc(hDIB, dwLen, 0))
hDIB = h;
else
{
/* clean up and return NULL */
GlobalFree(hDIB);
hDIB = NULL;
SelectPalette(hDC, hPal, TRUE);
RealizePalette(hDC);
ReleaseDC(NULL, hDC);
return NULL;
}

/* lock memory block and get pointer to it */
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);

/* call GetDIBits with a NON-NULL lpBits param, and actualy get the
* bits this time
*/
if (GetDIBits(hDC, hBitmap, 0, (WORD)bi.biHeight, (LPSTR)lpbi + (WORD)lpbi
->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi,
DIB_RGB_COLORS) == 0)
{
/* clean up and return NULL */
GlobalUnlock(hDIB);
hDIB = NULL;
SelectPalette(hDC, hPal, TRUE);
RealizePalette(hDC);
ReleaseDC(NULL, hDC);
return NULL;
}
bi = *lpbi;

/* clean up */
GlobalUnlock(hDIB);
SelectPalette(hDC, hPal, TRUE);
RealizePalette(hDC);
ReleaseDC(NULL, hDC);

/* return handle to the DIB */
return hDIB;
}

WORD GPrint::DIBNumColors(LPSTR lpDIB)
{
WORD wBitCount; // DIB bit count

// If this is a Windows-style DIB, the number of colors in the
// color table can be less than the number of bits per pixel
// allows for (i.e. lpbi->biClrUsed can be set to some value).
// If this is the case, return the appropriate value.


if (IS_WIN30_DIB(lpDIB))
{
DWORD dwClrUsed;

dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed;
if (dwClrUsed)

return (WORD)dwClrUsed;
}

if (IS_WIN30_DIB(lpDIB))
wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
else
wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;

// return number of colors based on bits per pixel

switch (wBitCount)
{
case 1:
return 2;

case 4:
return 16;

case 8:
return 256;

default:
return 0;
}
}

BOOL WINAPI GPrint::PaintDIB(HDC hDC,
LPRECT lpDCRect,
HANDLE hDIB,
LPRECT lpDIBRect,
CPalette* pPal)
{
LPSTR lpDIBHdr; // Pointer to BITMAPINFOHEADER
LPSTR lpDIBBits; // Pointer to DIB bits
BOOL bSuccess=FALSE; // Success/fail flag
HPALETTE hPal=NULL; // Our DIB's palette
HPALETTE hOldPal=NULL; // Previous palette

/* Check for valid DIB handle */
if (hDIB == NULL)
return FALSE;

/* Lock down the DIB, and get a pointer to the beginning of the bit
* buffer
*/
lpDIBHdr = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
lpDIBBits = FindDIBBits(lpDIBHdr);

// Get the DIB's palette, then select it into DC
if (pPal != NULL)
{
hPal = (HPALETTE) pPal->m_hObject;

// Select as background since we have
// already realized in forground if needed
hOldPal = ::SelectPalette(hDC, hPal, TRUE);
}

/* Make sure to use the stretching mode best for color pictures */
::SetStretchBltMode(hDC, COLORONCOLOR);

/* Determine whether to call StretchDIBits() or SetDIBitsToDevice() */
if ((RECTWIDTH(lpDCRect) == RECTWIDTH(lpDIBRect)) &&
(RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect)))
bSuccess = ::SetDIBitsToDevice(hDC, // hDC
lpDCRect->left, // DestX
lpDCRect->top, // DestY
RECTWIDTH(lpDCRect), // nDestWidth
RECTHEIGHT(lpDCRect), // nDestHeight
lpDIBRect->left, // SrcX
(int)DIBHeight(lpDIBHdr) -
lpDIBRect->top -
RECTHEIGHT(lpDIBRect), // SrcY
0, // nStartScan
(WORD)DIBHeight(lpDIBHdr), // nNumScans
lpDIBBits, // lpBits
(LPBITMAPINFO)lpDIBHdr, // lpBitsInfo
DIB_RGB_COLORS); // wUsage
else
bSuccess = ::StretchDIBits(hDC, // hDC
lpDCRect->left, // DestX
lpDCRect->top, // DestY
RECTWIDTH(lpDCRect), // nDestWidth
RECTHEIGHT(lpDCRect), // nDestHeight
lpDIBRect->left, // SrcX
lpDIBRect->top, // SrcY
RECTWIDTH(lpDIBRect), // wSrcWidth
RECTHEIGHT(lpDIBRect), // wSrcHeight
lpDIBBits, // lpBits
(LPBITMAPINFO)lpDIBHdr, // lpBitsInfo
DIB_RGB_COLORS, // wUsage
SRCCOPY); // dwROP

::GlobalUnlock((HGLOBAL) hDIB);

/* Reselect old palette */
if (hOldPal != NULL)
{
::SelectPalette(hDC, hOldPal, TRUE);
}

return bSuccess;
}

LPSTR WINAPI GPrint::FindDIBBits(LPSTR lpbi)
{
return (lpbi + *(LPDWORD)lpbi + PaletteSize(lpbi));
}

DWORD WINAPI GPrint::DIBHeight(LPSTR lpDIB)
{
LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB
LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB

/* point to the header (whether old or Win 3.0 */

lpbmi = (LPBITMAPINFOHEADER)lpDIB;
lpbmc = (LPBITMAPCOREHEADER)lpDIB;

/* return the DIB height if it is a Win 3.0 DIB */
if (IS_WIN30_DIB(lpDIB))
return lpbmi->biHeight;
else /* it is an other-style DIB, so return its height */
return (DWORD)lpbmc->bcHeight;
}

WORD GPrint::PaletteSize(LPSTR lpDIB)
{
/* calculate the size required by the palette */
if (IS_WIN30_DIB (lpDIB))
return (DIBNumColors(lpDIB) * sizeof(RGBQUAD));
else
return (DIBNumColors(lpDIB) * sizeof(RGBTRIPLE));
}

Wes Rogers
May 17th, 1999, 02:46 PM
Dear Fooo,

You could also look at the article I submitted
under "Bitmaps and graphics" at this site,
entitled "Print transparent bitmap via regions".

It works for me for any type of bitmap, and
prints transparently on HP printers.

It is too slow for actual video display, but
works fine for printing.

Yours,
Wes Rogers

Fooo
May 17th, 1999, 05:35 PM
Unfortunately, neither solution has worked yet for printing a 256 Color CBitmap.
It has something to do with the palettes I think. All I get is a big black page still.

I have narrowed my printing code down a little. Here's what I have so far:
(I can basically printing monochrome, although I'm still working on the kinks. I used to have
tons of commented out code of all the different things I've tried).


int nheight = pDC->GetDeviceCaps(VERTRES);
int nwidth = pDC->GetDeviceCaps(HORZRES);
int clip = pDC->GetDeviceCaps(CLIPCAPS);
int pResX = pDC->GetDeviceCaps(LOGPIXELSX);
int pResY = pDC->GetDeviceCaps(LOGPIXELSY);
int outwidth = ((float)nwidth/pResX)*resolution;
int outheight = ((float)nheight/pResY)*resolution;

int ox = bitmap->ReturnBmapInfo()->bmiHeader.biWidth;
int oy = bitmap->ReturnBmapInfo()->bmiHeader.biHeight;

int nsx = (PageAlignInfo->shift_x.Num *pResX)/resolution;
int nsy = (PageAlignInfo->shift_y.Num*pResY)/resolution;

int bpp = bitmap->ReturnBmapInfo()->bmiHeader.biPlanes;
int bpc = bitmap->ReturnBmapInfo()->bmiHeader.biBitCount;

long SIZEIMAGE = bitmap->ReturnBmapInfo()->bmiHeader.biSize;

//START THE PRINTING/SCALING
CBitmap* tbits = (CBitmap*)bitmap->Memdc->SelectObject(bitmap->cbits);
CDC *memDC = new CDC;
CBitmap wholething;
wholething.CreateBitmap( outwidth, outheight, bpp, bpc, NULL);
memDC->CreateCompatibleDC(bitmap->Memdc);
CBitmap *oldfoo = memDC->SelectObject(&wholething);

memDC->BitBlt(0,0, outwidth, outheight, NULL, 0,0,WHITENESS);
memDC->BitBlt(PageAlignInfo->shift_x.Num,PageAlignInfo->shift_y.Num, outwidth, outheight, bitmap->Memdc, 0,0,SRCCOPY);

bitmap->Memdc->SelectObject(tbits);
delete bitmap;

//wholething is now our image that should be sclaed to the paper size


BITMAPINFO BitmapInfo;
BitmapInfo.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
BitmapInfo.bmiHeader.biWidth = outwidth;
BitmapInfo.bmiHeader.biHeight = outheight;
BitmapInfo.bmiHeader.biPlanes = 1;
BitmapInfo.bmiHeader.biBitCount = bpc;
BitmapInfo.bmiHeader.biCompression = BI_RGB;
BitmapInfo.bmiHeader.biSizeImage = 0;
BitmapInfo.bmiHeader.biXPelsPerMeter = 0;
BitmapInfo.bmiHeader.biYPelsPerMeter = 0;
BitmapInfo.bmiHeader.biClrUsed = (1<<bpc);
BitmapInfo.bmiHeader.biClrImportant = 0;
/*
//MEMSET THE PALETTE
for (int i=0; i< (1 << biBits); i++) {
RGBQUAD *foo = (RGBQUAD *)(lpbi + lpbi->biSize + i*sizeof(RGBQUAD));
foo->rgbBlue = i;
foo->rgbGreen = i;
foo->rgbRed = i;
foo->rgbReserved = i;
}

lpbi->biClrUsed=(1 << biBits);
*/

long ImageSize = ( ( ( ( outwidth * bpc ) + 31 ) & ~31 ) >> 3 )
* outheight;

BitmapInfo.bmiHeader.biSizeImage = ImageSize;

// This would calc the palette size
//ImageSize += BitmapInfo.bmiHeader.biSize + (1<<bpc)*sizeof(RGBQUAD);

BYTE* pBitmapBits = new BYTE[ ImageSize ];

// Select a palette for the PDC
CPalette pal;
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * (1 << bpc));
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];

pLP->palVersion = 0x300;
pLP->palNumEntries = (1 << bpc);

for( int i=0; i < pLP->palNumEntries; i++)
{
pLP->palPalEntry[i].peRed = i;
pLP->palPalEntry[i].peGreen = i;
pLP->palPalEntry[i].peBlue = i;
pLP->palPalEntry[i].peFlags = 0;
}

pal.CreatePalette( pLP );

delete[] pLP;

HPALETTE hPal = SelectPalette(pDC->GetSafeHdc(), (HPALETTE)pal, FALSE);
RealizePalette(pDC->GetSafeHdc());

// Get the bitmap bits
int xf0 = wholething.GetBitmapBits(ImageSize, pBitmapBits);
memDC->SelectObject(oldfoo);
delete memDC;
wholething.DeleteObject();

//StretchDIBits
int boogy = StretchDIBits(
pDC->GetSafeHdc(),
0,
0,
nwidth-1,
nheight-1,
0,
0,
outwidth,
outheight,
(LPVOID) pBitmapBits,
&BitmapInfo,
DIB_RGB_COLORS //DIB_RGB_COLORS DIB_PAL_COLORS
,SRCCOPY
);

delete pBitmapBits;
SelectPalette(pDC->GetSafeHdc(), hPal, FALSE);
RealizePalette(pDC->GetSafeHdc());

} // end else scan file opened
} // end if front page
iCurPage++;
}