Page 1 of 2

[Solved] Capture window as an image

Posted: Thu Jun 01, 2017 8:18 am
by Fangbeast
Is there a way for a running program to take a graphic snapshot of one of its windows and all objects on it as an image?

Re: Capture window as an image

Posted: Thu Jun 01, 2017 8:22 am
by RSBasic

Re: Capture window as an image

Posted: Thu Jun 01, 2017 9:01 am
by Bisonte
hm my idea with GrabDrawingImage and WindowOutPut don't work .... the text of the button have another color ....

Code: Select all

OpenWindow(0, 0, 0, 640, 480, "Test", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
ButtonGadget(1, 20, 20, 100, 20, "Go")
ImageGadget(2, 20, 50, 640, 480, 0)
AddKeyboardShortcut(0, #PB_Shortcut_1, 2)

Repeat
  Event = WaitWindowEvent()
  Select Event
    Case #PB_Event_CloseWindow
      Quit = #True
    Case #PB_Event_Menu
      Select EventMenu()
        Case 2
          If StartDrawing(WindowOutput(0))
            GrabDrawingImage(1, 0, 0, OutputWidth(), OutputHeight())
            StopDrawing()
            SetGadgetState(2, ImageID(1))
          EndIf
      EndSelect      
  EndSelect
Until Quit

Re: Capture window as an image

Posted: Thu Jun 01, 2017 10:12 am
by Fangbeast
Thanks for that you two, this gives me some new, useful ideas to play with. Woohoo, PB is fun!

Re: Capture window as an image

Posted: Thu Jun 01, 2017 10:41 am
by Fangbeast
I've combined RSBASIC's code and a printrequester example to send the image to the printer but the resulting image is only slightly larger than a postage stamp?

Anyone have an idea? I thought \right, \bottom were the correct image size grabbed?

Code: Select all

Procedure PrintMyStuffNow()
  Protected Handle
  Protected hDC
  Protected RECT.RECT
  Protected hPrinterDC
  Handle  = GetForegroundWindow_()
  hDC     = GetWindowDC_(Handle)
  GetWindowRect_(Handle, @RECT.RECT)
  With RECT
    \right - \left
    \bottom - \top
    ImageHandle.i = CreateImage(#PB_Any, \right, \bottom)
    hPrinterDC    = StartDrawing(ImageOutput(ImageHandle.i))
    If hPrinterDC
      BitBlt_(hPrinterDC, 0, 0, \right, \bottom, hDC, 0, 0, #SRCCOPY)
      StopDrawing()
    EndIf
   ;EndWith
    ReleaseDC_(Handle,  hDC)
    If PrintRequester()
      If StartPrinting("Print window")
        If StartDrawing(PrinterOutput())
          DrawImage(ImageID(ImageHandle.i), \right, \bottom)
          StopDrawing()
        EndIf
        StopPrinting()
      EndIf
    EndIf
  EndWith
  ;SetClipboardImage(ImageHandle.i)
EndProcedure

  

Re: Capture window as an image

Posted: Thu Jun 01, 2017 11:38 am
by Olliv
Hi Fangbeast,

I ask myself if a 'output image format getting' and then a resizing could solve,
inserting these 3 lines in the drawing job.

Code: Select all

Width =  OutputWidth()
Height = OutputHeight()
ResizeImage(ImageHandle, Width, Height)

Re: Capture window as an image

Posted: Thu Jun 01, 2017 12:09 pm
by RASHAD
Hi
You are using \right, \bottom as x & y not as width and height

Code: Select all

DrawImage(ImageID, x, y [, Width, Height]) 
Better use

Code: Select all

        If StartVectorDrawing(PrinterOutput(#PB_Unit_Millimeter)
            MovePathCursor(x.d, y.d [, Flags])
            DrawVectorImage(ImageID [, Alpha [, Width.d, Height.d]])
          StopDrawing()
        EndIf

Re: Capture window as an image

Posted: Thu Jun 01, 2017 12:15 pm
by Bisonte
or change your Print Routine with this

Code: Select all

    If PrintRequester()
      If StartPrinting("Print window")
        Factor.f = PrinterPageWidth() / ImageWidth(ImageHandle)
        If StartVectorDrawing(PrinterVectorOutput(#PB_Unit_Pixel))
          MovePathCursor(0, 0)
          DrawVectorImage(ImageID(ImageHandle), 255, ImageWidth(ImageHandle)*Factor, ImageHeight(ImageHandle)*Factor)
          StopVectorDrawing()
        EndIf
        StopPrinting()
      EndIf
    EndIf

Re: Capture window as an image

Posted: Thu Jun 01, 2017 1:08 pm
by Fangbeast
Ouch, shows how dumb I am. But it's getting better:)

Re: Capture window as an image

Posted: Thu Jun 01, 2017 1:28 pm
by Fangbeast
Tested the print results in landscape mode using my PDF printer and they look great except for some thin black borders on both sides part of the way. Other than that, pretty damned good.

Re: [Solved] Capture window as an image

Posted: Sun Jun 04, 2017 7:24 am
by Fangbeast
Just doing about 20 prints and I have finally realised that it isn't just grabbing the foreground window but part of the background wallpaper?

Re: [Solved] Capture window as an image

Posted: Sun Jun 04, 2017 8:28 am
by idle
Have you tried PrintWindow_ ?
https://msdn.microsoft.com/en-us/librar ... s.85).aspx

__________________________________________________
URL tags added
06.06.2017
RSBasic

Re: [Solved] Capture window as an image

Posted: Sun Jun 04, 2017 12:40 pm
by Fangbeast
idle wrote:Have you tried PrintWindow_ ?
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
"The requested page could not be found".

I went looking for it but don't know how to use it. The code below works but grabs a tiny slice of the background that it's on as well.

Code: Select all

  Protected Handle
  Protected hDC
  Protected RECT.RECT
  Protected hPrinterDC
  Handle  = GetForegroundWindow_()
  hDC     = GetWindowDC_(Handle)
  GetWindowRect_(Handle, @RECT.RECT)
  With RECT
    \right - \left
    \bottom - \top
    ImageHandle.i = CreateImage(#PB_Any, \right, \bottom)
    hPrinterDC    = StartDrawing(ImageOutput(ImageHandle.i))
    \If hPrinterDC
      BitBlt_(hPrinterDC, 0, 0, \right, \bottom, hDC, 0, 0, #SRCCOPY)
      StopDrawing()
    EndIf
    ReleaseDC_(Handle,  hDC)
    If PrintRequester()
      If StartPrinting("MyStuff Record Print")
        Factor.f = PrinterPageWidth() / ImageWidth(ImageHandle)
        If StartVectorDrawing(PrinterVectorOutput(#PB_Unit_Pixel))
          MovePathCursor(0, 0)
          DrawVectorImage(ImageID(ImageHandle), 255, ImageWidth(ImageHandle) * Factor, ImageHeight(ImageHandle) * Factor)
          StopVectorDrawing()
        EndIf
        StopPrinting()
      EndIf
    EndIf 
  EndWith

Re: [Solved] Capture window as an image

Posted: Sun Jun 04, 2017 1:55 pm
by RASHAD
Hi Fang
All you need is the Handle of the requested Window
(It is not OK all the times but you can copy any window even if it is in the back)

Code: Select all

Prototype.i ptPrintWindow(hWnd, hdc, flags)

OpenLibrary(0, "User32.dll")
PrintWindow.ptPrintWindow = GetFunction(0, "PrintWindow")

ID = RunProgram("Notepad.exe","","",#PB_Program_Open)
Delay(100)
Repeat
  hWnd = FindWindow_(0,"Untitled - Notepad")
Until hWnd

SetWindowLongPtr_(hWnd, #GWL_STYLE, GetWindowLongPtr_(hWnd, #GWL_STYLE) | #WS_CLIPSIBLINGS)
SetWindowPos_(hWnd, #HWND_BOTTOM, -1, -1, -1, -1, #SWP_NOSIZE | #SWP_NOMOVE)

GetWindowRect_(hWnd,r.RECT)
 ww = r\right-r\left
 wh = r\bottom-r\top
  If CreateImage(1, ww,wh, 24)
    hdc = StartDrawing(ImageOutput(1))
    If hdc
      PrintWindow(hWnd, hdc,0)
      StopDrawing()
    EndIf
  EndIf
  
SaveImage(1,GetHomeDirectory()+"Test.bmp")
KillProgram(ID)
CloseLibrary(0)


Re: [Solved] Capture window as an image

Posted: Mon Jun 05, 2017 4:49 am
by Fangbeast
Hi RASHAD, just tried your solution. It's still printing black borders from the window underneath it. But thinner than before.

I have massaged your code into MyStuff and it works.

Code: Select all

Procedure PrintThisStuffFromRecord()
  
  ; 
  
  HideGadget(#Gadget_Datasheet_cControl, #True)
  
  ResizeWindow(#Window_Datasheet, #PB_Ignore, #PB_Ignore, 1000, 645)
  
  ; Test function from RASHAD to print window image without side bars from wallpaper
  
  OpenLibrary(0, "User32.dll")                                                                           ; 
  
  PrintWindow.ptPrintWindow = GetFunction(0, "PrintWindow")                                             ; 
  
  WindowHandle.i = WindowID(#Window_Datasheet)
  
  SetWindowLongPtr_(WindowHandle.i, #GWL_STYLE, GetWindowLongPtr_(WindowHandle.i, #GWL_STYLE) | #WS_CLIPSIBLINGS)
  
  SetWindowPos_(WindowHandle.i, #HWND_BOTTOM, -1, -1, -1, -1, #SWP_NOSIZE | #SWP_NOMOVE)
  
  GetWindowRect_(WindowHandle.i, r.RECT)
  
  WindowsWidth.i = r\right  - r\left
  
  WindowsHeight.i = r\bottom - r\top
  
  PrintableImage.i = CreateImage(#PB_Any, WindowsWidth.i, WindowsHeight.i, 24)
  
  If PrintableImage.i
    
    DeviceContextHandle.i = StartDrawing(ImageOutput(PrintableImage.i))
    
    If DeviceContextHandle.i
      
      PrintWindow(WindowHandle.i, DeviceContextHandle.i, 0)
      
      StopDrawing()
      
    EndIf
    
    ;SaveImage(PrintableImage.i,"D:\Test.jpg", #PB_ImagePlugin_PNG)
    
    If PrintRequester()
      
      If StartPrinting("MyStuff Record Print")
        
        Factor.f = PrinterPageWidth() / ImageWidth(PrintableImage.i)
        
        If StartVectorDrawing(PrinterVectorOutput(#PB_Unit_Pixel))
          
          MovePathCursor(0, 0)
          
          DrawVectorImage(ImageID(PrintableImage.i), 255, ImageWidth(PrintableImage.i) * Factor, ImageHeight(PrintableImage.i) * Factor)
          
          StopVectorDrawing()
          
        Else
          
          ; Could not print to the requested output
          
        EndIf
        
        StopPrinting()
        
      Else
        
        ; Vector printer failed to start
        
      EndIf
      
    Else
      
      ; Print requester failed
      
    EndIf 
    
  Else
    
    ; No image generated, could not print
    
  EndIf  
  
  ;
  
  CloseLibrary(0)

  ; 
  
  HideGadget(#Gadget_Datasheet_cControl, #False)
  
  ResizeWindow(#Window_Datasheet, #PB_Ignore, #PB_Ignore, 1000, 750)
  
  ; 
  
EndProcedure