Skip to content

Commit 444b5eb

Browse files
committed
upload v1.18.8.
1 parent 4cc565c commit 444b5eb

File tree

9 files changed

+103
-62
lines changed

9 files changed

+103
-62
lines changed

PKG-INFO

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Metadata-Version: 1.1
22
Name: PyMuPDF
3-
Version: 1.18.7
3+
Version: 1.18.8
44
Author: Jorj McKie
55
Author-email: [email protected]
66
Maintainer: Jorj McKie
@@ -9,7 +9,7 @@ Home-page: https://github.com/pymupdf/PyMuPDF
99
Download-url: https://github.com/pymupdf/PyMuPDF
1010
Summary: PyMuPDF is a Python binding for the PDF rendering library MuPDF
1111
Description:
12-
Release date: January 31, 2021
12+
Release date: February 3, 2021
1313

1414
Authors
1515
=======
@@ -20,7 +20,7 @@ Description:
2020
Introduction
2121
============
2222

23-
This is **version 1.18.7 of PyMuPDF**, a Python binding for `MuPDF <http://mupdf.com/>`_ - "a lightweight PDF and XPS viewer".
23+
This is **version 1.18.8 of PyMuPDF**, a Python binding for `MuPDF <http://mupdf.com/>`_ - "a lightweight PDF and XPS viewer".
2424

2525
MuPDF can access files in PDF, XPS, OpenXPS, epub, comic and fiction book formats, and it is known for both, its top performance and high rendering quality.
2626

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
# PyMuPDF 1.18.7
1+
# PyMuPDF 1.18.8
22

33
![logo](https://github.com/pymupdf/PyMuPDF/blob/master/demo/pymupdf.jpg)
44

5-
Release date: January 31, 2021
5+
Release date: February 3, 2021
66

77
**Travis-CI:** [![Build Status](https://travis-ci.org/JorjMcKie/py-mupdf.svg?branch=master)](https://travis-ci.org/JorjMcKie/py-mupdf)
88

@@ -15,7 +15,7 @@ On **[PyPI](https://pypi.org/project/PyMuPDF)** since August 2016: [![Downloads]
1515

1616
# Introduction
1717

18-
This is **version 1.18.7 of PyMuPDF**, a Python binding with support for [MuPDF 1.18.*](http://mupdf.com/) - "a lightweight PDF, XPS, and E-book viewer".
18+
This is **version 1.18.8 of PyMuPDF**, a Python binding with support for [MuPDF 1.18.*](http://mupdf.com/) - "a lightweight PDF, XPS, and E-book viewer".
1919

2020
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.
2121

docs/changes.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
Change Logs
22
===============
33

4+
Changes in Version 1.18.8
5+
-------------------------
6+
7+
This is a bug fix version only. We are publishing early because of the potentially widely used functions.
8+
9+
* **Fixed** issue `#881 <https://github.com/pymupdf/PyMuPDF/issues/881>`_. Fixed a memory leak in :meth:`Page.insert_image` when inserting images from files or memory.
10+
* **Fixed** issue `#878 <https://github.com/pymupdf/PyMuPDF/issues/878>`_. ``pathlib.Path`` objects should now correctly handle file path hierarchies.
11+
12+
413
Changes in Version 1.18.7
514
-------------------------
615

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
# built documents.
4141
#
4242
# The full version, including alpha/beta/rc tags.
43-
release = "1.18.7"
43+
release = "1.18.8"
4444

4545
# The short X.Y version
4646
version = release

docs/version.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Covered Version
22
--------------------
33

4-
This documentation covers PyMuPDF v1.18.7 features as of **2021-01-31 00:00:01**.
4+
This documentation covers PyMuPDF v1.18.8 features as of **2021-02-03 19:56:11**.
55

66
.. note:: The major and minor versions of **PyMuPDF** and **MuPDF** will always be the same. Only the third qualifier (patch level) may deviate from that of MuPDF.

fitz/fitz.i

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,8 @@ struct Document
295295
"""
296296
if not filename or type(filename) is str:
297297
pass
298+
elif hasattr(filename, "absolute"):
299+
filename = str(filename)
298300
elif hasattr(filename, "name"):
299301
filename = filename.name
300302
else:
@@ -691,9 +693,10 @@ struct Document
691693
_extend_toc_items(PyObject *items)
692694
{
693695
pdf_document *pdf = pdf_specifics(gctx, (fz_document *)$self);
694-
pdf_obj *bm, *col;
696+
pdf_obj *bm, *col, *obj;
695697
int count, flags;
696-
PyObject *item=NULL, *itemdict=NULL, *xrefs, *bold, *italic, *collapse;
698+
PyObject *item=NULL, *itemdict=NULL, *xrefs, *bold, *italic, *collapse, *zoom;
699+
zoom = PyUnicode_FromString("zoom");
697700
bold = PyUnicode_FromString("bold");
698701
italic = PyUnicode_FromString("italic");
699702
collapse = PyUnicode_FromString("collapse");
@@ -704,7 +707,7 @@ struct Document
704707
if (!olroot) goto finished;
705708
pdf_obj *first = pdf_dict_get(gctx, olroot, PDF_NAME(First));
706709
if (!first) goto finished;
707-
xrefs = PyList_New(0);
710+
xrefs = PyList_New(0); // pre-allocate an empty list
708711
xrefs = JM_outline_xrefs(gctx, first, xrefs);
709712
Py_ssize_t i, n = PySequence_Size(xrefs);
710713
if (!n) goto finished;
@@ -743,6 +746,15 @@ struct Document
743746
PyTuple_SET_ITEM(color, 2, Py_BuildValue("f", pdf_to_real(gctx, pdf_array_get(gctx, col, 2))));
744747
DICT_SETITEM_DROP(itemdict, dictkey_color, color);
745748
}
749+
float z=0;
750+
obj = pdf_dict_get(gctx, bm, PDF_NAME(Dest));
751+
if (!obj || !pdf_is_array(gctx, obj)) {
752+
obj = pdf_dict_getl(gctx, bm, PDF_NAME(A), PDF_NAME(D), NULL);
753+
}
754+
if (pdf_is_array(gctx, obj) && pdf_array_len(gctx, obj) == 5) {
755+
z = pdf_to_real(gctx, pdf_array_get(gctx, obj, 4));
756+
}
757+
DICT_SETITEM_DROP(itemdict, zoom, Py_BuildValue("f", z));
746758
PyList_SetItem(item, 3, itemdict);
747759
PyList_SetItem(items, i, item);
748760
pdf_drop_obj(gctx, bm);
@@ -755,6 +767,7 @@ struct Document
755767
Py_CLEAR(bold);
756768
Py_CLEAR(italic);
757769
Py_CLEAR(collapse);
770+
Py_CLEAR(zoom);
758771
pdf_drop_obj(gctx, bm);
759772
PyErr_Clear();
760773
}
@@ -1749,8 +1762,10 @@ struct Document
17491762
pass
17501763
elif hasattr(filename, "open"): # assume: pathlib.Path
17511764
filename = str(filename)
1752-
elif not hasattr(filename, "seek"): # assume: file pointer
1753-
raise ValueError("filename must be str, Path or file pointer")
1765+
elif hasattr(filename, "name"): # assume: file object
1766+
filename = filename.name
1767+
elif not hasattr(filename, "seek"): # assume file object
1768+
raise ValueError("filename must be str, Path or file object")
17541769
if filename == self.name and not incremental:
17551770
raise ValueError("save to original must be incremental")
17561771
if self.page_count < 1:
@@ -3876,7 +3891,7 @@ if basestate:
38763891
raise ValueError("bad page number(s)")
38773892
38783893
# remove TOC bookmarks pointing to deleted page
3879-
old_toc = self.getToC()
3894+
old_toc = self.get_toc()
38803895
for i, item in enumerate(old_toc):
38813896
if item[2] == pno + 1:
38823897
self.del_toc_item(i)
@@ -3904,7 +3919,7 @@ if basestate:
39043919
if not f <= t < page_count:
39053920
raise ValueError("bad page number(s)")
39063921
3907-
old_toc = self.getToC()
3922+
old_toc = self.get_toc()
39083923
for i, item in enumerate(old_toc):
39093924
if f + 1 <= item[2] <= t + 1:
39103925
self.del_toc_item(i)
@@ -5509,9 +5524,9 @@ def get_oc_items(self) -> list:
55095524
fz_rect cropbox = fz_empty_rect;
55105525
fz_rect r = JM_rect_from_py(rect);
55115526
cropbox.x0 = r.x0;
5512-
cropbox.y0 = mediabox.y1 - r.y1;
55135527
cropbox.x1 = r.x1;
5514-
cropbox.y1 = mediabox.y1 - r.y0;
5528+
cropbox.y0 = mediabox.y1 - r.y1 + mediabox.y0;
5529+
cropbox.y1 = mediabox.y1 - r.y0 + mediabox.y0;
55155530
pdf_dict_put_drop(gctx, page->obj, PDF_NAME(CropBox),
55165531
pdf_new_rect(gctx, page->doc, cropbox));
55175532
}
@@ -5920,7 +5935,7 @@ if not sanitize and not self.is_wrapped:
59205935
// insert an image
59215936
//----------------------------------------------------------------
59225937
FITZEXCEPTION(_insertImage, !result)
5923-
PyObject *_insertImage(const char *filename=NULL, struct Pixmap *pixmap=NULL, PyObject *stream=NULL, PyObject *imask=NULL, int overlay=1, int oc=0, int xref = 0, PyObject *matrix=NULL,
5938+
PyObject *_insertImage(const char *filename=NULL, struct Pixmap *pixmap=NULL, PyObject *stream=NULL, PyObject *imask=NULL, int overlay=1, int oc=0, int xref=0, int alpha=0, PyObject *matrix=NULL,
59245939
const char *_imgname=NULL, PyObject *_imgpointer=NULL)
59255940
{
59265941
pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);
@@ -5944,8 +5959,7 @@ if not sanitize and not self.is_wrapped:
59445959
//-------------------------------------------------------------
59455960
// create the image
59465961
//-------------------------------------------------------------
5947-
if (filename || EXISTS(stream) || EXISTS(_imgpointer))
5948-
{
5962+
if (filename || EXISTS(stream) || EXISTS(_imgpointer)) {
59495963
if (filename) {
59505964
image = fz_new_image_from_file(gctx, filename);
59515965
} else if (EXISTS(stream)) {
@@ -5968,11 +5982,11 @@ if not sanitize and not self.is_wrapped:
59685982
fz_drop_image(gctx, image);
59695983
image = zimg;
59705984
zimg = NULL;
5971-
} else {
5972-
pix = fz_get_pixmap_from_image(gctx, image, NULL, NULL, 0, 0);
5973-
pix->xres = xres;
5974-
pix->yres = yres;
5975-
if (pix->alpha == 1) { // have alpha: create an SMask
5985+
} else if (alpha == 1) {
5986+
// have alpha: create an SMask
5987+
pix = fz_get_pixmap_from_image(gctx, image, NULL, NULL, 0, 0);
5988+
pix->xres = xres;
5989+
pix->yres = yres;
59765990
pm = fz_convert_pixmap(gctx, pix, NULL, NULL, NULL, fz_default_color_params, 1);
59775991
pm->alpha = 0;
59785992
pm->colorspace = fz_keep_colorspace(gctx, fz_device_gray(gctx));
@@ -5981,10 +5995,6 @@ if not sanitize and not self.is_wrapped:
59815995
fz_drop_image(gctx, image);
59825996
image = zimg;
59835997
zimg = NULL;
5984-
} else {
5985-
fz_drop_pixmap(gctx, pix);
5986-
pix = NULL;
5987-
}
59885998
}
59895999
} else { // pixmap specified
59906000
fz_pixmap *arg_pix = (fz_pixmap *) pixmap;
@@ -7212,6 +7222,28 @@ Use pillowWrite to reflect this in output image."""%}
72127222
return rc;
72137223
}
72147224
7225+
//-----------------------------------------------------------------
7226+
// check if monochrome
7227+
//-----------------------------------------------------------------
7228+
%pythoncode %{@property%}
7229+
%pythonprepend is_monochrome %{"""Check if pixmap is monochrome."""%}
7230+
PyObject *is_monochrome()
7231+
{
7232+
return JM_BOOL(fz_is_pixmap_monochrome(gctx, (fz_pixmap *) $self));
7233+
}
7234+
7235+
//-----------------------------------------------------------------
7236+
// MD5 digest of pixmap
7237+
//-----------------------------------------------------------------
7238+
%pythoncode %{@property%}
7239+
%pythonprepend digest %{"""MD5 digest of pixmap (bytes)."""%}
7240+
PyObject *digest()
7241+
{
7242+
unsigned char digest[16];
7243+
fz_md5_pixmap(gctx, (fz_pixmap *) $self, digest);
7244+
return Py_BuildValue("y", digest);
7245+
}
7246+
72157247
//-----------------------------------------------------------------
72167248
// get length of one image row
72177249
//-----------------------------------------------------------------

fitz/utils.py

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ def insertImage(*args, **kwargs) -> None:
240240
overlay = bool(kwargs.get("overlay", True))
241241

242242
def calc_hash(stream):
243-
m = hashlib.sha1()
243+
m = hashlib.md5()
244244
m.update(stream)
245245
return m.digest()
246246

@@ -336,31 +336,30 @@ def calc_matrix(fw, fh, tr, rotate=0):
336336
# to the actual C-level function (_imgpointer), and set all other
337337
# parameters to None.
338338
# -------------------------------------------------------------------------
339-
if keep_proportion is True: # for this we need the image dimension
340-
if pixmap: # this is the easy case
341-
w = pixmap.width
342-
h = pixmap.height
343-
digest = calc_hash(pixmap.samples)
344-
345-
elif stream: # use tool to access the information
346-
# we also pass through the generated fz_image address
347-
if type(stream) is io.BytesIO:
348-
stream = stream.getvalue()
349-
img_prof = TOOLS.image_profile(stream, keep_image=True)
350-
w, h = img_prof["width"], img_prof["height"]
351-
digest = calc_hash(stream)
352-
stream = None # make sure this arg is NOT used
353-
_imgpointer = img_prof["image"] # pointer to fz_image
354-
355-
else: # worst case: must read the file
356-
stream = open(filename, "rb").read()
357-
digest = calc_hash(stream)
358-
img_prof = TOOLS.image_profile(stream, keep_image=True)
359-
w, h = img_prof["width"], img_prof["height"]
360-
stream = None # make sure this arg is NOT used
361-
filename = None # make sure this arg is NOT used
362-
_imgpointer = img_prof["image"] # pointer to fz_image
363339

340+
if pixmap:
341+
w = pixmap.width
342+
h = pixmap.height
343+
alpha = pixmap.alpha
344+
digest = calc_hash(pixmap.samples)
345+
elif stream:
346+
pix = Pixmap(stream)
347+
w = pix.width
348+
h = pix.height
349+
alpha = pix.alpha
350+
digest = calc_hash(pix.samples)
351+
del pix
352+
if type(stream) is io.BytesIO:
353+
stream = stream.getvalue()
354+
else:
355+
pix = Pixmap(filename)
356+
w = pix.width
357+
h = pix.height
358+
alpha = pix.alpha
359+
digest = calc_hash(pix.samples)
360+
del pix
361+
362+
if keep_proportion is True: # for this we need the image dimension
364363
maxf = max(w, h)
365364
fw = w / maxf
366365
fh = h / maxf
@@ -393,6 +392,7 @@ def calc_matrix(fw, fh, tr, rotate=0):
393392
overlay=overlay,
394393
oc=oc, # optional content object
395394
xref=xref,
395+
alpha=alpha,
396396
_imgname=_imgname, # generated PDF resource name
397397
_imgpointer=_imgpointer, # address of fz_image
398398
)
@@ -831,7 +831,7 @@ def set_toc_item(
831831
title: OptStr = None,
832832
to: point_like = None,
833833
filename: OptStr = None,
834-
zoom: int = 0,
834+
zoom: float = 0,
835835
) -> None:
836836
"""Update TOC item by index.
837837
@@ -978,8 +978,8 @@ def getDestStr(xref: int, ddict: dict) -> str:
978978
"""
979979
if not ddict:
980980
return ""
981-
str_goto = "/A<</S/GoTo/D[%i 0 R/XYZ %g %g %i]>>"
982-
str_gotor1 = "/A<</S/GoToR/D[%s /XYZ %s %s %s]/F<</F%s/UF%s/Type/Filespec>>>>"
981+
str_goto = "/A<</S/GoTo/D[%i 0 R/XYZ %g %g %g]>>"
982+
str_gotor1 = "/A<</S/GoToR/D[%s /XYZ %g %g %g]/F<</F%s/UF%s/Type/Filespec>>>>"
983983
str_gotor2 = "/A<</S/GoToR/D%s/F<</F%s/UF%s/Type/Filespec>>>>"
984984
str_launch = "/A<</S/Launch/F<</F%s/UF%s/Type/Filespec>>>>"
985985
str_uri = "/A<</S/URI/URI%s>>"

fitz/version.i

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
%pythoncode %{
22
VersionFitz = "1.18.0"
3-
VersionBind = "1.18.7"
4-
VersionDate = "2021-01-31 00:00:01"
5-
version = (VersionBind, VersionFitz, "202101310001")
6-
%}
3+
VersionBind = "1.18.8"
4+
VersionDate = "2021-02-03 19:56:11"
5+
version = (VersionBind, VersionFitz, "20210203195611")
6+
%}

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def load_libraries():
131131

132132
setup(
133133
name="PyMuPDF",
134-
version="1.18.7",
134+
version="1.18.8",
135135
description="Python bindings for the PDF rendering library MuPDF",
136136
long_description=long_desc,
137137
classifiers=classifier,

0 commit comments

Comments
 (0)