RTL窗口上的PrintWindow生成带有PW_RENDERFULLCONTENT标志的镜像图像

问题描述

我正在尝试使用以下使用pywin32的python代码获取RTL窗口的图像:

def get_window_image(hwnd: int,window_region: Region) -> np.ndarray:
    PW_RENDERFULLCONTENT = 2

    dc_handle = None
    dc_obj = None
    save_bitmap = None
    memory_dc_obj = None

    try:
        # Creating device context for retrieving the screenshot. Based on the following:
        # https://stackoverflow.com/questions/19695214/python-screenshot-of-inactive-window-printwindow-win32gui
        # Documentation about device context:
        # https://docs.microsoft.com/en-us/cpp/mfc/device-contexts?view=vs-2019

        dc_handle = win32gui.GetwindowDC(hwnd)
        dc_obj = win32ui.CreateDCFromHandle(dc_handle)
        memory_dc_obj = dc_obj.CreateCompatibleDC()

        # Create a bitmap from the device context
        save_bitmap = win32ui.CreateBitmap()
        save_bitmap.CreateCompatibleBitmap(dc_obj,window_region.get_width(),window_region.get_height())
        memory_dc_obj.SelectObject(save_bitmap)

        if sys.getwindowsversion().major >= 8:
            render_flags = PW_RENDERFULLCONTENT
        else:
            render_flags = 0

        # Take a screenshot of the window
        windll.user32.Printwindow(hwnd,memory_dc_obj.GetSafeHdc(),render_flags)

        # Retrieve the bitmap content from the taken screenshot
        bmp_info = save_bitmap.GetInfo()
        bmp_str = save_bitmap.GetBitmapBits(True)

        bmp_height,bmp_width = bmp_info['bmHeight'],bmp_info['bmWidth']
        window_image = np.fromstring(string=bmp_str,dtype=np.uint8)

        window_image = window_image.reshape((bmp_height,bmp_width,4))
        window_image[:,:,3] = 255  # remove alpha channel

        return window_image

    finally:
        if save_bitmap is not None:
            win32gui.DeleteObject(save_bitmap.GetHandle())

        if memory_dc_obj is not None:
            memory_dc_obj.DeleteDC()

        if dc_obj is not None:
            dc_obj.DeleteDC()

        if dc_handle is not None:
            win32gui.ReleaseDC(hwnd,dc_handle)

生成RTL窗口的代码

win32gui.MessageBox(None,'משהו בעברית','test-rtl',win32con.MB_ICONWARNING | win32con.MB_RTLREADING)

我正在传递Printwindow标志-PW_RENDERFULLCONTENT = 2,这应该有助于使用正确的框架而不是经典框架来渲染窗口(另请参见https://stackoverflow.com/a/40042587/4313487

我有2台具有相同规格的PC。在第一台PC上,图像以镜像方式打印,在第二台PC上,图像以原始显示的方式打印。

两台PC的Windows 10都具有相同的区域和区域设置。在两台PC上,消息框窗口具有相同的样式标志,包括WS_EX_LAYOUTRTL。

来自PC1的图像-被镜像:

enter image description here

来自PC2的图像(相同代码):

enter image description here

当传递给Printwindow的标志为0(而不是PW_RENDERFULLCONTENT)时,图像将在两台PC上镜像:

enter image description here

为什么会发生?

如何确保在不同PC上以相同方向打印图像?

解决方法

如果不建议使用。什么是最好的打印方式 窗口应用程序(例如铬),如果没有此标志,则该应用程序是 呈现为黑屏?

我使用PrintWindow(无PW_RENDERFULLCONTENT)来打印chrome窗口,如果没有最小化chrome窗口,则没有黑屏问题。话虽如此,Chrome在过去很长一段时间内都返回黑屏存在很多问题。

但是PrintWindow()不能很好地工作。您可以从该DC尝试GetWindowDC()BitBlt()到您的位图中。或GetClientRect()+ClientToScreen()BitBlt()从屏幕DC到位图的矩形。

或者查看Win10中添加的Screen Capture API。或在Win8中添加的Desktop Duplication API。或Direct3D。参见Ways to capture the screen

引用:Getting Black Screenshots with Windows API

由于您需要在python中实现它,因此建议您使用第一种方法(相对简单)GetClientRect()+ClientToScreen() and BitBlt()...

代码示例:Capturing screenshots with win32api python returns black image