Easily add PDF image extraction capability to the viewer. Download each image separately or all images in a compressed ZIP file.
This demo allows you to:
Implementation steps
To add image extraction capability to WebViewer:
Step 1: Choose your preferred web stack
Step 2: Add the ES6 JavaScript sample code provided in this guide
Once you generate your license key, it will automatically be included in your sample code below.
Apryse collects some data regarding your usage of the SDK for product improvement.
The data that Apryse collects include:
For clarity, no other data is collected by the SDK and Apryse has no access to the contents of your documents.
If you wish to continue without data collection, contact us and we will email you a no-tracking trial key for you to get started.
1// ES6 Compliant Syntax
2// GitHub Copilot v1.0 - GPT-4o model - July 24, 2025
3// File: index.js
4
5import WebViewer from '@pdftron/webviewer';
6import JSZip from 'jszip';
7import saveAs from 'file-saver';
8
9// extracted images array
10let extractedImages = [];
11
12// Customize the WebViewer UI
13const customizeUI = (instance) => {
14 const { UI } = instance;
15
16 // Set the toolbar group to the annotate tools
17 UI.setToolbarGroup('toolbarGroup-Annotate');
18
19 // Extract images button
20 const extractImagesButton = new UI.Components.CustomButton({
21 dataElement: 'extractImagesButton',
22 className: 'custom-button-class',
23 label: 'Extract Images',
24 onClick: () => extractImages(instance), // extract images from the PDF
25 style: {
26 padding: '10px 10px',
27 backgroundColor: 'blue',
28 color: 'white',
29 }
30 });
31
32 const defaultHeader = UI.getModularHeader('default-top-header');
33 defaultHeader.setItems([...defaultHeader.items, extractImagesButton]);
34};
35
36// Extract images by traversing the display list for
37// every page. With this approach it is possible to obtain
38// image positioning information and DPI.
39const extractImages = async (instance) => {
40 // Clear previously extracted images
41 extractedImages = [];
42
43 // PDFNet is only available with full API enabled
44 const { PDFNet, documentViewer } = instance.Core;
45 let pageLimit = 5;
46 try {
47 // Start the full workers
48 PDFNet.initialize().then(async () => {
49 const document = documentViewer.getDocument();
50 const doc = await document.getPDFDoc();
51 doc.initSecurityHandler();
52
53 const reader = await PDFNet.ElementReader.create();
54 const itr = await doc.getPageIterator(1);
55
56 // Read every page
57 for (itr; (await itr.hasNext()) && pageLimit > 0; await itr.next()) {
58 const page = await itr.current();
59 reader.beginOnPage(page);
60 await extractImagesFromPage(reader, PDFNet);
61 reader.end();
62 pageLimit--;
63 }
64
65 extractedImagesDialogBox();
66 });
67
68 } catch (e) {
69 console.error('❌ Failed to extract images:', e);
70 }
71}
72
73// Recursive function to extract images from a page
74const extractImagesFromPage = async (reader, PDFNet) => {
75 let element;
76 while ((element = await reader.next()) !== null) {
77 switch (await element.getType()) {
78 case PDFNet.Element.Type.e_image:
79 case PDFNet.Element.Type.e_inline_image:
80 if ((await element.getType()) == PDFNet.Element.Type.e_image) {
81 const image = await PDFNet.Image.createFromObj(await element.getXObject());
82 const filter = await PDFNet.Filter.createMemoryFilter(65536, false);
83 const writer = await PDFNet.FilterWriter.create(filter);
84
85 await image.exportAsPngFromStream(writer);
86 await writer.flush();
87 await filter.memoryFilterSetAsInputFilter();
88
89 const reader = await PDFNet.FilterReader.create(filter);
90 const pngBuffer = await reader.readAllIntoBuffer();
91
92 const file = new Blob([pngBuffer], { type: 'image/png' });
93 extractedImages.push(file);
94 }
95 break;
96 case PDFNet.Element.Type.e_form: // Process form XObjects
97 reader.formBegin();
98 await extractImagesFromPage(reader, PDFNet);
99 reader.end();
100 break;
101 }
102 }
103};
104
105// Dialog box for displaying extracted images
106const extractedImagesDialogBox = async () => {
107 // Create overlay
108 const overlay = document.createElement('div');
109 overlay.style.position = 'fixed';
110 overlay.style.top = '0';
111 overlay.style.left = '0';
112 overlay.style.width = '100%';
113 overlay.style.height = '100%';
114 overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
115 overlay.style.zIndex = '999';
116 overlay.style.display = 'flex';
117 overlay.style.justifyContent = 'center';
118 overlay.style.alignItems = 'center';
119
120 // Create dialog box
121 const dialogBox = document.createElement('div');
122 dialogBox.style.backgroundColor = 'white';
123 dialogBox.style.padding = '20px';
124 dialogBox.style.border = '2px solid #ccc';
125 dialogBox.style.boxShadow = '0 4px 8px rgba(0,0,0,0.2)';
126 dialogBox.style.width = '300px';
127 dialogBox.style.textAlign = 'center';
128 dialogBox.style.borderRadius = '8px';
129
130 // Message
131 const message = document.createElement('p');
132 message.style.fontFamily = 'Arial';
133 message.style.fontWeight = 'bold';
134 message.textContent = 'Extracted Images';
135 dialogBox.appendChild(message);
136
137 // Note
138 const note = document.createElement('p');
139 note.style.marginTop = "20px";
140 note.style.fontFamily = 'Arial';
141 note.textContent = 'For demo purposes, only the first 5 pages of the PDF will be processed.';
142 dialogBox.appendChild(note);
143
144 // Listbox (select element)
145 const listBox = document.createElement('select');
146 listBox.size = 6;
147 listBox.id = 'listBox';
148 listBox.style.marginTop = "20px";
149 listBox.style.alignItems = 'center';
150 listBox.style.border = '2px solid blue';
151 listBox.style.borderRadius = '4px';
152
153 // Add images to the listbox dynamically
154 extractedImages.forEach((image, index) => {
155 const imageFileName = `image${index + 1}.png`;
156 const item = document.createElement('option');
157 item.value = index;
158 item.textContent = `Download ${imageFileName}`;
159 item.style.color = 'blue';
160 item.style.cursor = 'pointer';
161 item.onclick = () => saveAs(image, imageFileName); // Download the image when clicked
162 listBox.appendChild(item);
163 });
164 dialogBox.appendChild(listBox);
165
166 // Download all images button
167 const downloadButton = document.createElement('button');
168 downloadButton.textContent = 'Download All Images (.zip)';
169 downloadButton.style.marginTop = "20px";
170 downloadButton.style.backgroundColor = 'blue';
171 downloadButton.style.color = 'white';
172 downloadButton.style.border = '1px solid blue';
173 downloadButton.style.borderRadius = '4px';
174 downloadButton.style.cursor = 'pointer';
175 downloadButton.onclick = () => downloadAllImagesZip();
176 dialogBox.appendChild(downloadButton);
177
178 // Close button
179 const closeButton = document.createElement('button');
180 closeButton.textContent = 'Close';
181 closeButton.style.marginLeft = '10px';
182 closeButton.style.color = 'blue';
183 closeButton.style.border = '1px solid blue';
184 closeButton.style.borderColor = 'blue';
185 closeButton.style.borderRadius = '4px';
186 closeButton.style.cursor = 'pointer';
187 closeButton.onclick = () => document.body.removeChild(overlay);
188 dialogBox.appendChild(closeButton);
189
190 // Append dialog to overlay and overlay to body
191 overlay.appendChild(dialogBox);
192 document.body.appendChild(overlay);
193};
194
195const downloadAllImagesZip = () => {
196 const zip = new JSZip();
197 extractedImages.forEach((image, index) => {
198 zip.file(`image${index + 1}.png`, image);
199 });
200
201 zip.generateAsync({ type: 'blob' }).then(function (content) {
202 saveAs(content, 'extracted.zip');
203 });
204
205 // Close dialog box after download
206 const overlay = document.body.querySelector('div[style*="position: fixed"]');
207 document.body.removeChild(overlay);
208};
209
210WebViewer(
211 {
212 path: '/lib',
213 initialDoc: 'https://apryse.s3.us-west-1.amazonaws.com/public/files/samples/lexpress.pdf',
214 fullAPI: true, // Enable full API access. This will make the PDFNet namespace available on the WebViewer instance and allow accessing a PDFDoc instance from the WebViewer document object.
215 enableFilePicker: true, // Enable file picker to open files
216 licenseKey: 'YOUR_LICENSE_KEY',
217 },
218 document.getElementById('viewer')
219).then((instance) => {
220
221 // customize WebViewer UI
222 customizeUI(instance);
223
224 console.log('✅ WebViewer loaded successfully.');
225}).catch((error) => {
226 console.error('❌ Failed to initialize WebViewer:', error);
227});
Did you find this helpful?
Trial setup questions?
Ask experts on DiscordNeed other help?
Contact SupportPricing or product questions?
Contact Sales