I'm trying to load an image (a jpeg in that case from bytes, as it is downloaded from web content).
I've already consulted some posts (for ex. 1 & 2), but for some reason I can't reproduce those answers, though JPEG is a wholy implemented format by PyQT4 as stated in the doc.
Let's say the picture to load in a QImage is this one.
I'm first downloading picture using request (though I'm certain this isn't related to this particular problem - I put it here mainly for portability reasons...).
import requests
r = requests.get(href, stream=True)
pict_bytes = r.content
After that, I can check this image is 100% correct using PIL and io modules :
from PIL import Image
import io
image = Image.open(io.BytesIO(pict_bytes))
image.show()
image.save('./test.jpeg')
It gets confusing afterwards, while trying to convert bytes to QImage :
from PyQt4 import QtGui
qim = QtGui.QImage()
qim.loadFromData(pict_bytes)
qim.loadFromData(..) returns False whatever the picture I chose, which I can't understand regarding to the function's description in the doc. I also checked directly from the file :
with open('./test.jpeg', 'rb') as f:
content = f.read()
qim.loadFromData(content)
Is there something obvious that I missed, or is this some strange comportment of PyQt4 with python 3 ? I would be grateful for your insights...
EDIT
I'm starting to believe there is some bug here (responses are all coherent with what I had already tried, in one way or another). Something doesn't feel quite right with the PyQt4 QImage (as well as QPixmap I suspect).
I'm currently using Windows 10 (and used Windows 2008 Server at the office), Winpython 3.6 x64, with PyQt4 4.11.4 installed from the unofficial depositery of Christoph Gohlke.
Your example is not very clear, but you always have to do the verifications, for this you can use assert
import sys
import requests
from PyQt4.QtGui import QImage, QApplication, QLabel, QPixmap
app = QApplication(sys.argv)
href = "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6f/OrteliusWorldMap.jpeg/800px-OrteliusWorldMap.jpeg"
r = requests.get(href, stream=True)
assert r.status_code == 200
img = QImage()
assert img.loadFromData(r.content)
w = QLabel()
w.setPixmap(QPixmap.fromImage(img))
w.show()
sys.exit(app.exec_())
Libraries:
requests 2.18.4
PyQt4 4.12.1
Python 2.7.14 and Python 3.6.4
It is always good to verify the appropriate formats, for this you must use:
print(QImageReader.supportedImageFormats())
Related
I'm using latest PyQt5 5.12.2 and I'm getting a weird message for every JPG picture that I'm showing in my script using QPixmap or QIcon.
qt.gui.icc: fromIccProfile: failed minimal tag size sanity
It isn't causing anything and the script works as it should. The problem is that I'm trying to display a huge amount of jpg pictures at the same time (as a photo gallery) so the window gets unresponsive until all messages are printed for each photo.
I tried for hours to find something useful online but unfortunately, it seems like nearly no one had the same issue. I'm using some PNG files too and they don't raise this error so I'm assuming that the problem is with jpg format. I tried using older pyqt5 versions but the only difference is that they are not printing the message but the problem remains.
Meanwhile, I tried to use this command to mute those messages since there is no use of them but the problem with unresponsive window for a few seconds remains even when it's not printing in the console.
def handler(*args):
pass
qInstallMessageHandler(handler)
EDIT: I tried converting these images to PNG but the error remains. So the JPG format wasn't the problem
I dug more deeply into ICC profiles and colour spaces and it seems like the colour space that your pictures are using is somehow non-standard for PyQt.
My solution is to convert these pictures to an ICC profile that is classical such as sRGB.
Here's an example function:
import io
from PIL import Image, ImageCms
def convert_to_srgb(file_path):
'''Convert PIL image to sRGB color space (if possible)'''
img = Image.open(file_path)
icc = img.info.get('icc_profile', '')
if icc:
io_handle = io.BytesIO(icc) # virtual file
src_profile = ImageCms.ImageCmsProfile(io_handle)
dst_profile = ImageCms.createProfile('sRGB')
img_conv = ImageCms.profileToProfile(img, src_profile, dst_profile)
icc_conv = img_conv.info.get('icc_profile','')
if icc != icc_conv:
# ICC profile was changed -> save converted file
img_conv.save(file_path,
format = 'JPEG',
quality = 50,
icc_profile = icc_conv)
Using PIL library is a fast and effective way how to properly resolve that error.
I am making a GUI Image Viewer with Pyside2 and was having a similar issue.
The images were loading fine and for my case there was no performances issues, but I keep getting these ICC warnings.
And I didn't want to fix the original files, because my app is supposed to be only a viewer.
I don't know it will help for your case, but my solution is to first load the image with pillow ImageQT module
from pathlib import Path
from PIL.ImageQt import ImageQt
def load_image(path):
if Path(path).is_file():
return ImageQt(path)
Then in my QT Widget class that display the image, I load this image on a empty QPixmap:
def on_change(self, path):
pixmap = QtGui.QPixmap()
image = load_image(path)
if image:
pixmap.convertFromImage(image)
if pixmap.isNull():
self.display_area_label.setText('No Image')
else:
self.display_area_label.setPixmap(pixmap)
I was following this tutorial on how to write a chess program in Python.
It uses the python-chess engine. The functions from that engine apparently return SVG data, that could be used to display a chessboard.
Code from the tutorial:
import chess
import chess.svg
from IPython.display import SVG
board = chess.Board()
SVG(chess.svg.board(board=board,size=400))
but when I run that code, all I see is a line in the terminal and no image.
<IPython.core.display.SVG object>
The tutorial makes a passing reference to Jupyter Notebooks and how they can be used to display SVG images. I have no experience with Jupyter Notebooks and even though I installed the package from pip and I dabbled a little into how to use it, I couldn't make much progress with regards to my original chessboard problem. But what I do have, is, experience with Qt development using C++ and since Qt has Python bindings, I decided to use those bindings.
Here is what I wrote:
import sys
import chess
import chess.svg
from PyQt5 import QtGui, QtSvg
from PyQt5.QtWidgets import QApplication
from IPython.display import SVG, display
app = QApplication(sys.argv);
board = chess.Board();
svgWidget = QtSvg.QSvgWidget(chess.svg.board(board=board, size=400));
#svgWidget.setGeometry(50,50,759,668)
svgWidget.show()
sys.exit(app.exec_())
A Qt window opens and shows nothing and in the terminal I see a lot of text - (apparently the SVG data is ending up in the console and not in the Qt window that is opening?).
I figured I have to install some SVG library under python so I installed drawSvg from pip. But it seems that library generates SVG images. And was of no use for me.
What is even more strange is, after seeing this SO question, I tried the following:
import sys
import chess
import chess.svg
from PyQt5 import QtGui, QtSvg
from PyQt5.QtWidgets import QApplication
from IPython.display import SVG, display
app = QApplication(sys.argv);
board = chess.Board();
svgWidget = QtSvg.QSvgWidget('d:\projects\python_chess\Zeichen_123.svg');
#svgWidget.setGeometry(50,50,759,668)
svgWidget.show()
sys.exit(app.exec_())
And it showed an image - an SVG image! What is the difference then between my case and this case?
Question: So my question is, what I am doing wrong in the case of the chessboard SVG data? Is the SVG data generated by the python-chess library not compatible with QtSvg?
I think you are getting confused by the scripting nature of Python. You say, you have experience with Qt development under C++. Wouldn't you create a main window widget there first and add to it your SVG widget within which you would call or load SVG data?
I would rewrite your code something like this.
import chess
import chess.svg
from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtWidgets import QApplication, QWidget
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(100, 100, 1100, 1100)
self.widgetSvg = QSvgWidget(parent=self)
self.widgetSvg.setGeometry(10, 10, 1080, 1080)
self.chessboard = chess.Board()
self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
self.widgetSvg.load(self.chessboardSvg)
if __name__ == "__main__":
app = QApplication([])
window = MainWindow()
window.show()
app.exec()
EDIT
It would be even better if you would add a paint function to the MainWindow class. Because for sure in future, you would want to repaint your board image many times, whenever you would move a piece. So I would do something like this.
def paintEvent(self, event):
self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
self.widgetSvg.load(self.chessboardSvg)
this is how i display SVG image with python, no need third party to do that.
First i save SVG image on disk
second i just call it like os.Startfile("exemple.svg")
Exemple:
boardsvg = svg.board(board(fen), size=600, coordinates=True)
with open('temp.svg', 'w') as outputfile:
outputfile.write(boardsvg)
time.sleep(0.1)
os.startfile('temp.svg')
that's it !
I just installed Python3 (3.5.2) and Pyqt5 (5.8.2) and I am following this tutorial to learn and make a GUI: http://zetcode.com/gui/pyqt5/firstprograms/
I'm trying to run the 2nd example but program is returning an error (which also happened on the 1st one, but since it had no image i took no notice) which is the following:
QApplication: invalid style override passed, ignoring it.
No XVisualInfo for format QSurfaceFormat(version 2.0, options QFlags<QSurfaceFormat::FormatOption>(), depthBufferSize -1, redBufferSize 1, greenBufferSize 1, blueBufferSize 1, alphaBufferSize -1, stencilBufferSize -1, samples -1, swapBehavior QSurfaceFormat::SwapBehavior(SingleBuffer), swapInterval 1, profile QSurfaceFormat::OpenGLContextProfile(NoProfile))
Falling back to using screens root_visual.
What is the meaning of this? Am i missing some packages?
I installed pyqt first with this command:
sudo -H pip3 install PyQt5
but Python3 was not acknowledging its existence so i searched the apt ubuntu repos and installed with:
sudo apt install python3-PyQt5
I also tried to reference the image by full path /foo/bar/image.png and nothing
What is the problem?
EDIT #1
The code that i am using is from example 2:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
ZetCode PyQt5 tutorial
This example shows an icon
in the titlebar of the window.
author: Jan Bodnar
website: zetcode.com
last edited: January 2015
"""
import sys
import os
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QIcon
base_dir = os.path.dirname(os.path.abspath(__file__))
os.chdir(base_dir)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 220)
self.setWindowTitle('Icon')
self.setWindowIcon(QIcon('image.png'))
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
After your post i reinstalled all my packages. The error is slightly different but the result is the same:
python3 example_02.py
QApplication: invalid style override passed, ignoring it.
Screencapture:
Notice that you are having no icons at all for all applications, not just for the PyQt icon example. This is because by default, certain environments turn off the icons in the titlebar. You have to enable them.
For instance in Xfce Desktop Environment, we can use the xfce4-settings-editor tool. In Settings/Settings Editor select xfwm4.
Find the show_app_icon option and check it. Change a theme back and forth to see the changes; they are not visible right away.
After this, you will see the icon in the titlebar of the PyQt5 example.
As for the warning; it is a recent thing and it has to do something
with the incopatibilities between Qt and GTK theming. I have not found
a solution to remove the warning so far.
So first off, you have no errors in your code. That's more akin to a warning but not even. What the following line is telling you
QApplication: invalid style override passed, ignoring it
is that your style option is invalid. If that were an error your script wouldn't run at all.
What I see right off the bat is this, you never supply a path to your image.
Now if the image is in the same root directory as the script then it should recognize said image without a path. But if you're attempting to do what I think you are it wouldn't work like that anyway. I think you're trying to create a launcher icon as well as a title bar icon, which typically goes hand in hand.
It appears to me that you've added it to Atom as some form of resource file. In which case most Ide's create a path for that file. Sometimes it's a path, other times a local url. QT its self does both when working with the QT creator.
I've never used Atom so I can't tell you how that works.
What I can say is this. you're using Linux which means .ico files are useless. I told you before linux doesn't handle icon files the same way windows does. This is most likely your problem.
So I sugesst you take a look at this
https://askubuntu.com/questions/476981/how-do-i-make-a-desktop-icon-to-launch-a-program
After you read that take a look at this if you have to https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Using_a_text_editor
Both of those links explain how to create a launcher icon for your program.
The following link will explain how to set the icon on the menu bar (title bar) in your program.
PyQt4 set windows taskbar icon
I hope this helps you out!
I study PyQt5 from author who give this question,also I have this problem that my icons can't show,I try some ways to catch it,that's what I do,hope it works!
First, it's important that you should use absolute path of the icons,for example:
self.setWindowIcon(QIcon("F:/Workspace/PyQT5-Study/images/web.png"))
but this not a good idea,so you can use second way like this:
from PyQt5.QtCore import QFileInfo
# ...
def initUI(self):
# ...
root = QFileInfo(__file__).absolutePath()
self.setWindowIcon(QIcon(root+'/images/web.png'))
# or
# import os
# current_dir = os.path.dirname(os.path.realpath(__file__))
# self.setWindowIcon(QIcon(os.path.join(current_dir, 'images/web.png')))
# ...
Last, if your icons also can't show, you should check this icon, if it's a legal icon.
In short, the normal images are unlimited so more, they can store many images and transform easily, but the icons have sure size,color kind,and more important,the icons have transparency, that means you can see the background, they have frame(not always straight). So you can use the web online tools to transform your image and try again,that really help me!
Also you should check the icon's source format, ensure you never change it, like .jpg to .png,and other. This will produce problem!
Wish you can solve the problem!
On windows be sure to use a real .ico file and a full path
iconpath = os.path.join(os.getcwd(),'qtlearning','assets','python.ico')
self.setWindowIcon(QIcon(iconpath))
I faced the exact same problem.
First things first. There is no setWindowIcon() method under QWidget or QMainWindow classes, in fact. you should be trying to set the QIcon at the Application level as follows.
app = QApplication(sys.argv)
app.setWindowIcon(QtGui.QIcon('home.png'))
Second, the icon thus created using this code does not reflect on the title of the window, instead it will reflect as an application icon as shown in the image below. the home.png
" icon for Application" in Ubuntu and not the " icon over the Window Title"
Finally, the path does not really matter, it can be an absolute path or a relative path, the system will consider either.
i just provided the full path of icon as simple as that
I found this question : Get screenshot on Windows with Python?
to take a screenshot of the full desktop:
import sys
from PyQt4.QtGui import QPixmap, QApplication
from datetime import datetime
date = datetime.now()
filename = date.strftime('%Y-%m-%d_%H-%M-%S.jpg')
app = QApplication(sys.argv)
QPixmap.grabWindow(QApplication.desktop().winId()).save(filename, 'jpg')
However, I would like to take a screenshot of an external window.
I have the hwnd of the window I want to take the screenshot off using win32gui.
According to the documentation for winId, the returned value is platform dependent.
So for Windows, it surely must (famous last words), return a hwnd and thus need no further conversion. If so, then try:
QPixmap.grabWindow(hwnd).save(filename, 'jpg')
(PS: I have actually tested this now on WinXP, and it works okay for me).
Ive tried the gtk method, but it is very slow and doesn't work for a 'large' image (120 kb)
import pygtk
pygtk.require('2.0')
import gtk
import os
def copy_image(f):
assert os.path.exists(f), "file does not exist"
clipboard = gtk.clipboard_get()
img = gtk.Image()
img.set_from_file(f)
clipboard.set_image(img.get_pixbuf())
clipboard.store()
Ive tried xclip and it only does text, so what other options are there? What does ubuntu use ?
One way of getting text from/to the clipboard is using XSel. It's not pretty and requires you to communicate with an external program. But it works and is quite fast.
Not sure if it's the best solution but I know it works :)
[edit]You're right, it seems that xsel does not support images.
In that case, how about a slightly modified GTK version.
def copy_image(f):
assert os.path.exists(f), "file does not exist"
image = gtk.gdk.pixbuf_new_from_file(f)
clipboard = gtk.clipboard_get()
clipboard.set_image(image)
clipboard.store()
Do note that you might have to change the owner if your program exits right away because of how X keeps track of the clipboard.
You might want to use the set_with_data method instead, but that's slightly more work (the image data is only sent when an application requests it, so it needs callback-functions). This has also advantages when you paste in the same application instead of to another application.