如何获取屏幕截图并更改剪贴板上的DPI?

时间:2018-08-16 14:11:11

标签: python-3.x python-imaging-library screenshot dpi win32gui

在Win7下,我想在剪贴板上获取一个窗口的内容,并设置/调整剪贴板上的DPI设置,然后将其复制到最终应用程序中。

下面的MCVE尚未按预期运行。 有一个问题: 有时可能会发生,显然窗口尚未设置为前景,并且def a(): b() return x def b(): x=10 的内容错误。等待一段时间(2-5秒)会有所帮助,但这不是很实际。如何避免或解决此问题?

代码如下:

ImageGrab.grab(bbox)

编辑:

这种改进的尝试有时仍然会得到错误的内容。也许有人可以解释为什么?

from io import BytesIO
from PIL import Image,ImageGrab
import win32gui, win32clipboard
import time

def get_screenshot(window_name, dpi):
    hwnd = win32gui.FindWindow(None, window_name)
    if hwnd != 0:
        win32gui.SetForegroundWindow(hwnd)
        time.sleep(2)  ### sometimes window is not yet in foreground. delay/timing problem???
        bbox = win32gui.GetWindowRect(hwnd)
        screenshot = ImageGrab.grab(bbox)
        width, height = screenshot.size
        lmargin = 9
        tmargin = 70
        rmargin = 9
        bmargin = 36
        screenshot = screenshot.crop(box = (lmargin,tmargin,width-rmargin,height-bmargin))
        win32clipboard.OpenClipboard()
        win32clipboard.EmptyClipboard()
        output = BytesIO()
        screenshot.convert("RGB").save(output, "BMP", dpi=(dpi,dpi))
        data = output.getvalue()[14:]
        output.close()
        win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data)
        win32clipboard.CloseClipboard()
        print("Screenshot taken...")
    else:
        print("No window found named:", window_name)

window_name = "Gnuplot (window id : 0)"
get_screenshot(window_name,200)

2 个答案:

答案 0 :(得分:0)

感谢@Tarun Lalwani指向 this answer,目前我终于有了一个代码,该代码目前对我有用。但是,在我看来,包含许多不同模块的时间很长。也许它仍然可以简化。欢迎提出建议。

代码:

### get the content of a window and crop it
import win32gui, win32ui, win32clipboard
from io import BytesIO
from ctypes import windll
from PIL import Image

# user input
window_name = 'Gnuplot (window id : 0)'
margins = [8,63,8,31]    # left, top, right, bottom
dpi = 96

hwnd = win32gui.FindWindow(None, window_name)
left, top, right, bottom = win32gui.GetWindowRect(hwnd)
width = right - left 
height = bottom - top
crop_box = (margins[0],margins[1],width-margins[2],height-margins[3])

hwndDC = win32gui.GetWindowDC(hwnd)
mfcDC  = win32ui.CreateDCFromHandle(hwndDC)
saveDC = mfcDC.CreateCompatibleDC()

saveBitMap = win32ui.CreateBitmap()
saveBitMap.CreateCompatibleBitmap(mfcDC, width, height)
saveDC.SelectObject(saveBitMap)
result = windll.user32.PrintWindow(hwnd, saveDC.GetSafeHdc(), 0)
bmpinfo = saveBitMap.GetInfo()
bmpstr = saveBitMap.GetBitmapBits(True)

im = Image.frombuffer( 'RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']),
    bmpstr, 'raw', 'BGRX', 0, 1).crop(crop_box)
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
output = BytesIO()
im.convert("RGB").save(output, "BMP", dpi=(dpi,dpi))
data = output.getvalue()[14:]
output.close()
win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data)
win32clipboard.CloseClipboard()

win32gui.DeleteObject(saveBitMap.GetHandle())
saveDC.DeleteDC()
mfcDC.DeleteDC()
win32gui.ReleaseDC(hwnd, hwndDC)

print('"'+window_name+'"', "is now on the clipboard with", dpi, "dpi.")
### end of code

答案 1 :(得分:0)

如前所述,您可以使用下面讨论的方法

Python Screenshot of inactive window PrintWindow + win32gui

import win32gui
import win32ui
from ctypes import windll
import Image

hwnd = win32gui.FindWindow(None, 'Calculator')

# Change the line below depending on whether you want the whole window
# or just the client area. 
#left, top, right, bot = win32gui.GetClientRect(hwnd)
left, top, right, bot = win32gui.GetWindowRect(hwnd)
w = right - left
h = bot - top

hwndDC = win32gui.GetWindowDC(hwnd)
mfcDC  = win32ui.CreateDCFromHandle(hwndDC)
saveDC = mfcDC.CreateCompatibleDC()

saveBitMap = win32ui.CreateBitmap()
saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)

saveDC.SelectObject(saveBitMap)

# Change the line below depending on whether you want the whole window
# or just the client area. 
#result = windll.user32.PrintWindow(hwnd, saveDC.GetSafeHdc(), 1)
result = windll.user32.PrintWindow(hwnd, saveDC.GetSafeHdc(), 0)
print result

bmpinfo = saveBitMap.GetInfo()
bmpstr = saveBitMap.GetBitmapBits(True)

im = Image.frombuffer(
    'RGB',
    (bmpinfo['bmWidth'], bmpinfo['bmHeight']),
    bmpstr, 'raw', 'BGRX', 0, 1)

win32gui.DeleteObject(saveBitMap.GetHandle())
saveDC.DeleteDC()
mfcDC.DeleteDC()
win32gui.ReleaseDC(hwnd, hwndDC)

if result == 1:
    #PrintWindow Succeeded
    im.save("test.png")