I made a graph in matplotlib, and wanted to make it in to an image and use it in my pyqt5 application. Someone suggested I use BytesIO for this. This is my code so far:
Drawing my graph:
...
plt.axis('equal')
buff = io.BytesIO()
plt.savefig(buff, format="png")
print(buff)
return buff
This is then called in another script:
def minionRatioGraphSetup(self, recentMinionRatioAvg):
image = minionRatioGraph(recentMinionRatioAvg)
label = QtWidgets.QLabel()
pixmap = QtGui.QPixmap(image)
label.setPixmap(pixmap)
label.setGeometry(QtCore.QRect(0,0,200,200))
It stops working at pixmap = QtGui.QPixmap(image) and I'm unsure why. Also: How could I place this in my MainWindow? because I doubt the code there will work lol
I'm sure there is a solution using a buffer. However, it seems rather complicated to get the byte format correct. So an alternative is to save the image to disk, and then load it from there.
import sys
from PyQt4 import QtGui
import matplotlib.pyplot as plt
import numpy as np
def minionRatioGraph():
plt.plot([1,3,2])
plt.savefig(__file__+".png", format="png")
class App(QtGui.QWidget):
def __init__(self):
super(App, self).__init__()
self.setGeometry(300, 300, 250, 150)
self.setLayout(QtGui.QVBoxLayout())
label = QtGui.QLabel()
label2 = QtGui.QLabel("Some other text label")
minionRatioGraph()
qimg = QtGui.QImage(__file__+".png")
pixmap = QtGui.QPixmap(qimg)
label.setPixmap(pixmap)
self.layout().addWidget(label)
self.layout().addWidget(label2)
self.show()
if __name__ == '__main__':
app = QtGui.QApplication([])
ex = App()
sys.exit(app.exec_())
a snippet using pillow, might help avoiding file io
im = PIL.Image.open("filename")
with BytesIO() as f:
im.save(f, format='png')
f.seek(0)
image_data = f.read()
qimg = QImage.fromData(image_data)
patch_qt = QPixmap.fromImage(qimg)
Here's a solution that only uses the buffer, you need to use PIL to create an ImageQT and then load it to the QPixap
import matplotlib.pyplot as plt
import io
from PIL.ImageQt import ImageQt
from PIL import Image
...
buff = io.BytesIO()
plt.savefig(buff, format="png")
img = Image.open(buff)
img_qt = ImageQt(img)
return img_qt
Then, in your GUI setup, you call your function to return the ImageQT and generate the QPixmap using QPixmap.fromImage()
def minionRatioGraphSetup(self, recentMinionRatioAvg):
image = minionRatioGraph(recentMinionRatioAvg)
label = QtWidgets.QLabel()
pixmap = QtGui.QPixmap.fromImage(image)
label.setPixmap(pixmap)
label.setGeometry(QtCore.QRect(0,0,200,200))
Related
this is my first post in stackoverflow, be patient :D
I want to build a little picture editor with python/kivy.
It is my first time using kivy. I got some experience in python.
I donĀ“t know how to update/reload an added image (widget). For example if I want to setup the contrast of a picture, the picture needs to be reloaded. I want to avoid saving pictures to disk, thats why I use BytesIO -> speed.
My solution right now is to delete the old image(widget) and add a new one. But I get in trouble if want to add other widgets, like buttons. So right now the code only works with one widget :-/
I tried also with kv language, but while I use BytesIO for processing my Image I cant use the kv/id function. Source only accepts string (path/files). But I got ByteArray.
Please take a look at my code, may you can show me how to access an added widget and update it later on in the running app. Or maybe there is a solution with kv and BytesIO?
Most of the code is gathered from web and put together...
from kivy.app import App
from kivy.uix.image import Image as UixImage
import rawpy
import imageio
from PIL import Image, ExifTags, ImageEnhance
import colorcorrect.algorithm as cca
from colorcorrect.util import from_pil, to_pil
from kivy.core.image import Image as CoreImage
import io
from kivy.clock import Clock
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
import kivy.uix.button as btn
import time
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.properties import NumericProperty, ObjectProperty
# used .raf (Fujifilm Raw) in this project
# https://filesamples.com/samples/image/raf/sample1.raf
class MyImageWidget(GridLayout):
def __init__(self,**kwargs):
super(MyImageWidget,self).__init__(**kwargs)
self.cols = 1 #1 column grid layout
self.contrast_counter = 0 # counter for contrast sweep
# Load Image (+standard features)
self.thumbnail_path = self.create_thumbnailpath() # set path to thumbnail (create thumbnail)
self.image = Image.open(self.thumbnail_path) # open thumbnail
self.image = self.set_size(self.image, 0.1) # minimize thumbail size for speed
self.image = self.whitebalance_auto(self.image) # do whitebalance on thumbnail
self.image = self.set_greyscale(self.image) # do black white conversion
# add Image to widget (kivy_image)
self.kivy_image = UixImage(source=self.thumbnail_path)
self.add_widget(self.kivy_image) # <--- how can i access this widget later?
# here a object is creatd for the widget, but how do I access it later on?
print(self.children)
# TEST: reload Image in cycles (to see changing contrast effect on picture)
Clock.schedule_interval(self.update_pic,0.025) # refreshrate of app (25ms)
def update_pic(self, dt):
new_image = self.process_image(self.image)
self.remove_widget(self.kivy_image) # current widget need to be removed, so that contrast sweep is shown
self.kivy_image = new_image
self.add_widget(self.kivy_image) # new processed widget need to be added, so that contrast sweep is shown
#self.kivy_image.reload() # <--- how can i reload the widget (kivy_image), to not need to remove the old widget?
#print("reloaded")
def create_thumbnailpath(self):
# https://filesamples.com/samples/image/raf/sample1.raf
path = 'lab2raw/sample1.raf'
with rawpy.imread(path) as raw_image:
thumbnail_path = self.create_thumbnail(raw_image)
return thumbnail_path
def process_image(self,image):
self.contrast_counter = self.contrast_counter + 0.02 # cycle through contrast levels 0.0 - 2.0
if self.contrast_counter >= 2:
self.contrast_counter = 0 # reset contrast level cycle
#image = self.set_size(image, 0.2)
#image = self.whitebalance_auto(image)
#print_exif(image)
#image = self.set_greyscale(image)
#image = self.set_contrast(image,1.1)
image = self.set_contrast(image,self.contrast_counter)
#image = self.set_sharpness(image, 2.0)
image_processed = self.create_kivy_image(image, 'png')
return image_processed
def create_kivy_image(self,image, file_extension):
imgByteArr = io.BytesIO()
image.save(imgByteArr, file_extension)
# Return a Kivy image set from a bytes variable
imgByteArr.seek(0)
buf = io.BytesIO(imgByteArr.read())
buf.seek(0)
cim = CoreImage(buf, ext=file_extension)
image_to_show = UixImage(source='')
image_to_show.texture = cim.texture
return image_to_show
def whitebalance_auto(self,im):
image = to_pil(cca.retinex_with_adjust(from_pil(im)))
return image
def create_thumbnail(self,raw_image):
# Create JPG Thumbnail
try:
thumb = raw_image.extract_thumb()
except rawpy.LibRawNoThumbnailError:
print('no thumbnail found')
except rawpy.LibRawUnsupportedThumbnailError:
print('unsupported thumbnail')
else:
if thumb.format == rawpy.ThumbFormat.JPEG:
with open('lab2raw/thumb.jpg', 'wb') as file:
file.write(thumb.data)
return 'lab2raw/thumb.jpg'
elif thumb.format == rawpy.ThumbFormat.BITMAP:
imageio.imsave('lab2raw/thumb.tiff', thumb.data)
return 'lab2raw/thumb.tiff'
def print_exif(self,image):
img_exif = image.getexif()
if img_exif is None:
print('Sorry, image has no exif data.')
else:
for key, val in img_exif.items():
if key in ExifTags.TAGS:
if ExifTags.TAGS[key]=="XMLPacket":
pass
elif ExifTags.TAGS[key]=="PrintImageMatching":
pass
else:
print(f'{ExifTags.TAGS[key]}:{val}')
def set_greyscale (self,im):
image = im.convert("L")
return image
def set_contrast (self,im, contrast_level):
enhancer = ImageEnhance.Contrast(im)
return_image = enhancer.enhance(contrast_level)
return return_image
def set_sharpness (self,im, sharpness_level):
enhancer = ImageEnhance.Sharpness(im)
image = enhancer.enhance(sharpness_level)
return image
def set_size(self,im, size_factor):
width, height = im.size
im = im.resize((round(width*size_factor),round(height*size_factor)),Image.ANTIALIAS)
return im
def save_jpg(self,im,quality, optimize, path):
im.save(path,optimize=optimize, quality=quality)
class MyApp(App):
def build(self):
return MyImageWidget()
if __name__ == "__main__":
MyApp().run()
You don't have to delete self.kivy_image and create it again but you have to replace .texture instead of full Image
self.kivy_image.texture = new_image.texture
And this means you can also reduce code in create_kivy_image. You can return CoreImage instead of UixImage. You may also use one io.BufferIO
def create_kivy_image(self, image, file_extension):
buf = io.BytesIO()
image.save(buf, file_extension)
buf.seek(0)
return CoreImage(buf, ext=file_extension)
def update_pic(self, dt):
new_image = self.process_image(self.image)
self.kivy_image.texture = new_image.texture
You could also use io.BytesIo() to create thumbnail and you wouldn't have to write in file. I could test it only with JPG but I don't know if it is correct for BITMAP
def raw_to_pil(self, path):
"""Load RAW and convert to PIL.Image."""
with rawpy.imread(path) as raw_image:
try:
thumb = raw_image.extract_thumb()
except rawpy.LibRawNoThumbnailError:
print('no thumbnail found')
except rawpy.LibRawUnsupportedThumbnailError:
print('unsupported thumbnail')
else:
if thumb.format == rawpy.ThumbFormat.JPEG:
print('thumbnail JPG')
return Image.open(io.BytesIO(thumb.data))
elif thumb.format == rawpy.ThumbFormat.BITMAP:
print('thumbnail BITMAP')
buf = io.BytesIO()
imageio.imsave(buf, thumb.data, 'tiff')
buf.seek(0)
return Image.open(buf)
My full code for tests:
import io
import time
import rawpy
import imageio
from PIL import Image, ExifTags, ImageEnhance
import colorcorrect.algorithm as cca
from colorcorrect.util import from_pil, to_pil
from kivy.app import App
from kivy.clock import Clock
from kivy.core.image import Image as CoreImage
from kivy.uix.image import Image as UixImage
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.properties import NumericProperty, ObjectProperty
# used .raf (Fujifilm Raw) in this project
# https://filesamples.com/samples/image/raf/sample1.raf
class MyImageWidget(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 1 # 1 column grid layout
self.contrast_counter = 0 # counter for contrast sweep
# add Image to widget (kivy_image)
self.kivy_image = UixImage() # empty image
self.add_widget(self.kivy_image)
self.image = self.raw_to_pil('lab2raw/sample1.raf')
if self.image: # can be `None`
self.image = self.set_size(self.image, 0.1) # minimize thumbail size for speed
#self.image = self.whitebalance_auto(self.image) # do whitebalance on thumbnail
self.image = self.set_greyscale(self.image) # do black white conversion
core_image = self.pil_to_kivy(self.image, 'png')
self.kivy_image.texture = core_image.texture
# TEST: reload Image in cycles (to see changing contrast effect on picture)
Clock.schedule_interval(self.update_pic, 0.025) # refreshrate of app (25ms)
def update_pic(self, dt):
if self.image: # can be `None`
pil_image = self.process_image(self.image)
core_image = self.pil_to_kivy(pil_image, 'png')
self.kivy_image.texture = core_image.texture
def process_image(self, image):
"""Process PIL.Image without converting to other formats."""
self.contrast_counter += 0.02 # cycle through contrast levels 0.0 - 2.0
if self.contrast_counter >= 2:
self.contrast_counter = 0 # reset contrast level cycle
#image = self.set_size(image, 0.2)
#image = self.whitebalance_auto(image)
#image = self.set_greyscale(image)
#image = self.set_contrast(image, 1.1)
image = self.set_contrast(image, self.contrast_counter)
#image = self.set_sharpness(image, 2.0)
#self.print_exif(image)
return image
def pil_to_kivy(self, image, file_extension):
"""Convert PIL.Image to CoreImage (to get later .texture)."""
buf = io.BytesIO()
image.save(buf, file_extension)
buf.seek(0)
return CoreImage(buf, ext=file_extension)
def raw_to_pil(self, path):
"""Load RAW and convert to PIL.Image. Can return `None`."""
with rawpy.imread(path) as raw_image:
try:
thumb = raw_image.extract_thumb()
except rawpy.LibRawNoThumbnailError:
print('no thumbnail found')
except rawpy.LibRawUnsupportedThumbnailError:
print('unsupported thumbnail')
else:
if thumb.format == rawpy.ThumbFormat.JPEG:
print('thumbnail JPG')
buf = io.BytesIO(thumb.data)
return Image.open(buf)
elif thumb.format == rawpy.ThumbFormat.BITMAP:
print('thumbnail BITMAP')
buf = io.BytesIO()
imageio.imsave(buf, thumb.data, 'tiff')
buf.seek(0)
return Image.open(buf)
#return Image.new('RGB', (1500, 1500), 'white') # create empty Image
def print_exif(self, im):
im_exif = im.getexif()
if im_exif is None:
print('Sorry, image has no exif data.')
else:
for key, val in im_exif.items():
if key in ExifTags.TAGS:
if ExifTags.TAGS[key] == "XMLPacket":
print('pass (XMLPacket)')
pass
elif ExifTags.TAGS[key] == "PrintImageMatching":
print('pass (PrintImageMatching)')
pass
else:
print(f'{ExifTags.TAGS[key]}:{val}')
# ---
def whitebalance_auto(self, im):
return to_pil(cca.retinex_with_adjust(from_pil(im)))
def set_greyscale(self, im):
return im.convert("L")
def set_contrast(self, im, contrast_level):
return ImageEnhance.Contrast(im).enhance(contrast_level)
def set_sharpness(self, im, sharpness_level):
return ImageEnhance.Sharpness(im).enhance(sharpness_level)
def set_size(self, im, factor):
return im.resize((round(im.width*factor), round(im.height*factor)), Image.ANTIALIAS)
def save_jpg(self, im, quality, optimize, path):
im.save(path, optimize=optimize, quality=quality)
class MyApp(App):
def build(self):
return MyImageWidget()
if __name__ == "__main__":
MyApp().run()
I have created a gif using pillow from some images and I am trying to copy this gif stored as a BytesIO object to the clipboard to save onto a presentation as a gif image. code below; where imageList = [] is a list of image file names.
any method of copying a gif to the clipboard from python would be helpful?! thanks
def copyGif(self):
imageList = []
gif = BytesIO()
imageList[0].save(gif, format='GIF', save_all=True, append_images=imageList[1:], optimize=False, duration=1000,
loop=0)
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardData(win32clipboard.CF_DIB, gif.getvalue())
win32clipboard.CloseClipboard()
Try it:
import sys
from PyQt5.Qt import *
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setGeometry(50, 50, 600, 600)
# Create a URL.
url1 = QUrl.fromLocalFile('Loader.gif')
url2 = QUrl.fromLocalFile('animated-dancing-image-0028.gif')
# Create MIME data with URL.
mime_data = QMimeData()
mime_data.setUrls([url1, url2])
self.labelList = [ i for i in range(len([url1, url2]))]
# Copy the MIME data to the clipboard.
clipboard = QApplication.clipboard()
clipboard.setMimeData(mime_data)
cm = clipboard.mimeData()
for i, m in enumerate(cm.urls()):
self.labelList[i] = QMovie(m.toLocalFile())
self.labelList[i].frameChanged.connect(self.repaint)
self.labelList[i].start()
def paintEvent(self, event):
currentFrame1 = self.labelList[0].currentPixmap()
currentFrame2 = self.labelList[1].currentPixmap()
frameRect2 = currentFrame2.rect()
frameRect2.moveCenter(self.rect().center())
if frameRect2.intersects(event.rect()):
painter = QPainter(self)
painter.drawPixmap(frameRect2.left(), frameRect2.top(), currentFrame2)
frameRect1 = currentFrame1.rect()
frameRect1.moveCenter(self.rect().center())
if frameRect1.intersects(event.rect()):
painter.drawPixmap(frameRect1.left(), frameRect1.top(), currentFrame1)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainWindow()
ex.show()
QTimer.singleShot(10000, app.quit)
sys.exit(app.exec_())
Currently I am working on a program, to display SIP-Trace log files. It is written in Python 3.7 using the PyQt 5(.11.3) module to load and operate a GUI made in QDesigner. As a main feature it parses the SIP-Trace file and displays it as a sequence diagram to a QGraphicsScene with QGraphicsObjects.
My problem lies in the following: For later reference, the content of the QGraphicsScene should be saved as an image file, like .jpg or .png. In the Qt/PyQt documentation I found the useful sounding command QGraphicsScene.render() which renders the content of the GraphicsScene to a saveable file like QImage using QPainter. In the last days, I tried a couple of ways/sample codes found here and elsewhere, but cannot render the GraphicsScene to the QImage much less to an image file. Since I am rather new to Python and Qt, I think I am missing some basic setting somewhere. Following is a minimal version of my code.
# -*- coding: utf8 -*-
"""Class for getting a sequence diagram of a sip traffic"""
from PyQt5.QtWidgets import *
from PyQt5 import uic
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class VoipGui(QMainWindow):
""" Class that handles the interaction with the UI """
def __init__(self, parent=None):
super().__init__(parent)
self.ui = uic.loadUi("main_window.ui", self)
self.showMaximized()
self.sequence_scene = QGraphicsScene()
self.ui.graphicsView.setScene(self.sequence_scene)
# self.sequence_scene.setSceneRect(0, 0, 990, 2048)
# sets the spacing between nodes
# For more than three nodes columns should be generated in a more automatic way
self.left_column = 51
self.middle_column = 381
self.right_column = 711
self.flow_height = 60 # Sets the spacing between the arrows in the flowchart
# --------------------------------- /class init and var set -------------------------------------------
self.actionOpenFile.triggered.connect(self.on_open_file)
self.actionCloseFile.triggered.connect(self.on_close_file)
self.actionCloseProgram.triggered.connect(self.close)
self.actionSaveFile.triggered.connect(self.save_seq_image)
# --------------------------------- /connecting slots and signals ----------------------------
def on_open_file(self):
"""Dummy version of the open file dialog"""
self.draw_node(self.left_column, 5, "192.168.2.1", 10)
self.draw_node(self.middle_column, 5, "192.168.2.22", 10)
def on_close_file(self):
self.ui.textBrowser.clear()
self.sequence_scene.clear()
def save_seq_image(self):
""" Here lies the problem: Save the rendered sequence scene to file for later use"""
rect_f = self.sequence_scene.sceneRect()
# rect = self.sequence_scene.sceneRect().toRect()
# img = QPixmap(rect.size())
img = QImage()
p = QPainter()
# p.setPen(QColor(255, 255, 255))
# p.setViewport(rect)
painting = p.begin(img)
self.sequence_scene.render(p, target=QRectF(img.rect()), source=rect_f)
p.end()
if painting:
print("Painter init pass")
elif not painting:
print("Painter init fail")
saving = img.save("save.jpg")
if saving:
print("Saving Pass")
elif not saving:
print("Saving Not Pass")
def draw_node(self, x_pos, y_pos, ip_address, y_stops):
"""Participating devices are displayed as these nodes"""
width = 100.0
height = 40.0
pc_box = QGraphicsRectItem(x_pos - 50, y_pos, width, height)
self.sequence_scene.addItem(pc_box)
pc_ip = QGraphicsTextItem("%s" % ip_address)
pc_ip.setPos(x_pos - 50, y_pos)
self.sequence_scene.addItem(pc_ip)
node_line = QGraphicsLineItem(x_pos, y_pos + 40, x_pos, y_pos + (y_stops * self.flow_height))
self.sequence_scene.addItem(node_line)
def show_window():
app = QApplication(sys.argv)
dialog = VoipGui()
dialog.show()
sys.exit(app.exec_())
if __name__ == "__main__":
show_window()
The problem is simple, in render() you are indicating that the size of the target is equal to that of QImage, and how size is QImage?, how are you using QImage() the size is QSize(0, 0) so it can not be generated the image, the solution is to create a QImage with a size:
def save_seq_image(self):
""" Here lies the problem: Save the rendered sequence scene to file for later use"""
rect_f = self.sequence_scene.sceneRect()
img = QImage(QSize(640, 480), QImage.Format_RGB888)
img.fill(Qt.white)
p = QPainter(img)
self.sequence_scene.render(p, target=QRectF(img.rect()), source=rect_f)
p.end()
saving = img.save("save.jpg")
print("Saving Pass" if saving else "Saving Not Pass")
Output:
I'm having trouble using a QTimer to repeatedly
generate a height-by-width-by-3 numpy array
convert the numpy array to a Qt-friendly image, and
display the image in the main Qt window
(Eventually the images won't be random.)
Here is the relevant code.
import numpy as np
from scipy.misc.pilutil import toimage
from PIL.ImageQt import ImageQt
def nparrayToQPixmap(arrayImage):
pilImage = toimage(arrayImage)
qtImage = ImageQt(pilImage)
qImage = QtGui.QImage(qtImage)
qPixmap = QtGui.QPixmap(qImage)
return qPixmap
class DetectionWidget(QtGui.QWidget):
def __init__(self):
super(DetectionWidget, self).__init__()
self.timer = QtCore.QTimer()
self.init_UI()
def init_UI(self):
self.setFixedSize(self.WIDTH, self.HEIGHT)
self.label = QtGui.QLabel(self)
self.label.resize(self.WIDTH, self.HEIGHT)
self.timer.timeout.connect(self.onTimeout)
self.timer.start(1000)
def onTimeout(self):
npImage = np.random.rand(self.HEIGHT, self.WIDTH, 3)
qPixmap = nparrayToQPixmap(npImage)
self.label.setPixmap(qPixmap)
This displays the FIRST image, but Python segmentation faults on the second iteration at self.label.setPixmap(qPixmap). Also, it segmentation faults even if I DON'T update the label but instead save the image using qPixmap.save(...), which makes me think that the resulting qPixmap is somehow corrupt after the first iteration.
I will appreciate any help!
This seems to be because of a bug in the QImage to QPixmap conversion. The code works as long as the QImage is in the right format..
qImage = QtGui.QImage(qtImage)
becomes
qImage = QtGui.QImage(qtImage).convertToFormat(QtGui.QImage.Format_ARGB32)
I have downloaded and installed python-poppler-qt4 and I am now trying out a simple Qt application to display a PDF page. I've followed what I've been able to get from the web, i.e. convert the PDF to a QImage, then to a QPixMap, but it doesn't work (all I get is a small window with no visible content).
I may have failed at some point (QImage.width() returns the width I have input, QPixMap.width() returns 0).
Here is the code:
#!/usr/bin/env python
import sys
from PyQt4 import QtGui, QtCore
import popplerqt4
class Application(QtGui.QApplication):
def __init__(self):
QtGui.QApplication.__init__(self, sys.argv)
self.main = MainWindow()
self.main.show()
class MainWindow(QtGui.QFrame):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.layout = QtGui.QVBoxLayout()
self.doc = popplerqt4.Poppler.Document.load('/home/benjamin/test.pdf')
self.page = self.doc.page(1)
# here below i entered almost random dpi, position and size, just to test really
self.image = self.page.renderToImage(150, 150, 0, 0, 210, 297)
self.pixmap = QtGui.QPixmap()
self.pixmap.fromImage(self.image)
self.label = QtGui.QLabel(self)
self.label.setPixmap(self.pixmap)
self.layout.addWidget(self.label)
self.setLayout(self.layout)
if __name__ == "__main__":
application = Application()
sys.exit(application.exec_())
Where does it go wrong here? Thanks.
I'm not familiar with python, so this might not apply directly, but QPixmap::fromImage is a static function that returns a QPixmap. So your code should read something like:
self.pixmap = QtGui.QPixmap.fromImage(self.image)
In other words, self.pixmap.fromImage doesn't change self.pixmap, it returns a new pixmap generated from the image you give it as a parameter.
yes i know that the question has an answer.
but i faced an error when i do the same thing in PyQt5 to show a PDF file as an image.
and i found the solution of my problem.
i posted this answer to help who faced the same problem.
if you want to show a pdf file in your PyQt5 program you have 2 choices
1 - the first one is to use web engine (but it takes a lot of resources from the ram)
2 - the second it to convert the pdf into an image and show it on label
i chose the second choice
and this is my code to show a pdf file as an image and to solve the problem :
from PyQt5 import QtWidgets,QtCore,QtGui
import pypdfium2 as pdfium
the_file = "My_PDF_File.pdf"
application = QtWidgets.QApplication([])
window = QtWidgets.QWidget()
window.resize(700,600)
window_layout = QtWidgets.QGridLayout()
label_to_display_the_page = QtWidgets.QLabel()
label_to_display_the_page.setAlignment(QtCore.Qt.AlignCenter)
label_to_display_the_page_geometry = label_to_display_the_page.geometry()
pdf = pdfium.PdfDocument(the_file)
page = pdf.get_page(1)
pil_image = page.render_topil(scale=1,rotation=0,crop=(0, 0, 0, 0),greyscale=False,optimise_mode=pdfium.OptimiseMode.NONE)
image = pil_image.toqimage()
label_pixmap = QtGui.QPixmap.fromImage(image)
size = QtCore.QSize(label_to_display_the_page_geometry.width()-50,label_to_display_the_page_geometry.height()-50)
label_to_display_the_page.setPixmap(label_pixmap.scaled(size,QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation))
window_layout.addWidget(label_to_display_the_page)
window.setLayout(window_layout)
window.show()
application.exec()