Mercurial > hgrepos > Python2 > PyMuPDF
diff tests/test_drawings.py @ 3:2c135c81b16c
MERGE: upstream PyMuPDF 1.26.4 with MuPDF 1.26.7
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:44:09 +0200 |
| parents | 1d09e1dec1d9 |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_drawings.py Mon Sep 15 11:44:09 2025 +0200 @@ -0,0 +1,230 @@ +""" +Extract drawings of a PDF page and compare with stored expected result. +""" + +import io +import os +import sys +import pprint + +import pymupdf + +scriptdir = os.path.abspath(os.path.dirname(__file__)) +filename = os.path.join(scriptdir, "resources", "symbol-list.pdf") +symbols = os.path.join(scriptdir, "resources", "symbols.txt") + + +def test_drawings1(): + symbols_text = open(symbols).read() # expected result + doc = pymupdf.open(filename) + page = doc[0] + paths = page.get_cdrawings() + out = io.StringIO() # pprint output goes here + pprint.pprint(paths, stream=out) + assert symbols_text == out.getvalue() + + +def test_drawings2(): + delta = (0, 20, 0, 20) + doc = pymupdf.open() + page = doc.new_page() + + r = pymupdf.Rect(100, 100, 200, 200) + page.draw_circle(r.br, 2, color=0) + r += delta + + page.draw_line(r.tl, r.br, color=0) + r += delta + + page.draw_oval(r, color=0) + r += delta + + page.draw_rect(r, color=0) + r += delta + + page.draw_quad(r.quad, color=0) + r += delta + + page.draw_polyline((r.tl, r.tr, r.br), color=0) + r += delta + + page.draw_bezier(r.tl, r.tr, r.br, r.bl, color=0) + r += delta + + page.draw_curve(r.tl, r.tr, r.br, color=0) + r += delta + + page.draw_squiggle(r.tl, r.br, color=0) + r += delta + + rects = [p["rect"] for p in page.get_cdrawings()] + bboxes = [b[1] for b in page.get_bboxlog()] + for i, r in enumerate(rects): + assert pymupdf.Rect(r) in pymupdf.Rect(bboxes[i]) + + +def _dict_difference(a, b): + """ + Verifies that dictionaries "a", "b" + * have the same keys and values, except for key "items": + * the items list of "a" must be one shorter but otherwise equal the "b" items + + Returns last item of b["items"]. + """ + assert a.keys() == b.keys() + for k in a.keys(): + v1 = a[k] + v2 = b[k] + if k != "items": + assert v1 == v2 + else: + assert v1 == v2[:-1] + rc = v2[-1] + return rc + + +def test_drawings3(): + doc = pymupdf.open() + page1 = doc.new_page() + shape1 = page1.new_shape() + shape1.draw_line((10, 10), (10, 50)) + shape1.draw_line((10, 50), (100, 100)) + shape1.finish(closePath=False) + shape1.commit() + drawings1 = page1.get_drawings()[0] + + page2 = doc.new_page() + shape2 = page2.new_shape() + shape2.draw_line((10, 10), (10, 50)) + shape2.draw_line((10, 50), (100, 100)) + shape2.finish(closePath=True) + shape2.commit() + drawings2 = page2.get_drawings()[0] + + assert _dict_difference(drawings1, drawings2) == ("l", (100, 100), (10, 10)) + + page3 = doc.new_page() + shape3 = page3.new_shape() + shape3.draw_line((10, 10), (10, 50)) + shape3.draw_line((10, 50), (100, 100)) + shape3.draw_line((100, 100), (50, 70)) + shape3.finish(closePath=False) + shape3.commit() + drawings3 = page3.get_drawings()[0] + + page4 = doc.new_page() + shape4 = page4.new_shape() + shape4.draw_line((10, 10), (10, 50)) + shape4.draw_line((10, 50), (100, 100)) + shape4.draw_line((100, 100), (50, 70)) + shape4.finish(closePath=True) + shape4.commit() + drawings4 = page4.get_drawings()[0] + + assert _dict_difference(drawings3, drawings4) == ("l", (50, 70), (10, 10)) + + +def test_2365(): + """Draw a filled rectangle on a new page. + + Then extract the page's vector graphics and confirm that only one path + was generated which has all the right properties.""" + doc = pymupdf.open() + page = doc.new_page() + rect = pymupdf.Rect(100, 100, 200, 200) + page.draw_rect( + rect, color=pymupdf.pdfcolor["black"], fill=pymupdf.pdfcolor["yellow"], width=3 + ) + paths = page.get_drawings() + assert len(paths) == 1 + path = paths[0] + assert path["type"] == "fs" + assert path["fill"] == pymupdf.pdfcolor["yellow"] + assert path["fill_opacity"] == 1 + assert path["color"] == pymupdf.pdfcolor["black"] + assert path["stroke_opacity"] == 1 + assert path["width"] == 3 + assert path["rect"] == rect + + +def test_2462(): + """ + Assertion happens, if this code does NOT bring down the interpreter. + + Background: + We previously ignored clips for non-vector-graphics. However, ending + a clip does not refer back the object(s) that have been clipped. + In order to correctly compute the "scissor" rectangle, we now keep track + of the clipped object type. + """ + doc = pymupdf.open(f"{scriptdir}/resources/test-2462.pdf") + page = doc[0] + vg = page.get_drawings(extended=True) + + +def test_2556(): + """Ensure that incomplete clip paths will be properly ignored.""" + doc = pymupdf.open() # new empty PDF + page = doc.new_page() # new page + # following contains an incomplete clip + c = b"q 50 697.6 400 100.0 re W n q 0 0 m W n Q " + xref = doc.get_new_xref() # prepare /Contents object for page + doc.update_object(xref, "<<>>") # new xref now is a dictionary + doc.update_stream(xref, c) # store drawing commands + page.set_contents(xref) # give the page this xref as /Contents + # following will bring down interpreter if fix not installed + assert page.get_drawings(extended=True) + + +def test_3207(): + """Example graphics with multiple "close path" commands within same path. + + The fix translates a close-path commands into an additional line + which connects the current point with a preceding "move" target. + The example page has 2 paths which each contain 2 close-path + commands after 2 normal "line" commands, i.e. 2 command sequences + "move-to, line-to, line-to, close-path". + This is converted into 3 connected lines, where the last end point + is connect to the start point of the first line. + So, in the sequence of lines / points + + (p0, p1), (p2, p3), (p4, p5), (p6, p7), (p8, p9), (p10, p11) + + point p5 must equal p0, and p11 must equal p6 (for each of the + two paths in the example). + """ + filename = os.path.join(scriptdir, "resources", "test-3207.pdf") + doc = pymupdf.open(filename) + page = doc[0] + paths = page.get_drawings() + assert len(paths) == 2 + + path0 = paths[0] + items = path0["items"] + assert len(items) == 6 + p0 = items[0][1] + p5 = items[2][2] + p6 = items[3][1] + p11 = items[5][2] + assert p0 == p5 + assert p6 == p11 + + path1 = paths[1] + items = path1["items"] + assert len(items) == 6 + p0 = items[0][1] + p5 = items[2][2] + p6 = items[3][1] + p11 = items[5][2] + assert p0 == p5 + assert p6 == p11 + + +def test_3591(): + """Confirm correct scaling factor for rotation matrices.""" + filename = os.path.join(scriptdir, "resources", "test-3591.pdf") + doc = pymupdf.open(filename) + page = doc[0] + paths = page.get_drawings() + for p in paths: + assert p["width"] == 15
