Skip to content

Commit 9878940

Browse files
committed
changes for version 1.18.11
1 parent 2e2a5b4 commit 9878940

File tree

14 files changed

+173
-94
lines changed

14 files changed

+173
-94
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.10
3+
Version: 1.18.11
44
Author: Jorj McKie
55
Author-email: [email protected]
66
License: GNU AFFERO GPL 3.0
@@ -10,7 +10,7 @@ Home-page: https://github.com/pymupdf/PyMuPDF
1010
Download-url: https://github.com/pymupdf/PyMuPDF
1111
Summary: PyMuPDF is a Python binding for the document renderer and toolkit MuPDF
1212
Description:
13-
Release date: March 22, 2021
13+
Release date: March 26, 2021
1414

1515
Authors
1616
=======
@@ -21,7 +21,7 @@ Description:
2121
Introduction
2222
============
2323

24-
PyMuPDF (current version 1.18.10) is a Python binding with support for `MuPDF <http://mupdf.com/>`_ (current version 1.18.*), a lightweight PDF, XPS, and E-book viewer, renderer and toolkit, which is maintained and developed by Artifex Software, Inc.
24+
PyMuPDF (current version 1.18.11) is a Python binding with support for `MuPDF <http://mupdf.com/>`_ (current version 1.18.*), a lightweight PDF, XPS, and E-book viewer, renderer and toolkit, which is maintained and developed by Artifex Software, Inc.
2525

2626
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.
2727

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# PyMuPDF 1.18.10
1+
# PyMuPDF 1.18.11
22

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

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

1616
# Introduction
1717

18-
PyMuPDF (current version 1.18.10) is a Python binding with support for [MuPDF](https://mupdf.com/) (current version 1.18.*), a lightweight PDF, XPS, and E-book viewer, renderer, and toolkit, which is maintained and developed by Artifex Software, Inc.
18+
PyMuPDF (current version 1.18.11) is a Python binding with support for [MuPDF](https://mupdf.com/) (current version 1.18.*), a lightweight PDF, XPS, and E-book viewer, renderer, and toolkit, which is maintained and developed by Artifex Software, Inc.
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

fitz/fitz.i

Lines changed: 75 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ dictkey_id = PyUnicode_InternFromString("id");
186186
dictkey_image = PyUnicode_InternFromString("image");
187187
dictkey_length = PyUnicode_InternFromString("length");
188188
dictkey_lines = PyUnicode_InternFromString("lines");
189+
dictkey_matrix = PyUnicode_InternFromString("transform");
189190
dictkey_modDate = PyUnicode_InternFromString("modDate");
190191
dictkey_name = PyUnicode_InternFromString("name");
191192
dictkey_number = PyUnicode_InternFromString("number");
@@ -2842,44 +2843,30 @@ if not self.is_form_pdf:
28422843
fz_try(gctx) {
28432844
ASSERT_PDF(pdf);
28442845
int xreflen = pdf_xref_len(gctx, pdf);
2845-
if (!INRANGE(xref, 1, xreflen-1))
2846+
if (!INRANGE(xref, 1, xreflen-1) && xref != -1)
28462847
THROWMSG(gctx, "bad xref");
2847-
obj = pdf_load_object(gctx, pdf, xref);
2848+
if (xref > 0) {
2849+
obj = pdf_load_object(gctx, pdf, xref);
2850+
} else {
2851+
obj = pdf_trailer(gctx, pdf);
2852+
}
28482853
res = JM_object_to_buffer(gctx, pdf_resolve_indirect(gctx, obj), compressed, ascii);
28492854
text = JM_EscapeStrFromBuffer(gctx, res);
28502855
}
28512856
fz_always(gctx) {
2852-
pdf_drop_obj(gctx, obj);
2857+
if (xref > 0) {
2858+
pdf_drop_obj(gctx, obj);
2859+
}
28532860
fz_drop_buffer(gctx, res);
28542861
}
28552862
fz_catch(gctx) return EMPTY_STRING;
28562863
return text;
28572864
}
2865+
%pythoncode %{
2866+
def pdf_trailer(self, compressed: bool=False, ascii:bool=False)->str:
2867+
"""Get PDF trailer as a string."""
2868+
return self.xref_object(-1, compressed=compressed, ascii=ascii)%}
28582869
2859-
//------------------------------------------------------------------
2860-
// Get String of PDF trailer
2861-
//------------------------------------------------------------------
2862-
FITZEXCEPTION(pdf_trailer, !result)
2863-
CLOSECHECK0(pdf_trailer, """Get PDF trailer as a string.""")
2864-
PyObject *
2865-
pdf_trailer(int compressed=0, int ascii=0)
2866-
{
2867-
pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);
2868-
if (!pdf) Py_RETURN_NONE;
2869-
PyObject *text = NULL;
2870-
fz_buffer *res=NULL;
2871-
fz_try(gctx) {
2872-
res = JM_object_to_buffer(gctx, pdf_trailer(gctx, pdf), compressed, ascii);
2873-
text = JM_EscapeStrFromBuffer(gctx, res);
2874-
}
2875-
fz_always(gctx) {
2876-
fz_drop_buffer(gctx, res);
2877-
}
2878-
fz_catch(gctx) {
2879-
return PyUnicode_FromString("PDF trailer damaged");
2880-
}
2881-
return text;
2882-
}
28832870
28842871
//------------------------------------------------------------------
28852872
// Get compressed stream of an object by xref
@@ -3265,7 +3252,7 @@ if not self.is_form_pdf:
32653252
pdf_obj *item = NULL;
32663253
pdf_obj *obj = NULL;
32673254
Py_ssize_t i;
3268-
float f;
3255+
double f;
32693256
pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);
32703257
fz_try(gctx) {
32713258
item = pdf_new_indirect(gctx, pdf, xref, 0);
@@ -3873,7 +3860,8 @@ if basestate:
38733860
if not self.is_pdf:
38743861
return ()
38753862
val = self._getPageInfo(pno, 3)
3876-
return val
3863+
rc = [(v[0], v[1], v[2], Rect(v[3]), Matrix(v[4])) for v in val]
3864+
return rc
38773865
38783866
38793867
def copy_page(self, pno: int, to: int =-1):
@@ -4156,30 +4144,55 @@ struct Page {
41564144
doc = self.parent
41574145
if doc.is_closed or doc.is_encrypted:
41584146
raise ValueError("document closed or encrypted")
4147+
41594148
inf_rect = Rect(1, 1, -1, -1)
4149+
null_mat = Matrix()
4150+
if transform == 1:
4151+
rc = (inf_rect, null_mat)
4152+
else:
4153+
rc = inf_rect
4154+
41604155
if type(name) in (list, tuple):
41614156
if not type(name[-1]) is int:
4162-
raise ValueError("need a full page image list item")
4157+
raise ValueError("need item of full page image list")
41634158
item = name
41644159
else:
41654160
imglist = [i for i in doc.get_page_images(self.number, True) if name == i[-3]]
41664161
if len(imglist) == 1:
41674162
item = imglist[0]
41684163
elif imglist == []:
4169-
raise ValueError("no valid image found")
4164+
raise ValueError("bad image name")
41704165
else:
4171-
raise ValueError("found more than one image of that name.")%}
4166+
raise ValueError("found multiple images named '%s'." % name)
4167+
xref = item[-1]
4168+
if xref != 0:
4169+
xobjs = [x for x in self.get_xobjects() if x[0] == xref and x[2] == 0]
4170+
if xobjs == []:
4171+
raise ValueError("image in unsupported Form XObject")
4172+
%}
41724173
%pythonappend get_image_bbox %{
41734174
if not bool(val):
4174-
return inf_rect
4175-
rc = inf_rect
4175+
return rc
4176+
41764177
for v in val:
4177-
if v[0] == item[-3]:
4178-
rc = Quad(v[1]).rect
4178+
if v[0] != item[-3]:
4179+
continue
4180+
q = Quad(v[1])
4181+
bbox = q.rect
4182+
if transform == 0:
4183+
rc = bbox
41794184
break
4180-
val = rc * self.transformation_matrix%}
4185+
4186+
hm = Matrix(TOOLS._hor_matrix(q.ll, q.lr))
4187+
h = abs(q.ll - q.ul)
4188+
w = abs(q.ur - q.ul)
4189+
m0 = Matrix(1 / w, 0, 0, 1 / h, 0, 0)
4190+
m = ~(hm * m0)
4191+
rc = (bbox, m)
4192+
break
4193+
val = rc%}
41814194
PyObject *
4182-
get_image_bbox(PyObject *name)
4195+
get_image_bbox(PyObject *name, int transform=0)
41834196
{
41844197
pdf_page *pdf_page = pdf_page_from_fz_page(gctx, (fz_page *) $self);
41854198
PyObject *rc =NULL;
@@ -6457,6 +6470,12 @@ def insert_font(self, fontname="helv", fontfile=None, fontbuffer=None,
64576470
return self.parent.get_page_images(self.number, full=full)
64586471
64596472
6473+
def get_xobjects(self):
6474+
"""List of xobjects defined in the page object."""
6475+
CheckParent(self)
6476+
return self.parent.get_page_xobjects(self.number)
6477+
6478+
64606479
def read_contents(self):
64616480
"""All /Contents streams concatenated to one bytes object."""
64626481
return TOOLS._get_all_contents(self)
@@ -9850,7 +9869,7 @@ struct TextPage {
98509869
} else if (fz_contains_rect(tp_rect, block->bbox) || fz_is_infinite_rect(tp_rect)) {
98519870
fz_image *img = block->u.i.image;
98529871
fz_colorspace *cs = img->colorspace;
9853-
text = PyUnicode_FromFormat("<image: %s, width %d, height %d, bpc %d>", fz_colorspace_name(gctx, cs), img->w, img->h, img->bpc);
9872+
text = PyUnicode_FromFormat("<image: %s, width: %d, height: %d, bpc: %d>", fz_colorspace_name(gctx, cs), img->w, img->h, img->bpc);
98549873
blockrect = fz_union_rect(blockrect, block->bbox);
98559874
}
98569875
if (!fz_is_empty_rect(blockrect)) {
@@ -11167,29 +11186,41 @@ struct Tools
1116711186
fz_point c = JM_point_from_py(C);
1116811187
fz_point p = JM_point_from_py(P);
1116911188
fz_point q = JM_point_from_py(Q);
11170-
fz_point s = fz_normalize_vector(fz_make_point(q.x - p.x, q.y - p.y));
11189+
fz_point s = JM_normalize_vector(q.x - p.x, q.y - p.y);
1117111190
fz_matrix m1 = fz_make_matrix(1, 0, 0, 1, -p.x, -p.y);
1117211191
fz_matrix m2 = fz_make_matrix(s.x, -s.y, s.y, s.x, 0, 0);
1117311192
m1 = fz_concat(m1, m2);
1117411193
c = fz_transform_point(c, m1);
11175-
c = fz_normalize_vector(c);
11194+
c = JM_normalize_vector(c.x, c.y);
1117611195
return Py_BuildValue("f", c.y);
1117711196
}
1117811197
11198+
// Return matrix that maps point C to (0,0) and point P to the
11199+
// x-axis such that abs(x) equals abs(P - C).
1117911200
PyObject *
1118011201
_hor_matrix(PyObject *C, PyObject *P)
1118111202
{
11182-
// calculate matrix m that maps line CP to the x-axis,
11183-
// such that C * m = (0, 0), and target line has same length.
1118411203
fz_point c = JM_point_from_py(C);
1118511204
fz_point p = JM_point_from_py(P);
11186-
fz_point s = fz_normalize_vector(fz_make_point(p.x - c.x, p.y - c.y));
11205+
11206+
// compute (cosine, sine) of vector P-C with double precision:
11207+
fz_point s = JM_normalize_vector(p.x - c.x, p.y - c.y);
11208+
1118711209
fz_matrix m1 = fz_make_matrix(1, 0, 0, 1, -c.x, -c.y);
1118811210
fz_matrix m2 = fz_make_matrix(s.x, -s.y, s.y, s.x, 0, 0);
1118911211
return JM_py_from_matrix(fz_concat(m1, m2));
1119011212
}
1119111213
1119211214
11215+
PyObject *
11216+
_point_in_quad(PyObject *P, PyObject *Q)
11217+
{
11218+
fz_point p = JM_point_from_py(P);
11219+
fz_quad q = JM_quad_from_py(Q);
11220+
return JM_BOOL(fz_is_point_inside_quad(p, q));
11221+
}
11222+
11223+
1119311224
FITZEXCEPTION(set_font_width, !result)
1119411225
PyObject *
1119511226
set_font_width(struct Document *doc, int xref, int width)

fitz/helper-defines.i

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ PyObject *dictkey_id;
386386
PyObject *dictkey_image;
387387
PyObject *dictkey_length;
388388
PyObject *dictkey_lines;
389+
PyObject *dictkey_matrix;
389390
PyObject *dictkey_modDate;
390391
PyObject *dictkey_name;
391392
PyObject *dictkey_number;

fitz/helper-fields.i

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ void JM_set_widget_properties(fz_context *ctx, pdf_annot *annot, PyObject *Widge
629629
if (value && PySequence_Check(value)) {
630630
n = PySequence_Size(value);
631631
fill_col = pdf_new_array(ctx, pdf, n);
632-
float col = 0;
632+
double col = 0;
633633
for (i = 0; i < n; i++) {
634634
JM_FLOAT_ITEM(value, i, &col);
635635
pdf_array_push_real(ctx, fill_col, col);
@@ -660,7 +660,7 @@ void JM_set_widget_properties(fz_context *ctx, pdf_annot *annot, PyObject *Widge
660660
if (value && PySequence_Check(value)) {
661661
n = PySequence_Size(value);
662662
border_col = pdf_new_array(ctx, pdf, n);
663-
float col = 0;
663+
double col = 0;
664664
for (i = 0; i < n; i++) {
665665
JM_FLOAT_ITEM(value, i, &col);
666666
pdf_array_push_real(ctx, border_col, col);

fitz/helper-geo-c.i

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ JM_INT_ITEM(PyObject *obj, Py_ssize_t idx, int *result)
1818
}
1919

2020
static int
21-
JM_FLOAT_ITEM(PyObject *obj, Py_ssize_t idx, float *result)
21+
JM_FLOAT_ITEM(PyObject *obj, Py_ssize_t idx, double *result)
2222
{
2323
PyObject *temp = PySequence_ITEM(obj, idx);
2424
if (!temp) return 1;
25-
*result = (float) PyFloat_AsDouble(temp);
25+
*result = PyFloat_AsDouble(temp);
2626
Py_DECREF(temp);
2727
if (PyErr_Occurred()) {
2828
PyErr_Clear();
@@ -31,6 +31,21 @@ JM_FLOAT_ITEM(PyObject *obj, Py_ssize_t idx, float *result)
3131
return 0;
3232
}
3333

34+
35+
static fz_point
36+
JM_normalize_vector(float x, float y)
37+
{
38+
double px = x, py = y, len = (double) (x * x + y * y);
39+
40+
if (len != 0) {
41+
len = sqrt(len);
42+
px /= len;
43+
py /= len;
44+
}
45+
return fz_make_point((float) px, (float) py);
46+
}
47+
48+
3449
//-----------------------------------------------------------------------------
3550
// PySequence to fz_rect. Default: infinite rect
3651
//-----------------------------------------------------------------------------
@@ -40,12 +55,12 @@ JM_rect_from_py(PyObject *r)
4055
if (!r || !PySequence_Check(r) || PySequence_Size(r) != 4)
4156
return fz_infinite_rect;
4257
Py_ssize_t i;
43-
float f[4];
58+
double f[4];
4459

4560
for (i = 0; i < 4; i++)
4661
if (JM_FLOAT_ITEM(r, i, &f[i]) == 1) return fz_infinite_rect;
4762

48-
return fz_make_rect(f[0], f[1], f[2], f[3]);
63+
return fz_make_rect((float) f[0], (float) f[1], (float) f[2], (float) f[3]);
4964
}
5065

5166
//-----------------------------------------------------------------------------
@@ -91,15 +106,15 @@ static fz_point
91106
JM_point_from_py(PyObject *p)
92107
{
93108
fz_point p0 = fz_make_point(0, 0);
94-
float x, y;
109+
double x, y;
95110

96111
if (!p || !PySequence_Check(p) || PySequence_Size(p) != 2)
97112
return p0;
98113

99114
if (JM_FLOAT_ITEM(p, 0, &x) == 1) return p0;
100115
if (JM_FLOAT_ITEM(p, 1, &y) == 1) return p0;
101116

102-
return fz_make_point(x, y);
117+
return fz_make_point((float) x, (float) y);
103118
}
104119

105120
//-----------------------------------------------------------------------------
@@ -119,15 +134,15 @@ static fz_matrix
119134
JM_matrix_from_py(PyObject *m)
120135
{
121136
Py_ssize_t i;
122-
float a[6];
137+
double a[6];
123138

124139
if (!m || !PySequence_Check(m) || PySequence_Size(m) != 6)
125140
return fz_identity;
126141

127142
for (i = 0; i < 6; i++)
128143
if (JM_FLOAT_ITEM(m, i, &a[i]) == 1) return fz_identity;
129144

130-
return fz_make_matrix(a[0], a[1], a[2], a[3], a[4], a[5]);
145+
return fz_make_matrix((float) a[0], (float) a[1], (float) a[2], (float) a[3], (float) a[4], (float) a[5]);
131146
}
132147

133148
//-----------------------------------------------------------------------------
@@ -148,7 +163,7 @@ JM_quad_from_py(PyObject *r)
148163
{
149164
fz_quad q = fz_make_quad(0, 0, 0, 0, 0, 0, 0, 0);
150165
fz_point p[4];
151-
float test;
166+
double test, x, y;
152167
Py_ssize_t i;
153168
PyObject *obj = NULL;
154169

@@ -163,8 +178,9 @@ JM_quad_from_py(PyObject *r)
163178
if (!obj || !PySequence_Check(obj) || PySequence_Size(obj) != 2)
164179
goto exit_result; // invalid: cancel the rest
165180

166-
if (JM_FLOAT_ITEM(obj, 0, &p[i].x) == 1) goto exit_result;
167-
if (JM_FLOAT_ITEM(obj, 1, &p[i].y) == 1) goto exit_result;
181+
if (JM_FLOAT_ITEM(obj, 0, &x) == 1) goto exit_result;
182+
if (JM_FLOAT_ITEM(obj, 1, &y) == 1) goto exit_result;
183+
p[i] = fz_make_point((float) x, (float) y);
168184

169185
Py_CLEAR(obj);
170186
}

0 commit comments

Comments
 (0)