Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-qpageview for
openSUSE:Factory checked in at 2026-03-19 17:38:52
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-qpageview (Old)
and /work/SRC/openSUSE:Factory/.python-qpageview.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-qpageview"
Thu Mar 19 17:38:52 2026 rev:3 rq:1341042 version:1.0.3
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-qpageview/python-qpageview.changes
2025-04-08 17:52:11.820924649 +0200
+++
/work/SRC/openSUSE:Factory/.python-qpageview.new.8177/python-qpageview.changes
2026-03-19 17:40:46.218244709 +0100
@@ -1,0 +2,13 @@
+Wed Mar 18 22:15:13 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 1.0.3:
+ * Fix an OverflowError during rapid kinetic scrolling (#47).
+ * This fixes frescobaldi/frescobaldi#2130.
+ * Set resolution metadata in ImageExporter.export() (#45).
+ * This fixes frescobaldi/frescobaldi#2117 (copy to image
+ * always had 96dpi regardless of the set DPI).
+ * Fix a few missing imports (#43).
+ * Remove remaining pieces that depend on Poppler
+ * Raster page layout renamed to Grid Layout
+
+-------------------------------------------------------------------
Old:
----
qpageview-1.0.0.tar.gz
New:
----
qpageview-1.0.3.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-qpageview.spec ++++++
--- /var/tmp/diff_new_pack.JOpbL7/_old 2026-03-19 17:40:46.898272881 +0100
+++ /var/tmp/diff_new_pack.JOpbL7/_new 2026-03-19 17:40:46.902273047 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-qpageview
#
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
%{?!python_module:%define python_module() python3-%{**}}
Name: python-qpageview
-Version: 1.0.0
+Version: 1.0.3
Release: 0
Summary: Widget to display page-based documents for Qt5/PyQt5
License: GPL-3.0-only
++++++ qpageview-1.0.0.tar.gz -> qpageview-1.0.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/CHANGELOG.md
new/qpageview-1.0.3/CHANGELOG.md
--- old/qpageview-1.0.0/CHANGELOG.md 2025-01-06 14:42:37.000000000 +0100
+++ new/qpageview-1.0.3/CHANGELOG.md 2020-02-02 01:00:00.000000000 +0100
@@ -7,6 +7,30 @@
All notable changes to the qpageview project are documented in this file.
+## [1.0.3] - 2026-01-23
+
+### Fixed
+
+* Fix an OverflowError during rapid kinetic scrolling (#47).
+This fixes frescobaldi/frescobaldi#2130.
+
+## [1.0.2] - 2026-01-06
+
+### Fixed
+
+* Set resolution metadata in ImageExporter.export() (#45).
+This fixes frescobaldi/frescobaldi#2117 (copy to image
+always had 96dpi regardless of the set DPI).
+* Fix a few missing imports (#43).
+
+## [1.0.1] - 2025-07-04
+
+### Changed
+
+* Remove remaining pieces that depend on Poppler (#35)
+* Raster page layout renamed to Grid Layout (#40)
+
+
## [1.0.0] - 2025-01-06
### Added
@@ -80,3 +104,6 @@
[0.6.1]: https://github.com/frescobaldi/qpageview/compare/v0.6.0...v0.6.1
[0.6.2]: https://github.com/frescobaldi/qpageview/compare/v0.6.1...v0.6.2
[1.0.0]: https://github.com/frescobaldi/qpageview/compare/v0.6.2...v1.0.0
+[1.0.1]: https://github.com/frescobaldi/qpageview/compare/v1.0.0...v1.0.1
+[1.0.2]: https://github.com/frescobaldi/qpageview/compare/v1.0.1...v1.0.2
+[1.0.3]: https://github.com/frescobaldi/qpageview/compare/v1.0.2...v1.0.3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/PKG-INFO new/qpageview-1.0.3/PKG-INFO
--- old/qpageview-1.0.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
+++ new/qpageview-1.0.3/PKG-INFO 2020-02-02 01:00:00.000000000 +0100
@@ -0,0 +1,75 @@
+Metadata-Version: 2.4
+Name: qpageview
+Version: 1.0.3
+Summary: Widget to display page-based documents for Qt6/PyQt6
+Project-URL: Homepage, https://github.com/frescobaldi/qpageview
+Project-URL: Documentation, https://qpageview.org
+Project-URL: Issue tracker, https://github.com/frescobaldi/qpageview/issues
+Maintainer-email: Wilbert Berendsen <[email protected]>
+License: GPL v3
+License-File: LICENSE
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: GNU General Public License v3 or later
(GPLv3+)
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: POSIX
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Topic :: Multimedia :: Graphics
+Requires-Python: >=3.7
+Requires-Dist: pyqt6>=6.6
+Provides-Extra: cups
+Requires-Dist: pycups; extra == 'cups'
+Description-Content-Type: text/x-rst
+
+The qpageview module
+====================
+
+*qpageview* provides a page based document viewer widget for Qt6/PyQt6.
+
+It has a flexible architecture potentionally supporting many formats.
+Currently, it supports PDF and SVG documents and several image formats.
+
+.. code-block:: python
+
+ import qpageview
+
+ from PyQt6.QtWidgets import *
+ a = QApplication([])
+
+ v = qpageview.View()
+ v.show()
+ v.loadPdf("path/to/afile.pdf")
+
+ a.exec()
+
+
+`Homepage <https://qpageview.org/>`_ •
+`Development <https://github.com/frescobaldi/qpageview>`_ •
+`Download <https://pypi.org/project/qpageview/>`_ •
+`Documentation <https://qpageview.org/>`_ •
+`License <https://www.gnu.org/licenses/gpl-3.0>`_
+
+Features
+~~~~~~~~
+
+* Versatile View widget with many optional mixin classes to cater for
+ anything between basic or powerful functionality.
+* Rendering in a background thread, with smart priority control, so display of
+ large PDF documents remains fast and smooth.
+* Almost infinite zooming thanks to tile-based rendering and caching.
+* Magnifier glass.
+* Printing functionality, directly to cups or via Qt/QPrinter.
+* Can display pages originating from different documents at the same time.
+* Can show the difference between pages that are almost the same via
+ color composition.
+* And much more! And...all classes are extendable and heavily customizable,
+ so it is easy to inherit and add any functionality you want.
+
+Dependencies
+~~~~~~~~~~~~
+
+* Python 3.7+
+* Qt 6.6+
+* PyQt6
+* pycups (optionally, needed to print to a local CUPS server)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/docs/source/advanced.rst
new/qpageview-1.0.3/docs/source/advanced.rst
--- old/qpageview-1.0.0/docs/source/advanced.rst 2025-01-06
14:42:37.000000000 +0100
+++ new/qpageview-1.0.3/docs/source/advanced.rst 2020-02-02
01:00:00.000000000 +0100
@@ -184,7 +184,7 @@
- Show pages two by two
* - ``layout_raster``
- - Raster
+ - Grid Layout
- Show pages in a grid
* - ``vertical``
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/docs/source/conf.py
new/qpageview-1.0.3/docs/source/conf.py
--- old/qpageview-1.0.0/docs/source/conf.py 2025-01-06 14:42:37.000000000
+0100
+++ new/qpageview-1.0.3/docs/source/conf.py 2020-02-02 01:00:00.000000000
+0100
@@ -20,7 +20,6 @@
#autodoc_mock_imports = [
# 'sip',
# 'PyQt6',
-# 'popplerqt6',
#]
import os
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/docs/source/modoverview.rst
new/qpageview-1.0.3/docs/source/modoverview.rst
--- old/qpageview-1.0.0/docs/source/modoverview.rst 2025-01-06
14:42:37.000000000 +0100
+++ new/qpageview-1.0.3/docs/source/modoverview.rst 2020-02-02
01:00:00.000000000 +0100
@@ -21,8 +21,8 @@
magnifier.rst
multipage.rst
page.rst
+ pdf.rst
pkginfo.rst
- poppler.rst
printing.rst
rectangles.rst
render.rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/docs/source/pdf.rst
new/qpageview-1.0.3/docs/source/pdf.rst
--- old/qpageview-1.0.0/docs/source/pdf.rst 1970-01-01 01:00:00.000000000
+0100
+++ new/qpageview-1.0.3/docs/source/pdf.rst 2020-02-02 01:00:00.000000000
+0100
@@ -0,0 +1,8 @@
+The pdf module
+==============
+
+.. automodule:: qpageview.pdf
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/docs/source/poppler.rst
new/qpageview-1.0.3/docs/source/poppler.rst
--- old/qpageview-1.0.0/docs/source/poppler.rst 2025-01-06 14:42:37.000000000
+0100
+++ new/qpageview-1.0.3/docs/source/poppler.rst 1970-01-01 01:00:00.000000000
+0100
@@ -1,8 +0,0 @@
-The poppler module
-==================
-
-.. automodule:: qpageview.poppler
- :members:
- :undoc-members:
- :show-inheritance:
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/docs/source/rendering.rst
new/qpageview-1.0.3/docs/source/rendering.rst
--- old/qpageview-1.0.0/docs/source/rendering.rst 2025-01-06
14:42:37.000000000 +0100
+++ new/qpageview-1.0.3/docs/source/rendering.rst 2020-02-02
01:00:00.000000000 +0100
@@ -60,11 +60,6 @@
- :class:`~pdf.PdfDocument`
- PDF documents, multiple pages per file
- * - :mod:`~qpageview.poppler`
- - :class:`~poppler.PopplerPage`
- - :class:`~poppler.PopplerDocument`
- - PDF documents, multiple pages per file
-
* - :mod:`~qpageview.diff`
- :class:`~diff.DiffPage`
- :class:`~diff.DiffDocument`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/qpageview/__init__.py
new/qpageview-1.0.3/qpageview/__init__.py
--- old/qpageview-1.0.0/qpageview/__init__.py 2025-01-06 14:42:37.000000000
+0100
+++ new/qpageview-1.0.3/qpageview/__init__.py 2020-02-02 01:00:00.000000000
+0100
@@ -69,12 +69,6 @@
from . import util
from .pkginfo import version_string
-# loadPdf() uses this to determine if Poppler is available
-try:
- import popplerqt6
-except ImportError:
- popplerqt6 = None
-
class View(
@@ -92,17 +86,11 @@
"""Convenience function to create a Document with the specified PDF file.
The filename can also be a QByteArray or an already loaded
- popplerqt6.Poppler.Document (if Poppler is available) or
QPdfDocument instance.
"""
- # Use Poppler if it is available, otherwise fall back on QtPdf
- if popplerqt6:
- from . import poppler
- return poppler.PopplerDocument(filename, renderer)
- else:
- from . import pdf
- return pdf.PdfDocument(filename, renderer)
+ from . import pdf
+ return pdf.PdfDocument(filename, renderer)
def loadSvgs(filenames, renderer=None):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/qpageview/export.py
new/qpageview-1.0.3/qpageview/export.py
--- old/qpageview-1.0.0/qpageview/export.py 2025-01-06 14:42:37.000000000
+0100
+++ new/qpageview-1.0.3/qpageview/export.py 2020-02-02 01:00:00.000000000
+0100
@@ -28,7 +28,6 @@
from PyQt6.QtCore import QBuffer, QIODevice, QMimeData, QPoint, QSizeF, Qt,
QUrl
from PyQt6.QtGui import QDrag, QGuiApplication, QImage, QPageSize, QPdfWriter
-from . import poppler
from . import util
@@ -46,8 +45,6 @@
oversample = 1
grayscale = False
paperColor = None
- forceVector = True # force the render backend to be Arthur for
- # exporting PDF pages to vector-based formats
After setting the attributes, you call one or more of save(), copyData(),
copyFile(), mimeData() or tempFileMimeData(), which will trigger the export
@@ -65,7 +62,6 @@
oversample = 1
grayscale = False
paperColor = None
- forceVector = True # force the render backend to be Arthur for PDF pages
# properties of exporter:
wantsVector = True
@@ -103,10 +99,6 @@
p.renderer = self._page.renderer.copy()
p.renderer.paperColor = self.paperColor
p.renderer.antialiasing = self.antialiasing
- if self.forceVector and self.wantsVector and \
- isinstance(p, poppler.PopplerPage) and poppler.popplerqt6:
- p.renderer.printRenderBackend = \
- poppler.popplerqt6.Poppler.Document.ArthurBackend
return p
def autoCroppedRect(self):
@@ -258,6 +250,9 @@
i = i.convertToFormat(QImage.Format.Format_Grayscale8)
if self.autocrop:
i = i.copy(util.autoCropRect(i))
+ # needed for correct resolution metadata; see issue #44
+ i.setDotsPerMeterX(int(res / .0254))
+ i.setDotsPerMeterY(int(res / .0254))
return i
def image(self):
@@ -319,34 +314,8 @@
return buf.data()
def createDocument(self):
- from . import poppler
- return poppler.PopplerDocument(self.data(), self.renderer())
-
-
-class EpsExporter(AbstractExporter):
- """Export a rectangular area of a Page (or the whole page) to an EPS
file."""
- mimeType = "application/postscript"
- supportsGrayscale = False
- supportsOversample = False
- defaultExt = ".eps"
-
- def export(self):
- rect = self.autoCroppedRect()
- buf = QBuffer()
- buf.open(QBuffer.OpenModeFlag.WriteOnly)
- success = self.page().eps(buf, rect, self.resolution, self.paperColor)
- buf.close()
- if success:
- return buf.data()
-
- def createDocument(self):
- from . import poppler
- rect = self.autoCroppedRect()
- buf = QBuffer()
- buf.open(QBuffer.OpenModeFlag.WriteOnly)
- success = self.page().pdf(buf, rect, self.resolution, self.paperColor)
- buf.close()
- return poppler.PopplerDocument(buf.data(), self.renderer())
+ from . import pdf
+ return pdf.PdfDocument(self.data(), self.renderer())
def pdf(filename, pageList, resolution=72, paperColor=None):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/qpageview/locking.py
new/qpageview-1.0.3/qpageview/locking.py
--- old/qpageview-1.0.0/qpageview/locking.py 2025-01-06 14:42:37.000000000
+0100
+++ new/qpageview-1.0.3/qpageview/locking.py 2020-02-02 01:00:00.000000000
+0100
@@ -23,7 +23,7 @@
"""
Manages locking access (across threads) to any object.
-Use it for example to lock access to Poppler.Document instances.
+Use it for example to lock access to Document instances.
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/qpageview/page.py
new/qpageview-1.0.3/qpageview/page.py
--- old/qpageview-1.0.0/qpageview/page.py 2025-01-06 14:42:37.000000000
+0100
+++ new/qpageview-1.0.3/qpageview/page.py 2020-02-02 01:00:00.000000000
+0100
@@ -308,39 +308,6 @@
pdf.setPageLayout(layout)
return self.output(pdf, source, paperColor)
- def eps(self, filename, rect=None, resolution=72.0, paperColor=None):
- """Create a EPS (Encapsulated Postscript) file for the selected rect
or the whole page.
-
- This needs the popplerqt6 module.
- The filename may be a string or a QIODevice object. The rectangle is
- relative to our top-left position. Normally vector graphics are
- rendered, but in cases where that is not possible, the resolution will
- be used to determine the DPI for the generated rendering.
-
- """
- buf = QBuffer()
- buf.open(QBuffer.OpenModeFlag.WriteOnly)
- success = self.pdf(buf, rect, resolution, paperColor)
- buf.close()
- if success:
- from . import poppler
- for pdf in poppler.PopplerPage.load(buf.data()):
- ps = pdf.document.psConverter()
- ps.setPageList([pdf.pageNumber+1])
- if isinstance(filename, str):
- ps.setOutputFileName(filename)
- else:
- ps.setOutputDevice(filename)
- try:
- ps.setPSOptions(ps.PSOption(ps.Printing |
ps.StrictMargins))
- ps.setPSOptions(ps.PSOption(ps.Printing | ps.StrictMargins
| ps.PrintToEPS))
- except AttributeError:
- pass
- ps.setVDPI(resolution)
- ps.setHDPI(resolution)
- return ps.convert()
- return False
-
def svg(self, filename, rect=None, resolution=72.0, paperColor=None):
"""Create a SVG file for the selected rect or the whole page.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/qpageview/pdf.py
new/qpageview-1.0.3/qpageview/pdf.py
--- old/qpageview-1.0.0/qpageview/pdf.py 2025-01-06 14:42:37.000000000
+0100
+++ new/qpageview-1.0.3/qpageview/pdf.py 2020-02-02 01:00:00.000000000
+0100
@@ -25,11 +25,10 @@
"""
-import contextlib
import weakref
import platform
-from PyQt6.QtCore import Qt, QCoreApplication, QModelIndex, QRect, QRectF,
QSize
+from PyQt6.QtCore import Qt, QByteArray, QCoreApplication, QModelIndex, QRect,
QRectF, QSize, QUrl
from PyQt6.QtGui import QPainter
from PyQt6.QtPdf import QPdfDocument, QPdfDocumentRenderOptions, QPdfLinkModel
@@ -40,7 +39,7 @@
from . import render
-# store the links in the page of a Poppler document as long as the document
exists
+# store the links in the page of a document as long as the document exists
_linkscache = weakref.WeakKeyDictionary()
@@ -187,7 +186,7 @@
self._document = None
def invalidate(self):
- """Reimplemented to clear the Poppler Document reference."""
+ """Reimplemented to clear the Document reference."""
super().invalidate()
self._document = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/qpageview/pkginfo.py
new/qpageview-1.0.3/qpageview/pkginfo.py
--- old/qpageview-1.0.0/qpageview/pkginfo.py 2025-01-06 14:42:37.000000000
+0100
+++ new/qpageview-1.0.3/qpageview/pkginfo.py 2020-02-02 01:00:00.000000000
+0100
@@ -21,4 +21,4 @@
"""Version information on the qpageview package."""
-version_string = "1.0.0"
+version_string = "1.0.3"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/qpageview/poppler.py
new/qpageview-1.0.3/qpageview/poppler.py
--- old/qpageview-1.0.0/qpageview/poppler.py 2025-01-06 14:42:37.000000000
+0100
+++ new/qpageview-1.0.3/qpageview/poppler.py 1970-01-01 01:00:00.000000000
+0100
@@ -1,351 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# This file is part of the qpageview package.
-#
-# Copyright (c) 2016 - 2019 by Wilbert Berendsen
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 3
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-# See http://www.gnu.org/licenses/ for more information.
-
-"""
-Interface with popplerqt6, popplerqt6-specific classes etc.
-
-This module depends on popplerqt6, although it can be imported when
-popplerqt6 is not available.
-
-This module is no longer used, but is being kept for now as a
-reference for implementing the new QtPdf-based backend in pdf.py.
-
-"""
-
-import contextlib
-import weakref
-
-from PyQt6.QtCore import Qt, QRectF
-from PyQt6.QtGui import QRegion, QPainter, QPicture, QTransform
-
-try:
- import popplerqt6
-except ImportError:
- popplerqt6 = None
-
-from . import document
-from . import page
-from . import link
-from . import locking
-from . import render
-
-from .constants import (
- Rotate_0,
- Rotate_90,
- Rotate_180,
- Rotate_270,
-)
-
-
-
-# store the links in the page of a Poppler document as long as the document
exists
-_linkscache = weakref.WeakKeyDictionary()
-
-
-class Link(link.Link):
- """A Link that encapsulates a Poppler.Link object."""
- def __init__(self, linkobj):
- self.linkobj = linkobj
- self.area = link.Area(*linkobj.linkArea().normalized().getCoords())
-
- @property
- def fileName(self):
- """The file name if this is an external link."""
- return self.linkobj.fileName() if self.linkobj.isExternal() else ""
-
- @property
- def isExternal(self):
- """Indicates whether this is an external link."""
- return self.linkobj.isExternal()
-
- @property
- def targetPage(self):
- """If this is an internal link, the page number to which the
- link should jump; otherwise -1."""
- if (isinstance(self.linkobj, popplerqt6.Poppler.LinkGoto)
- and not self.linkobj.isExternal()):
- return self.linkobj.destination().pageNumber()
- else:
- return -1
-
- @property
- def url(self):
- """The url the link points to."""
- if isinstance(self.linkobj, popplerqt6.Poppler.LinkBrowse):
- return self.linkobj.url()
- return ""
-
-
-class PopplerPage(page.AbstractRenderedPage):
- """A Page capable of displaying one page of a Poppler.Document instance.
-
- It has two additional instance attributes:
-
- `document`: the Poppler.Document instance
- `pageNumber`: the page number to render
-
- """
- def __init__(self, document, pageNumber, renderer=None):
- super().__init__(renderer)
- self.document = document
- self.pageNumber = pageNumber
- self.setPageSize(document.page(pageNumber).pageSizeF())
-
- @classmethod
- def loadPopplerDocument(cls, document, renderer=None, pageSlice=None):
- """Convenience class method yielding instances of this class.
-
- The Page instances are created from the document, in page number order.
- The specified Renderer is used, or else the global poppler renderer.
- If pageSlice is given, it should be a slice object and only those pages
- are then loaded.
-
- """
- it = range(document.numPages())
- if pageSlice is not None:
- it = it[pageSlice]
- for num in it:
- yield cls(document, num, renderer)
-
- @classmethod
- def load(cls, filename, renderer=None):
- """Load a Poppler document, and yield of instances of this class.
-
- The filename can also be a QByteArray or a popplerqt6.Poppler.Document
- instance. The specified Renderer is used, or else the global poppler
- renderer.
-
- """
- doc = load(filename)
- return cls.loadPopplerDocument(doc, renderer) if doc else ()
-
- def mutex(self):
- """No two pages of same Poppler document are rendered at the same
time."""
- return self.document
-
- def group(self):
- """Reimplemented to return the Poppler document our page displays a
page from."""
- return self.document
-
- def ident(self):
- """Reimplemented to return the page number of this page."""
- return self.pageNumber
-
- def text(self, rect):
- """Returns text inside rectangle."""
- rect = self.mapFromPage(self.pageWidth, self.pageHeight).rect(rect)
- with locking.lock(self.document):
- page = self.document.page(self.pageNumber)
- return page.text(rect)
-
- def links(self):
- """Reimplemented to use a different caching mechanism."""
- document, pageNumber = self.document, self.pageNumber
- try:
- return _linkscache[document][pageNumber]
- except KeyError:
- with locking.lock(document):
- links = link.Links(map(Link,
document.page(pageNumber).links()))
- _linkscache.setdefault(document, {})[pageNumber] = links
- return links
-
-
-class PopplerDocument(document.SingleSourceDocument):
- """A lazily loaded Poppler (PDF) document."""
- pageClass = PopplerPage
-
- def __init__(self, source=None, renderer=None):
- super().__init__(source, renderer)
- self._document = None
-
- def invalidate(self):
- """Reimplemented to clear the Poppler Document reference."""
- super().invalidate()
- self._document = None
-
- def createPages(self):
- doc = self.document()
- if doc:
- return self.pageClass.loadPopplerDocument(doc, self.renderer)
- return ()
-
- def document(self):
- """Return the Poppler Document object.
-
- Returns None if no source was yet set, and False if loading failed.
-
- """
- if self._document is None:
- source = self.source()
- if source:
- self._document = load(source) or False
- return self._document
-
-
-class PopplerRenderer(render.AbstractRenderer):
- if popplerqt6:
- renderBackend = popplerqt6.Poppler.Document.SplashBackend
- printRenderBackend = popplerqt6.Poppler.Document.SplashBackend
- else:
- renderBackend = printRenderBackend = 0
-
- oversampleThreshold = 96
-
- def render(self, page, key, tile, paperColor=None):
- """Generate an image for the Page referred to by key."""
- if paperColor is None:
- paperColor = page.paperColor or self.paperColor
-
- doc = page.document
- num = page.pageNumber
- s = page.pageSize()
- if key.rotation & 1:
- s.transpose()
-
- xres = 72.0 * key.width / s.width()
- yres = 72.0 * key.height / s.height()
- multiplier = 2 if xres < self.oversampleThreshold else 1
- image = self.render_poppler_image(doc, num,
- xres * multiplier, yres * multiplier,
- tile.x * multiplier, tile.y * multiplier, tile.w * multiplier,
tile.h * multiplier,
- key.rotation, paperColor)
- if multiplier == 2:
- image = image.scaledToWidth(tile.w,
Qt.TransformationMode.SmoothTransformation)
- image.setDotsPerMeterX(int(xres * 39.37))
- image.setDotsPerMeterY(int(yres * 39.37))
- return image
-
- def setRenderHints(self, doc):
- """Set the poppler render hints we want to set."""
- if self.antialiasing:
- doc.setRenderHint(popplerqt6.Poppler.Document.Antialiasing)
- doc.setRenderHint(popplerqt6.Poppler.Document.TextAntialiasing)
-
- @contextlib.contextmanager
- def setup(self, doc, backend=None, paperColor=None):
- """Use the poppler document in context, properly configured and
locked."""
- with locking.lock(doc):
- if backend is not None:
- oldbackend = doc.renderBackend()
- doc.setRenderBackend(backend)
- oldhints = int(doc.renderHints())
- doc.setRenderHint(oldhints, False)
- self.setRenderHints(doc)
- if paperColor is not None:
- oldcolor = doc.paperColor()
- doc.setPaperColor(paperColor)
- try:
- yield
- finally:
- if backend is not None:
- doc.setRenderBackend(oldbackend)
- doc.setRenderHint(int(doc.renderHints()), False)
- doc.setRenderHint(oldhints)
- if paperColor is not None:
- doc.setPaperColor(oldcolor)
-
- def render_poppler_image(self, doc, pageNum,
- xres=72.0, yres=72.0,
- x=-1, y=-1, w=-1, h=-1, rotate=Rotate_0,
- paperColor=None):
- """Render an image, almost like calling page.renderToImage().
-
- The document is properly locked during rendering and render options
- are set.
-
- """
- with self.setup(doc, self.renderBackend, paperColor):
- return doc.page(pageNum).renderToImage(xres, yres, x, y, w, h,
rotate)
-
- def draw(self, page, painter, key, tile, paperColor=None):
- """Draw a tile on the painter.
-
- The painter is already at the right position and rotation.
- For the Poppler page and renderer, draw() is only used for printing.
- (See AbstractPage.print().)
-
- """
- source = self.map(key,
page.pageRect()).mapRect(QRectF(*tile)).toRect() # rounded
- target = QRectF(0, 0, tile.w, tile.h)
- if key.rotation & 1:
- target.setSize(target.size().transposed())
-
- doc = page.document
- p = doc.page(page.pageNumber)
-
- with self.setup(doc, self.printRenderBackend, paperColor):
- if self.printRenderBackend ==
popplerqt6.Poppler.Document.ArthurBackend:
- # Poppler's Arthur backend removes the current transform from
- # the painter (it sets a default CTM, instead of combining it
- # with the current transform). We let Poppler draw on a
QPicture,
- # and draw that on our painter.
- pic = QPicture()
- p.renderToPainter(QPainter(pic), page.dpi, page.dpi,
source.x(), source.y(), source.width(), source.height())
- # our resolution could be different, scale accordingly
- painter.save()
- painter.scale(pic.logicalDpiX() /
painter.device().logicalDpiX(),
- pic.logicalDpiY() /
painter.device().logicalDpiY())
- pic.play(painter)
- painter.restore()
- else:
- # Make an image exactly in the printer's resolution
- m = painter.transform()
- r = m.mapRect(source) # see where the source ends up
- w, h = r.width(), r.height()
- if m.m11() == 0:
- w, h = h, w # swap if rotation & 1 :-)
- # now we know the scale from our dpi to the paintdevice's
logicalDpi!
- hscale = w / source.width()
- vscale = h / source.height()
- s = QTransform().scale(hscale, vscale).mapRect(source)
- dpiX = page.dpi * hscale
- dpiY = page.dpi * vscale
- img = p.renderToImage(dpiX, dpiY, s.x(), s.y(), s.width(),
s.height())
- painter.drawImage(target, img, QRectF(img.rect()))
-
-
-def load(source):
- """Load a Poppler document.
-
- Source may be:
- - a Poppler document, which is then simply returned :-)
- - a filename
- - q QByteArray instance.
-
- Returns None if popplerqt6 is not available or the document could not be
- loaded.
-
- """
- if popplerqt6:
- if isinstance(source, popplerqt6.Poppler.Document):
- return source
- elif isinstance(source, str):
- return popplerqt6.Poppler.Document.load(source)
- else:
- return popplerqt6.Poppler.Document.loadFromData(source)
-
-
-
-# install a default renderer, so PopplerPage can be used directly
-PopplerPage.renderer = PopplerRenderer()
-
-
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/qpageview/scrollarea.py
new/qpageview-1.0.3/qpageview/scrollarea.py
--- old/qpageview-1.0.0/qpageview/scrollarea.py 2025-01-06 14:42:37.000000000
+0100
+++ new/qpageview-1.0.3/qpageview/scrollarea.py 2020-02-02 01:00:00.000000000
+0100
@@ -25,7 +25,9 @@
import math
-from PyQt6.QtCore import QPoint, QRect, QSize, Qt
+# we use util.Point here rather than raw QPoint to prevent an overflow
+# during rapid kinetic scrolling (Frescobaldi issue #2130)
+from PyQt6.QtCore import QRect, QSize, Qt
from PyQt6.QtWidgets import QAbstractScrollArea
from . import util
@@ -80,7 +82,7 @@
left = -self.horizontalScrollBar().value()
if top < 0:
top = -self.verticalScrollBar().value()
- return QPoint(left, top)
+ return util.Point(left, top)
def visibleArea(self):
"""Return a rectangle describing the part of the area that is
visible."""
@@ -107,7 +109,7 @@
dx = rect.right() - area.right()
if rect.left() < area.left() + dx:
dx = rect.left() - area.left()
- return QPoint(dx, dy)
+ return util.Point(dx, dy)
def ensureVisible(self, rect, margins=None, allowKinetic=True):
"""Performs the minimal scroll to make rect visible.
@@ -152,7 +154,7 @@
"""Return the current scroll offset."""
x = self.horizontalScrollBar().value()
y = self.verticalScrollBar().value()
- return QPoint(x, y)
+ return util.Point(x, y)
def canScrollBy(self, diff):
"""Does not scroll, but return the actual distance the View would
scroll.
@@ -165,7 +167,7 @@
x = min(max(0, hbar.value() + diff.x()), hbar.maximum())
y = min(max(0, vbar.value() + diff.y()), vbar.maximum())
- return QPoint(x - hbar.value(), y - vbar.value())
+ return util.Point(x - hbar.value(), y - vbar.value())
def scrollForDragging(self, pos):
"""Slowly scroll the View if pos is close to the edge of the viewport.
@@ -180,7 +182,7 @@
dy = pos.y() - viewport.top() - 12
if dy >= 0:
dy = max(0, pos.y() - viewport.bottom() + 12)
- self.steadyScroll(QPoint(dx*10, dy*10))
+ self.steadyScroll(util.Point(dx*10, dy*10))
def scrollTo(self, pos):
"""Scroll the View to get pos (QPoint) in the top left corner (if
possible).
@@ -204,7 +206,7 @@
y = vbar.value()
vbar.setValue(vbar.value() + diff.y())
y = vbar.value() - y
- return QPoint(x, y)
+ return util.Point(x, y)
def kineticScrollTo(self, pos):
"""Scroll the View to get pos (QPoint) in the top left corner (if
possible).
@@ -328,7 +330,7 @@
diffy = int(sy * (sy + 1) / 2)
if speed.x() < 0: diffx = -diffx
if speed.y() < 0: diffy = -diffy
- self.kineticScrollBy(QPoint(diffx, diffy))
+ self.kineticScrollBy(util.Point(diffx, diffy))
self._dragPos = None
self._dragTime = None
self._dragSpeed = None
@@ -348,23 +350,23 @@
# add Home and End, even in non-kinetic mode
scroll = self.kineticScrollBy if self.kineticScrollingEnabled else
self.scrollBy
if ev.key() == Qt.Key.Key_Home:
- scroll(QPoint(0, -vbar.value()))
+ scroll(util.Point(0, -vbar.value()))
elif ev.key() == Qt.Key.Key_End:
- scroll(QPoint(0, vbar.maximum() - vbar.value()))
+ scroll(util.Point(0, vbar.maximum() - vbar.value()))
elif self.kineticScrollingEnabled:
# make arrow keys and PgUp and PgDn kinetic
if ev.key() == Qt.Key.Key_PageDown:
- self.kineticAddDelta(QPoint(0, vbar.pageStep()))
+ self.kineticAddDelta(util.Point(0, vbar.pageStep()))
elif ev.key() == Qt.Key.Key_PageUp:
- self.kineticAddDelta(QPoint(0, -vbar.pageStep()))
+ self.kineticAddDelta(util.Point(0, -vbar.pageStep()))
elif ev.key() == Qt.Key.Key_Down:
- self.kineticAddDelta(QPoint(0, vbar.singleStep()))
+ self.kineticAddDelta(util.Point(0, vbar.singleStep()))
elif ev.key() == Qt.Key.Key_Up:
- self.kineticAddDelta(QPoint(0, -vbar.singleStep()))
+ self.kineticAddDelta(util.Point(0, -vbar.singleStep()))
elif ev.key() == Qt.Key.Key_Left:
- self.kineticAddDelta(QPoint(-hbar.singleStep(), 0))
+ self.kineticAddDelta(util.Point(-hbar.singleStep(), 0))
elif ev.key() == Qt.Key.Key_Right:
- self.kineticAddDelta(QPoint(hbar.singleStep(), 0))
+ self.kineticAddDelta(util.Point(hbar.singleStep(), 0))
else:
super().keyPressEvent(ev)
else:
@@ -416,7 +418,7 @@
dy += dy1
# scroll in the right direction
- diff = QPoint(-dx if x < 0 else dx, -dy if y < 0 else dy)
+ diff = util.Point(-dx if x < 0 else dx, -dy if y < 0 else dy)
return diff
def finished(self):
@@ -465,7 +467,7 @@
self._x = sx
self._y = sy
# the offset is accounted for in the first step
- self._offset = QPoint(offx, offy)
+ self._offset = util.Point(offx, offy)
def remainingDistance(self):
"""Return the remaining distance."""
@@ -477,7 +479,7 @@
dy = sy * (sy + 1) // 2
if self._y < 0:
dy = -dy
- return QPoint(dx, dy)
+ return util.Point(dx, dy)
def remainingTicks(self):
"""Return the remaining ticks of this scroll."""
@@ -485,7 +487,7 @@
def step(self):
"""Return a QPoint indicating the diff to scroll in this step."""
- ret = QPoint(self._x, self._y)
+ ret = util.Point(self._x, self._y)
if self._offset:
ret += self._offset
self._offset = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/qpageview/util.py
new/qpageview-1.0.3/qpageview/util.py
--- old/qpageview-1.0.0/qpageview/util.py 2025-01-06 14:42:37.000000000
+0100
+++ new/qpageview-1.0.3/qpageview/util.py 2020-02-02 01:00:00.000000000
+0100
@@ -179,6 +179,24 @@
super().mouseReleaseEvent(ev)
+class Point(QPoint):
+ """An overflow-safe QPoint.
+
+ This works around an oversight in PyQt, which does not
+ constrain integer arguments to fixed sizes as used in C++,
+ causing an OverflowError when those limits are exceeded.
+
+ """
+ def __init__(self, x, y):
+ super().__init__(clamp_int32(x), clamp_int32(y))
+
+ def setX(self, x):
+ super().setX(clamp_int32(x))
+
+ def setY(self, y):
+ super().setY(clamp_int32(y))
+
+
def rotate(matrix, rotation, width, height, dest=False):
"""Rotate matrix inside a rectangular area of width x height.
@@ -243,6 +261,15 @@
rect.moveBottom(point.y())
+def clamp(x, lower, upper):
+ """Return x bounded such that lower <= x <= upper."""
+ return lower if x < lower else upper if x > upper else x
+
+def clamp_int32(x):
+ """Return x bounded to the range of a 32-bit signed integer."""
+ return clamp(x, -2**31, 2**31 - 1)
+
+
# Found at:
https://stackoverflow.com/questions/1986152/why-doesnt-python-have-a-sign-function
def sign(x):
"""Return the sign of x: -1 if x < 0, 0 if x == 0, or 1 if x > 0."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/qpageview/viewactions.py
new/qpageview-1.0.3/qpageview/viewactions.py
--- old/qpageview-1.0.0/qpageview/viewactions.py 2025-01-06
14:42:37.000000000 +0100
+++ new/qpageview-1.0.3/qpageview/viewactions.py 2020-02-02
01:00:00.000000000 +0100
@@ -287,7 +287,7 @@
self.layout_single.setText(_("Single Pages"))
self.layout_double_right.setText(_("Two Pages (first page right)"))
self.layout_double_left.setText(_("Two Pages (first page left)"))
- self.layout_raster.setText(_("Raster"))
+ self.layout_raster.setText(_("Grid Layout"))
self.vertical.setText(_("Vertical"))
self.horizontal.setText(_("Horizontal"))
self.continuous.setText(_("&Continuous"))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/qpageview-1.0.0/qpageview/widgetoverlay.py
new/qpageview-1.0.3/qpageview/widgetoverlay.py
--- old/qpageview-1.0.0/qpageview/widgetoverlay.py 2025-01-06
14:42:37.000000000 +0100
+++ new/qpageview-1.0.3/qpageview/widgetoverlay.py 2020-02-02
01:00:00.000000000 +0100
@@ -25,9 +25,10 @@
import collections
-from PyQt6.QtCore import QPoint, QRect, Qt
+from PyQt6.QtCore import QPoint, Qt
from . import constants
+from . import util
OverlayData = collections.namedtuple("OverlayData", "page point rect
alignment")