在 QMovie 中加载动画 gif 数据

Loading animated gif data in QMovie

我是 Qt(特别是 PySide)的新手,我正在尝试编写一个脚本,将动画 gif 从文件加载到 QByteArray,然后再加载到 QMovie。从文件转到 QByteArray 的原因是因为我无法将该 gif 文件保存在内存中。我希望能够以这样一种方式存储动画 gif,以便稍后可以将其写出到 JSON 文件(因此是 QByteArray)。我尝试使用 here 中 ekhumoro 的回答,虽然没有出现错误,但动画 gif 也没有出现。 (那里可能有东西,但我什么也没看到。)简而言之,我的代码如下所示:

data = open("img.gif", "rb").read()
self.bArray = QtCore.QByteArray(data)
self.bBuffer = QtCore.QBuffer(self.bArray)
self.bBuffer.open(QtCore.QIODevice.ReadOnly)
self.movie = QtGui.QMovie(self.bBuffer, 'GIF')
self.movieLabel.setMovie(self.movie) # a QLabel
self.movie.start()

我想稍后将 self.bArray 的内容存储到 JSON 文件中。

当我为 QMovie 构造函数提供文件路径时,我可以看到动画 gif,但是我将无法将 gif 的内容保存到 JSON 文件。

我想知道数据是否未正确读入或未正确传递给 QMovie。

有什么想法吗?

谢谢!

这看起来像是一个 PySide 错误,因为相同的代码在 PyQt 中工作得很好。

该错误似乎出现在 QMovie 构造函数中,它不会从传递给它的设备中读取任何内容。解决方法是显式设置设备,如下所示:

import sys
from PySide import QtCore, QtGui
# from PyQt4 import QtCore, QtGui

app = QtGui.QApplication(sys.argv)

data = open('anim.gif', 'rb').read()
a = QtCore.QByteArray(data)
b = QtCore.QBuffer(a)

print('open: %s' % b.open(QtCore.QIODevice.ReadOnly))

m = QtGui.QMovie()
m.setFormat('GIF')
m.setDevice(b)

print('valid: %s' % m.isValid())

w = QtGui.QLabel()
w.setMovie(m)
m.start()

w.resize(500, 500)
w.show()
app.exec_()

print('pos: %s' % b.pos())

看来 ekhumoro 的解决方案是针对 PyQt4 的,gif 会在第一帧冻结。

我只想分享能够在 Python3 和 PyQt5 上工作的代码,并读取包含 base64 编码的 .gif 文件的 .py 文件,这样它甚至可以将图像打包成 .通过pyinstaller.exe文件。

这是代码,干杯!

from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import QtCore

import base64

def cv2ImageToBase64String(variableName, imagePath, outputPath):
    """
    Parameters: imagePath [str]  -> path of image including file extension
                outputPath [str] -> path of .py file including file extension
    """    
    # read image as binary
    with open(imagePath, "rb") as image:
        data = image.read()

    # turn binary data into string by base64
    base64Image = base64.b64encode(data)

    # save it in a .py file with a variable called "image"
    with open(outputPath, "a") as f:
        f.write(f"{variableName}={base64Image}\n")


class Main(QtWidgets.QDialog):
    def __init__(self, dataInByte):
        # inherit and init QDialog
        super().__init__()

        # layout setting
        layout = QtWidgets.QVBoxLayout()
        label  = QtWidgets.QLabel()
        self.setLayout(layout)
        layout.addWidget(label)
        
        # decode and transform the data type
        rawData = base64.b64decode(dataInByte.decode())
        data    = QtCore.QByteArray(rawData)
        buffer  = QtCore.QBuffer(data)

        # it seems like a bug here that it shows nothing since we put buffer into QMovie like the example below
        # example: movie = QtGui.QMovie(buffer)
        movie = QtGui.QMovie()
        movie.setDevice(buffer)
        
        # start movie
        label.setMovie(movie)
        movie.start()
        self.exec_()

if __name__ == "__main__":
    # step 1: encode your gif by base64
    cv2ImageToBase64String(variableName="dataInByte", imagePath = "./src/Assets/loading.gif", outputPath = "./encodedGif.py")

    # step 2: load your gif from .py file
    from encodedGif import dataInByte

    # step 3: start the app
    app = QtWidgets.QApplication([])
    main = Main(dataInByte = dataInByte)