comparison mupdf-source/docs/examples/pdf-bake.js @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 // usage: mutool run pdf-bake.js input.pdf output.pdf
2 //
3 // This tool will rewrite all Widgets and Annotations as plain XObjects
4 // drawn on the page and remove them as interactive objects.
5 //
6 // Links will be preserved. All other Annotations will be removed.
7 // The AcroForm object will be deleted if present.
8 //
9
10 "use strict"
11
12 function request_synthesis(list) {
13 if (list)
14 for (var i = 0; i < list.length; ++i)
15 list[i].requestSynthesis()
16 }
17
18 function bake_document(doc, do_bake_annots, do_bake_widgets) {
19 var i, n, page, list
20 n = doc.countPages()
21 for (i = 0; i < n; ++i) {
22 page = doc.loadPage(i)
23 if (do_bake_annots)
24 request_synthesis(page.getAnnotations())
25 if (do_bake_widgets)
26 request_synthesis(page.getWidgets())
27 page.update()
28 bake_page(doc, page.getObject(), do_bake_annots, do_bake_widgets)
29 }
30 if (do_bake_widgets)
31 delete doc.getTrailer().Root.AcroForm
32 }
33
34 function bake_page(doc, page, do_bake_annots, do_bake_widgets) {
35 var i, n, list, keep, buf
36 list = page.Annots
37 if (list) {
38 if (!page.Resources)
39 page.Resources = {}
40 if (!page.Resources.XObject)
41 page.Resources.XObject = {}
42 if (!page.Contents.isArray())
43 page.Contents = [ page.Contents ]
44
45 keep = []
46 buf = ""
47 for (i = 0; i < list.length; ++i) {
48 if (list[i].Subtype == "Link") {
49 keep.push(list[i])
50 } else if (list[i].Subtype == "Widget") {
51 if (do_bake_widgets)
52 buf += bake_annot(doc, page, list[i])
53 else
54 keep.push(list[i])
55 } else {
56 if (do_bake_annots)
57 buf += bake_annot(doc, page, list[i])
58 else
59 keep.push(list[i])
60 }
61 }
62
63 if (keep.length > 0)
64 page.Annots = keep
65 else
66 delete page.Annots
67
68 page.Contents.push(doc.addStream(buf))
69 }
70 }
71
72 function get_annot_ap(annot) {
73 var ap = annot.AP
74 if (ap) {
75 ap = ap.N
76 if (ap.isStream())
77 return ap
78 ap = ap[annot.AS]
79 if (ap.isStream())
80 return ap
81 }
82 return null
83 }
84
85 function get_annot_transform(rect, bbox, transform) {
86 var w, h, x, y
87 if (!transform)
88 transform = [ 1, 0, 0, 1, 0, 0 ]
89 bbox = mupdf.Rect.transform(bbox, transform)
90 w = (rect[2] - rect[0]) / (bbox[2] - bbox[0])
91 h = (rect[3] - rect[1]) / (bbox[3] - bbox[1])
92 x = rect[0] - bbox[0] * w
93 y = rect[1] - bbox[1] * h
94 return [ w, 0, 0, h, x, y ]
95 }
96
97 function bake_annot(doc, page, annot) {
98 var name = "Annot" + annot.asIndirect()
99 var ap = get_annot_ap(annot)
100 if (ap) {
101 var transform = get_annot_transform(annot.Rect, ap.BBox, ap.Matrix)
102 page.Resources.XObject[name] = ap
103 ap.Type = "XObject"
104 ap.Subtype = "Form"
105 return "q\n" + transform.join(" ") + " cm\n/" + name + " Do\nQ\n"
106 }
107 return ""
108 }
109
110 var doc = mupdf.Document.openDocument(scriptArgs[0])
111 doc.enableJournal()
112 doc.beginOperation("bake")
113 bake_document(doc, true, true)
114 doc.endOperation()
115 doc.save(scriptArgs[1], "garbage,compress")