PyMuPDFでPDFをSVGに変換してPyQt5に表示する

2022/02/13 categories:Python| tags:Python|PyMuPDF|PyQt5|SVG|

PyMuPDFでPDFをSVGに変換して、PyQt5に表示するプログラムを作ってみました。

処理内容

PyMuPDFには、PDFのページをPixmapに変換する機能があり、それを利用するとPyQt5のQGraphicsViewにPDFを表示することが出来ます。しかしPixmapはラスター画像なので、ベクターのPDFをPixmapに変換してしまうとズームをしたときに表示が荒くなってしまいます。PyMuPDFにはPixmapへの変換のほかにSVGへの変換機能もあるようなので、SVGに変換してQGraphicsViewに表示してみました。

PyMuPDFでPDFをSVGに変換するコードは下記の通りで、変換後のsvg_stringはSVGデータの文字列です。

doc = fitz.open('test01.pdf')
page = doc.load_page(0)
svg_string = page.get_svg_image()

QtでSVGデータの文字列をQGraphicsViewに表示可能なデータに変化するためには以下の手順で変換すると良いようです。

実行結果

pixmapの表示では荒い画像が表示されていますが、SVGの表示ではズームしても描画が荒くなることが無いことが確認できます。しかし、PDFにフォントが埋め込まれていないからか、コンソールには以下のようなエラーがいくつか表示されていました。

qt.svg: link #font_0_4b is undefined!

Pythonコード

import fitz
import sys
from PyQt5 import QtWidgets, QtCore, QtGui, QtSvg

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.resize(600, 800)
        self.setWindowTitle('PyQt5 test of PyMuPDF pixmap svg')
        self.pixmap_view = GraphicsView()
        self.pixmap_view.setScene( QtWidgets.QGraphicsScene() )
        self.svg_view = GraphicsView()
        self.svg_view.setScene( QtWidgets.QGraphicsScene() )

        self.setCentralWidget( QtWidgets.QWidget() )
        self.centralWidget().setLayout( QtWidgets.QGridLayout() )
        self.centralWidget().layout().addWidget( QtWidgets.QLabel('Pixmap View'), 0, 0, 1, 1)
        self.centralWidget().layout().addWidget( QtWidgets.QLabel('SVG View'),    0, 1, 1, 1)
        self.centralWidget().layout().addWidget( self.pixmap_view,                1, 0, 1, 1)
        self.centralWidget().layout().addWidget( self.svg_view,                   1, 1, 1, 1)

        self.doc = fitz.open('test01.pdf')
        page = self.doc.load_page(0)
        self.set_pixmap(page)
        self.set_svg(page)

    def set_pixmap(self, page):
        pix = page.get_pixmap()
        byte_array = QtCore.QByteArray( pix.tobytes() )
        qpixmap = QtGui.QPixmap()
        qpixmap.loadFromData(byte_array)
        self.pixmap_view.scene().addPixmap(qpixmap)

    def set_svg(self, page):
        reader = QtCore.QXmlStreamReader( page.get_svg_image() )
        renderer = QtSvg.QSvgRenderer(reader)
        item = QtSvg.QGraphicsSvgItem()
        item.setSharedRenderer(renderer)
        self.svg_view.scene().addItem(item)

class GraphicsView(QtWidgets.QGraphicsView):
    dragged = QtCore.pyqtSignal(QtCore.QPointF, QtCore.QPointF)
    def __init__(self, *argv, **keywords):
        super(GraphicsView, self).__init__(*argv, **keywords)
        self._numScheduledScalings = 0
        self.points = []
        self.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(200,200,200)))
        self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)

    def wheelEvent(self, event):
        scale = 1 + event.angleDelta().y()/120 * 0.2
        self.scale(scale, scale)

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec()

Share post

Related Posts

Comments

comments powered by Disqus