Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
New Contributor I
19 Views

Drawing graphs in a bitmap

Jump to solution

Hi,

I am trying to create several bitmaps, draw graphs, output text, etc in them and then bitblt them onto the screen. My code follows but it does no work. Any help will be much appreciated.  Brooks V.

In WinMainProc...

   case (WM_CREATE)

   hDC = BeginPaint(hWndMain,lppaint)
   hDCMem1 = CreateCompatibleDC(hDC)
   hBM1 = CreateCompatibleBitMap(hDCMem1,maxx, maxy)
   hTemp = SelectObject(hDCMem1, hBM1)
   hOldPen = SelectObject (hDCMem1,hPen)

   hDCMem2 = CreateCompatibleDC(hDC)
   hBM2 = CreateCompatibleBitMap(hDCMem2,maxx, maxy)
   hTemp = SelectObject(hDCMem2, hBM2)
   hOldPen = SelectObject (hDCMem2,hPen)

   bret = EndPaint(hWndMain,lppaint)

Later in the sequence of things...

   case (WM_PAINT)

   hDC = BeginPaint(hWndMain,lppaint)
   nx =  Rectxy%right - Rectxy%left
   ny = Rectxy%bottom - Rectxy%top
   Select Case (myOption)
     case (1)
        bret = BitBlt (hdc, 0, 0, nx, ny, hBM1, 0, 0, SRCCOPY)
     case (2)
        bret = BitBlt (hdc, 0, 0, nx, ny, hBM2, 0, 0, SRCCOPY)
   End Select
   bret = EndPaint(hWndMain,lppaint)

Then in a button callback

   if (myOpt == 1) Then
      hBM = hBM1
   else
      hBM = hBM2
   end if

   bret = MoveToEx(hBM, x, y, NULL)
   do i = 1, 50
      x = ptx(i)
      y = PtY(i)
      bret = LineTo(hBM, x, y)
   end do

 

0 Kudos

Accepted Solutions
Highlighted
Valued Contributor III
19 Views

I no longer use Quickwin but

Jump to solution

I no longer use Quickwin but I used to use it a lot and you can have modeless dialogs. I recall then documentation was a bit misleading on this subject. Have you verified that the bitmap structure that you are pointing at is valid? 

I have not quite worked out what you are trying to do. is it capture a window data as a bmp, and repaint it adding some more graphic elements on top?

Did you look at http://msdn.microsoft.com/en-us/library/windows/desktop/dd183402(v=vs.85).aspx

I have my own working fortrainised version of that if it helps....

 

View solution in original post

0 Kudos
13 Replies
Highlighted
19 Views

You might want to take a look

Jump to solution

You might want to take a look at the SCIGRAPH sample in the QuickWin.zip sample collection installed along with the compiler.

Retired 12/31/2016
0 Kudos
Highlighted
New Contributor I
19 Views

I did but it does appear to

Jump to solution

I did but it does appear to be the same. They use MDI rather than SDI architecture. But I will look again.

Thanks,

Brooks V

0 Kudos
Highlighted
New Contributor I
19 Views

Sorry, that was doesn't and

Jump to solution

Sorry, that was doesn't and not does. Brooks V

0 Kudos
Highlighted
New Contributor I
19 Views

I generate data in fortran

Jump to solution

I generate data in fortran applications but the Windows interfaces, graphs etc. are developed using C++.

Probably would be more convenient to use  OpenGL for creating graphs in Fortran.

You can also browse www.codeproject.com where you can find a very huge amount of cases and samples.

Regards

0 Kudos
Highlighted
New Contributor I
19 Views

Since you want bitmap graphs,

Jump to solution

Since you want bitmap graphs, you might also consider a Quickwin project. This gives you access to powerful primitive graphics functions, similar (but different) from the Windows functions you showed. The advantage over SciGraph or other 3rd party libraries is that you have complete control over every detail of your graph. The disadvantage is that you have to take control over every detail of your graph. Another advantage is the very tight integration of the graphics functions with the rest of the programs.

My company does so much graphing of output that we developed, with a fair amount of effort, our own Quickwin library to handle xy graphs with a minimal amount of additional effort.

Unfortunately Quickwin projects are MDI only, and they do not handle vector formats at all.

0 Kudos
Highlighted
Valued Contributor III
19 Views

What does not work creating

Jump to solution

What does not work creating the bitmap or doing the bitBlt in the paint loop?

0 Kudos
Highlighted
New Contributor I
19 Views

Let me answer both points

Jump to solution

Let me answer both points above. I cannot use Quickwin because my application is being driven by a modeless dialog. For the second, I guess it's the bitblt that is not working.

 

Brooks

0 Kudos
Highlighted
Valued Contributor III
20 Views

I no longer use Quickwin but

Jump to solution

I no longer use Quickwin but I used to use it a lot and you can have modeless dialogs. I recall then documentation was a bit misleading on this subject. Have you verified that the bitmap structure that you are pointing at is valid? 

I have not quite worked out what you are trying to do. is it capture a window data as a bmp, and repaint it adding some more graphic elements on top?

Did you look at http://msdn.microsoft.com/en-us/library/windows/desktop/dd183402(v=vs.85).aspx

I have my own working fortrainised version of that if it helps....

 

View solution in original post

0 Kudos
Highlighted
New Contributor I
19 Views

You were right about the

Jump to solution

You were right about the beginpaint/endpaint in that is does something you don't see and it is apparently necessary.

To answer your question, I have a set of radiobuttons in a modeless dialog and when the user clicks on one of the radiobuttons, I want to bitblt a bitmap onto the screen so I don't have to redraw it all the time and I want it done quickly. The types of graphs are (1) a text only, (2) a complex graph, (3) another comples graph mixed with some text, (4) a histogram of some pseudo-random sample, and (5) is another text window. All of these bitmaps are done when certain buttons and data are fed to the dialog and do not occur during a WM_PAINT event.

Thanks,

Brooks V

0 Kudos
Highlighted
New Contributor I
19 Views

Andrew,

 

Yes I would like to see the capture routine.

Thanks,

Brooks V

0 Kudos
Highlighted
Valued Contributor III
19 Views

module capture_image

Jump to solution
module capture_image
    use :: ifwin, only: handle, t_rect, bool, sint, LPVOID, t_bitmap, t_BITMAPFILEHEADER, t_BITMAPINFOHEADER, &
                        DWORD, SIZE_T, T_POINT, NULL, GetDC, CreateCompatibleDC, GetClientRect, GetWindowRect, &
                        CreateCompatibleBitmap, SelectObject, BitBlt, ScreenToClient, SRCCOPY, GetObject, BI_RGB, &
                        GHND, GlobalAlloc, GlobalLock, GetDIBits, DIB_RGB_COLORS, GENERIC_WRITE, CREATE_ALWAYS, &
                        FILE_ATTRIBUTE_NORMAL, CreateFile, WriteFile,  GlobalUnlock, GlobalFree, CloseHandle, &
                        DeleteObject, ReleaseDC, INVALID_HANDLE_VALUE
    use, intrinsic :: ISO_C_BINDING, only: C_SIZEOF, C_INTPTR_T, C_LOC
    !!!!!use axs6, only: cc_getlasterror !
    implicit none
    private
    public   :: CaptureAnImageToBMP_file , Write_pixarrayToBMP_File
    contains
    subroutine cc_getlasterror() ! dummy error handler provide your own 
    end subroutine cc_getlasterror 
    subroutine CaptureAnImageToBMP_file(hWnd,gfile,iopt,istat)
        !based on parts of C++ example at http://msdn.microsoft.com/en-us/library/windows/desktop/dd183402(v=vs.85).aspx
        !MSDN Topic "Capturing an Image" // GDI_CapturingAnImage.cpp : Defines the entry point for the application.       
        implicit none
        integer(handle),intent(in)   :: hWnd   ! handle to window to capture
        character(len=*),intent(in)  :: gfile  ! name of BMP file to write, must be c string
        integer, intent(in)          :: iopt   ! 0 to capture whole window, 1 for just client area of window       
        integer, intent(out)         :: istat  ! error status 0=OK, <0 NOK
        integer(handle)              :: hdcWindow            ! hDc
        integer(handle)              :: hdcMemDC             ! hDc
        type(t_rect)                 :: rcClient             ! client coord bit grab rectangle of hWnd
        integer(bool)                :: bret
        integer(sint)                :: isint, isize
        integer(handle)              :: hbmWindow            ! HBITMAP 
        integer(LPVOID)              :: ilpvoid              ! HGDIOBJ
        type(t_bitmap)               :: bmpWindow
        type(t_BITMAPFILEHEADER)     :: bmfHeader  
        type(t_BITMAPINFOHEADER)     :: bi
        integer(SIZE_T)              :: dwBmpSize            ! another 4 or 8 byter like handle 
        integer(HANDLE)              :: hDIB 
        integer(LPVOID)              :: ilpbitmap
        integer(HANDLE)              :: ihan                 ! HGLOBAL
        integer(HANDLE)              :: hfile
        integer(DWORD)               :: dwBytesWritten, dwSizeofDIB
        type(T_POINT)                :: tp1, tp2
        integer(C_INTPTR_T)          :: locvar, locbi        ! integer pointers to data for api calls
        istat=NULL                      !assume OK   
        hdcMemDC=NULL ; hbmWindow=NULL !init handles
        hdcWindow = GetDC(hWnd)   !Retrieve the handle to a display device context for the window. 
        ! Create a compatible DC which is used in a BitBlt from the window DC
        hdcMemDC = CreateCompatibleDC(hdcWindow)
        if(hdcMemDC == NULL) then !"CreateCompatibleDC has failed"
            istat=-1; goto 999
        endif  
        if(iopt == 1) then        
           bret=GetClientRect(hWnd, rcClient) ! Get the client area for size calculation top rt (0,0)
        else
           bret=GetWindowRect(hWnd, rcClient) ! use the whole window area, this is in screen coords
           tp1%x=rcClient%left;  tp1%y=rcClient%top
           tp2%x=rcClient%right; tp2%y=rcClient%bottom
           bret=ScreenToClient(hwnd,tp1) ! convert to client area
           bret=ScreenToClient(hwnd,tp2) ! convert to client area
           rcClient%left  = tp1%x  ; rcClient%top    = tp1%y
           rcClient%right = tp2%x  ; rcClient%bottom = tp2%y !that conversion is tedious!!!           
        endif
        ! Create a compatible bitmap from the Window DC
        hbmWindow = CreateCompatibleBitmap(hdcWindow, rcClient%right-rcClient%left, rcClient%bottom-rcClient%top)
        if(hbmWindow == NULL) then !"CreateCompatibleBitmap Failed"
            istat=-2; goto 999
        endif
        ilpvoid=SelectObject(hdcMemDC,hbmWindow)       ! Select the compatible bitmap into the compatible memory DC.
        ! Bit block transfer into our compatible memory DC
        bret = BitBlt(hdcMemDC,                     &  ! target dc for bit copy
                      0_sint,                       &  ! target left
                      0_sint,                       &  ! target top  
                      rcClient%right-rcClient%left, &  ! width 
                      rcClient%bottom-rcClient%top, &  ! height
                      hdcWindow,                    &  ! source hdc
                      rcClient%left,                &  ! source left (client coord) 
                      rcClient%top,                 &  ! source right(client coord)
                      SRCCOPY)                         ! just copy don't merge /dither etc
        if(bret == NULL) then !"BitBlt has failed"
            istat=-3
            goto 999
        endif
        isize = int(c_sizeof(bmpWindow),sint) !note c_sizeof is 4 or 8 byte dependent on platform      
        isint = GetObject(hbmWindow,isize,transfer(c_loc(bmpWindow),locvar))   ! Get the BITMAP from the HBITMAP
        ! fill the bitmapinfoheader 
        bi%biSize          = int(c_sizeof(bi),dword)    
        bi%biWidth         = bmpWindow%bmWidth    
        bi%biHeight        = bmpWindow%bmHeight  
        bi%biPlanes        = 1    
        bi%biBitCount      = 32    
        bi%biCompression   = BI_RGB    
        bi%biSizeImage     = NULL  
        bi%biXPelsPerMeter = NULL    
        bi%biYPelsPerMeter = NULL   
        bi%biClrUsed       = NULL    
        bi%biClrImportant  = NULL
               
        dwBmpSize = ((bmpWindow%bmWidth * bi%biBitCount + 31) / 32) * 4 * bmpWindow%bmHeight  ! size of the bitmap
        hDIB = GlobalAlloc(GHND,dwBmpSize)    !make a buffer
        if( hdib == NULL) call cc_getlasterror()
        ilpbitmap = GlobalLock(hDIB)          !protect buffer and get a handle to it 
        if( ilpbitmap == NULL) call cc_getlasterror()
        ! Gets the "bits" from the bitmap and copies them into a buffer which is pointed to by ilpbitmap
        locbi= transfer(c_loc(bi),locvar)     !memory address of var in integer(C_INTPTR_T) form
        isint = GetDIBits(hdcWindow, hbmWindow, 0,bmpWindow%bmHeight, ilpbitmap,locbi, DIB_RGB_COLORS)
        ! A file is created, this is where we will save the screen capture.
        hFile = CreateFile(gfile//char(0), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)   
        if( hfile == INVALID_HANDLE_VALUE) then
            call cc_getlasterror()
            istat=-4
            goto 999
        endif
        ! Add the size of the headers to the size of the bitmap to get the total file size
        dwSizeofDIB = dwBmpSize + c_sizeof(bmfHeader) + c_sizeof(bi)
       
        bmfHeader%bfType = int(z'4D42')                          ! "BM" bfType must always be BM for Bitmaps 
        bmfHeader%bfSize = dwSizeofDIB                           ! Size of the file SOF
        bmfHeader%bfReserved1 = NULL                             ! where SOF is 8 bytes, could overflow here and still conform BTW
        bmfHeader%bfReserved2 = NULL                             ! the reserved bytes define the application that made - redundant 
        bmfHeader%bfOffBits = c_sizeof(bmfHeader) + c_sizeof(bi) ! Offset to where the actual bitmap bits start.     
         
        dwBytesWritten = NULL     
        locvar=transfer(c_loc(dwBytesWritten),locvar) !memory address of var in integer(C_INTPTR_T) form
        
        bret = WriteFile(hFile, transfer(c_loc(bmfHeader),locvar), int(c_sizeof(bmfHeader),Sint), locvar, NULL)
        bret = WriteFile(hFile, locbi, int(c_sizeof(bi),Sint), locvar, NULL)
        bret = WriteFile(hFile, ilpbitmap, int(dwBmpSize,sint), locvar, NULL)
        bret = GlobalUnlock(hDIB)    ! Unlock and Free the DIB from the heap 
        if(bret == NULL) call cc_getlasterror()
        ihan = GlobalFree(hDIB)
        bret = CloseHandle(hFile)   ! Close the handle for the file that was created
        999 continue !cleanup
        bret = DeleteObject(hbmWindow)
        bret = DeleteObject(hdcMemDC)
        isint = ReleaseDC(hWnd,hdcWindow)  
    end subroutine CaptureAnImageToBMP_file 
    subroutine Write_pixarrayToBMP_File(bmpixels,bmWidth,bmHeight, gfile, istat)
        integer(DWORD), intent(in)   :: bmpixels(*)
        integer(DWORD), intent(in)   :: bmWidth, bmHeight
        character(len=*),intent(in)  :: gfile  ! name of BMP file to write, must be c string       
        integer, intent(out)         :: istat  ! error status 0=OK, <0 NOK
        integer(bool)                :: bret
        !type(t_bitmap)               :: bmpWindow
        type(t_BITMAPFILEHEADER)     :: bmfHeader  
        type(t_BITMAPINFOHEADER)     :: bi
        integer(SIZE_T)              :: dwBmpSize            ! another 4 or 8 byter like handle 
        integer(HANDLE)              :: hfile
        integer(DWORD)               :: dwBytesWritten, dwSizeofDIB
        integer(C_INTPTR_T)          :: LocVar, LocBitmap, LocBmfHeader, LocBi    ! integer pointers to data for api calls       
           
        istat = 0 
        ! fill the bitmapinfoheader 
        bi%biSize          = int(c_sizeof(bi),dword)    
        bi%biWidth         = bmWidth    
        bi%biHeight        = bmHeight  
        bi%biPlanes        = 1    
        bi%biBitCount      = 32    
        bi%biCompression   = BI_RGB    
        bi%biSizeImage     = NULL  
        bi%biXPelsPerMeter = NULL    
        bi%biYPelsPerMeter = NULL   
        bi%biClrUsed       = NULL    
        bi%biClrImportant  = NULL    !end subroutine Write_pixarrayToBMP_File
        
        dwBmpSize = (( bmWidth * bi%biBitCount + 31) / 32) * 4 *  bmHeight  ! size of the bitmap
        ! Add the size of the headers to the size of the bitmap to get the total file size
        dwSizeofDIB = dwBmpSize + c_sizeof(bmfHeader) + c_sizeof(bi)
        
        bmfHeader%bfType = int(z'4D42')                          ! "BM" bfType must always be BM for Bitmaps 
        bmfHeader%bfSize = dwSizeofDIB                           ! Size of the file SOF
        bmfHeader%bfReserved1 = NULL                             ! where SOF is 8 bytes, could overflow here and still conform BTW
        bmfHeader%bfReserved2 = NULL                             ! the reserved bytes define the application that made - redundant 
        bmfHeader%bfOffBits = c_sizeof(bmfHeader) + c_sizeof(bi) ! Offset to where the actual bitmap bits start.     
         
        dwBytesWritten = NULL     
        LocVar       = transfer(c_loc(dwBytesWritten),LocVar)  ! memory address of var in integer(C_INTPTR_T) form
        LocBitmap    = transfer(c_loc(bmpixels),      LocVar)    ! memory address of bitmap start
        LocBmfHeader = transfer(c_loc(bmfHeader),     LocVar)
        LocBi        = transfer(c_loc(bi),            LocVar)
        
        hFile = CreateFile(gfile//char(0), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)   
        if( hfile == INVALID_HANDLE_VALUE) then
            call cc_getlasterror()
            istat=-4
            goto 999
        endif
        bret = WriteFile(hFile, LocBmfHeader, int(c_sizeof(bmfHeader),Sint), locvar, NULL)
        bret = WriteFile(hFile, LocBi,        int(c_sizeof(bi),Sint),        locvar, NULL)
        bret = WriteFile(hFile, LocBitmap,    int(dwBmpSize,Sint),           locvar, NULL)
        999 continue        
        bret = CloseHandle(hFile)   ! Close the handle for the file that was created        
     end subroutine Write_pixarrayToBMP_File   
end module capture_image

That code works the MSDN ref is in the code the error handler is a dummy routine. The write pixarray I use when I grab OPENGL screen buffers.

0 Kudos
Highlighted
New Contributor I
19 Views

This may be closed out.

Jump to solution

This may be closed out. Thanks, Brooks V

0 Kudos
Highlighted
Beginner
19 Views

[quote=dboggs]

Jump to solution

dboggs wrote:

Since you want bitmap graphs, you might also consider a Quickwin project. This gives you access to powerful primitive graphics functions, similar (but different) from the Windows functions you showed. The advantage over SciGraph or other 3rd party libraries is that you have complete control over every detail of your graph. The disadvantage is that you have to take control over every detail of your graph. Another advantage is the very tight integration of the graphics functions with the rest of the programs.

My company does so much graphing of output that we developed, with a fair amount of effort, our own Quickwin library to handle xy graphs with a minimal amount of additional effort.

Unfortunately Quickwin projects are MDI only, and they do not handle vector formats at all.

[/quote

I have used PGPlot in Quickwin projects quite a bit. It makes clean 2D graphs and is easy to use. An added bonus is that you can make it output Postscript files (from your QuickWin program), so if you need real publication-quality graphs that look the same as the graphs on the screen you can get these easily too.

http://www.astro.caltech.edu/~tjp/pgplot/

https://sukhbinder.wordpress.com/2012/01/04/how-to-use-pgplot-in-windows-with-intel-fortran/

 

 

0 Kudos