$COMPILE EXE $DIM ALL $INCLUDE "WIN32API.INC" $INCLUDE "COMDLG32.INC" '================================================================== ' 1. PRELIMINARY STEP - **** IMPORTANT **** ' You need to go into your win32api.inc file and change the declaration ' for the BITMAPINFO structure's bmi Colors member to 256. If you don't ' you'll gpf on all bitmaps that aren't monochrome. ' ' TYPE BITMAPINFO ' bmiHeader AS BITMAPINFOHEADER ' bmiColors(256) AS RGBQUAD ' END TYPE '================================================================== '================================================================== FUNCTION BltImage(zFile AS ASCIIZ, BYVAL iPrinting AS INTEGER, _ BYVAL x AS DOUBLE, BYVAL y AS DOUBLE, BYVAL wid AS DOUBLE, _ BYVAL hgt AS DOUBLE, BYVAL dcOut AS LONG) EXPORT AS INTEGER ' The function will take the name of a .BMP file (sImageFile) ' and a value (iPrinting) to tell us whether or not we're printing. ' If printing we'll need to use the DIB calls. ' Also passed are the left and top coordinates (x and y) and ' width and height of the bitmap to display (wid and hgt). ' The function will fit the image inside the rectangle defined ' by x, y, wid, and hgt. All measurements are in inches. ' Finally, the DC of the surface to blt to is passed (hDC) ' ' Variable declarations DIM ppiX AS LONG ' pixels per inch in X direction DIM ppiY AS LONG ' pixels per inch in Y direction DIM x1 AS LONG ' This will contain the X position in Pixels DIM y1 AS LONG ' This will contain the Y position in Pixels DIM w1 AS LONG ' This will contain the width in Pixels DIM h1 AS LONG ' This will contain the height in Pixels DIM hDesktop AS LONG ' A handle to the desktop window (for reference) DIM hBitmap AS LONG ' A handle to the bitmap while it's in memory DIM dcWindow AS LONG ' We need to obtain a temporary DC DIM dcBitmap AS LONG ' Another temporary DC compatible with the ' dcWindow that will be used to reference ' the bitmap hBitmap. DIM hOldBM AS LONG ' Another temporary handle. DIM bmSize AS LONG ' How big is our DIB going to have to be DIM ptrMem AS LONG ' Pointer to the gMemory string. DIM gMemory AS STRING ' Space to put the DIB Bits DIM rBitmap AS BITMAP ' Structure describing the dependent bitmap DIM bmInfo AS BITMAPINFO ' Structure describing the independent bitmap '- STEP 1 - ensure that we have properly altered the BITMAPINFO structure IF SIZEOF(bmInfo) < 40 + 256 * 4 THEN MsgBox "The BITMAPINFO structure doesn't have enough space in the " + _ "bmiColors array. Please define it with at least 256 array members." FUNCTION = %False ELSE '- STEP 2 - Do unit conversions from inches to output units ppiX = GetDeviceCaps(dcOut, %LOGPIXELSX) ppiY = GetDeviceCaps(dcOut, %LOGPIXELSY) x1 = ppiX * x y1 = ppiY * y w1 = ppiX * wid h1 = ppiY * hgt '- STEP 3 Load the BMP ' Load the bitmap into memory. This function requires Win95 or WinNT v4. ' Instead of doing this, you could also pass the handle to the bitmap. ' This call requires the width and height of the bitmap be passed as ' well as the name of the file. hBitmap = LoadImage(0, zFile, %IMAGE_BITMAP, 0, 0, %LR_LOADFROMFILE) IF hBitmap = 0 THEN MsgBox "Can't load bitmap" FUNCTION = %FALSE ELSE '- STEP 4 Get a temp DC for bmp manipulation ' For printing the bitmap, we will need a temporary dc ' compatible with the display. For blting to the screen, ' we need a temporary dc to hold the bitmap that will ' be blted to the screen. We'll just create one compaible ' with the desktop window. hDesktop = GetDesktopWindow() dcWindow = GetDC(hDesktop) dcBitmap = CreateCompatibleDC(dcWindow) ReleaseDC hDesktop, dcWindow IF iPrinting = %False THEN '- STEP 5-A Not printing, so blt the image. ' If we're not printing, then copying the bitmap is a simple ' matter of calling bitblt. We need to first get the height and ' width of the bitmap so it can be proportionally fit into the ' defined rectangle. GetObject hBitmap, len(rBitmap), rBitmap '- Proportionally fit the bitmap inside of the defined rectangle IF (rBitmap.bmWidth / rBitmap.bmHeight) > (w1 / h1) THEN h1 = w1 * rBitmap.bmHeight / rBitmap.bmWidth ELSE w1 = h1 * rBitmap.bmWidth / rBitmap.bmHeight END IF hOldBM = SelectObject(dcBitmap, hBitmap) BitBlt dcOut, x1, y1, w1, h1, dcBitmap, 0, 0, %SRCCOPY SelectObject dcBitmap, hOldBM FUNCTION = %True ELSE '- STEP 4-B Create a DIB ' If we're blting to a printer, then we need to create ' a DIB from the device dependent bitmap (hBitmap). ' This area of the routine is the most involved. For those ' not familiar with a DIB, I will quickly explain ... ' A device dependent bitmap is a window object that ' can be manipulated with API calls. A DIB is merely ' a memory area containing pixel information and a ' structure describing it. You can't use SelectObject ' on a dib because it isn't a Windows Object. To convert ' a device dependent bitmap into a DIB requires 2 things. ' 1. Fill out a structure containing the description of ' the DIB's Bits ' 2. Get the actual bits in the correct format into an ' area of memory. ' Once these things are done, the API has a few calls ' to manipulate the dibs based on it's structure and a ' pointer to it's bits. GetObject hBitmap, len(rBitmap), rBitmap bmInfo.bmiHeader.biSize = len(bmInfo.bmiHeader) bmInfo.bmiHeader.biWidth = rBitmap.bmWidth bmInfo.bmiHeader.biHeight = rBitmap.bmHeight bmInfo.bmiHeader.biPlanes = 1 bmInfo.bmiHeader.biBitCount = rBitmap.bmBitsPixel bmInfo.bmiHeader.biCompression = %BI_RGB '- Calculate space needed for the dib bits bmSize = bmInfo.bmiHeader.biWidth bmSize = (bmSize + 1) * (bmInfo.bmiHeader.biBitCount / 8) bmSize = ((bmSize + 3) / 4) * 4 bmSize = bmSize * bmInfo.bmiHeader.biHeight '- Allocate the memory ON ERROR RESUME NEXT gMemory = STRING$(bmSize, CHR$(0)) ON ERROR GOTO 0 IF ERR THEN '- Couldn't get the memory FUNCTION = %FALSE ELSE '- Proportionally fit the bitmap inside of the defined rectangle IF (rBitmap.bmWidth / rBitmap.bmHeight) > (w1 / h1) THEN h1 = w1 * rBitmap.bmHeight / rBitmap.bmWidth ELSE w1 = h1 * rBitmap.bmWidth / rBitmap.bmHeight END IF '- STEP 6 Copy Bits ' This step takes the hBitmap object and copies it's ' bits over to our memory in a DIB format. ptrMem = STRPTR(gMemory) GetDIBits dcBitmap, hBitmap, 0, bmInfo.bmiHeader.biHeight, _ BYVAL ptrMem, bmInfo, %DIB_RGB_COLORS '- STEP 7 Blt the bits to the printer ' FINALLY, the moment of truth. We have our structure ' and memory full of DIB Bits, so we can call StretchDIBits ' to blt the bits onto the printer's DC StretchDIBits dcOut, x1, y1, w1, h1, 0, 0, bmInfo.bmiHeader.biWidth, _ bmInfo.bmiHeader.biHeight, BYVAL ptrMem, bmInfo, _ %DIB_RGB_COLORS, %SRCCOPY FUNCTION = %True END IF '_ err, else '- STEP 8 Clean up after myself ' To ensure we don't have any memory leaks, we need ' to clean up after ourselves. DeleteObject hBitmap DeleteDC dcBitmap gMemory = "" END IF '_ if printing% = 0, else END IF '_ if hBitmap = 0, else END IF '_ if bad structure, else END FUNCTION '=================================================================== FUNCTION WinMain(BYVAL hInstance AS LONG, BYVAL hPrevInstance AS LONG, _ lpCmdLine AS ASCIIZ PTR, BYVAL iCmdShow AS LONG) AS LONG DIM zCommand AS ASCIIZ * 255 DIM i AS LONG DIM dcPrint AS LONG DIM iCopies AS LONG, iFrom AS LONG, iTo AS LONG DIM iMin AS LONG, iMax AS LONG, iOptions AS LONG DIM rDocInfo AS DOCINFO DIM zString AS ASCIIZ * 256 '- The command line should contain the name of the bmp file zCommand = @lpCmdLine IF INSTR(zCommand, ".") < 1 THEN zCommand = TRIM$(zCommand) + ".bmp" END IF IF DIR$(zCommand) = "" THEN MsgBox "Usage: printbmp bitmap.bmp" + CHR$(13) + _ "Pass the bitmap name on the command line." ELSE '- Prompt the user for a printer iOptions = %PD_COLLATE + %PD_HIDEPRINTTOFILE + %PD_RETURNDC + _ %PD_NOSELECTION + %PD_PAGENUMS iFrom = 1: iTo = 1: iMin = 1: iMax = 1: iCopies = 1 PrinterDialog %NULL, iOptions, dcPrint, iCopies, iFrom, iTo, iMin, iMax IF dcPrint THEN SetCursor LoadCursor(%NULL, BYVAL %IDC_WAIT) '- Init the document zString = "Bitmap Printed: " + zCommand rDocInfo.lpszDocName = VARPTR(zString) rDocInfo.lpszOutput = %NULL StartDoc dcPrint, rDocInfo FOR i = 1 TO iCopies StartPage dcPrint TextOut dcPrint, 200, 200, zString, LEN(zString) '- Here's the big call to do the printing. For test purposes ' I print it in at 1" over, 1" down, 3" wide, and 2" high ' rectangle. BltImage zCommand, %True, 1, 1, 3, 2, dcPrint EndPage dcPrint NEXT i '- Clean up EndDoc dcPrint DeleteDC dcPrint SetCursor LoadCursor(%NULL, BYVAL %IDC_ARROW) END IF '_ if dcPrint END IF '_ if bitmap file exist END FUNCTION