ViewerEdit

This JavaScript sample lets you perform complex editing on PDF, DOCX, XLSX or PPTX documents as they are displayed in a web browser (no servers or other external dependencies required). In particular, this sample lets you change all text to blue and images to red in your document when you click the refresh button in the viewer. In the case of MS Office files, edits are saved into the PDF file. This sample works on all browsers (including IE11) and mobile devices without using plug-ins. Learn more about our Web SDK and PDF Editing & Manipulation Library.

1(exports => {
2 const PDFNet = exports.Core.PDFNet;
3 const refreshSVG = color =>
4 '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="' +
5 color +
6 '"><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/><path d="M0 0h24v24H0z" fill="none"/></svg>';
7
8 const runElementEditTest = pdfDoc => {
9 let ProcessElements = () => {};
10 // getting around gulp error for recurive async functions
11 ProcessElements = async (reader, writer, visited) => {
12 await PDFNet.startDeallocateStack();
13 console.log('Processing elements');
14 let element;
15 let gs;
16 const colorspace = await PDFNet.ColorSpace.createDeviceRGB();
17 const redColor = await PDFNet.ColorPt.init(1, 0, 0, 0);
18 const blueColor = await PDFNet.ColorPt.init(0, 0, 1, 0);
19 for (element = await reader.next(); element !== null; element = await reader.next()) {
20 const elementType = await element.getType();
21 let formObj;
22 let formObjNum;
23 let insertedObj;
24 let newWriter;
25
26 switch (elementType) {
27 case PDFNet.Element.Type.e_image:
28 case PDFNet.Element.Type.e_inline_image:
29 // remove all images by skipping them
30 break;
31 case PDFNet.Element.Type.e_path:
32 // Set all paths to red
33 gs = await element.getGState();
34 gs.setFillColorSpace(colorspace);
35 gs.setFillColorWithColorPt(redColor);
36 // Note: since writeElement does not return an object, the await is technically unneeded.
37 // However, on a slower computer or browser writeElement may not finish before the page is
38 // updated, so the await ensures that all changes are finished before continuing.
39 await writer.writeElement(element);
40 break;
41 case PDFNet.Element.Type.e_text:
42 // Set all text to blue
43 gs = await element.getGState();
44 gs.setFillColorSpace(colorspace);
45 gs.setFillColorWithColorPt(blueColor);
46 // Same as above comment on writeElement
47 await writer.writeElement(element);
48 break;
49 case PDFNet.Element.Type.e_form:
50 await writer.writeElement(element);
51 formObj = await element.getXObject();
52 formObjNum = formObj.getObjNum();
53 // if XObject not yet processed
54 if (visited.indexOf(formObjNum) === -1) {
55 // Set Replacement
56 insertedObj = await formObj.getObjNum();
57 if (!visited.includes(insertedObj)) {
58 visited.push(insertedObj);
59 }
60 newWriter = await PDFNet.ElementWriter.create();
61 reader.formBegin();
62 newWriter.beginOnObj(formObj, true);
63 await ProcessElements(reader, newWriter, visited);
64 newWriter.end();
65 reader.end();
66 if (newWriter) {
67 newWriter.destroy();
68 }
69 }
70 break;
71 default:
72 await writer.writeElement(element);
73 }
74 }
75 await PDFNet.endDeallocateStack();
76 };
77
78 const main = async () => {
79 let ret = 0;
80 try {
81 const doc = pdfDoc;
82 doc.lock();
83 doc.initSecurityHandler();
84
85 const writer = await PDFNet.ElementWriter.create();
86 const reader = await PDFNet.ElementReader.create();
87 const visited = [];
88
89 const pageCount = await doc.getPageCount();
90
91 let pageCounter = 1;
92 while (pageCounter <= pageCount) {
93 // This section is only required to ensure the page is available
94 // for incremental download. At the moment the call to requirePage must be
95 // be wrapped in this manner to avoid potential deadlocks and
96 // allow other parts of the viewer to run while the page is being downloaded.
97 doc.unlock();
98 await PDFNet.finishOperation();
99 await doc.requirePage(pageCounter);
100 await PDFNet.beginOperation();
101 doc.lock();
102
103 // load the page and begin processing
104 const page = await doc.getPage(pageCounter);
105 const sdfObj = await page.getSDFObj();
106 const insertedObj = await sdfObj.getObjNum();
107 if (!visited.includes(insertedObj)) {
108 visited.push(insertedObj);
109 }
110 reader.beginOnPage(page);
111 writer.beginOnPage(page, PDFNet.ElementWriter.WriteMode.e_replacement, false);
112 await ProcessElements(reader, writer, visited);
113 writer.end();
114 reader.end();
115 console.log('page ' + pageCounter + ' finished editing');
116 // refresh the cache with the newly updated document
117 instance.Core.documentViewer.refreshPage(pageCounter);
118 // update viewer with new document
119 instance.Core.documentViewer.updateView([pageCounter]);
120 pageCounter++;
121 }
122 console.log('Done.');
123 } catch (err) {
124 console.log(err.stack);
125 ret = 1;
126 }
127 return ret;
128 };
129
130 // add your own license key as the second parameter, e.g. PDFNet.runWithCleanup(main, 'YOUR_LICENSE_KEY')
131 return PDFNet.runWithCleanup(main);
132 };
133
134 window.addEventListener('documentLoaded', () => {
135 PDFNet.initialize().then(() => {
136 const doc = instance.Core.documentViewer.getDocument();
137 doc.getPDFDoc().then(pdfDoc => {
138 instance.UI.setHeaderItems(headerItems => {
139 headerItems.push({
140 initialState: 'enabled',
141 type: 'statefulButton',
142 dataElement: 'refreshButton',
143 states: {
144 enabled: {
145 img: refreshSVG('currentColor'),
146 className: 'not-disabled',
147 onClick: update => {
148 update('disabled');
149 runElementEditTest(pdfDoc).then(() => {
150 // re-enable our button
151 update('enabled');
152 });
153 },
154 },
155 disabled: {
156 img: refreshSVG('lightgray'),
157 onClick: () => {},
158 className: 'disabled',
159 },
160 },
161 mount: () => {},
162 });
163
164 return headerItems;
165 });
166 });
167 });
168 });
169})(window);
170// eslint-disable-next-line spaced-comment
171//# sourceURL=config.js

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales