This question is kind of a follow up to this one.
I'm using the code in the first answer to get a region of the desktop, and copying it to the clipboard. It might seem like i didn't research, but i did. The problem is that this is my first contact with ctypes, winapi and all that jazz.
MS Paint, Paint.net and LibreOffice can read the image perfectly, but MS Word changes the aspect ratio; it just sets width and height to 15cm.
My question is: what kind of data is Word expecting? Also a code example would be great.
This is the current code (same as the other answer):
import ctypes
from ctypes import wintypes
from PIL import ImageGrab
from io import BytesIO
msvcrt = ctypes.cdll.msvcrt
windll = ctypes.windll
kernel32 = windll.kernel32
user32 = windll.user32
gdi32 = windll.gdi32
img = ImageGrab.grab()
output = BytesIO()
img.convert("RGB").save(output, "BMP")
data = output.getvalue()[14:]
output.close()
CF_DIB = 8
GMEM_MOVEABLE = 0x0002
global_mem = kernel32.GlobalAlloc(GMEM_MOVEABLE, len(data))
global_data = kernel32.GlobalLock(global_mem)
msvcrt.memcpy(ctypes.c_char_p(global_data), data, len(data))
kernel32.GlobalUnlock(global_mem)
user32.OpenClipboard(None)
user32.EmptyClipboard()
user32.SetClipboardData(CF_DIB, global_mem)
user32.CloseClipboard()
UPDATE
I thought that maybe it would be easier to use winapi for everything instead of using PIL. Now the dimensions look correct, but the image is black everywhere (LibreOffice, Word...).
class RECT(ctypes.Structure):
_fields_ = [
('left', ctypes.c_long),
('top', ctypes.c_long),
('right', ctypes.c_long),
('bottom', ctypes.c_long)
]
rect = RECT()
# self.whandle is the result of user32.GetDesktopWindow()
user32.GetWindowRect(self.whandle, ctypes.byref(rect))
hdcScreen = user32.GetDC(None)
hdc = gdi32.CreateCompatibleDC(hdcScreen)
hbmp = gdi32.CreateCompatibleBitmap(
hdcScreen,
rect.right - rect.left,
rect.bottom - rect.top
)
gdi32.SelectObject(hdc, hbmp)
PW_CLIENTONLY = 0x00000001
# This returns 0
user32.PrintWindow(self.whandle, hdc, PW_CLIENTONLY)
CF_BITMAP = 2
user32.OpenClipboard(None)
user32.EmptyClipboard()
user32.SetClipboardData(CF_BITMAP, hbmp)
user32.CloseClipboard()
gdi32.DeleteDC(hdc)
gdi32.DeleteObject(hbmp)
user32.ReleaseDC(None, hdcScreen)
PrintWindow returns 0 so it is failing :(
UPDATE 2
I tried patching the image header with this snippet:
import struct
fmt = "LllHHLLllLL"
header_size = struct.calcsize(fmt)
# data comes from the first snippet
image_header = data[:header_size]
image_data = data[header_size:]
unpacked_header = list(struct.unpack_from(fmt, image_header))
# Indexes:
biWidth = 1
biHeight = 2
biXPelsPerMeter = 7
biYPelsPerMeter = 8
unpacked_header[biXPelsPerMeter] = 2835
unpacked_header[biYPelsPerMeter] = 2835
image_header = struct.pack(fmt, *unpacked_header)
data = image_header + image_data
The values for *PelsPerMeter
were extracted from here.