Screen Capture

Share your advanced PureBasic knowledge/code with the community.
BarryG
Addict
Addict
Posts: 4128
Joined: Thu Apr 18, 2019 8:17 am

Re: Screen Capture

Post by BarryG »

@doctorized, the extra captured pixels on the sides and bottom of the window are part of the actual window, because Windows 10 has invisible borders for touch-screen reasons. There's lots of complaints on StackOverflow about this, and that Microsoft shouldn't include them in the visible size calculations.

So the capture size is technically correct, but visually ugly. Whichever code you're using has to manually subtract the extra pixel widths and height to get only the actual visible window area.
breeze4me
Enthusiast
Enthusiast
Posts: 633
Joined: Thu Mar 09, 2006 9:24 am
Location: S. Kor

Re: Screen Capture

Post by breeze4me »

doctorized wrote: Sat Mar 19, 2022 10:11 pm In my case, "My computer" window is captured with some extra pixels. Why? See the image below. Win 10 Pro x64 fully updated
https://ibb.co/qdPggpj
Try this.

Code: Select all

;capture a piece of screen 
Procedure CaptureScreen(Left, Top, Width, Height)
  Protected dm.DEVMODE, BMPHandle
  Protected old, trgDC, srcDC = CreateDC_("DISPLAY", "", "", dm)
  
  If srcDC
    trgDC = CreateCompatibleDC_(srcDC)
    If trgDC
      BMPHandle = CreateCompatibleBitmap_(srcDC, Width, Height)
      If BMPHandle
        old = SelectObject_(trgDC, BMPHandle)
        BitBlt_(trgDC, 0, 0, Width, Height, srcDC, Left, Top, #SRCCOPY)
        SelectObject_(trgDC, old)
      EndIf
      DeleteDC_(trgDC)
    EndIf
    DeleteDC_(srcDC)
  EndIf
  
  ProcedureReturn BMPHandle 
EndProcedure 

#DWMWA_EXTENDED_FRAME_BOUNDS = 9

Procedure GetWindowRect_modified(hWnd, *rt.RECT)
  Protected Lib, DwmIsCompositionEnabled, DwmGetWindowAttribute, flag
  
  If *rt = 0 : ProcedureReturn 0 : EndIf
  
  GetWindowRect_(hWnd, *rt)
  
  If OSVersion() >= #PB_OS_Windows_Vista
    Lib = OpenLibrary(#PB_Any, "dwmapi.dll")
    If Lib
      DwmIsCompositionEnabled = GetFunction(Lib, "DwmIsCompositionEnabled")
      If DwmIsCompositionEnabled
        CallFunctionFast(DwmIsCompositionEnabled, @flag)
      EndIf
      If flag = 1
        DwmGetWindowAttribute = GetFunction(Lib, "DwmGetWindowAttribute")
        If DwmGetWindowAttribute
          CallFunctionFast(DwmGetWindowAttribute, hWnd, #DWMWA_EXTENDED_FRAME_BOUNDS, *rt, SizeOf(RECT))
        EndIf
      EndIf
      CloseLibrary(Lib)
    EndIf
  EndIf
  
  ProcedureReturn 1
EndProcedure

Procedure CaptureWindow(WindowName.s)
  Protected Image, ScreenCaptureAddress, WindowSize.RECT, WinHndl = FindWindow_(0, WindowName)
  If WinHndl
    GetWindowRect_modified(WinHndl, @WindowSize)
    ScreenCaptureAddress = CaptureScreen(WindowSize\Left, WindowSize\Top, WindowSize\Right - WindowSize\Left, WindowSize\Bottom - WindowSize\Top)
    If ScreenCaptureAddress
      Image = CreateImage(#PB_Any, WindowSize\Right - WindowSize\Left, WindowSize\Bottom - WindowSize\Top)
      If Image
        If StartDrawing(ImageOutput(Image))
          DrawImage(ScreenCaptureAddress, 0, 0)
          StopDrawing()
          SaveImage(Image, "Screenshot.bmp")
        EndIf
        FreeImage(Image)
      EndIf
      DeleteObject_(ScreenCaptureAddress)
    EndIf
  Else
    ProcedureReturn 0
  EndIf
  ProcedureReturn 1
EndProcedure

CaptureWindow("My Computer")
User avatar
doctorized
Addict
Addict
Posts: 882
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: Screen Capture

Post by doctorized »

Works great! Thank you!
Post Reply