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