Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-PyMuPDF for openSUSE:Factory checked in at 2022-02-09 20:39:36 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-PyMuPDF (Old) and /work/SRC/openSUSE:Factory/.python-PyMuPDF.new.1898 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-PyMuPDF" Wed Feb 9 20:39:36 2022 rev:19 rq:952839 version:1.19.5 Changes: -------- --- /work/SRC/openSUSE:Factory/python-PyMuPDF/python-PyMuPDF.changes 2022-01-16 23:19:23.350381145 +0100 +++ /work/SRC/openSUSE:Factory/.python-PyMuPDF.new.1898/python-PyMuPDF.changes 2022-02-09 20:40:53.434618590 +0100 @@ -1,0 +2,28 @@ +Sun Feb 6 14:02:23 UTC 2022 - Hsiu-Ming Chang <cges30...@gmail.com> + +- Update to v1.19.5 + * Fixed #1518. A limited ???fix???: in some cases, rectangles and + quadrupels were not correctly encoded to support re-drawing by + Shape. + * Fixed #1521. This had the same ultimate reason behind issue + #1510. + * Fixed #1513. Some Optional Content functions did not support + non-ASCII characters. + * Fixed #1510. Support more soft-mask image subtypes. + * Fixed #1507. Immunize against items in the outlines chain, + that are "null" objects. + * Fixed re-opened #1417. (???too many open files???). This was due + to insufficient calls to MuPDF???s fz_drop_document(). This also + fixes #1550. + * Fixed several undocumented issues in relation to incorrectly + setting the text span origin point_like. + * Fixed undocumented error computing the character bbox in + method Page.get_texttrace() when text is flipped (as opposed to + just rotated). + * Added items to the dictionary returned by image_properties(): + orientation and transform report the natural image orientation + (EXIF data). + * Added method Document.xref_copy(). It will make a given target + PDF object an exact copy of a source object. + +------------------------------------------------------------------- @@ -98 +126,3 @@ - specifically are now thought of being ???open???: not all corners and sides are considered part of the retangle. Please do read the Rect section for details. + specifically are now thought of being ???open???: not all corners + and sides are considered part of the retangle. Please do read + the Rect section for details. Old: ---- PyMuPDF-1.19.4.tar.gz New: ---- PyMuPDF-1.19.5.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-PyMuPDF.spec ++++++ --- /var/tmp/diff_new_pack.Ky4vRj/_old 2022-02-09 20:40:54.042620045 +0100 +++ /var/tmp/diff_new_pack.Ky4vRj/_new 2022-02-09 20:40:54.046620055 +0100 @@ -21,7 +21,7 @@ %define skip_python2 1 %define pypi_name PyMuPDF Name: python-%{pypi_name} -Version: 1.19.4 +Version: 1.19.5 Release: 0 Summary: Python binding for MuPDF, a PDF and XPS viewer License: AGPL-3.0-only ++++++ PyMuPDF-1.19.4.tar.gz -> PyMuPDF-1.19.5.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyMuPDF-1.19.4/PKG-INFO new/PyMuPDF-1.19.5/PKG-INFO --- old/PyMuPDF-1.19.4/PKG-INFO 2022-01-01 18:20:22.375151600 +0100 +++ new/PyMuPDF-1.19.5/PKG-INFO 2022-02-03 18:10:34.325506400 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: PyMuPDF -Version: 1.19.4 +Version: 1.19.5 Summary: Python bindings for the PDF toolkit and renderer MuPDF Home-page: https://github.com/pymupdf/PyMuPDF Author: Jorj McKie @@ -28,11 +28,11 @@ Description-Content-Type: text/markdown License-File: COPYING -# PyMuPDF 1.19.4 +# PyMuPDF 1.19.5  -Release date: January 01, 2022 +Release date: February 01, 2022 On **[PyPI](https://pypi.org/project/PyMuPDF)** since August 2016: [](https://pepy.tech/project/pymupdf) @@ -41,7 +41,7 @@ # Introduction -PyMuPDF (current version 1.19.4) is a Python binding with support for [MuPDF](https://mupdf.com/) (current version 1.19.*), a lightweight PDF, XPS, and E-book viewer, renderer, and toolkit, which is maintained and developed by Artifex Software, Inc. +PyMuPDF (current version 1.19.5) is a Python binding with support for [MuPDF](https://mupdf.com/) (current version 1.19.*), a lightweight PDF, XPS, and E-book viewer, renderer, and toolkit, which is maintained and developed by Artifex Software, Inc. MuPDF can access files in PDF, XPS, OpenXPS, CBZ, EPUB and FB2 (e-books) formats, and it is known for its top performance and high rendering quality. @@ -100,7 +100,7 @@ PyMuPDF **requires Python 3.6 or later**. -Python wheels exist for **Windows** (32bit and 64bit), **Linux** (64bit, Intel and ARM) and **Mac OSX** (64bit, Intel only), so it can be installed from [PyPI](https://pypi.org/search/?q=pymupdf) in the usual way: +For versions 3.7 and up, Python wheels exist for **Windows** (32bit and 64bit), **Linux** (64bit, Intel and ARM) and **Mac OSX** (64bit, Intel only), so it can be installed from [PyPI](https://pypi.org/search/?q=pymupdf) in the usual way: ``` python -m pip install --upgrade pip @@ -117,11 +117,9 @@ Older wheels - also with support for older Python versions - can be found [here](https://github.com/pymupdf/PyMuPDF-Optional-Material/tree/master/wheels-upto-Py3.5>) and on PyPI. -> Starting with v1.18.15, to minimize network traffic we no longer redundantly store wheels in this repository's `releases` folder. You can find older versions back to v1.9.2 on [PyPI](https://pypi.org/project/PyMuPDF/#history). Sources for every release continue to be stored in [here](https://github.com/pymupdf/PyMuPDF/releases). - Other platforms **require installation from sources**, follow [these](https://pymupdf.readthedocs.io/en/latest/installation.html) instructions in the documentation. -> **Note:** If `pip` cannot find a wheel that is compatible with your platform, it will automatically start an installation from sources - **_which will fail_** if MuPDF is not installed on your system. +> **Note:** If `pip` cannot find a wheel that is compatible with your platform, it will automatically try an installation from sources - **_which will fail_** if MuPDF (including its sources) is not installed on your system. This repo's folder [installation](https://github.com/pymupdf/PyMuPDF/tree/master/installation) contains several platform-specific source installation scripts contributed by users. You may also find the following Wiki pages useful: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyMuPDF-1.19.4/PyMuPDF.egg-info/PKG-INFO new/PyMuPDF-1.19.5/PyMuPDF.egg-info/PKG-INFO --- old/PyMuPDF-1.19.4/PyMuPDF.egg-info/PKG-INFO 2022-01-01 18:20:22.000000000 +0100 +++ new/PyMuPDF-1.19.5/PyMuPDF.egg-info/PKG-INFO 2022-02-03 18:10:33.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: PyMuPDF -Version: 1.19.4 +Version: 1.19.5 Summary: Python bindings for the PDF toolkit and renderer MuPDF Home-page: https://github.com/pymupdf/PyMuPDF Author: Jorj McKie @@ -28,11 +28,11 @@ Description-Content-Type: text/markdown License-File: COPYING -# PyMuPDF 1.19.4 +# PyMuPDF 1.19.5  -Release date: January 01, 2022 +Release date: February 01, 2022 On **[PyPI](https://pypi.org/project/PyMuPDF)** since August 2016: [](https://pepy.tech/project/pymupdf) @@ -41,7 +41,7 @@ # Introduction -PyMuPDF (current version 1.19.4) is a Python binding with support for [MuPDF](https://mupdf.com/) (current version 1.19.*), a lightweight PDF, XPS, and E-book viewer, renderer, and toolkit, which is maintained and developed by Artifex Software, Inc. +PyMuPDF (current version 1.19.5) is a Python binding with support for [MuPDF](https://mupdf.com/) (current version 1.19.*), a lightweight PDF, XPS, and E-book viewer, renderer, and toolkit, which is maintained and developed by Artifex Software, Inc. MuPDF can access files in PDF, XPS, OpenXPS, CBZ, EPUB and FB2 (e-books) formats, and it is known for its top performance and high rendering quality. @@ -100,7 +100,7 @@ PyMuPDF **requires Python 3.6 or later**. -Python wheels exist for **Windows** (32bit and 64bit), **Linux** (64bit, Intel and ARM) and **Mac OSX** (64bit, Intel only), so it can be installed from [PyPI](https://pypi.org/search/?q=pymupdf) in the usual way: +For versions 3.7 and up, Python wheels exist for **Windows** (32bit and 64bit), **Linux** (64bit, Intel and ARM) and **Mac OSX** (64bit, Intel only), so it can be installed from [PyPI](https://pypi.org/search/?q=pymupdf) in the usual way: ``` python -m pip install --upgrade pip @@ -117,11 +117,9 @@ Older wheels - also with support for older Python versions - can be found [here](https://github.com/pymupdf/PyMuPDF-Optional-Material/tree/master/wheels-upto-Py3.5>) and on PyPI. -> Starting with v1.18.15, to minimize network traffic we no longer redundantly store wheels in this repository's `releases` folder. You can find older versions back to v1.9.2 on [PyPI](https://pypi.org/project/PyMuPDF/#history). Sources for every release continue to be stored in [here](https://github.com/pymupdf/PyMuPDF/releases). - Other platforms **require installation from sources**, follow [these](https://pymupdf.readthedocs.io/en/latest/installation.html) instructions in the documentation. -> **Note:** If `pip` cannot find a wheel that is compatible with your platform, it will automatically start an installation from sources - **_which will fail_** if MuPDF is not installed on your system. +> **Note:** If `pip` cannot find a wheel that is compatible with your platform, it will automatically try an installation from sources - **_which will fail_** if MuPDF (including its sources) is not installed on your system. This repo's folder [installation](https://github.com/pymupdf/PyMuPDF/tree/master/installation) contains several platform-specific source installation scripts contributed by users. You may also find the following Wiki pages useful: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyMuPDF-1.19.4/README.md new/PyMuPDF-1.19.5/README.md --- old/PyMuPDF-1.19.4/README.md 2022-01-01 00:20:04.000000000 +0100 +++ new/PyMuPDF-1.19.5/README.md 2022-01-28 15:28:54.000000000 +0100 @@ -1,8 +1,8 @@ -# PyMuPDF 1.19.4 +# PyMuPDF 1.19.5  -Release date: January 01, 2022 +Release date: February 01, 2022 On **[PyPI](https://pypi.org/project/PyMuPDF)** since August 2016: [](https://pepy.tech/project/pymupdf) @@ -11,7 +11,7 @@ # Introduction -PyMuPDF (current version 1.19.4) is a Python binding with support for [MuPDF](https://mupdf.com/) (current version 1.19.*), a lightweight PDF, XPS, and E-book viewer, renderer, and toolkit, which is maintained and developed by Artifex Software, Inc. +PyMuPDF (current version 1.19.5) is a Python binding with support for [MuPDF](https://mupdf.com/) (current version 1.19.*), a lightweight PDF, XPS, and E-book viewer, renderer, and toolkit, which is maintained and developed by Artifex Software, Inc. MuPDF can access files in PDF, XPS, OpenXPS, CBZ, EPUB and FB2 (e-books) formats, and it is known for its top performance and high rendering quality. @@ -70,7 +70,7 @@ PyMuPDF **requires Python 3.6 or later**. -Python wheels exist for **Windows** (32bit and 64bit), **Linux** (64bit, Intel and ARM) and **Mac OSX** (64bit, Intel only), so it can be installed from [PyPI](https://pypi.org/search/?q=pymupdf) in the usual way: +For versions 3.7 and up, Python wheels exist for **Windows** (32bit and 64bit), **Linux** (64bit, Intel and ARM) and **Mac OSX** (64bit, Intel only), so it can be installed from [PyPI](https://pypi.org/search/?q=pymupdf) in the usual way: ``` python -m pip install --upgrade pip @@ -87,11 +87,9 @@ Older wheels - also with support for older Python versions - can be found [here](https://github.com/pymupdf/PyMuPDF-Optional-Material/tree/master/wheels-upto-Py3.5>) and on PyPI. -> Starting with v1.18.15, to minimize network traffic we no longer redundantly store wheels in this repository's `releases` folder. You can find older versions back to v1.9.2 on [PyPI](https://pypi.org/project/PyMuPDF/#history). Sources for every release continue to be stored in [here](https://github.com/pymupdf/PyMuPDF/releases). - Other platforms **require installation from sources**, follow [these](https://pymupdf.readthedocs.io/en/latest/installation.html) instructions in the documentation. -> **Note:** If `pip` cannot find a wheel that is compatible with your platform, it will automatically start an installation from sources - **_which will fail_** if MuPDF is not installed on your system. +> **Note:** If `pip` cannot find a wheel that is compatible with your platform, it will automatically try an installation from sources - **_which will fail_** if MuPDF (including its sources) is not installed on your system. This repo's folder [installation](https://github.com/pymupdf/PyMuPDF/tree/master/installation) contains several platform-specific source installation scripts contributed by users. You may also find the following Wiki pages useful: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyMuPDF-1.19.4/changes.txt new/PyMuPDF-1.19.5/changes.txt --- old/PyMuPDF-1.19.4/changes.txt 2022-01-01 18:19:16.000000000 +0100 +++ new/PyMuPDF-1.19.5/changes.txt 2022-01-29 10:46:43.000000000 +0100 @@ -3,6 +3,31 @@ ------ +**Changes in Version 1.19.5** + +* **Fixed** `#1518 <https://github.com/pymupdf/PyMuPDF/issues/1518>`_. A limited "fix": in some cases, rectangles and quadrupels were not correctly encoded to support re-drawing by :ref:`Shape`. + +* **Fixed** `#1521 <https://github.com/pymupdf/PyMuPDF/issues/1521>`_. This had the same ultimate reason behind issue #1510. + +* **Fixed** `#1513 <https://github.com/pymupdf/PyMuPDF/issues/1513>`_. Some Optional Content functions did not support non-ASCII characters. + +* **Fixed** `#1510 <https://github.com/pymupdf/PyMuPDF/issues/1510>`_. Support more soft-mask image subtypes. + +* **Fixed** `#1507 <https://github.com/pymupdf/PyMuPDF/issues/1507>`_. Immunize against items in the outlines chain, that are ``"null"`` objects. + +* **Fixed** re-opened `#1417 <https://github.com/pymupdf/PyMuPDF/issues/1417>`_. ("too many open files"). This was due to insufficient calls to MuPDF's ``fz_drop_document()``. This also fixes `#1550 <https://github.com/pymupdf/PyMuPDF/issues/1550>`_. + +* **Fixed** several undocumented issues in relation to incorrectly setting the text span origin :data:`point_like`. + +* **Fixed** undocumented error computing the character bbox in method :meth:`Page.get_texttrace` when text is **flipped** (as opposed to just rotated). + +* **Added** items to the dictionary returned by :meth:`image_properties`: ``orientation`` and ``transform`` report the natural image orientation (EXIF data). + +* **Added** method :meth:`Document.xref_copy`. It will make a given target PDF object an exact copy of a source object. + + +------ + **Changes in Version 1.19.4** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyMuPDF-1.19.4/fitz/__init__.py new/PyMuPDF-1.19.5/fitz/__init__.py --- old/PyMuPDF-1.19.4/fitz/__init__.py 2022-01-01 00:24:21.000000000 +0100 +++ new/PyMuPDF-1.19.5/fitz/__init__.py 2022-02-01 11:02:28.000000000 +0100 @@ -77,6 +77,7 @@ fitz.Document.subset_fonts = fitz.utils.subset_fonts fitz.Document.get_oc = fitz.utils.get_oc fitz.Document.set_oc = fitz.utils.set_oc +fitz.Document.xref_copy = fitz.utils.xref_copy # ------------------------------------------------------------------------------ @@ -429,7 +430,7 @@ _alias(fitz, "PaperSize", "paper_size") _alias(fitz, "PaperRect", "paper_rect") _alias(fitz, "paperSizes", "paper_sizes") - _alias(fitz, "ImageProperties", "image_properties") + _alias(fitz, "ImageProperties", "image_profile") _alias(fitz, "planishLine", "planish_line") _alias(fitz, "getTextLength", "get_text_length") _alias(fitz, "getTextlength", "get_text_length") @@ -449,4 +450,5 @@ 64 if sys.maxsize > 2 ** 32 else 32, ) -restore_aliases() +if VersionBind.startswith("1.19"): # don't generate aliases after this + restore_aliases() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyMuPDF-1.19.4/fitz/fitz.py new/PyMuPDF-1.19.5/fitz/fitz.py --- old/PyMuPDF-1.19.4/fitz/fitz.py 2022-01-01 16:13:09.000000000 +0100 +++ new/PyMuPDF-1.19.5/fitz/fitz.py 2022-02-03 18:02:09.000000000 +0100 @@ -104,9 +104,9 @@ VersionFitz = "1.19.0" -VersionBind = "1.19.4" -VersionDate = "2022-01-01 00:00:01" -version = (VersionBind, VersionFitz, "20220101000001") +VersionBind = "1.19.5" +VersionDate = "2022-02-01 00:00:01" +version = (VersionBind, VersionFitz, "20220201000001") EPSILON = _fitz.EPSILON PDF_ANNOT_TEXT = _fitz.PDF_ANNOT_TEXT @@ -2937,7 +2937,7 @@ return Matrix(TOOLS._hor_matrix(p1, p2)) -def image_properties(img: typing.ByteString) -> dict: +def image_profile(img: typing.ByteString) -> dict: """Return basic properties of an image. Args: @@ -6372,7 +6372,7 @@ if rect == None: return self.cropbox mb = self.mediabox - return Rect(rect[0], mb.y1 - rect[1], rect[2], mb.y1 - rect[3]) + return Rect(rect[0], mb.y1 - rect[3], rect[2], mb.y1 - rect[1]) @property def trimbox(self): @@ -6381,7 +6381,7 @@ if rect == None: return self.cropbox mb = self.mediabox - return Rect(rect[0], mb.y1 - rect[1], rect[2], mb.y1 - rect[3]) + return Rect(rect[0], mb.y1 - rect[3], rect[2], mb.y1 - rect[1]) @property def bleedbox(self): @@ -6390,7 +6390,7 @@ if rect == None: return self.cropbox mb = self.mediabox - return Rect(rect[0], mb.y1 - rect[1], rect[2], mb.y1 - rect[3]) + return Rect(rect[0], mb.y1 - rect[3], rect[2], mb.y1 - rect[1]) def _set_pagebox(self, boxtype, rect): doc = self.parent @@ -6566,10 +6566,21 @@ del pymupdf_fonts # install the font for the page + if fontfile != None: + if type(fontfile) is str: + fontfile_str = fontfile + elif hasattr(fontfile, "absolute"): + fontfile_str = str(fontfile) + elif hasattr(fontfile, "name"): + fontfile_str = fontfile.name + else: + raise ValueError("bad fontfile") + else: + fontfile_str = None val = self._insertFont( fontname, bfname, - fontfile, + fontfile_str, fontbuffer, set_simple, idx, @@ -7230,12 +7241,14 @@ return self def __exit__(self, *args): - self.__swig_destroy__(self) + if getattr(self, "thisown", False): + self.__swig_destroy__(self) def __del__(self): if not type(self) is Pixmap: return - self.__swig_destroy__(self) + if getattr(self, "thisown", False): + self.__swig_destroy__(self) # Register Pixmap in _fitz: @@ -8376,7 +8389,8 @@ def __del__(self): if not type(self) is DisplayList: return - self.__swig_destroy__(self) + if getattr(self, "thisown", False): + self.__swig_destroy__(self) # Register DisplayList in _fitz: @@ -8563,7 +8577,8 @@ def __del__(self): if not type(self) is TextPage: return - self.__swig_destroy__(self) + if getattr(self, "thisown", False): + self.__swig_destroy__(self) # Register TextPage in _fitz: @@ -8583,7 +8598,8 @@ def __del__(self): if not type(self) is Graftmap: return - self.__swig_destroy__(self) + if getattr(self, "thisown", False): + self.__swig_destroy__(self) # Register Graftmap in _fitz: @@ -8834,7 +8850,8 @@ def __del__(self): if not type(self) is TextWriter: return - self.__swig_destroy__(self) + if getattr(self, "thisown", False): + self.__swig_destroy__(self) # Register TextWriter in _fitz: @@ -9060,7 +9077,8 @@ def __del__(self): if not type(self) is Font: return - self.__swig_destroy__(self) + if getattr(self, "thisown", False): + self.__swig_destroy__(self) # Register Font in _fitz: @@ -9573,7 +9591,8 @@ def __del__(self): if not type(self) is Tools: return - self.__swig_destroy__(self) + if getattr(self, "thisown", False): + self.__swig_destroy__(self) def __init__(self): _fitz.Tools_swiginit(self, _fitz.new_Tools()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyMuPDF-1.19.4/fitz/fitz_wrap.c new/PyMuPDF-1.19.5/fitz/fitz_wrap.c --- old/PyMuPDF-1.19.4/fitz/fitz_wrap.c 2022-01-01 16:13:03.000000000 +0100 +++ new/PyMuPDF-1.19.5/fitz/fitz_wrap.c 2022-02-03 18:02:05.000000000 +0100 @@ -3416,7 +3416,7 @@ static fz_irect JM_irect_from_py(PyObject *r) { - if (!PySequence_Check(r) || PySequence_Size(r) != 4) + if (!r || !PySequence_Check(r) || PySequence_Size(r) != 4) return fz_infinite_irect; int x[4]; Py_ssize_t i; @@ -4275,16 +4275,20 @@ thisobj = obj; while (thisobj) { newxref = PyLong_FromLong((long) pdf_to_num(ctx, thisobj)); - if (PySequence_Contains(xrefs, newxref)) { + if (PySequence_Contains(xrefs, newxref) || + pdf_dict_get(ctx, thisobj, PDF_NAME(Type))) { + // circular ref or top of chain: terminate Py_DECREF(newxref); break; } LIST_APPEND_DROP(xrefs, newxref); first = pdf_dict_get(ctx, thisobj, PDF_NAME(First)); // try go down - if (first) xrefs = JM_outline_xrefs(ctx, first, xrefs); + if (pdf_is_dict(ctx, first)) xrefs = JM_outline_xrefs(ctx, first, xrefs); thisobj = pdf_dict_get(ctx, thisobj, PDF_NAME(Next)); // try go next parent = pdf_dict_get(ctx, thisobj, PDF_NAME(Parent)); // get parent - if (!thisobj) thisobj = parent; // goto parent if no next + if (!pdf_is_dict(ctx, thisobj)) { + thisobj = parent; + } } return xrefs; } @@ -4927,14 +4931,20 @@ res = fz_new_buffer_from_shared_data(ctx, c, (size_t) len); } image = fz_new_image_from_buffer(ctx, res); - int xres, yres; + int xres, yres, orientation; + fz_matrix ctm = fz_image_orientation_matrix(ctx, image); fz_image_resolution(image, &xres, &yres); + orientation = (int) fz_image_orientation(ctx, image); const char *cs_name = fz_colorspace_name(ctx, image->colorspace); result = PyDict_New(); DICT_SETITEM_DROP(result, dictkey_width, Py_BuildValue("i", image->w)); DICT_SETITEM_DROP(result, dictkey_height, Py_BuildValue("i", image->h)); + DICT_SETITEMSTR_DROP(result, "orientation", + Py_BuildValue("i", orientation)); + DICT_SETITEM_DROP(result, dictkey_matrix, + JM_py_from_matrix(ctm)); DICT_SETITEM_DROP(result, dictkey_xres, Py_BuildValue("i", xres)); DICT_SETITEM_DROP(result, dictkey_yres, @@ -6996,7 +7006,7 @@ dsc = dsc * fsize / asc_dsc; /* ------------------------------ - Re-compute quad with adjusted ascender / descender values: + Re-compute quad with the adjusted ascender / descender values: Move ch->origin to (0,0) and de-rotate quad, then adjust the corners, re-rotate and move back to ch->origin location. ------------------------------ */ @@ -7006,6 +7016,10 @@ s = line->dir.y; // sine trm1 = fz_make_matrix(c, -s, s, c, 0, 0); // derotate trm2 = fz_make_matrix(c, s, -s, c, 0, 0); // rotate + if (c == -1) { // left-right flip + trm1.d = 1; + trm2.d = 1; + } xlate1 = fz_make_matrix(1, 0, 0, 1, -ch->origin.x, -ch->origin.y); xlate2 = fz_make_matrix(1, 0, 0, 1, ch->origin.x, ch->origin.y); @@ -7013,11 +7027,17 @@ quad = fz_transform_quad(quad, trm1); // de-rotate corners // adjust vertical coordinates - - quad.ll.y = -dsc; - quad.lr.y = -dsc; - quad.ul.y = -asc; - quad.ur.y = -asc; + if (c == 1 && quad.ul.y > 0) { // up-down flip + quad.ul.y = asc; + quad.ur.y = asc; + quad.ll.y = dsc; + quad.lr.y = dsc; + } else { + quad.ul.y = -asc; + quad.ur.y = -asc; + quad.ll.y = -dsc; + quad.lr.y = -dsc; + } // adjust horizontal coordinates that are too crazy: // (1) left x must be >= 0 @@ -7451,9 +7471,6 @@ } span_rect = fz_union_rect(span_rect, r); - if (origin.y > span_origin.y) { - span_origin.y = origin.y; - } if (raw) { // make and append a char dict char_dict = PyDict_New(); @@ -8924,6 +8941,9 @@ static fz_rect dev_pathrect; static float dev_pathfactor = 0; static int dev_linecount = 0; +static int path_type = 0; +#define FILL_PATH 1 +#define STROKE_PATH 2 static void @@ -9002,9 +9022,9 @@ PyTuple_SET_ITEM(rect, 0, PyUnicode_FromString("qu")); /* relationship of float array to quad points: - (0, 1) = ul, (2, 3) = ur, (6, 7) = ll, (4, 5) = lr + (0, 1) = ul, (2, 3) = ll, (6, 7) = ur, (4, 5) = lr */ - fz_quad q = fz_make_quad(f[0], f[1], f[2], f[3], f[6], f[7], f[4], f[5]); + fz_quad q = fz_make_quad(f[0], f[1], f[6], f[7], f[2], f[3], f[4], f[5]); PyTuple_SET_ITEM(rect, 1, JM_py_from_quad(q)); finish:; PyList_SetItem(items, len - 4, rect); // replace item -4 by rect @@ -9054,13 +9074,13 @@ --------------------------------------------------------------------- */ if (ll.y != lr.y) { // not horizontal - goto make_quad; + goto drop_out; } if (lr.x != ur.x) { // not vertical - goto make_quad; + goto drop_out; } if (ur.y != ul.y) { // not horizontal - goto make_quad; + goto drop_out; } // we have a rect, determine orientation if (ll.x < lr.x) { // move left to right @@ -9085,16 +9105,9 @@ PyTuple_SET_ITEM(rect, 0, PyUnicode_FromString("re")); PyTuple_SET_ITEM(rect, 1, JM_py_from_rect(r)); PyTuple_SET_ITEM(rect, 2, PyLong_FromLong(orientation)); - goto finish; - - make_quad:; - rect = PyTuple_New(2); - PyTuple_SET_ITEM(rect, 0, PyUnicode_FromString("qu")); - fz_quad q = fz_make_quad(ul.x, ul.y, ur.x, ur.y, ll.x, ll.y, lr.x, lr.y); - PyTuple_SET_ITEM(rect, 1, JM_py_from_quad(q)); - finish:; PyList_SetItem(items, len - 3, rect); // replace item -3 by rect PyList_SetSlice(items, len - 2, len, NULL); // delete remaining 2 items + drop_out:; return 1; } @@ -9134,7 +9147,7 @@ PyObject *items = PyDict_GetItem(dev_pathdict, dictkey_items); LIST_APPEND_DROP(items, list); dev_linecount += 1; // counts consecutive lines - if (dev_linecount >= 4) { // shrink to "re" or "qu" item + if (dev_linecount >= 4 && path_type != FILL_PATH) { // shrink to "re" or "qu" item jm_checkquad(); } } @@ -9249,7 +9262,7 @@ jm_tracedraw_device *dev = (jm_tracedraw_device *) dev_; PyObject *out = dev->out; trace_device_ctm = ctm; //fz_concat(ctm, trace_device_ptm); - + path_type = FILL_PATH; jm_tracedraw_path(ctx, dev, path); if (!dev_pathdict) { return; @@ -9279,6 +9292,7 @@ dev_pathfactor = fz_abs(ctm.a); } trace_device_ctm = ctm; // fz_concat(ctm, trace_device_ptm); + path_type = STROKE_PATH; jm_tracedraw_path(ctx, dev, path); if (!dev_pathdict) { @@ -9335,14 +9349,11 @@ float x0, y0, x1, y1; asc = (double) JM_font_ascender(ctx, span->font); dsc = (double) JM_font_descender(ctx, span->font); - if ((asc - dsc) >= 1 && small_glyph_heights == 0) { - ; - } else { - if (asc < 1e-3) { - dsc = -0.1; - asc = 0.9; - } + if (asc < 1e-3) { // probably Tesseract font + dsc = -0.1; + asc = 0.9; } + double ascsize = asc * fsize / (asc - dsc); double dscsize = dsc * fsize / (asc - dsc); int fflags = 0; @@ -9367,6 +9378,10 @@ fz_rect span_bbox; dir = fz_normalize_vector(dir); fz_matrix rot = fz_make_matrix(dir.x, dir.y, -dir.y, dir.x, 0, 0); + if (dir.x == -1) { // left-right flip + rot.d = 1; + } + for (i = 0; i < span->len; i++) { adv = 0; if (span->items[i].gid >= 0) { @@ -9385,8 +9400,13 @@ m1 = fz_concat(m1, fz_make_matrix(1, 0, 0, 1, char_orig.x, char_orig.y)); x0 = char_orig.x; x1 = x0 + adv; - y0 = char_orig.y - ascsize; - y1 = char_orig.y - dscsize; + if (dir.x == 1 && span->trm.d < 0) { // up-down flip + y0 = char_orig.y + dscsize; + y1 = char_orig.y + ascsize; + } else { + y0 = char_orig.y - ascsize; + y1 = char_orig.y - dscsize; + } fz_rect char_bbox = fz_make_rect(x0, y0, x1, y1); char_bbox = fz_transform_rect(char_bbox, m1); PyTuple_SET_ITEM(chars, (Py_ssize_t) i, Py_BuildValue("ii(ff)(ffff)", @@ -9417,7 +9437,8 @@ DICT_SETITEM_DROP(span_dict, dictkey_font, Py_BuildValue("s",fontname)); DICT_SETITEM_DROP(span_dict, dictkey_wmode, PyLong_FromLong((long) span->wmode)); DICT_SETITEM_DROP(span_dict, dictkey_flags, PyLong_FromLong((long) fflags)); - DICT_SETITEMSTR_DROP(span_dict, "bidi", PyLong_FromLong((long) span->bidi_level)); + DICT_SETITEMSTR_DROP(span_dict, "bidi_lvl", PyLong_FromLong((long) span->bidi_level)); + DICT_SETITEMSTR_DROP(span_dict, "bidi_dir", PyLong_FromLong((long) span->markup_dir)); DICT_SETITEM_DROP(span_dict, dictkey_ascender, PyFloat_FromDouble(asc)); DICT_SETITEM_DROP(span_dict, dictkey_descender, PyFloat_FromDouble(dsc)); if (colorspace) { @@ -9676,6 +9697,9 @@ SWIGINTERN void delete_Document(struct Document *self){ DEBUGMSG1("Document"); fz_document *this_doc = (fz_document *) self; + while (this_doc->refs > 1) { + fz_drop_document(gctx, this_doc); + } fz_drop_document(gctx, this_doc); DEBUGMSG2; } @@ -10338,8 +10362,11 @@ if (!first) goto finished; xrefs = PyList_New(0); // pre-allocate an empty list xrefs = JM_outline_xrefs(gctx, first, xrefs); - Py_ssize_t i, n = PySequence_Size(xrefs); + Py_ssize_t i, n = PySequence_Size(xrefs), m = PySequence_Size(items); if (!n) goto finished; + if (n != m) { + THROWMSG(gctx, "internal error finding outline xrefs"); + } int xref; // update all TOC item dictionaries @@ -12543,9 +12570,9 @@ case (2): type = "radiobox"; break; default: type = "label"; break; } - PyObject *item = Py_BuildValue("{s:i,s:s,s:i,s:s,s:O,s:O}", + PyObject *item = Py_BuildValue("{s:i,s:N,s:i,s:s,s:N,s:N}", "number", i, - "text", info.text, + "text", JM_EscapeStrFromStr(info.text), "depth", info.depth, "type", type, "on", JM_BOOL(info.selected), @@ -14001,6 +14028,9 @@ fz_pixmap *src_pix = (fz_pixmap *) spix; fz_try(gctx) { fz_irect bbox = JM_irect_from_py(clip); + if (clip != Py_None && (fz_is_infinite_irect(bbox) || fz_is_empty_irect(bbox))) { + THROWMSG(gctx, "bad clip parameter"); + } if (!fz_is_infinite_irect(bbox)) { pm = fz_scale_pixmap(gctx, src_pix, src_pix->x, src_pix->y, w, h, &bbox); } else { @@ -14133,7 +14163,9 @@ THROWMSG(gctx, "bad xref"); ref = pdf_new_indirect(gctx, pdf, xref, 0); type = pdf_dict_get(gctx, ref, PDF_NAME(Subtype)); - if (!pdf_name_eq(gctx, type, PDF_NAME(Image))) + if (!pdf_name_eq(gctx, type, PDF_NAME(Image)) && + !pdf_name_eq(gctx, type, PDF_NAME(Alpha)) && + !pdf_name_eq(gctx, type, PDF_NAME(Luminosity))) THROWMSG(gctx, "not an image"); img = pdf_load_image(gctx, pdf, ref); pix = fz_get_pixmap_from_image(gctx, img, NULL, NULL, NULL, NULL); @@ -14706,7 +14738,8 @@ } SWIGINTERN void delete_Annot(struct Annot *self){ DEBUGMSG1("Annot"); - pdf_drop_annot(gctx, (pdf_annot *) self); + pdf_annot *this_annot = (pdf_annot *) self; + pdf_drop_annot(gctx, this_annot); DEBUGMSG2; } SWIGINTERN PyObject *Annot_rect(struct Annot *self){ @@ -15727,7 +15760,8 @@ } SWIGINTERN void delete_Link(struct Link *self){ DEBUGMSG1("Link"); - fz_drop_link(gctx, (fz_link *) self); + fz_link *this_link = (fz_link *) self; + fz_drop_link(gctx, this_link); DEBUGMSG2; } SWIGINTERN PyObject *Link__border(struct Link *self,struct Document *doc,int xref){ @@ -15790,7 +15824,8 @@ } SWIGINTERN void delete_DisplayList(struct DisplayList *self){ DEBUGMSG1("DisplayList"); - fz_drop_display_list(gctx, (fz_display_list *) self); + fz_display_list *this_dl = (fz_display_list *) self; + fz_drop_display_list(gctx, this_dl); DEBUGMSG2; } SWIGINTERN struct DisplayList *new_DisplayList(PyObject *mediabox){ @@ -15848,7 +15883,8 @@ } SWIGINTERN void delete_TextPage(struct TextPage *self){ DEBUGMSG1("TextPage"); - fz_drop_stext_page(gctx, (fz_stext_page *) self); + fz_stext_page *this_tp = (fz_stext_page *) self; + fz_drop_stext_page(gctx, this_tp); DEBUGMSG2; } SWIGINTERN struct TextPage *new_TextPage(PyObject *mediabox){ @@ -16165,7 +16201,8 @@ } SWIGINTERN void delete_Graftmap(struct Graftmap *self){ DEBUGMSG1("Graftmap"); - pdf_drop_graft_map(gctx, (pdf_graft_map *) self); + pdf_graft_map *this_gm = (pdf_graft_map *) self; + pdf_drop_graft_map(gctx, this_gm); DEBUGMSG2; } SWIGINTERN struct Graftmap *new_Graftmap(struct Document *doc){ @@ -16182,7 +16219,8 @@ } SWIGINTERN void delete_TextWriter(struct TextWriter *self){ DEBUGMSG1("TextWriter"); - fz_drop_text(gctx, (fz_text *) self); + fz_text *this_tw = (fz_text *) self; + fz_drop_text(gctx, this_tw); DEBUGMSG2; } SWIGINTERN struct TextWriter *new_TextWriter(PyObject *page_rect,float opacity,PyObject *color){ @@ -16267,7 +16305,8 @@ } SWIGINTERN void delete_Font(struct Font *self){ DEBUGMSG1("Font"); - fz_drop_font(gctx, (fz_font *) self); + fz_font *this_font = (fz_font *) self; + fz_drop_font(gctx, this_font); DEBUGMSG2; } SWIGINTERN struct Font *new_Font(char *fontname,char *fontfile,PyObject *fontbuffer,int script,char *language,int ordering,int is_bold,int is_italic,int is_serif){ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyMuPDF-1.19.4/fitz/utils.py new/PyMuPDF-1.19.5/fitz/utils.py --- old/PyMuPDF-1.19.4/fitz/utils.py 2022-01-01 00:24:23.000000000 +0100 +++ new/PyMuPDF-1.19.5/fitz/utils.py 2022-01-26 09:44:14.000000000 +0100 @@ -5206,7 +5206,7 @@ pass try: # invoke fontTools subsetter fts.main(args) - font = fitz.Font(fontfile=newfont_path) + font = Font(fontfile=newfont_path) new_buffer = font.buffer if len(font.valid_codepoints()) == 0: new_buffer = None @@ -5278,7 +5278,7 @@ font_ext = f[1] # font file extension basename = f[3] # font basename - if font_ext not in ( # supported by fontTools + if font_ext not in ( # skip if not supported by fontTools "otf", "ttf", "woff", @@ -5298,7 +5298,7 @@ xref_set.add(font_xref) for name in names: name_set.add(name) - font = fitz.Font(fontbuffer=fontbuffer) + font = Font(fontbuffer=fontbuffer) name_set.add(font.name) del font font_buffers[fontbuffer] = (name_set, xref_set, subsets) @@ -5372,3 +5372,43 @@ new_fontsize += len(new_buffer) return old_fontsize - new_fontsize + + +# ------------------------------------------------------------------- +# Copy XREF object to another XREF +# ------------------------------------------------------------------- +def xref_copy(doc: Document, source: int, target: int, *, keep: list = None) -> None: + """Copy a PDF dictionary object to another one given their xref numbers. + + Args: + doc: PDF document object + source: source xref number + target: target xref number, the xref must already exist + keep: an optional list of 1st level keys in target that should not be + removed before copying. + Notes: + This works similar to the copy() method of dictionaries in Python. The + source may be a stream object. + """ + if doc.xref_is_stream(source): + # read new xref stream, maintaining compression + stream = doc.xref_stream_raw(source) + doc.update_stream( + target, + stream, + compress=False, # keeps source compression + new=True, # in case target is no stream + ) + + # empty the target completely, observe exceptions + if keep is None: + keep = [] + for key in doc.xref_get_keys(target): + if key in keep: + continue + doc.xref_set_key(target, key, "null") + # copy over all source dict items + for key in doc.xref_get_keys(source): + item = doc.xref_get_key(source, key) + doc.xref_set_key(target, key, item[1]) + return None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyMuPDF-1.19.4/setup.py new/PyMuPDF-1.19.5/setup.py --- old/PyMuPDF-1.19.4/setup.py 2021-12-25 22:50:57.000000000 +0100 +++ new/PyMuPDF-1.19.5/setup.py 2022-01-01 21:35:17.000000000 +0100 @@ -155,7 +155,7 @@ setup( name="PyMuPDF", - version="1.19.4", + version="1.19.5", description="Python bindings for the PDF toolkit and renderer MuPDF", long_description=readme, long_description_content_type="text/markdown", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyMuPDF-1.19.4/tests/resources/symbols.txt new/PyMuPDF-1.19.5/tests/resources/symbols.txt --- old/PyMuPDF-1.19.4/tests/resources/symbols.txt 2021-11-07 14:39:01.000000000 +0100 +++ new/PyMuPDF-1.19.5/tests/resources/symbols.txt 2022-01-10 16:29:02.000000000 +0100 @@ -69,8 +69,9 @@ 'even_odd': False, 'fill': (1.0, 0.0, 0.0), 'fill_opacity': 1.0, - 'items': [('qu', - ((50.0, 255.0), (75.0, 280.0), (75.0, 230.0), (100.0, 255.0)))], + 'items': [('l', (75.0, 230.0), (100.0, 255.0)), + ('l', (100.0, 255.0), (75.0, 280.0)), + ('l', (75.0, 280.0), (50.0, 255.0))], 'lineCap': (0, 0, 0), 'lineJoin': 0.0, 'rect': (50.0, 230.0, 100.0, 280.0), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyMuPDF-1.19.4/tests/test_general.py new/PyMuPDF-1.19.5/tests/test_general.py --- old/PyMuPDF-1.19.4/tests/test_general.py 2021-11-12 13:18:35.000000000 +0100 +++ new/PyMuPDF-1.19.5/tests/test_general.py 2022-01-12 08:45:27.000000000 +0100 @@ -1,6 +1,7 @@ # encoding utf-8 """ -Confirm sample doc has no links and no annots. +* Confirm sample doc has no links and no annots. +* Confirm proper release of file handles via Document.close() """ import os diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyMuPDF-1.19.4/tests/test_geometry.py new/PyMuPDF-1.19.5/tests/test_geometry.py --- old/PyMuPDF-1.19.4/tests/test_geometry.py 2021-10-03 19:03:58.000000000 +0200 +++ new/PyMuPDF-1.19.5/tests/test_geometry.py 2022-01-10 16:11:40.000000000 +0100 @@ -313,3 +313,23 @@ except: failed = True assert failed + + +def test_pageboxes(): + """Tests concerning ArtBox, TrimBox, BleedBox.""" + doc = fitz.open() + page = doc.new_page() + assert page.cropbox == page.artbox == page.bleedbox == page.trimbox + rect_methods = ( + page.set_cropbox, + page.set_artbox, + page.set_bleedbox, + page.set_trimbox, + ) + keys = ("CropBox", "ArtBox", "BleedBox", "TrimBox") + rect = fitz.Rect(100, 200, 400, 700) + for f in rect_methods: + f(rect) + for key in keys: + assert doc.xref_get_key(page.xref, key) == ("array", "[100 142 400 642]") + assert page.cropbox == page.artbox == page.bleedbox == page.trimbox diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyMuPDF-1.19.4/tests/test_insertpdf.py new/PyMuPDF-1.19.5/tests/test_insertpdf.py --- old/PyMuPDF-1.19.4/tests/test_insertpdf.py 2021-04-18 22:35:01.000000000 +0200 +++ new/PyMuPDF-1.19.5/tests/test_insertpdf.py 2022-01-12 08:30:04.000000000 +0100 @@ -3,6 +3,7 @@ * Compare with stored earlier result: - must have identical object definitions - must have different trailers +* Try inserting files in a loop. """ import os @@ -35,3 +36,13 @@ ) assert old_output.xref_get_keys(-1) == new_output.xref_get_keys(-1) assert old_output.xref_get_key(-1, "ID") != new_output.xref_get_key(-1, "ID") + + +def test_issue1417_insertpdf_in_loop(): + """Using a context manager instead of explicitly closing files""" + f = os.path.join(resources, "1.pdf") + big_doc = fitz.open() + for n in range(0, 1025): + with fitz.open(f) as pdf: + big_doc.insert_pdf(pdf) + big_doc.close() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyMuPDF-1.19.4/tests/test_pixmap.py new/PyMuPDF-1.19.5/tests/test_pixmap.py --- old/PyMuPDF-1.19.4/tests/test_pixmap.py 2022-01-01 11:57:21.000000000 +0100 +++ new/PyMuPDF-1.19.5/tests/test_pixmap.py 2022-01-12 08:23:51.000000000 +0100 @@ -64,13 +64,15 @@ pass -def test_save(): +def test_save(tmpdir): # pixmaps from file then save to image + # make pixmap from this and confirm equality pix1 = fitz.Pixmap(imgfile) - stream2 = pix1.tobytes("png") - fp = tempfile.NamedTemporaryFile(suffix=".png") - pix1.save(str(fp.name)) - del fp + outfile = os.path.join(tmpdir, "foo.png") + pix1.save(outfile, output="png") + # read it back + pix2 = fitz.Pixmap(outfile) + assert repr(pix1) == repr(pix2) def test_setalpha():