'Pixmap' object has no attribute 'getImageData' - python

I am trying to create pdf reader in python and I have used tkPDFViewer library but when i run this according to tkPDFViewer library
and i used tkPDFViewer Library example at first it shows 'Page' object has no attribute 'getPixmap' but when i searched this problem i got an answer in stackoverflow and it said pix = page.get_pixmap() in code font i mean edit tkPDFViewer library by replacing getPixmap to get_pixmap() but when i change that it shows Pixmap' object has no attribute 'getImageData
how do I solve it?
from tkinter import *
from tkinter import filedialog
from tkPDFViewer import tkPDFViewer as pdf
import os
root = Tk()
root.geometry('630x700+400+100')
root.title('PDF viewer')
root.configure(bg='white')
def browseFiles():
filename = filedialog.askopenfilename(initialdir=os.getcwd(),
title='Select a pdf file',
filetypes=(('PDF File','.pdf'),
('PDF File','.PDF'),
('All File','.txt')))
v1 = pdf.ShowPdf()
v2 = v1.pdf_view(root,pdf_location=open(filename,'r'),
width=77,height=100)
v2.pack(pady=(0,0))
Button(root,text='Open',width=40,
command=browseFiles,
font='arial 20',bd=4).pack()
root.mainloop()
#and tkPDFViewer library after editing
try:
from tkinter import*
import fitz
from tkinter.ttk import Progressbar
from threading import Thread
import math
except Exception as e:
print(f"This error occured while importing neccesary modules or library {e}")
class ShowPdf():
img_object_li = []
def pdf_view(self,master,width=1200,height=600,pdf_location="",bar=True,load="after"):
self.frame = Frame(master,width= width,height= height,bg="white")
scroll_y = Scrollbar(self.frame,orient="vertical")
scroll_x = Scrollbar(self.frame,orient="horizontal")
scroll_x.pack(fill="x",side="bottom")
scroll_y.pack(fill="y",side="right")
percentage_view = 0
percentage_load = StringVar()
if bar==True and load=="after":
self.display_msg = Label(textvariable=percentage_load)
self.display_msg.pack(pady=10)
loading = Progressbar(self.frame,orient= HORIZONTAL,length=100,mode='determinate')
loading.pack(side = TOP,fill=X)
self.text = Text(self.frame,yscrollcommand=scroll_y.set,xscrollcommand= scroll_x.set,width= width,height= height)
self.text.pack(side="left")
scroll_x.config(command=self.text.xview)
scroll_y.config(command=self.text.yview)
def add_img():
precentage_dicide = 0
open_pdf = fitz.open(pdf_location)
for page in open_pdf:
pix = page.get_pixmap()
pix1 = fitz.Pixmap(pix,0) if pix.alpha else pix
img = pix1.getImageData("ppm")
timg = PhotoImage(data = img)
self.img_object_li.append(timg)
if bar==True and load=="after":
precentage_dicide = precentage_dicide + 1
percentage_view = (float(precentage_dicide)/float(len(open_pdf))*float(100))
loading['value'] = percentage_view
percentage_load.set(f"Please wait!, your pdf is loading {int(math.floor(percentage_view))}%")
if bar==True and load=="after":
loading.pack_forget()
self.display_msg.pack_forget()
for i in self.img_object_li:
self.text.image_create(END,image=i)
self.text.insert(END,"\n\n")
self.text.configure(state="disabled")
def start_pack():
t1 = Thread(target=add_img)
t1.start()
if load=="after":
master.after(250,start_pack)
else:
start_pack()
return self.frame
def main():
root = Tk()
root.geometry("700x780")
d = ShowPdf().pdf_view(root,pdf_location=r"D:\DELL\Documents\Encyclopedia GUI.pdf",width=50,height=200)
d.pack()
root.mainloop()
if __name__ == '__main__':
main()

please use
img = pix1.tobytes("ppm")
instead of
img = pix1.getImageData("ppm")
in line no 48 in tkPDFViewer library
after editing the tkPDFViewer library it will be looked like this
try:
from tkinter import*
import fitz
from tkinter.ttk import Progressbar
from threading import Thread
import math
except Exception as e:
print(f"This error occured while importing neccesary modules or library {e}")
class ShowPdf():
img_object_li = []
def pdf_view(self,master,width=1200,height=600,pdf_location="",bar=True,load="after"):
self.frame = Frame(master,width= width,height= height,bg="white")
scroll_y = Scrollbar(self.frame,orient="vertical")
scroll_x = Scrollbar(self.frame,orient="horizontal")
scroll_x.pack(fill="x",side="bottom")
scroll_y.pack(fill="y",side="right")
percentage_view = 0
percentage_load = StringVar()
if bar==True and load=="after":
self.display_msg = Label(textvariable=percentage_load)
self.display_msg.pack(pady=10)
loading = Progressbar(self.frame,orient= HORIZONTAL,length=100,mode='determinate')
loading.pack(side = TOP,fill=X)
self.text = Text(self.frame,yscrollcommand=scroll_y.set,xscrollcommand= scroll_x.set,width= width,height= height)
self.text.pack(side="left")
scroll_x.config(command=self.text.xview)
scroll_y.config(command=self.text.yview)
def add_img():
precentage_dicide = 0
open_pdf = fitz.open(pdf_location)
for page in open_pdf:
pix = page.get_pixmap()
pix1 = fitz.Pixmap(pix,0) if pix.alpha else pix
img = pix1.tobytes("ppm")
timg = PhotoImage(data = img)
self.img_object_li.append(timg)
if bar==True and load=="after":
precentage_dicide = precentage_dicide + 1
percentage_view = (float(precentage_dicide)/float(len(open_pdf))*float(100))
loading['value'] = percentage_view
percentage_load.set(f"Please wait!, your pdf is loading {int(math.floor(percentage_view))}%")
if bar==True and load=="after":
loading.pack_forget()
self.display_msg.pack_forget()
for i in self.img_object_li:
self.text.image_create(END,image=i)
self.text.insert(END,"\n\n")
self.text.configure(state="disabled")
def start_pack():
t1 = Thread(target=add_img)
t1.start()
if load=="after":
master.after(250,start_pack)
else:
start_pack()
return self.frame
def main():
root = Tk()
root.geometry("700x780")
d = ShowPdf().pdf_view(root,pdf_location=r"D:\DELL\Documents\Encyclopedia GUI.pdf",width=50,height=200)
d.pack()
root.mainloop()
if __name__ == '__main__':
main()

Related

how do i use tkinter to open a new script, then when closing the new window return to the first script?

these two scripts worked fine seperatly and after many differant approches i have got the page1 to open menu_func however when i close menu_func the window remains but deletes the photos etc?
i want the back command to return to the page1 script
i also get this error,
invalid command name "36335088time_now"
while executing
"36335088time_now"
("after" script)
not related to my actual problem but if anybody knows how to get rid of it help would be appreciated
1.page1 code
import tkinter as tk
from tkinter import *
from PIL import Image, ImageTk
from time import strftime
import subprocess
import menu_func
page1 = tk.Toplevel()
width_value=page1.winfo_screenwidth()
height_value=page1.winfo_screenheight()
page1.geometry('%dx%d-0+0' % (width_value, height_value))
page1.resizable(False, False)
BG1_img = Image.open('BG-BLK-1.png')
BG2_img = BG1_img.resize((width_value,height_value))
BG3_img = ImageTk.PhotoImage(BG2_img)
canvas = Canvas(page1)
canvas.pack(expand=True, fill=tk.BOTH)
limg = Label(canvas, i=BG3_img)
limg.pack()
SD1_img = Image.open('Bshut.png')
SD2_img = ImageTk.PhotoImage(SD1_img)
MU1_img = Image.open('./LIST.png')
MU2_img = ImageTk.PhotoImage(MU1_img)
def close():
page1.destroy()
#def MU_COMM():
# import menu_func.py
# page1.exit()
# exec(open('menu_func.py').read())
def time_now():
T_D = strftime('%A, %d %h %Y %H:%M:%S')
show_date.config(text = T_D)
show_date.after(1000, time_now)
exit_button = Button(canvas,image=SD2_img,
command=close,borderwidth='0',border='0',bg='#000000', highlightthickness='0')
exit_button.place(x=1700, y=900)
show_date = Label(canvas, font="Calibri, 46", fg="red", border='0',bg='#00090e')
show_date.place(x=440, y=960)
menu_button = Button(canvas, image=MU2_img, command= menu_func.menu, borderwidth=0,
bg='#000000', highlightthickness=0)
menu_button.place(x=50, y=900)
time_now()
page1.wm_attributes('-fullscreen', 'True')
page1.mainloop()
2.menu_func code
import tkinter as tk
from tkinter import *
from tkinter.messagebox import showinfo
from PIL import Image, ImageTk
from time import strftime
def menu():
pageM = tk.Toplevel()
w_v=pageM.winfo_screenwidth()
h_v=pageM.winfo_screenheight()
pageM.geometry('%dx%d-0+0' % (w_v, h_v))
pageM.resizable(False, False)
BG1m_img = Image.open('BG-BLK-1.png')
BG2m_img = BG1m_img.resize((w_v,h_v))
BG3m_img = ImageTk.PhotoImage(BG2m_img)
canvas = Canvas(pageM)
butt_W = int(w_v/28)
butt_H = int(h_v/31)
img_W = int(w_v/8)
img_H = int(h_v/4)
canvas = Canvas(pageM)
canvas.pack(expand=True, fill=tk.BOTH)
limg = Label(canvas, i=BG3m_img)
limg.pack()
def time_now():
T_D = strftime('%H:%M:%S')
show_time.config(text = T_D)
show_time.after(1000, time_now)
show_time = Label(canvas, font="Calibri, 46", fg="red", border='0',bg='#003a52')
show_time.place(x=int(w_v/2.3), y=int(h_v/50))
def call_COM():
showinfo(title='Information',message='phone Button clicked!')
call_img = Image.open('CALL.png')
cal1_img = call_img.resize((img_W,img_H))
cal2_img = ImageTk.PhotoImage(cal1_img)
button1=tk.Button(canvas, image=(cal2_img),borderwidth=0,bg='#000000', highlightthickness=0)
button1.place(x=int(w_v/5*1-(img_W)+50),y=int(h_v/3*0.8-(img_H/2)))
def map_COM():
exec(open("mapscreen.py").read())
c1_img = Image.open('comp.png')
c2_img = c1_img.resize((img_W,img_H))
c3_img = ImageTk.PhotoImage(c2_img)
button2=tk.Button(canvas, image=c3_img,command=map_COM,borderwidth=0,bg='#000000', highlightthickness=0)
button2.place(x=int(w_v/5*2-(img_W/1.2)+50),y=int(h_v/3*0.8-(img_H/2)))
def user_COM():
showinfo(title='Information',message='user Button clicked!')
u1_img = Image.open('user.png')
u2_img = u1_img.resize((img_W,img_H))
u3_img = ImageTk.PhotoImage(u2_img)
button3=tk.Button(canvas, image=u3_img,borderwidth=0,bg='#000000', highlightthickness=0)
button3.place(x=int(w_v/5*3-(img_W/1.5)+50),y=int(h_v/3*0.8-(img_H/2)))
def set_COM():
showinfo(title='Information',message='settings Button clicked!')
s1_img = Image.open('settings.png')
s2_img = s1_img.resize((img_W,img_H))
s3_img = ImageTk.PhotoImage(s2_img)
button4=tk.Button(canvas, image=s3_img,borderwidth=0,bg='#000000', highlightthickness=0)
button4.place(x=int(w_v/5*4-(img_W/2)+50),y=int(h_v/3*0.8-(img_H/2)))
def bro_COM():
exec(open('browser.py').read())
b1_img = Image.open('brows.png')
b2_img = b1_img.resize((img_W,img_H))
b3_img = ImageTk.PhotoImage(b2_img)
button5=tk.Button(canvas, image=b3_img,command=bro_COM,borderwidth=0,bg='#000000', highlightthickness=0)
button5.place(x=int(w_v/5*1-(img_W)+50),y=int(h_v/3*2.2-(img_H/1.5)))
def mus_COM():
showinfo(title='Information',message='Music Button clicked!')
m1_img = Image.open('music.png')
m2_img = m1_img.resize((img_W,img_H))
m3_img = ImageTk.PhotoImage(m2_img)
button6=tk.Button(canvas, image=m3_img,borderwidth=0,bg='#000000', highlightthickness=0)
button6.place(x=int(w_v/5*2-(img_W/1.2)+50),y=int(h_v/3*2.2-(img_H/1.5)))
def lite_COMM():
showinfo(title='Information',message='hardware Button clicked!')
t1_img = Image.open('Torch.png')
t2_img = t1_img.resize((img_W,img_H))
t3_img = ImageTk.PhotoImage(t2_img)
button7=tk.Button(canvas, image=t3_img,borderwidth=0,bg='#000000', highlightthickness=0)
button7.place(x=int(w_v/5*3-(img_W/1.5)+50),y=int(h_v/3*2.2-(img_H/1.5)))
def back_COM():
pageM.quit()
# exec(open('start_screen.py').read())
SD1_img = Image.open('home.png')
SD2_img = SD1_img.resize((img_W,img_H))
SD3_img = ImageTk.PhotoImage(SD2_img)
button8=tk.Button(canvas, image=SD3_img,command=back_COM,borderwidth=0,bg='#000000', highlightthickness=0)
button8.place(x=int(w_v/5*4-(img_W/2)+50),y=int(h_v/3*2.2-(img_H/1.5)))
time_now()
print(w_v/5*4-(img_W/2))
print(w_v/5*1-(img_W))
print(img_W)
print(h_v)
print(w_v)
pageM.mainloop()
the print(variables) arnt really part of the script there just there to help me work out locations of widgets!
i also understand this is a long code, if anybody know a way to make it shorter or more efficient please let me know, im not a programmer
thanks

Trying to make image slideshow with Tkinter (Python3)

I was trying to make an image slideshow program with Tkinter and Python3. No errors, but not showing the images that are inside my chosen directory. The other libraries that I have use are: PIL, random and glob. Your help will be greatly appreciated.
My system:
Ubuntu 20.04 LTS
Here is the code:
import tkinter as Tk
from PIL import Image, ImageTk
import random
import glob
class gui:
def __init__(self, mainwin):
self.counter = 0
self.mainwin = mainwin
self.mainwin.title("Our Photos")
self.colour()
self.mainwin.configure(bg = "yellow")
self.Frame = Tk.Frame(mainwin)
self.img = Tk.Label(self.Frame)
self.Frame.place(relheight = 0.85, relwidth = 0.9, relx = 0.05, rely = 0.05 )
self.img.pack()
self.pic()
def colour(self):
self.colours =['gray47','gray48']
c = random.choice(self.colours)
self.mainwin.configure(bg = c)
root.after(4000, self.colour)
def pic(self):
for name in glob.glob(r"/home/maheswar/Pictures/*"):
self.pic_list = []
val = name
self.pic_list.append(val)
if self.counter == len(self.pic_list) - 1:
self.counter = 0
else:
self.counter == self.counter + 1
self.file = self.pic_list[self.counter]
self.load = Image.open(self.file)
self.pic_width = self.load.size[0]
self.pic_height = self.load.size[1]
self.real_aspect = self.pic_width/self.pic_height
self.calc_width = int(self.real_aspect * 800)
self.load2 = self.load.resize((self.calc_width, 800))
self.render = ImageTk.PhotoImage(self.load2)
self.img.config(image = self.render)
self.img.image = self.render
root.after(2000, self.pic)
root = Tk.Tk()
myprog = gui(root)
root.geometry("1000x1000")
root.mainloop()
I found two mistaces - which probably you could see if you would use print() to debug code
First: you create list self.pic_list = [] inside loop so you replace previous content and this way you can get only one list. But you don't event need this loop but directly
self.pic_list = glob.glob(r"/home/maheswar/Pictures/*")
Second: you need = instead of == in line self.counter = self.counter + 1 or even simpler
self.counter += 1
Full working code with small changes.
import tkinter as Tk
from PIL import Image, ImageTk
import random
import glob
class GUI: # PEP8: `CamelCaseNames` for classes
def __init__(self, mainwin):
self.mainwin = mainwin
self.mainwin.title("Our Photos")
self.mainwin.configure(bg="yellow") # PEP8: inside `()` use `=` without spaces
self.counter = 0
self.frame = Tk.Frame(mainwin) # PEP8: `lower_case_names` for variables
self.frame.place(relheight=0.85, relwidth=0.9, relx=0.05, rely=0.05)
self.img = Tk.Label(self.frame)
self.img.pack()
self.pic_list = glob.glob("/home/maheswar/Pictures/*") # no need prefix `r`
self.colours = ['gray47', 'gray48'] # PEP8: space after `,`
self.colour()
self.pic()
def colour(self):
selected = random.choice(self.colours)
self.mainwin.configure(bg=selected)
root.after(4000, self.colour)
def pic(self):
filename = self.pic_list[self.counter]
image = Image.open(filename)
real_aspect = image.size[0]/image.size[1]
width = int(real_aspect * 800)
image = image.resize((width, 800))
self.photo = ImageTk.PhotoImage(image)
self.img.config(image=self.photo)
#self.img.image = self.render no need if you use `self.` to keep PhotoImage
self.counter += 1
if self.counter >= len(self.pic_list):
self.counter = 0
root.after(2000, self.pic)
# --- main ---
root = Tk.Tk()
myprog = GUI(root)
root.geometry("1000x1000")
root.mainloop()
PEP 8 -- Style Guide for Python Code

How to display an online .webp file in Tkinter using PIL

I have an animated .webp file which is hosted online and I tried to display it using Tkinter.Here is my code.
import urllib.request
from PIL import Image, ImageTk
root=tkinter.Tk()
u = urllib.request.urlopen("https://..../.....webp")
raw_data = u.read()
u.close()
im = Image.open(BytesIO(raw_data))
image = ImageTk.PhotoImage(im.resize((470,210)))
Label(root,image=image).pack()
root.mainloop()
This works without raising any errors but only displays one frame.Why is that so?
Is there any way how I can solve this issue
Based on #Atlas435's comment I have made a code which can display webp files in tkinter without downloading them.This is the code:
from io import BytesIO
from tkinter import *
import tkinter
import urllib.request
from PIL import Image, ImageTk
root=tkinter.Tk()
ar=0
import tkinter as tk
from PIL import Image, ImageTk
u = urllib.request.urlopen(url)
raw_data = u.read()
u.close()
im = Image.open(BytesIO(raw_data))
from itertools import count
class ImageLabel(tk.Label):
"""a label that displays images, and plays them if they are gifs"""
def load(self, im):
if isinstance(im, str):
im = im
self.loc = 0
self.frames = []
try:
for i in count(1):
self.frames.append(ImageTk.PhotoImage(im.copy().resize((470,210))))
im.seek(i)
except EOFError:
pass
try:
self.delay = im.info['duration']
except:
self.delay = 100
if len(self.frames) == 1:
self.config(image=self.frames[0])
else:
self.next_frame()
def unload(self):
self.config(image="")
self.frames = None
def next_frame(self):
if self.frames:
self.loc += 1
self.loc %= len(self.frames)
self.config(image=self.frames[self.loc])
self.after(self.delay, self.next_frame)
lbl = ImageLabel(root)
lbl.pack()
lbl.load(im)
root.mainloop()

Getting missing required dependencies Numpy while using Pyinstaller

I have created a mini app that is used for combining a bunch of excel files, but I cant execute the exe due to this error. What I find strange is that I am not even using Numpy in my script. I have installed and reinstalled numpy, but that did not fix the issue.
I created a virtual environment which has the following libraries installed.
Error on Executing exe
Here is my code:
import tkinter as tk
from tkinter.simpledialog import askstring, askinteger
from tkinter.messagebox import showerror
from tkinter import messagebox
from tkinter import filedialog
from tkinter import ttk
import os
from os import path
import pandas as pd
import fnmatch
import glob
import datetime
from datetime import datetime
import time
import calendar
class Splash(tk.Toplevel):
def __init__(self, parent, width=0.8, height=0.6, useFactor=True):
tk.Toplevel.__init__(self, parent)
self.title("Splash")
w = 300
h = 200
x = 50
y = 100
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
lbl = tk.Label(self,text="Combine Excel\n Version 1.0", bg = 'lightgrey' )
lbl.place(x=25, y=30)
self.master.overrideredirect(True)
self.lift()
## required to make window show before the program gets to the mainloop
self.update()
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.withdraw()
splash = Splash(self)
## simulate a delay while loading
time.sleep(1)
## finished loading so destroy splash
splash.destroy()
def getfiles():
listbox.delete(0,tk.END)
beginput = entry_1.get()
endinput = entry_2.get()
timefmt = "%m/%d/%y"
start = calendar.timegm(datetime.strptime(beginput, timefmt).timetuple())
end = calendar.timegm(datetime.strptime(endinput, timefmt).timetuple())
year = datetime.strptime(beginput, timefmt).strftime('%Y')
monthyr = datetime.strptime(beginput, timefmt).strftime('%m-%y') + ' Daily Collection'
yearmm = 'CA_LoanLvl_' + time.strftime("%Y%m%d")
yrnmsum = 'CA_Sum_' + time.strftime("%Y%m%d")
frame = pd.DataFrame()
list_ = []
cols = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,37,39,40,41,43,44,45,46,47,49,50,51,52,53,54,55,56,57]
path1 = path.join(r'\\corp.int\cms\DeptData\Monthly Reporting'
'\Daily Collection',year,monthyr,'Data')
pathexpt = path.join(r'\\corp.int\cms\DeptData\XX\DS\DataDownloads\Combine',yearmm)
pathexptsum = path.join(r'\\corp.int\cms\DeptData\XX\DS\DataDownloads\Combine',yrnmsum)
mypath = path1
def test(f):
if (not os.path.isfile(f)):
return 0
(mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(f)
return start<=ctime and end>=ctime
files = [f for f in glob.glob(os.path.join(mypath, "adv*")) if test(f)]
for item in files:
listbox.insert(tk.END, os.path.basename(item))
if __name__ == "__main__":
App()
# Create the main window
root = tk.Tk()
s = ttk.Style(root)
s.theme_use('clam')
root.title("Combine GNMA Files")
# set the root window's height, width and x,y position
# x and y are the coordinates of the upper left corner
w = 600
h = 400
x = 50
y = 100
# use width x height + x_offset + y_offset (no spaces!)
root.geometry("%dx%d+%d+%d" % (w, h, x, y))
# use a colorful frame
frame = tk.Frame(root, bg='darkblue')
frame.pack(fill='both', expand='yes')
label = tk.Label(frame, text="Start Date-mm/dd/yy", bg = 'lightblue')
label.place(x=20, y=30)
label2 = tk.Label(frame, text="End Date-mm/dd/yy", bg = 'lightblue')
label2.place(x=20, y=100)
entry_1 = tk.Entry(root)
entry_1.place(x=20,y=60)
entry_2 = tk.Entry(root)
entry_2.place(x=20,y=130)
btn_1 = tk.Button(root,text="Get Files", bg='light grey', command = getfiles)
btn_1.place(x=400, y=15)
listbox = tk.Listbox(root)
listbox.place(x=20, y=160, width = 400)
def on_closing():
if messagebox.askokcancel("Quit", "Do you want to quit?"):
root.destroy()
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()
If anyone runs across this, it seems it has to do with the version of Numpy that is causing errors with Pyinstaller. Take a look at the link below.
[How to fix 'Missing required dependencies ['numpy']' when running packaged app made with PyInstaller?

Python tkinter displaying images as movie stream

I am trying to screen-grab and display the image quickly like a recording. It seems to all function well except the display window is "blinking" occasionally with a white frame. It doesn't appear to be every update or every other frame, but rather every 5 or so. Any thoughts on the cause?
from tkinter import *
from PIL import Image, ImageGrab, ImageTk
import threading
from collections import deque
from io import BytesIO
class buildFrame:
def __init__(self):
self.root = Tk()
self.land = Canvas(self.root, width=800, height=600)
self.land.pack()
self.genObj()
self.thsObj = self.land.create_image(0,0, anchor='nw', image=self.imgObj)
self.sStream = deque()
self.spinning = True
prQ = threading.Thread(target=self.procQ)
prQ.start()
t1 = threading.Thread(target=self.snapS, args=[100])
t1.start()
def genObj(self):
tmp = Image.new('RGBA', (800, 600), color=(0, 0, 0))
self.imgObj = ImageTk.PhotoImage(image=tmp)
def procQ(self):
while self.spinning == True:
if self.sStream:
self.land.itemconfig(self.thsObj, image=self.sStream[0])
self.sStream.popleft()
def snapS(self, shtCount):
quality_val = 70
for i in range(shtCount):
mem_file = BytesIO()
ImageGrab.grab().save(mem_file, format="JPEG", quality=quality_val)
mem_file.seek(0)
tmp = Image.open(mem_file)
tmp.thumbnail([800, 600])
img = ImageTk.PhotoImage(tmp)
self.sStream.append(img)
mem_file.close()
world = buildFrame()
world.root.mainloop()
You should avoid making Tk calls on non GUI threads. This works much more smoothly if you get rid of the threads entirely and use after to schedule the image capture.
from tkinter import *
from PIL import Image, ImageGrab, ImageTk
from io import BytesIO
class buildFrame:
def __init__(self):
self.root = Tk()
self.land = Canvas(self.root, width=800, height=600)
self.land.pack()
tmp = Image.new('RGBA', (800, 600), color=(0, 0, 0))
self.imgObj = ImageTk.PhotoImage(image=tmp)
self.thsObj = self.land.create_image(0,0, anchor='nw', image=self.imgObj)
self.root.after("idle", self.snapS)
def snapS(self):
quality_val = 70
mem_file = BytesIO()
ImageGrab.grab().save(mem_file, format="JPEG", quality=quality_val)
mem_file.seek(0)
tmp = Image.open(mem_file)
tmp.thumbnail([800, 600])
self.image = ImageTk.PhotoImage(tmp)
self.land.itemconfig(self.thsObj, image=self.image)
mem_file.close()
self.root.after(10, self.snapS)
world = buildFrame()
world.root.mainloop()
If you really want to use threads, you should queue the image stream and have the UI thread deserialize the tkinter image from the stream and display it. So one thread for capture and the main thread doing display.
EDIT
The following version keeps using a thread for the capture and passes the data via the deque but ensures that only the Tk UI thread operates on Tk objects. This needs some work to avoid accumulating images in the queue but a delay of 100ms between images works fine for now.
from tkinter import *
from PIL import Image, ImageGrab, ImageTk
import sys, threading, time
from collections import deque
from io import BytesIO
class buildFrame:
def __init__(self):
self.root = Tk()
self.root.wm_protocol("WM_DELETE_WINDOW", self.on_destroy)
self.land = Canvas(self.root, width=800, height=600)
self.land.pack()
self.genObj()
self.thsObj = self.land.create_image(0,0, anchor='nw', image=self.imgObj)
self.sStream = deque()
self.image_ready = threading.Event()
self.spinning = True
self.prQ = threading.Thread(target=self.procQ)
self.prQ.start()
self.t1 = threading.Thread(target=self.snapS, args=[100])
self.t1.start()
def on_destroy(self):
self.spinning = False
self.root.after_cancel(self.afterid)
self.prQ.join()
self.t1.join()
self.root.destroy()
def genObj(self):
tmp = Image.new('RGBA', (800, 600), color=(0, 0, 0))
self.imgObj = ImageTk.PhotoImage(image=tmp)
def procQ(self):
while self.spinning == True:
if self.image_ready.wait(0.1):
print(len(self.sStream))
self.image_ready.clear()
self.afterid = self.root.after(1, self.show_image)
def show_image(self):
stream = self.sStream[0]
self.sStream.popleft()
tmp = Image.open(stream)
tmp.thumbnail([800, 600])
self.image = ImageTk.PhotoImage(tmp)
self.land.itemconfig(self.thsObj, image=self.image)
stream.close()
def snapS(self, shtCount):
quality_val = 70
while self.spinning:
mem_file = BytesIO()
ImageGrab.grab().save(mem_file, format="JPEG", quality=quality_val)
mem_file.seek(0)
self.sStream.append(mem_file)
self.image_ready.set()
time.sleep(0.1)
def main():
world = buildFrame()
world.root.mainloop()
return 0
if __name__ == '__main__':
sys.exit(main())

Categories

Resources