Printing main window in PyQt - python

I need to be able to save the main window of a pyqt app in a PS or similar file format so that I can send it to a printer. I would just make a built in screen shot function but my main window exceeds the size of my screen. Anyone know of a way to capture the window in it's entirety or is there a prebuilt class that could do this?

QPixmap has the static method grabWidget.
Pointing this method at your window will give you a pixmap that you can save to a file or use for printing.
If calling from inside your main window class:
sshot = QPixmap.grabWidget(self)
sshot.save('sshot.png')

QPixmap.grabWiget has been deprecated. We can instead use QWidget.grab() function instead to capture window. However, it only captures the currently visible parts of the screen which can be a problem when you have a window with a scroll area. So the only method/hack that worked for me was to use ScrollArea's page step functionality paired with widget grab.
# Get total pages in window
page_count = self.scrollArea.verticalScrollBar().maximum() / self.scrollArea.verticalScrollBar().pageStep()
image_list = []
# iterate through each page step
for i in range(int(round(page_count)) + 1):
step = self.scrollArea.verticalScrollBar().pageStep() * i
self.scrollArea.verticalScrollBar().setValue(step)
# capture and save each image
self.scrollArea.grab().save(f"page - {i}.jpg", quality=100)
# convert all images to Pillow Image() to later convert to pdf
image_list.append(Image.open(f"report_page - {i}.jpg"))
# save as pdf file
pdf_file_name = f'pdf_file.pdf'
image_list[0].save(pdf_file_name, "PDF", resolution=100.0, save_all=True, append_images=image_list[1:])
# delete images if not neccessary
for i in range(len(image_list)):
os.unlink(f"page - {i}.jpg")
P.s. Please let me know if there a more elegant solution to this problem

Related

TypeError: 'PngImageFile' object is not callable

I am trying to put images into a scrollable frame. These images are stored locally which i am successful in retiring corresponding to their id. However the issue I am running into is that i cant work out how to resize them properly so they fit on the canvas. I am coding in Python 3.10 and using tkinter to create the GUI.
def open_image(location):
photo = Image.open('D:\ShopifyApp\designs\\'+ str(location))
resized = photo((10,5), Image.Resampling.LANCZOS)
image = ImageTk.PhotoImage(resized)
return image
This is the code that fetches the image, location is the name of the file, all the images are JPGs (I dont know if thats the issue).
for i in range(len(orderDF)):
Label(myframe, text = str(orderDF.loc[i]['orderID'])).pack()
prodImg = find_pic(orderDF.loc[i]['productID'])
img = open_image(prodImg)
Label(myframe,image=img).pack()
This is my loop which grabs the image location and sends it to open_image to later be put in label.

Tkinter image not adding to text widget

I am trying to make text widget that get images from reddit then displaying it on a text widget, but for some reason, with no error, the image is not displaying on the widget.
This is the part of my code that get the image from reddit and adding it on the widget.
subreddit = reddit.subreddit("MinecraftMemes")
filtered = [x for x in subreddit.top() if not x.stickied and not x.is_self]
url = filtered[random.randint(0, len(filtered) - 1)].url
url_type = self.get_url_type(url)
urllib.request.urlretrieve(url,f"minecraft{url_type}")
image = Image.open(f"minecraft{url_type}")
image.save('minecraft.png')
img = tkinter.PhotoImage(file=r"minecraft.png")
self.text_widget.image_create(END,image=img)
print("activated")
The activated is printed, the minecraft.png is seen on file explorer, so it is the part of the code with tkinter that is not working
I believe the issue is that the image is an object and it gets discarded when the code executes, so you might want to do self.img.

Use PNG files from a dictionary to display in a Image widget in PySimpleGUI (Python)

I have Python GUI using PySimpleGUI that needs to display multiple plots which I intend to navigate via a set of buttons. I know I can have all the plots saved as PNG in a given folder and simply load them in a Image object and use the Update method of the element to load a new image when a button is clicked.
Something like the below works well:
[sg.Image(filename=os.getcwd() + pngFileName, key='key1', size=(5, 6))]
where I need to pass a filename of the plot I want to read from my current directory and show in the Image widget.
But this means that I will have all the files saved in a folder while I would rather prefer to have all the PNGs in a dictionary and refer that dictionary when I need to pass a given filename to the sg.Image().
The advantage I see is that this way I don't have to occupy space on the hard drive to store the PNGs and also instead of having to write and then read from disk, I guess it will be faster to get the PNGs directly from the dictionary that is in memory at run time.
I am not able to achieve this as the code seems to expect a filename that has a specific path rather than passing a specific value of a dictionary containing PNGs.
How can I achieve this?
Question: Use PNG files from a dictionary to display in a Image widget in PySimpleGUI (Python)
The class Image is defined as:
class Image(Element):
def __init__(self, filename=None, data=None, ...):
"""
:param filename: (str) image filename if there is a button image.
GIFs and PNGs only.
:param data: Union[bytes, str] Raw or Base64 representation of the image
to put on button.
Choose either filename or data
You can do:
import PySimpleGUI as sg
import os
cwd = os.getcwd()
fname = 'image1.png'
with open('{}/{}'.format(cwd, fname)) as fh:
image1 = fh.read()
[sg.Image(data=image1, key='key1', size=(5, 6))]
Something like this should work (assuming two images:image1, image2):
import PySimpleGUI as sg
# All the stuff inside your window.
layout [
[sg.Image(data=image1, key='__IMAGE__', size=(5, 6))]
]
# Create the Window
window = sg.Window('Window Title', layout)
# Event Loop to process "events" and get the "values" of the inputs
while True:
event, values = window.read()
if event in (None, 'Cancel'): # if user closes window or clicks cancel
break
window.Element('_IMAGE_').Update(data=image2)
window.close()
One of the Demo Programs listed on the PySimpleGUI GitHub is Demo_Img_Viewer.py. In it you'll find a function that takes a filename and returns the data that you can pass to the update method of your Image element.
This function is part of that demo. It will render a file into the format that the update method expects.
from PIL import Image
def get_img_data(f, maxsize=(1200, 850)):
"""
Generate image data using PIL
"""
img = Image.open(f)
img.thumbnail(maxsize)
bio = io.BytesIO()
img.save(bio, format="PNG")
del img
return bio.getvalue()
You can loop through your files and "pre-render" them by calling this function and saving the results.
Then later you can update your image element with one of these pre-rendered images.
window['My Image Element Key'].update(data=rendered)

python module ffpyplayer showing or displaying video frames to screen

Using python module ffpyplayer, How can I see the frames or get the img object to display or show the video image/frames to the screen?, in the tutorial that I followed, it seems very simple, it reads the frames and plays oudio but (does not display) any video image or frame to the screen, only if I add the (print img, t) will print the frame info to the screen but not video image is displayed on the screen.
I being following tutorials from: https://pypi.python.org/pypi/ffpyplayer, and here: http://matham.github.io/ffpyplayer/player.html, and searched google but the only relevant results point to the same info, I am somewhat new to programming and python, and so maybe I am missing something that seems to be very simple but I can't figure it out myself.
I am using: windows 7 64bit, python 2.7.11 32bit.
Any Help will be appreciated thank you very much.
from ffpyplayer.player import MediaPlayer
vid = 'test_video.flv'
player = MediaPlayer(vid)
val = ''
while val != 'eof':
frame, val = player.get_frame()
if val != 'eof' and frame is not None:
img, t = frame
print img, t #This prints the image object
# display img #This does nothing!
Kivy already provides such a video player, based on ffpyplayer, for you.
It also has the necessary threads already setup for you, to deal with buttons, file reading, audio and timing.
Check this page:
https://kivy.org/docs/api-kivy.uix.videoplayer.html
To install kivy:
https://kivy.org/docs/installation/installation.html
Then you might wish to take a look at the code in:
<< python_path >>\lib\site-packages\kivy\uix\videoplayer.py
That example could be rather complex, so you can also look at this url:
How to play videos from the web like youtube in kivy
Finally, in case Kivy complains that you only have opengl 1.1 (as happened to me), you might try adding the following lines to your code:
from kivy.config import Config
Config.set('graphics', 'multisamples', '0')
These solved the problem to me.

Working with the Python graphics module: is there any way to save the current window as an image?

I'm working with the python graphics module. What I am trying to do is save the current window as an image. In the module there is an option to save an "image" as an image (image.save()). But that isn't helpful because it just saves an image you have already loaded. OR if you load a blank image like I did in hopes drawing over it would change that, surprise, surprise: you get a blank image saved. Here is my code:
from graphics import *
w = 300
h = 300
anchorpoint=Point(150,150)
height=300
width=300
image=Image(anchorpoint, height, width) #creates a blank image in the background
win = GraphWin("Red Circle", w, h)
# circle needs center x, y coordinates and radius
center = Point(150, 150)
radius = 80
circle = Circle(center, radius)
circle.setFill('red')
circle.setWidth(2)
circle.draw(win)
point= circle.getCenter()
print point
pointx= point.getX()
pointy= point.getY()
print pointx
print pointy
findPixel=image.getPixel(150,150)
print findPixel
image.save("blank.gif")
# wait, click mouse to go on/exit
win.getMouse()
win.close()
#######that's it#####
so again here is my problem: How do I save what is now on the screen as "blank.gif"
Thanks!
The objects you are drawing are based on Tkinter. I don't believe you are actually drawing on the base image, but rather simply creating Tkinter objects by using the "graphics" library. I also don't believe you can save a Tkinter to a "gif" file, though you can definitely save them in postscript format, then covert them to a gif format.
In order to do this, you will need python's PIL library.
If all of your objects are actually TKinter objeccts, you can simply save the objects.
Start by replacing this line of code:
image.save("blank.gif")
With the following:
# saves the current TKinter object in postscript format
win.postscript(file="image.eps", colormode='color')
# Convert from eps format to gif format using PIL
from PIL import Image as NewImage
img = NewImage.open("image.eps")
img.save("blank.gif", "gif")
If you need additional information, please check out http://www.daniweb.com/software-development/python/code/216929 - which is where I got the suggested code.
I'm sure there are more elegant solutions available than save/convert, but since I don't know a lot about TKinter - this is the only way I've found.
Hope it helps!

Categories