- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi All,
I need to be able to generate a .bmp file froma bitmapcreated ina memory device context. In the online help, under Platform SDK, I have found the section "Storing an Image". This looks about right, but it refers to the handle of a bitmap, whereas I have the handle to a memory device context - how can I connect the two? Is this a silly question?
I realise I may be going about this entirely the wrong way and would appreciate some advice on the specific correct steps to take. Somehow I need to be able to generate a bitmap and save it to a file - what do I need to do?
With many thanks in advance
Mike
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You get the bitmap handle when you create itand before you select it into the device context. The attachment shows the way that I do it, based on a function supplied by Jugoslav Djugic. Oops, still no attachment button!! So here is the code in all it's glory. Sorry about the size! (get that attachment button working, please Steve!)
I assume you want to draw on a memory DC what you would otherwise draw
to a window on the the screen. Here's how I do it. By the way, I use Compaq
Visual Fortran version 6.6c
First I get the present screen size using GetClientRect (rc must be TYPE T_RECT).
Then I create a compatible DC in memory, which starts off with a default 1 by 1
pixel bitmap as a placeholder, which you then have to set up to be the size you want,
in my case the size of the present display window.
To do this, I create a compatible bitmap and then load this into the memory DC
using SelectObject. It is this function that gives me the handle to the bitmap
that I need later (you can ignore the brush selection if you want.
You can of course create your own brush and select it into the memory DC as you so wish)
!CODE STARTS
! Get dimensions of window in pixels
retlog=getclientrect(hWnd,rc)
ixwidth=rc%right-rc%left
iywidth=rc%bottom-rc%top
!***********************************************************************
!DRAW THE FIGURE ONTO A MEMORY BITMAP
! create a compatible device context. It will contain a 1x1 pixel bitmap
! as a placeholder which is then replaced with the full-size bitmap with
! dimensions to match the window
hMemDC=CreateCompatibleDC(hWndDC)
! select the class background brush
hBackBrush=SelectObject(hMemDC, hClassBrush)
! create a compatible bitmap and select it into the compatible Device context
hBitmap=CreateCompatibleBitmap(hWndDC,ixwidth,iywidth)
hOldBitmap=SelectObject(hMemDC, hBitmap)
!CODE ENDS
Next, you add here all the commands you need to draw your scene, or whatever,
but this time passing the handle to the memory DC (hMemDC) instead of using
the window DC to whatever routine or function you use.
Once I have drawn my scene/figure onto the hMemDC, I use the function GetOpenFilename
to prompt for a filename to use for the bitmap (this is hidden in a call to a
routine of my own called Getbitmapfilename) and then I use a modified version of a
function, kindly made available by Jugoslav Djugic, called SaveBitmap that
requires the bitmap handle (INTEGER), the full-path bitmap filename (CHARACTER)
and the bitmap colour depth (cClrBits, INTEGER) as arguments.
(In my code, the full-path filename is returned in CHARACTER variable BMP_FILE, with
trailing NULL character removed, which I have defined in a module which must be
INCLUDEd, otherwise you could make it an argument along with the logical flag
BMP_FILE_OK that I use to indicate whether or not a bitmap file name was
successfully selected). Code follows:
!CODE STARTS
!END OF YOUR DRAWING CODE
!***********************************************************************
!Get the color depth bits of the bitmap
cClrBits=GetDeviceCaps(hMemDC, BITSPIXEL)
! Get a filename to save the bitmap data to...returned in bmp_sav, flagged in bmp_file_
sav
call GetBitmapFilename(BMP_FILE_OK)
! If filename chosen, and not CANCELled, save the bitmap to the file...
if(bmp_file_ok) then
bitmapfile=BMP_FILE(1:LEN_TRIM(BMP_FILE) )
retint=SetStatusText(ghWndStatus,'Saving bitmap to '//BMP_FILE(1:LEN_TRIM(BMP_FILE))//' 'C )
IF(Savebitmap(hBitmap, bitmapfile, cClrBits))THEN
retlog=SetStatusText(ghWndStatus,'Plot saved in '//BMP_FILE//' 'C )
ELSE
retlog=SetStatusText(ghWndStatus,'Failed to save plot in '//BMP_FILE//' 'C )
ENDIF
ENDIF
CODE FOR LOGICAL FUNCTION SaveBitMap follows...
!======================================================================
!Modified version of Jugoslav Dujic's XSaveBitmap
! replaces first argument with handle to bitmap
! Saves the bitmap with handle hBmpIn to file name sFileName.
! color depth iDepth
! Jugoslav's code based on code from Compaq Forum posted by Soren Fredsgaard
!
LOGICAL FUNCTION SaveBitmap(hBmpIn, sFileName, iDepth)
USE DFWINTY
USE DFWIN
USE DFLIB
USE INPUTINFO
!
INTEGER, INTENT(IN)::hBmpIn
CHARACTER(*), INTENT(IN):: sFileName
INTEGER, OPTIONAL, INTENT(IN):: iDepth
TYPE(T_BITMAPFILEHEADER):: HDR
TYPE(T_BITMAPINFO):: BI; POINTER(pBI, BI)
TYPE(T_BITMAP):: BMP
INTEGER:: cClrBits, bmSize, iSt, iErr, Iret, hdcComp, hOldBmp, iFlags, nColorTable
INTEGER, PARAMETER:: RGBQUAD_SIZE = 4
INTEGER(1), ALLOCATABLE:: bmBits(:), bmInfo(:)
CHARACTER(LEN=60)MSG0, MSG1
SaveBitmap = .FALSE.
IF (PRESENT(iDepth)) THEN
cClrBits = iDepth
ELSE
cClrBits = 24
END IF
IF (GetObject(hBmpIn, SIZEOF(Bmp), LOC(Bmp)).EQ.0) RETURN
IF (PRESENT(iDepth)) THEN
cClrBits = iDepth
ELSE
cClrBits = (bmp%bmPlanes * bmp%bmBitsPixel)
END IF
IF (cClrBits == 1) THEN
cClrBits = 1
ELSE IF (cClrBits <= 4) THEN
cClrBits = 4
ELSE IF (cClrBits <= 8) THEN
cClrBits = 8
ELSE IF (cClrBits <= 16) THEN
cClrBits = 16
ELSE IF (cClrBits <= 24) THEN
cClrBits = 24
ELSE
cClrBits = 32
END IF
iFlags = DIB_RGB_COLORS
!*
!* Allocate memory for the BITMAPINFO structure. (This structure
!* contains a BITMAPINFOHEADER structure and an array of RGBQUAD data
!* structures.)
IF (cClrBits /= 24) THEN
ALLOCATE(bmInfo(SIZEOF(
BI%bmiHeader) + 32 * (2**cClrBits)) )
ELSE
! * There is no RGBQUAD array for the 24-bit-per-pixel format.
ALLOCATE(bmInfo(SIZEOF(BI%bmiHeader)))
END IF
bmInfo = 0_1
pBI = LOC(bmInfo)
! Initialize the fields in the BITMAPINFO structure. */
BI%bmiHeader%biSize = SIZEOF(BI%bmiHeader)
BI%bmiHeader%biWidth = Bmp%bmWidth
BI%bmiHeader%biHeight = Bmp%bmHeight
BI%bmiHeader%biPlanes = 1
BI%bmiHeader%biBitCount = cClrBits
BI%bmiHeader%biCompression = BI_RGB
BI%bmiHeader%biSizeImage = ((BI%bmiHeader%biWidth * cClrBits + 31) /8) * BI%bmiHeader%biHeight
BI%bmiHeader%biXPelsPerMeter = 96*100/2.54+1
BI%bmiHeader%biYPelsPerMeter = 96*100/2.54+1
BI%bmiHeader%biClrImportant = 0
IF (cClrBits < 24) then
nColorTable = 2**cClrBits
ELSE
nColorTable = 0
END IF
BI%bmiHeader%biClrUsed = nColorTable
hdcComp = CreateCompatibleDC(NULL)
hOldBmp = SelectObject(hdcComp, hBmpIn)
ALLOCATE(bmBits(BI%bmiHeader%biSizeImage))
! comment out compiler metacommands as first option for GetDIBits gives compiler error
!!DEC$IF (_DF_VERSION_.LT.650 .OR. .NOT.DEFINED(XLITE))
!iSt = GetDIBits(hdcComp, hBmpIn, 0, BI%bmiHeader%biHeight, LOC(bmBits), BI, DIB_RGB_COLORS)
!!DEC$ELSE
iSt = GetDIBits(hdcComp, hBmpIn, 0, BI%bmiHeader%biHeight, LOC(bmBits), LOC(BI), DIB_RGB_COLORS)
!!DEC$ENDIF
IF (iSt.EQ.0) THEN
iErr = GetLastError()
iSt = SelectObject(hdcComp, hOldBmp)
iSt = DeleteDC(hdcComp)
RETURN
END IF
iSt = DeleteDC(hdcComp)
iSt = SelectObject(hdcComp, hOldBmp)
hdr%bfType = Z'4d42'
hdr%bfSize = SIZEOF(hdr) + BI%bmiHeader%biSize + &
nColorTable * RGBQUAD_SIZE + BI%bmiHeader%biSizeImage
hdr%bfReserved1 = 0
hdr%bfReserved2 = 0
!Compute the offset to the array of color indices. */
hdr%bfOffBits = SIZEOF(hdr) + BI%bmiHeader%biSize + nColorTable * RGBQUAD_SIZE
!* OPEN OUTPUT FILE
OPEN(251, file = sFileName, ACTION = 'WRITE', ACCESS = 'SEQUENTIAL', STATUS = 'NEW', &
FORM = 'BINARY', IOSTAT = iErr)
IF(IERR .NE. 0)THEN
MSG0 = ' THE FILE ALREADY EXISTS. DO YOU WANT TO OVERWRITE IT?'C
MSG1 = ' ERROR OPENING BITMAP FILE 'C
IRET = MESSAGEBOX(GHWND,MSG0, MSG1, IOR(MB_ICONEXCLAMATION, MB_YESNOCANCEL))
IF(IRET == MB$IDYES)THEN
OPEN(251, file = sFileName, ACTION = 'WRITE', ACCESS = 'SEQUENTIAL', STATUS = 'OLD', &
FORM = 'BINARY', IOSTAT = iErr)
IF (iErr.NE.0) RETURN
REWIND(251)
WRITE(251, IOSTAT = iErr) hdr, bmInfo(1: SIZEOF(BI%bmiHeader)+ nColorTable*RGBQUAD_SIZE), &
bmBits
CLOSE(
251)
SaveBitmap = iErr.EQ.0
RETURN
ELSE
RETURN
ENDIF
ELSE
REWIND(251)
WRITE(251, IOSTAT = iErr) hdr, bmInfo(1: SIZEOF(BI%bmiHeader)+ nColorTable*RGBQUAD_SIZE), &
bmBits
CLOSE(251)
SaveBitmap = iErr.EQ.0
RETURN
ENDIF
END FUNCTION SaveBitmap
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Anthony,
Many thanks for that. The function, SaveBitMap, did exactly what I wanted with only trivial modification since I already had the bitmap in memory.
This is a great forum!
Thanks again
Mike

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page