tkinter bitmapimage "image doesn't exist" - python-3.x

So I had it working, not sure what I changed but maybe someone else can take a peek and see where the error is.
here is the code the image is made and set to display in
def app_openfile(self, w, o, s):
io_file = filedialog.askopenfilename()
self.hex_data=Util.openFile(io_file)
self.all_bin_data = Util.convertToBinary(self.hex_data)
self.bin_data = self.all_bin_data
##infor bar call goes here
self.bit_image = Util.makeImage(self.bin_data, w, o, s)
print(self.bit_image.size)
print(self.bit_image)
self.photo = ImageTk.BitmapImage(self.bit_image, background='white')
print(self.photo)
self.binViewBox.create_image((0,0), image=self.photo, anchor=N)
self.binViewBox.config(xscrollincrement=self.Scale,
yscrollincrement=self.Scale,
scrollregion=(0,
0,
math.ceil((int(w) * int(self.Scale))),
math.ceil(len(self.binData)/int(w)* int(self.Scale))))
Now in the Util.makeimage bit, I have it set to show before it returns to verify it makes an image, and it does. But for some reason I haven't figured out yet, is why its now throwing this error.
_tkinter.TclError: image "pyimage11" doesn't exist
this is the return of the print statement before the exception is thrown
making image 1000 0 1
(1000, 96)
"PIL.Image.Image image mode=1 size=1000x96 at 0xE1ADD30"
pyimage11
EDIT:
this is an example what it should produce, but isn't pushed to the tkinter canvas
enter image description here
Update as of 08/14/2018
def app_openfile():
io_file = filedialog.askopenfilename()
h_data=Util.openFile(io_file)
all_b_data = b_data = Util.convertToBinary(h_data)
all_b_data = b_data = Util.convertToBinary(h_data)
viewtest = Canvas(root, width=500, height=500,bd=0)
bimage = Util.makeImage(b_data, 800, 0, 5)
bimage = ImageTk.BitmapImage(bimage)
viewtest.create_image((0,0), image=bimage)
app_openfile()
root = Tk()
root.wm_title('PyDMT')
root.resizable(width=True, height=True)
root.mainloop()
Took out the class stuff to see if that was the issue, but still throws error.

Related

How do I restart my program without restarting the variable declarations

I'm still making my weather app and I need a function to change the City or Country, The problem is that I have to restart the program to display the changes but when I do restart- The default city gets loaded instead of the new one, I have tried many ways to fix this but they all didn't work, Thanks in advance!
# !/usr/bin/python3
#Please don't use my API-KEY for bad purposes, I have only included it to help run the code
import requests, json
from tkinter import *
import os
CITY = "Glasgow"
BASE_URL = "https://api.openweathermap.org/data/2.5/weather?"
URL = "https://api.openweathermap.org/data/2.5/weather?q=+" + CITY + "&units=metric&APPID=confedential"
response = requests.get(URL)
def func() :
def change():
y = Toplevel()
y.geometry("200x100")
en = Entry(y, width=10)
en.place(x=25, y=25)
en.focus()
def getr(e):
def restart():
x.destroy()
func()
CITY = en.get()
restart()
en.bind("<Return>", getr)
if response.status_code == 200:
data = response.json()
main = data['main']
temperature = main['temp']
humidity = main['humidity']
pressure = main['pressure']
report = data['weather']
print(f"{CITY:-^30}")
print(f"Temperature: {temperature}")
print(f"Humidity: {humidity}")
print(f"Pressure: {pressure}")
print(f"Weather Report: {report[0]['description']}")
rep = report[0]['main'].lower()
if "clear" in rep:
image = 'images/sunny.png'
if "cloud" in rep:
image = 'images/cloud.png'
if "rain" in rep:
image = 'images/rain.png'
if "thunder" in rep:
image = 'images/thunder.png'
if "mist" in rep:
image = 'images/mist.png'
if "snow" in rep:
image = 'images/snow.png'
x = Tk()
# Creating Menubar
menubar = Menu(x)
menubar.config(bg="#484848", fg="white", font=("Stencil Std", 10))
# Adding Help Menu
help_ = Menu(menubar, tearoff=0, bg="#484848", fg="white", font=("Stencil Std", 10))
menubar.add_cascade(label='Countries', menu=help_)
help_.add_command(label='Change Current Country', command=change)
help_.add_command(label='Show Current Country', command=None)
help_.add_separator()
help_.add_command(label='Change Timezone', command=None)
help_.add_command(label='Show Current Timezone', command=None)
help_.add_separator()
help_.add_command(label="Exit", command=x.destroy)
# display Menu
x.config(menu=menubar)
x.resizable(False, False)
gif = PhotoImage(file=image)
cvwid = gif.width()
cvhei = gif.height()
canvas = Canvas(x, width=cvwid, height=cvhei, bg='lightblue')
canvas.pack(fill=BOTH)
img = canvas.create_image(0, 0, image=gif, anchor=NW)
temp = canvas.create_text(cvwid / 2, 350, fill="White", font="Helvetica 30", text=str(int(temperature)) + "°C")
reportr = canvas.create_text(cvwid / 2, 400, fill="White", font="Helvetica 20", text=report[0]["main"])
x.title(f"{CITY:-^30}")
x.mainloop()
func()
The problem is that you assign response = requests.get(URL) only once. No matter how often you change the city, the response that was established with the parameter "Glasgow" will always stay the same.
The fastest fix without refactoring the whole codebase would be to make CITY and response global so you can modify them from within a function. For example:
CITY = "Glasgow"
URL = "https://api.openweathermap.org/data/2.5/weather?q=+{}&units=metric&APPID=confidential"
def get_response(city=CITY):
return requests.get(URL.format(city))
response = get_response()
Then you could global your variables in your getr(e) function like this.
def getr(e):
global CITY, response
CITY = en.get()
response = get_response(CITY)
restart()
This is a solution to the problem you currently have. However I would suggest, to go back to your codebase. With a good refactor you would not need this: You could think about seperating logic and ui, make your functions accept parameters and seperate them from each other, research how to update/change display values within a running Tk() mainloop instead of destroying and recalling it. Maybe it would help, to post your code on stackexchange for codereview.

_tkinter.TclError: couldn't open "ImmaginiDiProva/ImmagineProva1360x768.png": no such file or directory

I'm back here with a new error that I can't solve... it's a strange error, idk, I put the images in the same directory of the program, in the directory specified in the code...
Ah, I don't know, but this is all the code:
from tkinter import *
def toggle_fs():
"""
Function that enables fullscreen for the window I create
"""
state = False if root.attributes('-fullscreen') else True
root.attributes('-fullscreen', state)
if not state:
root.geometry('300x300+100+100')
print("Inserisci il nome della foto: ") # Enter the name of the image -> "ImmagineProva"
nomeImg = input()
def getImg(nomeImg):
"""
Function that obtaines the right image, because I have different images that are all the same picture but all are different in resolution (1360x768, 1920x1080...)
"""
# detect the resolution of the monitor
WIDTH, HEIGHT = root.winfo_screenwidth(), root.winfo_screenheight()
# Takes the right image thanks to its name and screen resolution took before
img = PhotoImage(file = "ImmaginiDiProva/" + nomeImg + str(WIDTH) + "x" + str(HEIGHT) + ".png")
# All the images have the same name "ImmagineProva" with the relative resolution
return img
root = Tk(screenName = "Prova")
root.attributes("-fullscreen", True)
canvas = Canvas(root, bg = "white")
canvas.pack(fill = BOTH, expand = True)
img = getImg(nomeImg)
canvas.create_image(0, 0, anchor = NW, image = img)
root.bind("<Escape>", toggle_fs())
mainloop()
I hope this is enough for you... I'm frustrated, I put the images everywhere and it doesn't recognize them, wtf O.o
I read the comments, so I post an image so you'll be able to see everything about the program, images...
An image of the folder of the program
Ah, I did what said the utent in the comment (I don't remember the nick and the page doesn't make me scroll up lol) -> import os; print(etc...) and raised the error FileNotFoundError: [WinError 3] Impossibile trovare il percorso specificato: 'ImmaginiDiProva'
Why this? there is also the folder in the image I posted... I don't understand ahahah
Thank you guys for your help, by the way <3

Is noLoop stopping execution of draw?

This is my first post here, so I apologize if I'm making any mistakes.
I recently started to study Processing in Python mode and I'm trying to develop a code that, after selecting an image from your computer, reads the colors and inserts them in a list. The final idea is to calculate the percentage of certain colors in the image. For this I am using the following code:
img = None
tam=5
cores_img = []
def setup():
size (500, 500)
selectInput(u"Escolha a ilustração para leitura de cores", "adicionar_imagens")
noLoop()
def adicionar_imagens(selection):
global img
if selection == None:
print(u"Seleção cancelada")
else:
print(u"Você selecionou " + selection.getAbsolutePath())
img = loadImage(selection.getAbsolutePath())
def draw():
if img is not None:
image (img, 0, 0)
for xg in range(0, img.width, tam):
x = map(xg, 0, img.width, 0, img.width)
for yg in range(0, img.height, tam):
y = map(yg, 0, img.height, 0, img.height)
cor = img.get(int(x), int(y))
cores_img.append(cor)
print (cores_img)
I'm using noLoop() so that the colors are added only once to the list. However, it seems that the draw is not running. It performs the setup actions, but when the image is selected, nothing happens. There is also no error message.
I'm completely lost about what might be happening. If anyone has any ideas and can help, I really appreciate it!
Calling noLoop() indeed stops the draw() loop from running, which means by the time you've selected and image nothing yould happen.
You can however manually call draw() (or redraw()) once the image is loaded:
img = None
tam=5
cores_img = []
def setup():
size (500, 500)
selectInput(u"Escolha a ilustração para leitura de cores", "adicionar_imagens")
noLoop()
def adicionar_imagens(selection):
global img
if selection == None:
print(u"Seleção cancelada")
else:
print(u"Você selecionou " + selection.getAbsolutePath())
img = loadImage(selection.getAbsolutePath())
redraw()
def draw():
if img is not None:
image (img, 0, 0)
for xg in range(0, img.width, tam):
x = map(xg, 0, img.width, 0, img.width)
for yg in range(0, img.height, tam):
y = map(yg, 0, img.height, 0, img.height)
cor = img.get(int(x), int(y))
cores_img.append(cor)
print (cores_img)
You should pay attention to a few details:
As the reference mentions, calling get() is slow: pixels[x + y * width] is faster (just remember to call loadPixels() if the array doesn't look right)
PImage already has a pixels array: calling img.resize(img.width / tam, img .height / tam) should downsample the image so you can read the same list
x = map(xg, 0, img.width, 0, img.width) (and similarly y) maps from one range to the same range which has no effect
e.g.
img = None
tam=5
cores_img = None
def setup():
size (500, 500)
selectInput(u"Escolha a ilustração para leitura de cores", "adicionar_imagens")
noLoop()
def adicionar_imagens(selection):
global img, cores_img
if selection == None:
print(u"Seleção cancelada")
else:
print(u"Você selecionou " + selection.getAbsolutePath())
img = loadImage(selection.getAbsolutePath())
print("total pixels",len(img.pixels))
img.resize(img.width / tam, img.height / tam);
cores_img = list(img.pixels)
print("resized pixels",len(img.pixels))
print(cores_img)
def draw():
pass
Update
I thought that calling noLoop on setup would make draw run once. Still
it won't print the image... I'm calling 'image (img, 0, 0)' at the end
of 'else', on 'def adicionar_imagens (selection)'. Should I call it
somewhere else?
think of adicionar_imagens time-wise, running separate to setup() and draw()
you are right, draw() should be called once (because of noLoop()), however it's called as soon as setup() completes but not later (as navigating the file system, selecting a file and confirming takes time)
draw() would need to be forced to run again after the image was loaded
Here's an updated snippet:
img = None
# optional: potentially useful for debugging
img_resized = None
tam=5
cores_img = None
def setup():
size (500, 500)
selectInput(u"Escolha a ilustração para leitura de cores", "adicionar_imagens")
noLoop()
def adicionar_imagens(selection):
global img, img_resized, cores_img
if selection == None:
print(u"Seleção cancelada")
else:
print(u"Você selecionou " + selection.getAbsolutePath())
img = loadImage(selection.getAbsolutePath())
# make a copy of the original image (to keep it intact)
img_resized = img.get()
# resize
img_resized.resize(img.width / tam, img.height / tam)
# convert pixels array to python list
cores_img = list(img.pixels)
# force redraw
redraw()
# print data
print("total pixels",len(img.pixels))
print("resized pixels",len(img.pixels))
# print(cores_img)
def draw():
print("draw called " + str(millis()) + "ms after sketch started")
# if an img was selected and loaded, display it
if(img != None):
image(img, 0, 0)
# optionally display resized image
if(img_resized != None):
image(img_resized, 0, 0)
Here are a couple of notes that may be helpful:
each pixel in the list is a 24 bit ARGB colour (e.g. all channels are stored in a single value). if you need individual colour channels remember you have functions like red(), green(), blue() available. (Also if that gets slow notice the example include faster versions using bit shifting and masking)
the Histogram example could be helpful. You would need to port from Java to Python syntax and use 3 histograms (one for each colour channel), however the principle of counting intensities is nicely illustrated

I need to make pytesseract.image_to_string faster

i'm capturing the screen and then reading text from it using tesseract to transform it to a string the problem is that it's to slow for what i need i'm doing about 5.6fps and I needed more like 10-20.(i didn't put the imports i used because u can just see them in the code)
i tried everithing i know and nothing helped
pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
time.sleep(7)
def getDesiredWindow():
"""Returns the top-left and bottom-right of the desired window."""
print('Click the top left of the desired region.')
pt1 = detectClick()
print('First position set!')
time.sleep(1)
print('Click the bottom right of the desired region.')
pt2 = detectClick()
print('Got the window!')
return pt1,pt2
def detectClick():
"""Detects and returns the click position"""
state_left = win32api.GetKeyState(0x01)
print("Waiting for click...")
while True:
a = win32api.GetKeyState(0x01)
if a != state_left: #button state changed
state_left = a
if a < 0:
print('Detected left click')
return win32gui.GetCursorPos()
def gettext(pt1,pt2):
# From the two input points, define the desired box
box = (pt1[0],pt1[1],pt2[0],pt2[1])
image = ImageGrab.grab(box)
return pytesseract.image_to_string(image)
"""this is the part where i need it to be faster"""
Hi my solution was to make the image smaller.
Yes it might affect the image_to_string result and make it inaccurate but in my case since my images were 1500 width I managed to get 3x speed with this.
Try to change basewidth and try again:
from PIL import Image
basewidth = 600
img = Image.open('yourimage.png')
wpercent = (basewidth/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
img = img.resize((basewidth, hsize), Image.ANTIALIAS)
img.save('yourimage.png')

How to get screenshot and change DPI on the clipboard?

Under Win7 I would like to get the content of a window on the clipboard and set/adjust the DPI setting on the clipboard and copy it to a final application.
The MCVE below is not yet working as desired.
There is an issue:
sometimes it can happen that apparently the window is not yet set to foreground and the ImageGrab.grab(bbox) gets the wrong content. Waiting for some time (2-5 sec) helps, but is not very practical. How to avoid or workaround this?
Here is the code:
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)
Edit:
also this attempt to improve still gets sometimes the wrong content. Maybe somebody can explain why?
win32gui.SetForegroundWindow(hwnd)
for i in range(1000):
print(i)
time.sleep(0.01)
if win32gui.GetForegroundWindow() == hwnd:
break
bbox = win32gui.GetWindowRect(hwnd)
Addition:
That's what I (typically) get when I remove the line with the delay time time.sleep(2).
Left: desired content, right: received content. How can I get a reliable capture of content the desired window? What's wrong with the code? The larger I set the delay time the higher the probability that I get the desired content. But I don't want to wait several seconds to be sure. How can I check whether the system is ready for a screenshot?
As discussed you can use the approach as discussed in below
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")
Thanks to #Tarun Lalwani pointing to
this answer, I finally have a code which is working for me for the time being. However, it seems to me quite lengthy with a lot of different modules. Maybe it still can be simplified. Suggestions are welcome.
Code:
### 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

Resources