Skip to content

Commit 546d88d

Browse files
authored
Merge pull request #240 from JorjMcKie/master
merge v1.14.4
2 parents 5292856 + c458775 commit 546d88d

File tree

10 files changed

+399
-347
lines changed

10 files changed

+399
-347
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
# PyMuPDF 1.14.3
1+
# PyMuPDF 1.14.4
22

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

5-
Release date: December 2, 2018
5+
Release date: December 18, 2018
66

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

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

1515
# Introduction
1616

17-
This is **version 1.14.3 of PyMuPDF (formerly python-fitz)**, a Python binding with support for [MuPDF 1.14.x](http://mupdf.com/) - "a lightweight PDF, XPS, and E-book viewer".
17+
This is **version 1.14.4 of PyMuPDF (formerly python-fitz)**, a Python binding with support for [MuPDF 1.14.x](http://mupdf.com/) - "a lightweight PDF, XPS, and E-book viewer".
1818

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

@@ -71,7 +71,7 @@ You can now also create and update Form PDFs and form fields with support for te
7171

7272
Have a look at the basic [demos](https://github.com/rk700/PyMuPDF/tree/master/demo), the [examples](https://github.com/rk700/PyMuPDF/tree/master/examples) (which contain complete, working programs), and the **recipes** section of our [Wiki](https://github.com/rk700/PyMuPDF/wiki) sidebar, which contains more than a dozen of guides in How-To-style.
7373

74-
Our documentation, written using Sphinx, is available in various formats from the following sources.
74+
Our documentation, written using Sphinx, is available in various formats from the following sources. It currently is a combination of a reference guide and a user manual. For a quick start to using PyMuPDF look at the [tutorial](https://pymupdf.readthedocs.io/en/latest/tutorial/) and the [recipes](https://pymupdf.readthedocs.io/en/latest/faq/) chapters.
7575

7676
* You can view it online at [Read the Docs](https://pymupdf.readthedocs.io/). For **best quality downloads** use the following links.
7777
* zipped [HTML](https://github.com/rk700/PyMuPDF/tree/master/doc/html.zip)

fitz/fitz.i

Lines changed: 112 additions & 108 deletions
Large diffs are not rendered by default.

fitz/fitz.py

Lines changed: 64 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,14 @@ class _object:
100100
import weakref
101101
from binascii import hexlify
102102
import math
103-
import platform
104-
platform_bitness = platform.architecture()[0]
105-
del platform
103+
104+
fitz_py2 = str is bytes # if true, this is Python 2
106105

107106

108107
VersionFitz = "1.14.0"
109-
VersionBind = "1.14.3"
110-
VersionDate = "2018-12-01 18:33:20"
111-
version = (VersionBind, VersionFitz, "20181201183320")
108+
VersionBind = "1.14.4"
109+
VersionDate = "2018-12-18 08:56:44"
110+
version = (VersionBind, VersionFitz, "20181218085644")
112111

113112

114113
class Matrix():
@@ -130,8 +129,8 @@ def __init__(self, *args):
130129
if len(args) == 1: # either an angle or a sequ
131130
if hasattr(args[0], "__float__"):
132131
theta = args[0] * math.pi / 180.0
133-
c = math.cos(theta)
134-
s = math.sin(theta)
132+
c = round(math.cos(theta), 10)
133+
s = round(math.sin(theta), 10)
135134
self.a = self.d = c
136135
self.b = s
137136
self.c = -s
@@ -240,19 +239,13 @@ def preRotate(self, theta):
240239

241240
def concat(self, one, two):
242241
"""Multiply two matrices and replace current one."""
243-
dst = Matrix()
244-
dst.a = one[0] * two[0] + one[1] * two[2]
245-
dst.b = one[0] * two[1] + one[1] * two[3]
246-
dst.c = one[2] * two[0] + one[3] * two[2]
247-
dst.d = one[2] * two[1] + one[3] * two[3]
248-
dst.e = one[4] * two[0] + one[5] * two[2] + two[4]
249-
dst.f = one[4] * two[1] + one[5] * two[3] + two[5]
250-
self.a = dst.a
251-
self.b = dst.b
252-
self.c = dst.c
253-
self.d = dst.d
254-
self.e = dst.e
255-
self.f = dst.f
242+
dst = TOOLS._concat_matrix(one, two)
243+
self.a = dst[0]
244+
self.b = dst[1]
245+
self.c = dst[2]
246+
self.d = dst[3]
247+
self.e = dst[4]
248+
self.f = dst[5]
256249
return self
257250

258251
def __getitem__(self, i):
@@ -285,13 +278,7 @@ def __mul__(self, m):
285278
if hasattr(m, "__float__"):
286279
return Matrix(self.a * m, self.b * m, self.c * m,
287280
self.d * m, self.e * m, self.f * m)
288-
a = self.a * m[0] + self.b * m[2]
289-
b = self.a * m[1] + self.b * m[3]
290-
c = self.c * m[0] + self.d * m[2]
291-
d = self.c * m[1] + self.d * m[3]
292-
e = self.e * m[0] + self.f * m[2] + m[4]
293-
f = self.e * m[1] + self.f * m[3] + m[5]
294-
return Matrix(a, b, c, d, e, f)
281+
return self.concat(self, m)
295282

296283
def __truediv__(self, m):
297284
if hasattr(m, "__float__"):
@@ -1456,11 +1443,11 @@ def getPDFstr(x):
14561443
# require full unicode: make a UTF-16BE hex string with BOM "feff"
14571444
r = hexlify(bytearray([254, 255]) + bytearray(x, "UTF-16BE"))
14581445
# r is 'bytes', so convert to 'str' if Python 3
1459-
t = r if str is bytes else r.decode()
1446+
t = r if fitz_py2 else r.decode()
14601447
return "<" + t + ">" # brackets indicate hex
14611448

14621449
s = x.replace("\x00", " ")
1463-
if str is bytes:
1450+
if fitz_py2:
14641451
if type(s) is str:
14651452
s = unicode(s, "utf-8", "replace")
14661453

@@ -1597,9 +1584,9 @@ def CheckMorph(o):
15971584
if not bool(o): return False
15981585
if not (type(o) in (list, tuple) and len(o) == 2):
15991586
raise ValueError("morph must be a sequence of length 2")
1600-
if not (type(o[0]) == Point and issubclass(type(o[1]), Matrix)):
1587+
if not (len(o[0]) == 2 and len(o[1]) == 6):
16011588
raise ValueError("invalid morph parm 0")
1602-
if not o[1].e == o[1].f == 0:
1589+
if not o[1][4] == o[1][5] == 0:
16031590
raise ValueError("invalid morph parm 1")
16041591
return True
16051592

@@ -1718,7 +1705,7 @@ def __init__(self, filename=None, stream=None, filetype=None, rect=None, width=0
17181705
if not filename or type(filename) is str:
17191706
pass
17201707
else:
1721-
if str is bytes: # Python 2
1708+
if fitz_py2: # Python 2
17221709
if type(filename) is unicode:
17231710
filename = filename.encode("utf8")
17241711
else:
@@ -2968,8 +2955,18 @@ def _insertFont(self, fontname, bfname, fontfile, fontbuffer, set_simple, idx, w
29682955
return _fitz.Page__insertFont(self, fontname, bfname, fontfile, fontbuffer, set_simple, idx, wmode, serif, encoding, ordering)
29692956

29702957

2958+
def _getTransformation(self):
2959+
"""_getTransformation(self) -> PyObject *"""
2960+
CheckParent(self)
2961+
2962+
val = _fitz.Page__getTransformation(self)
2963+
val = Matrix(val)
2964+
2965+
return val
2966+
2967+
29712968
def _getContents(self):
2972-
"""_getContents(self) -> PyObject *"""
2969+
"""Return list of /Contents objects as xref integers."""
29732970
CheckParent(self)
29742971

29752972
return _fitz.Page__getContents(self)
@@ -3551,7 +3548,7 @@ def color_string(cs, code):
35513548
col = " ".join(map(str, cs)) + app
35523549
else:
35533550
col = "%g" % cs + app
3554-
return bytes(col, "utf8") if str is not bytes else col
3551+
return bytes(col, "utf8") if not fitz_py2 else col
35553552

35563553
type = self.type[0] # get the annot type
35573554
dt = self.border["dashes"] # get the dashes spec
@@ -3560,6 +3557,8 @@ def color_string(cs, code):
35603557
fill = self.colors["fill"] # get the fill color
35613558
rect = None # used if we change the rect here
35623559
bfill = color_string(fill, "f")
3560+
p_ctm = self.parent._getTransformation() # page transformation matrix
3561+
imat = ~p_ctm # inverse page transf. matrix
35633562

35643563
line_end_le, line_end_ri = 0, 0 # line end codes
35653564
if self.lineEnds:
@@ -3626,7 +3625,11 @@ def color_string(cs, code):
36263625
ap = b"/Alp0 gs\n" + ap
36273626
ap_updated = True
36283627

3629-
if line_end_le + line_end_ri > 0 and type in (ANNOT_POLYGON, ANNOT_POLYLINE):
3628+
#----------------------------------------------------------------------
3629+
# the following handles line end symbols for 'Polygon' and 'Polyline
3630+
#----------------------------------------------------------------------
3631+
if max(line_end_le, line_end_ri) > 0 and type in (ANNOT_POLYGON, ANNOT_POLYLINE):
3632+
36303633
le_funcs = (None, TOOLS._le_square, TOOLS._le_circle,
36313634
TOOLS._le_diamond, TOOLS._le_openarrow,
36323635
TOOLS._le_closedarrow, TOOLS._le_butt,
@@ -3639,15 +3642,15 @@ def color_string(cs, code):
36393642
points = self.vertices
36403643
ap = b"q\n" + ap + b"\nQ\n"
36413644
if line_end_le in le_funcs_range:
3642-
p1 = Point(points[0])
3643-
p2 = Point(points[1])
3645+
p1 = Point(points[0]) * imat
3646+
p2 = Point(points[1]) * imat
36443647
left = le_funcs[line_end_le](self, p1, p2, False)
3645-
ap += bytes(left, "utf8") if str is not bytes else left
3648+
ap += bytes(left, "utf8") if not fitz_py2 else left
36463649
if line_end_ri in le_funcs_range:
3647-
p1 = Point(points[-2])
3648-
p2 = Point(points[-1])
3650+
p1 = Point(points[-2]) * imat
3651+
p2 = Point(points[-1]) * imat
36493652
left = le_funcs[line_end_ri](self, p1, p2, True)
3650-
ap += bytes(left, "utf8") if str is not bytes else left
3653+
ap += bytes(left, "utf8") if not fitz_py2 else left
36513654

36523655
if ap_updated:
36533656
if rect: # rect modified here?
@@ -4176,10 +4179,10 @@ def _extractText(self, format):
41764179

41774180
class b64encode(json.JSONEncoder):
41784181
def default(self,s):
4179-
if str is not bytes and type(s) is bytes:
4182+
if not fitz_py2 and type(s) is bytes:
41804183
return base64.b64encode(s).decode()
41814184
if type(s) is bytearray:
4182-
if str is bytes:
4185+
if fitz_py2:
41834186
return base64.b64encode(s)
41844187
else:
41854188
return base64.b64encode(s).decode()
@@ -4338,6 +4341,11 @@ def _union_rect(self, r1, r2):
43384341
return _fitz.Tools__union_rect(self, r1, r2)
43394342

43404343

4344+
def _concat_matrix(self, m1, m2):
4345+
"""Concatenate matrices m1, m2."""
4346+
return _fitz.Tools__concat_matrix(self, m1, m2)
4347+
4348+
43414349
def _invert_matrix(self, matrix):
43424350
"""Invert a matrix."""
43434351
return _fitz.Tools__invert_matrix(self, matrix)
@@ -4350,7 +4358,6 @@ def _hor_matrix(self, C, P):
43504358
S = (P - C).unit # unit vector C -> P
43514359
return Matrix(1, 0, 0, 1, -C.x, -C.y) * Matrix(S.x, -S.y, S.y, S.x, 0, 0)
43524360

4353-
43544361
def _le_annot_parms(self, annot, p1, p2):
43554362
"""Get common parameters for making line end symbols.
43564363
"""
@@ -4362,7 +4369,6 @@ def _le_annot_parms(self, annot, p1, p2):
43624369
if not fc: fc = (0,0,0)
43634370
fcol = " ".join(map(str, fc)) + " rg\n"
43644371
nr = annot.rect
4365-
h = nr.y1
43664372
np1 = p1 # point coord relative to annot rect
43674373
np2 = p2 # point coord relative to annot rect
43684374
m = self._hor_matrix(np1, np2) # matrix makes the line horizontal
@@ -4373,10 +4379,9 @@ def _le_annot_parms(self, annot, p1, p2):
43734379
opacity = "/Alp0 gs\n"
43744380
else:
43754381
opacity = ""
4376-
return m, im, L, R, w, h, scol, fcol, opacity
4382+
return m, im, L, R, w, scol, fcol, opacity
43774383

4378-
4379-
def _oval_string(self, h, p1, p2, p3, p4):
4384+
def _oval_string(self, p1, p2, p3, p4):
43804385
"""Return /AP string defining an oval within a 4-polygon provided as points
43814386
"""
43824387
def bezier(p, q, r):
@@ -4404,11 +4409,10 @@ def bezier(p, q, r):
44044409
ap += bezier(ul1, ul2, ml)
44054410
return ap
44064411

4407-
44084412
def _le_diamond(self, annot, p1, p2, lr):
44094413
"""Make stream commands for diamond line end symbol. "lr" denotes left (False) or right point.
44104414
"""
4411-
m, im, L, R, w, h, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
4415+
m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
44124416
shift = 2.5 # 2*shift*width = length of square edge
44134417
d = shift * max(1, w)
44144418
M = R - (d/2., 0) if lr else L + (d/2., 0)
@@ -4426,11 +4430,10 @@ def _le_diamond(self, annot, p1, p2, lr):
44264430
ap += scol + fcol + "b\nQ\n"
44274431
return ap
44284432

4429-
44304433
def _le_square(self, annot, p1, p2, lr):
44314434
"""Make stream commands for square line end symbol. "lr" denotes left (False) or right point.
44324435
"""
4433-
m, im, L, R, w, h, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
4436+
m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
44344437
shift = 2.5 # 2*shift*width = length of square edge
44354438
d = shift * max(1, w)
44364439
M = R - (d/2., 0) if lr else L + (d/2., 0)
@@ -4448,25 +4451,23 @@ def _le_square(self, annot, p1, p2, lr):
44484451
ap += scol + fcol + "b\nQ\n"
44494452
return ap
44504453

4451-
44524454
def _le_circle(self, annot, p1, p2, lr):
44534455
"""Make stream commands for circle line end symbol. "lr" denotes left (False) or right point.
44544456
"""
4455-
m, im, L, R, w, h, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
4457+
m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
44564458
shift = 2.5 # 2*shift*width = length of square edge
44574459
d = shift * max(1, w)
44584460
M = R - (d/2., 0) if lr else L + (d/2., 0)
44594461
r = Rect(M, M) + (-d, -d, d, d) # the square
4460-
ap = "q\n" + opacity + self._oval_string(h, r.tl * im, r.tr * im, r.br * im, r.bl * im)
4462+
ap = "q\n" + opacity + self._oval_string(r.tl * im, r.tr * im, r.br * im, r.bl * im)
44614463
ap += "%g w\n" % w
44624464
ap += scol + fcol + "b\nQ\n"
44634465
return ap
44644466

4465-
44664467
def _le_butt(self, annot, p1, p2, lr):
44674468
"""Make stream commands for butt line end symbol. "lr" denotes left (False) or right point.
44684469
"""
4469-
m, im, L, R, w, h, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
4470+
m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
44704471
shift = 3
44714472
d = shift * max(1, w)
44724473
M = R if lr else L
@@ -4478,11 +4479,10 @@ def _le_butt(self, annot, p1, p2, lr):
44784479
ap += scol + "s\nQ\n"
44794480
return ap
44804481

4481-
44824482
def _le_slash(self, annot, p1, p2, lr):
44834483
"""Make stream commands for slash line end symbol. "lr" denotes left (False) or right point.
44844484
"""
4485-
m, im, L, R, w, h, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
4485+
m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
44864486
rw = 1.1547 * max(1, w) * 1.0 # makes rect diagonal a 30 deg inclination
44874487
M = R if lr else L
44884488
r = Rect(M.x - rw, M.y - 2 * w, M.x + rw, M.y + 2 * w)
@@ -4494,11 +4494,10 @@ def _le_slash(self, annot, p1, p2, lr):
44944494
ap += scol + "s\nQ\n"
44954495
return ap
44964496

4497-
44984497
def _le_openarrow(self, annot, p1, p2, lr):
44994498
"""Make stream commands for open arrow line end symbol. "lr" denotes left (False) or right point.
45004499
"""
4501-
m, im, L, R, w, h, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
4500+
m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
45024501
shift = 2.5
45034502
d = shift * max(1, w)
45044503
p2 = R + (d/2., 0) if lr else L - (d/2., 0)
@@ -4514,11 +4513,10 @@ def _le_openarrow(self, annot, p1, p2, lr):
45144513
ap += scol + "S\nQ\n"
45154514
return ap
45164515

4517-
45184516
def _le_closedarrow(self, annot, p1, p2, lr):
45194517
"""Make stream commands for closed arrow line end symbol. "lr" denotes left (False) or right point.
45204518
"""
4521-
m, im, L, R, w, h, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
4519+
m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
45224520
shift = 2.5
45234521
d = shift * max(1, w)
45244522
p2 = R + (d/2., 0) if lr else L - (d/2., 0)
@@ -4534,11 +4532,10 @@ def _le_closedarrow(self, annot, p1, p2, lr):
45344532
ap += scol + fcol + "b\nQ\n"
45354533
return ap
45364534

4537-
45384535
def _le_ropenarrow(self, annot, p1, p2, lr):
45394536
"""Make stream commands for right open arrow line end symbol. "lr" denotes left (False) or right point.
45404537
"""
4541-
m, im, L, R, w, h, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
4538+
m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
45424539
shift = 2.5
45434540
d = shift * max(1, w)
45444541
p2 = R - (d/3., 0) if lr else L + (d/3., 0)
@@ -4554,11 +4551,10 @@ def _le_ropenarrow(self, annot, p1, p2, lr):
45544551
ap += scol + fcol + "S\nQ\n"
45554552
return ap
45564553

4557-
45584554
def _le_rclosedarrow(self, annot, p1, p2, lr):
45594555
"""Make stream commands for right closed arrow line end symbol. "lr" denotes left (False) or right point.
45604556
"""
4561-
m, im, L, R, w, h, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
4557+
m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2)
45624558
shift = 2.5
45634559
d = shift * max(1, w)
45644560
p2 = R - (2*d, 0) if lr else L + (2*d, 0)
@@ -4575,7 +4571,6 @@ def _le_rclosedarrow(self, annot, p1, p2, lr):
45754571
return ap
45764572

45774573

4578-
45794574
def __init__(self):
45804575
"""__init__(self) -> Tools"""
45814576
this = _fitz.new_Tools()

0 commit comments

Comments
 (0)