Mercurial > hgrepos > Python2 > PyMuPDF
comparison tests/test_drawings.py @ 1:1d09e1dec1d9 upstream
ADD: PyMuPDF v1.26.4: the original sdist.
It does not yet contain MuPDF. This normally will be downloaded when
building PyMuPDF.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:37:51 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 1:1d09e1dec1d9 |
|---|---|
| 1 """ | |
| 2 Extract drawings of a PDF page and compare with stored expected result. | |
| 3 """ | |
| 4 | |
| 5 import io | |
| 6 import os | |
| 7 import sys | |
| 8 import pprint | |
| 9 | |
| 10 import pymupdf | |
| 11 | |
| 12 scriptdir = os.path.abspath(os.path.dirname(__file__)) | |
| 13 filename = os.path.join(scriptdir, "resources", "symbol-list.pdf") | |
| 14 symbols = os.path.join(scriptdir, "resources", "symbols.txt") | |
| 15 | |
| 16 | |
| 17 def test_drawings1(): | |
| 18 symbols_text = open(symbols).read() # expected result | |
| 19 doc = pymupdf.open(filename) | |
| 20 page = doc[0] | |
| 21 paths = page.get_cdrawings() | |
| 22 out = io.StringIO() # pprint output goes here | |
| 23 pprint.pprint(paths, stream=out) | |
| 24 assert symbols_text == out.getvalue() | |
| 25 | |
| 26 | |
| 27 def test_drawings2(): | |
| 28 delta = (0, 20, 0, 20) | |
| 29 doc = pymupdf.open() | |
| 30 page = doc.new_page() | |
| 31 | |
| 32 r = pymupdf.Rect(100, 100, 200, 200) | |
| 33 page.draw_circle(r.br, 2, color=0) | |
| 34 r += delta | |
| 35 | |
| 36 page.draw_line(r.tl, r.br, color=0) | |
| 37 r += delta | |
| 38 | |
| 39 page.draw_oval(r, color=0) | |
| 40 r += delta | |
| 41 | |
| 42 page.draw_rect(r, color=0) | |
| 43 r += delta | |
| 44 | |
| 45 page.draw_quad(r.quad, color=0) | |
| 46 r += delta | |
| 47 | |
| 48 page.draw_polyline((r.tl, r.tr, r.br), color=0) | |
| 49 r += delta | |
| 50 | |
| 51 page.draw_bezier(r.tl, r.tr, r.br, r.bl, color=0) | |
| 52 r += delta | |
| 53 | |
| 54 page.draw_curve(r.tl, r.tr, r.br, color=0) | |
| 55 r += delta | |
| 56 | |
| 57 page.draw_squiggle(r.tl, r.br, color=0) | |
| 58 r += delta | |
| 59 | |
| 60 rects = [p["rect"] for p in page.get_cdrawings()] | |
| 61 bboxes = [b[1] for b in page.get_bboxlog()] | |
| 62 for i, r in enumerate(rects): | |
| 63 assert pymupdf.Rect(r) in pymupdf.Rect(bboxes[i]) | |
| 64 | |
| 65 | |
| 66 def _dict_difference(a, b): | |
| 67 """ | |
| 68 Verifies that dictionaries "a", "b" | |
| 69 * have the same keys and values, except for key "items": | |
| 70 * the items list of "a" must be one shorter but otherwise equal the "b" items | |
| 71 | |
| 72 Returns last item of b["items"]. | |
| 73 """ | |
| 74 assert a.keys() == b.keys() | |
| 75 for k in a.keys(): | |
| 76 v1 = a[k] | |
| 77 v2 = b[k] | |
| 78 if k != "items": | |
| 79 assert v1 == v2 | |
| 80 else: | |
| 81 assert v1 == v2[:-1] | |
| 82 rc = v2[-1] | |
| 83 return rc | |
| 84 | |
| 85 | |
| 86 def test_drawings3(): | |
| 87 doc = pymupdf.open() | |
| 88 page1 = doc.new_page() | |
| 89 shape1 = page1.new_shape() | |
| 90 shape1.draw_line((10, 10), (10, 50)) | |
| 91 shape1.draw_line((10, 50), (100, 100)) | |
| 92 shape1.finish(closePath=False) | |
| 93 shape1.commit() | |
| 94 drawings1 = page1.get_drawings()[0] | |
| 95 | |
| 96 page2 = doc.new_page() | |
| 97 shape2 = page2.new_shape() | |
| 98 shape2.draw_line((10, 10), (10, 50)) | |
| 99 shape2.draw_line((10, 50), (100, 100)) | |
| 100 shape2.finish(closePath=True) | |
| 101 shape2.commit() | |
| 102 drawings2 = page2.get_drawings()[0] | |
| 103 | |
| 104 assert _dict_difference(drawings1, drawings2) == ("l", (100, 100), (10, 10)) | |
| 105 | |
| 106 page3 = doc.new_page() | |
| 107 shape3 = page3.new_shape() | |
| 108 shape3.draw_line((10, 10), (10, 50)) | |
| 109 shape3.draw_line((10, 50), (100, 100)) | |
| 110 shape3.draw_line((100, 100), (50, 70)) | |
| 111 shape3.finish(closePath=False) | |
| 112 shape3.commit() | |
| 113 drawings3 = page3.get_drawings()[0] | |
| 114 | |
| 115 page4 = doc.new_page() | |
| 116 shape4 = page4.new_shape() | |
| 117 shape4.draw_line((10, 10), (10, 50)) | |
| 118 shape4.draw_line((10, 50), (100, 100)) | |
| 119 shape4.draw_line((100, 100), (50, 70)) | |
| 120 shape4.finish(closePath=True) | |
| 121 shape4.commit() | |
| 122 drawings4 = page4.get_drawings()[0] | |
| 123 | |
| 124 assert _dict_difference(drawings3, drawings4) == ("l", (50, 70), (10, 10)) | |
| 125 | |
| 126 | |
| 127 def test_2365(): | |
| 128 """Draw a filled rectangle on a new page. | |
| 129 | |
| 130 Then extract the page's vector graphics and confirm that only one path | |
| 131 was generated which has all the right properties.""" | |
| 132 doc = pymupdf.open() | |
| 133 page = doc.new_page() | |
| 134 rect = pymupdf.Rect(100, 100, 200, 200) | |
| 135 page.draw_rect( | |
| 136 rect, color=pymupdf.pdfcolor["black"], fill=pymupdf.pdfcolor["yellow"], width=3 | |
| 137 ) | |
| 138 paths = page.get_drawings() | |
| 139 assert len(paths) == 1 | |
| 140 path = paths[0] | |
| 141 assert path["type"] == "fs" | |
| 142 assert path["fill"] == pymupdf.pdfcolor["yellow"] | |
| 143 assert path["fill_opacity"] == 1 | |
| 144 assert path["color"] == pymupdf.pdfcolor["black"] | |
| 145 assert path["stroke_opacity"] == 1 | |
| 146 assert path["width"] == 3 | |
| 147 assert path["rect"] == rect | |
| 148 | |
| 149 | |
| 150 def test_2462(): | |
| 151 """ | |
| 152 Assertion happens, if this code does NOT bring down the interpreter. | |
| 153 | |
| 154 Background: | |
| 155 We previously ignored clips for non-vector-graphics. However, ending | |
| 156 a clip does not refer back the object(s) that have been clipped. | |
| 157 In order to correctly compute the "scissor" rectangle, we now keep track | |
| 158 of the clipped object type. | |
| 159 """ | |
| 160 doc = pymupdf.open(f"{scriptdir}/resources/test-2462.pdf") | |
| 161 page = doc[0] | |
| 162 vg = page.get_drawings(extended=True) | |
| 163 | |
| 164 | |
| 165 def test_2556(): | |
| 166 """Ensure that incomplete clip paths will be properly ignored.""" | |
| 167 doc = pymupdf.open() # new empty PDF | |
| 168 page = doc.new_page() # new page | |
| 169 # following contains an incomplete clip | |
| 170 c = b"q 50 697.6 400 100.0 re W n q 0 0 m W n Q " | |
| 171 xref = doc.get_new_xref() # prepare /Contents object for page | |
| 172 doc.update_object(xref, "<<>>") # new xref now is a dictionary | |
| 173 doc.update_stream(xref, c) # store drawing commands | |
| 174 page.set_contents(xref) # give the page this xref as /Contents | |
| 175 # following will bring down interpreter if fix not installed | |
| 176 assert page.get_drawings(extended=True) | |
| 177 | |
| 178 | |
| 179 def test_3207(): | |
| 180 """Example graphics with multiple "close path" commands within same path. | |
| 181 | |
| 182 The fix translates a close-path commands into an additional line | |
| 183 which connects the current point with a preceding "move" target. | |
| 184 The example page has 2 paths which each contain 2 close-path | |
| 185 commands after 2 normal "line" commands, i.e. 2 command sequences | |
| 186 "move-to, line-to, line-to, close-path". | |
| 187 This is converted into 3 connected lines, where the last end point | |
| 188 is connect to the start point of the first line. | |
| 189 So, in the sequence of lines / points | |
| 190 | |
| 191 (p0, p1), (p2, p3), (p4, p5), (p6, p7), (p8, p9), (p10, p11) | |
| 192 | |
| 193 point p5 must equal p0, and p11 must equal p6 (for each of the | |
| 194 two paths in the example). | |
| 195 """ | |
| 196 filename = os.path.join(scriptdir, "resources", "test-3207.pdf") | |
| 197 doc = pymupdf.open(filename) | |
| 198 page = doc[0] | |
| 199 paths = page.get_drawings() | |
| 200 assert len(paths) == 2 | |
| 201 | |
| 202 path0 = paths[0] | |
| 203 items = path0["items"] | |
| 204 assert len(items) == 6 | |
| 205 p0 = items[0][1] | |
| 206 p5 = items[2][2] | |
| 207 p6 = items[3][1] | |
| 208 p11 = items[5][2] | |
| 209 assert p0 == p5 | |
| 210 assert p6 == p11 | |
| 211 | |
| 212 path1 = paths[1] | |
| 213 items = path1["items"] | |
| 214 assert len(items) == 6 | |
| 215 p0 = items[0][1] | |
| 216 p5 = items[2][2] | |
| 217 p6 = items[3][1] | |
| 218 p11 = items[5][2] | |
| 219 assert p0 == p5 | |
| 220 assert p6 == p11 | |
| 221 | |
| 222 | |
| 223 def test_3591(): | |
| 224 """Confirm correct scaling factor for rotation matrices.""" | |
| 225 filename = os.path.join(scriptdir, "resources", "test-3591.pdf") | |
| 226 doc = pymupdf.open(filename) | |
| 227 page = doc[0] | |
| 228 paths = page.get_drawings() | |
| 229 for p in paths: | |
| 230 assert p["width"] == 15 |
