Screenshots taken with Python are totally black - python

So I have this code:
import win32gui
import win32ui
from ctypes import windll
from PIL import Image
hwnd = win32gui.FindWindow(None, "#chat - Discord")
# 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)
bmpinfo = saveBitMap.GetInfo()
bmpstr = saveBitMap.GetBitmapBits(True)
im = Image.frombuffer(
'RGB',
(bmpinfo['bmWidth'], bmpinfo['bmHeight']),
bmpstr, 'raw', 'BGRX', 0, 1)
if result:
#PrintWindow Succeeded
im.show()
win32gui.DeleteObject(saveBitMap.GetHandle())
saveDC.DeleteDC()
mfcDC.DeleteDC()
win32gui.ReleaseDC(hwnd, hwndDC)
The problem with it is that the screenshot it takes is all black. It does this with all windows, not just Discord. What is wrong with it, and what do I need to do to fix it?
Also as a side question - when I take screenshots the command prompt opens and then close real quick, is there also a way to stop that from happening?

The problem with it is that the screenshot it takes is all black.
I understand that you want to take a screenshot?
from PIL.ImageGrab import grab
image = grab()
image.save('Screenshot.png')
If you have the coordinates of the window, try this instead:
from PIL.ImageGrab import grab
box = (0,0,200,200)
image = grab(box)
image.save('Screenshot.png')
PIL has been discontinued though, so you may be able to use this code only for the next immediate future. Also, the command prompt does not appear with this code.

Related

Get color at point of mouse click in Tkinter

I'm working on a program (in Linux) where I need to know the color at the point where of mouse click. I can't install external modules (PIL is fine though). I did try and see if there are solutions posted in the net (Return RGB Color of Image Pixel under Mouse Tkinter) but all of them seem to use modules which I'll have to install. Is there a way I can do it with these restrictions in mind?
Here is a short script that enables colors to be found and displayed in tkinter.
It uses PIL ImageGrab.grab() to grab the entire screen as pic then you simply press space-bar to find the color under the mouse pointer. It uses pic.getpixel(x, y)
import tkinter as tk
from PIL import ImageGrab
master = tk.Tk()
master.columnconfigure(0, weight = 1)
master.title("Colors")
button = tk.Button(master, text = "Press Spacebar")
button.grid(sticky = tk.NSEW)
canvas = tk.Canvas(master, width = 200, height = 200)
canvas.grid(sticky = tk.NSEW)
pic = ImageGrab.grab()
def color():
x, y = master.winfo_pointerx(), master.winfo_pointery()
r, g, b = pic.getpixel((x, y))
hue = f"#{r:02x}{g:02x}{b:02x}"
button.config( text = f"{x}, {y} = {hue}")
canvas["background"] = hue
button["command"] = color
button.focus_force()
master.mainloop()

Python win32ui.error: CreateCompatibleDC failed when attempting to capture an application window

I think the same error as this thread; Python win32ui.error: CreateCompatibleDC failed
It's been a few months since I took a look at this code because I couldn't get past this error.
I'm using source_needle_images as the artefacts I'm trying to find, and haystack as the image I'm trying to find them in. My needles are currently two jpg's however, in future, this may be dozens of jpg's and my haystack is an application window named wincap
The eventual intention is to "do something" if anything whatsoever from source_needle_images is found within the application window.
This code is from my main.py, and I'm using two functions search and windowcapture
windowcapture captures the application window, search performs the OCR.
from windowcapture import WindowCapture
from search import Search
# the window to capture
wincap = WindowCapture('P')
# load needle images and start the matching process
source_needle_images = glob.glob(r'C:\\\\\\\*.jpg')
search = Search(source_needle_images)
loop_time = time()
while(True):
# get an updated image of the background
haystack_img = wincap.get_screenshot()
# display the processed image
points = search.find(haystack_img, 0.85, 'rectangles')
This is the section of code causing issue;
def get_screenshot(self):
# get the window image data
wDC = win32gui.GetWindowDC(self.hwnd)
dcObj = win32ui.CreateDCFromHandle(wDC)
cDC = dcObj.CreateCompatibleDC()
dataBitMap = win32ui.CreateBitmap()
dataBitMap.CreateCompatibleBitmap(dcObj, self.w, self.h)
cDC.SelectObject(dataBitMap)
cDC.BitBlt((0, 0), (self.w, self.h), dcObj, (self.cropped_x, self.cropped_y), win32con.SRCCOPY)
# convert the raw data into a format opencv can read
#dataBitMap.SaveBitmapFile(cDC, 'debug.bmp')
signedIntsArray = dataBitMap.GetBitmapBits(True)
img = np.fromstring(signedIntsArray, dtype='uint8')
img.shape = (self.h, self.w, 4)
# free resources
dcObj.DeleteDC()
cDC.DeleteDC()
win32gui.ReleaseDC(self.hwnd, wDC)
win32gui.DeleteObject(dataBitMap.GetHandle())
and this is the error in question;
Traceback (most recent call last):
File "c:\\\\\\main.py", line 23, in <module>
haystack_img = wincap.get_screenshot()
File "c:\\\\\\windowcapture.py", line 52, in get_screenshot
dataBitMap.CreateCompatibleBitmap(dcObj, self.w, self.h)
win32ui.error: CreateCompatibleDC failed
Updated with requested code:
# constructor
def __init__(self, window_name=None):
# find the handle for the window we want to capture.
# if no window name is given, capture the entire screen
if window_name is None:
self.hwnd = win32gui.GetDesktopWindow()
else:
self.hwnd = win32gui.FindWindow(None, window_name)
if not self.hwnd:
raise Exception('Window not found: {}'.format(window_name))

(C++/Python) Capture window screenshot without caret indicator

I want to capture the screenshot of the existing running window via Python.
Following is my sample code for capture Notepad window:
import time
import win32gui
import win32ui
import win32con
import pyautogui
def getWindowScreenshot(hwnd, output_file):
r = win32gui.GetWindowRect(hwnd)
width = r[2] - r[0]
height = r[3] - r[1]
wDC = win32gui.GetWindowDC(hwnd)
dcObj = win32ui.CreateDCFromHandle(wDC)
cDC = dcObj.CreateCompatibleDC()
dataBitMap = win32ui.CreateBitmap()
dataBitMap.CreateCompatibleBitmap(dcObj, width, height)
cDC.SelectObject(dataBitMap)
cDC.BitBlt((0, 0), (width, height), dcObj, (0, 0), win32con.SRCCOPY)
# save the bitmap to a file
dataBitMap.SaveBitmapFile(cDC, output_file)
dcObj.DeleteDC()
cDC.DeleteDC()
win32gui.ReleaseDC(hwnd, wDC)
win32gui.DeleteObject(dataBitMap.GetHandle())
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
window_title = "Untitled - Notepad"
winHandle = win32gui.FindWindow(None, window_title)
if winHandle == 0:
raise RuntimeError(f"Window '{window_title}' is not opening!")
# Bring the window to foreground in case it is overlap by other windows
win32gui.SetForegroundWindow(winHandle)
# Do something with Notepad
time.sleep(3)
# Capture the window
getWindowScreenshot(winHandle, "output.bmp")
However, sometimes the captured image will have the blinking caret indicator on the input textbox.
My question is, how to capture the screenshot without getting the caret indicator?
I already tried some solution, but not suitable:
Solution 1:
# Bring the window to foreground in case it is overlap by other windows
win32gui.SetForegroundWindow(winHandle)
# Do something with Notepad
time.sleep(3)
# Make the "Desktop window" focus
win32gui.SetForegroundWindow(win32gui.GetDesktopWindow())
# Capture the window
getWindowScreenshot(winHandle, "output.bmp")
Before capturing the screenshot, try to set "Desktop" as the foreground window.
However, the command win32gui.SetForegroundWindow(win32gui.GetDesktopWindow()) will raise an error:
pywintypes.error: (0, 'SetForegroundWindow', 'No error message is available')
Solution 2:
Replace win32gui.SetForegroundWindow(win32gui.GetDesktopWindow()) with win32gui.ShowWindow(winHandle, 4), where 4 is SW_SHOWNOACTIVATE.
The code run OK, but the Notepad window doesn't lose focus after execution.
Solution 3:
# Bring the window to foreground in case it is overlap by other windows
win32gui.SetForegroundWindow(winHandle)
# Do something with Notepad
time.sleep(3)
# Click outside of window
r = win32gui.GetWindowRect(winHandle)
pyautogui.click(r[2]+1, r[3]+1)
# Capture the window
getWindowScreenshot(winHandle, "output.bmp")
With this solution, I tried to click outside the Notepad window (click on the desktop). This code seems worked, but will not work if another window is behind the Notepad window like this:
When the code is executed, it will click on the Windows Explorer window. So, the code can perform clicking on something unexpectedly (example: deleting the system file unexpectedly?).
Solution 4
(from #SongZhu-MSFT)
if __name__ == '__main__':
window_title = "Untitled - Notepad"
winHandle = win32gui.FindWindow(None, window_title)
if winHandle == 0:
raise RuntimeError(f"Window '{window_title}' is not opening!")
# Bring the window to foreground in case it is overlap by other windows
win32gui.SetForegroundWindow(winHandle)
# Do something with Notepad
time.sleep(3)
win32gui.EnableWindow(winHandle,False)
# Capture the window
getWindowScreenshot(winHandle, "output.bmp")
time.sleep(0.5)
getWindowScreenshot(winHandle, "output1.bmp")
time.sleep(5)
win32gui.EnableWindow(winHandle,True)
When I run the code, I still see that the caret displaying all time.
And output.bmp + output1.bmp still exists one image with the caret.
System information:
Windows 10 1909
Python 3.7.9
After my test, I can use SendMessageW to send WM_KILLFOCUS to make the caret disappear.
This is the code that worked for me:
import time
import win32gui
import win32ui
import win32con
import pyautogui
from ctypes import windll
def getWindowScreenshot(hwnd, output_file):
r = win32gui.GetWindowRect(hwnd)
width = r[2] - r[0]
height = r[3] - r[1]
wDC = win32gui.GetWindowDC(hwnd)
dcObj = win32ui.CreateDCFromHandle(wDC)
cDC = dcObj.CreateCompatibleDC()
dataBitMap = win32ui.CreateBitmap()
dataBitMap.CreateCompatibleBitmap(dcObj, width, height)
cDC.SelectObject(dataBitMap)
cDC.BitBlt((0, 0), (width, height), dcObj, (0, 0), win32con.SRCCOPY)
# save the bitmap to a file
dataBitMap.SaveBitmapFile(cDC, output_file)
dcObj.DeleteDC()
cDC.DeleteDC()
win32gui.ReleaseDC(hwnd, wDC)
win32gui.DeleteObject(dataBitMap.GetHandle())
if __name__ == '__main__':
window_title = "Untitled - Notepad"
winHandle = win32gui.FindWindow(None, window_title)
if winHandle == 0:
raise RuntimeError(f"Window '{window_title}' is not opening!")
# Bring the window to foreground in case it is overlap by other windows
win32gui.SetForegroundWindow(winHandle)
# Do something with Notepad
windll.user32.SendMessageW(winHandle, win32con.WM_KILLFOCUS, None, None)
# Capture the window
getWindowScreenshot(winHandle, "output.bmp")
time.sleep(0.5)
getWindowScreenshot(winHandle, "output1.bmp")

Draw a Special text on a Picture with PIL

I just wanted to write some text on picture using PIL and Python 3.8.6 in my Discord Bot while a member joined but it did not shows correctly, Here is my code and result picture.
background = Image.open("./photos/Sans titre 1.png").convert("RGBA")
basewidth = 227
img = Image.open(BytesIO(response.content)).convert("RGBA")
wpercent = (basewidth/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
img = img.resize((basewidth,hsize), Image.ANTIALIAS)
cercle = Image.open("./photos/cercle_orange.png").convert("RGBA")
img_w, img_h = img.size
cr_w,cr_h = cercle.size
# make a blank image for the text, initialized to transparent text color
txt = Image.new("RGBA", background.size, (255,255,255,0))
msg = "WELCOME"
new_member = u"{}#{}".format(member.name,member.discriminator)
fnt = ImageFont.truetype("./fonts/DejaVuSans.ttf", 80)
fntname = ImageFont.truetype("./fonts/DejaVuSans.ttf",50)
# get a drawing context
d = ImageDraw.Draw(txt)
bg_w, bg_h = background.size
offset = ((bg_w - img_w) // 2, (bg_h - img_h) // 2)
w, h = d.textsize(msg,font=fnt)
w2, h2 = d.textsize(new_member,font=fntname)
d.text(((bg_w-w)/2,((bg_h-h)/2)+160), msg, font=fnt, fill='#FFAA39')
d.text((((bg_w-w2)/2),((bg_h-h2)/2)+220), new_member, font=fntname, fill=(255,255,255,255))
background.paste(profile, offset, profile)
my bot welcome picture in Discord
Discord Welcome Picture
i already search how to transfer the text to unicode and it didn't work however i changed the font that i use in my bot code, i want it to show the name 𝕯𝖆𝖗𝐀 𝔇𝔒𝕧𝒾𝖑 correctly in my code as this second picture from Koya Bot:
Koya Welcome Picture in Discord
Koya Welcome Picture
i Hope you can help me,Thank you guys for listening.
This behaviour of displaying squares typically happens when the font cannot render the specified characters, which could mean that the font is corrupted or simply that the specified font is missing glyphs for those specific characters. Most commonly used fonts have a wide range of glyphs that cover common scripts (latin, greek, hebrew, cyrillic, arabic, etc).
You might want to try changing the font to see if it that works, if it does, then the problem is the font, you might want to try finding another source for that font to see if it includes the necessary glyphs, or directly change the font.

Python win32gui app window flickers

I have been having a problem with win32gui while taking screenshot of certain application window.
My script (code below) take a screenshot of a window to analyze it. For certain windows it works perfectly, but I have just encountered one application that, while I have my script running the window that it takes screenshot from make the window flickers. (I keep seeing white flash on the whole window)
Anyone ever experienced it and had a solution for it?
def getImage(self,hwnd = None):
if hwnd == None:
hwnd = self.hwnd
self.whereIsWindow(hwnd)
left, top, right, bot = win32gui.GetWindowRect(hwnd)
w = right - left
h = bot - top
self.width = w
self.height = h
hwndDC = win32gui.GetWindowDC(hwnd)
mfcDC = win32ui.CreateDCFromHandle(hwndDC)
saveDC = mfcDC.CreateCompatibleDC()
saveBitMap = win32ui.CreateBitmap()
saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)
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)
win32gui.DeleteObject(saveBitMap.GetHandle())
saveDC.DeleteDC()
mfcDC.DeleteDC()
win32gui.ReleaseDC(hwnd, hwndDC)
I know the culprit are the last 5 lines, if i comment them out it stops flickering but it takes all the memory which is not an option.
I ended up putting more of a delay in my loop and there was no flickering at all.

Categories

Resources