comparison mupdf-source/platform/java/example/MultiThreadedWithPool.java @ 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 // Copyright (C) 2022 Artifex Software, Inc.
2 //
3 // This file is part of MuPDF.
4 //
5 // MuPDF is free software: you can redistribute it and/or modify it under the
6 // terms of the GNU Affero General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or (at your option)
8 // any later version.
9 //
10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU Affero General Public License
16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17 //
18 // Alternative licensing terms are available from the licensor.
19 // For commercial licensing, see <https://www.artifex.com/> or contact
20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21 // CA 94129, USA, for further information.
22
23 /**
24 * Multi-threaded rendering using a thread pool.
25 *
26 * First look at MultiThreaded.java and make sure you understand it.
27 * The caution at the top of the file mentions that creating one thread
28 * per page in a document with many pages may create performance issues.
29 *
30 * The code below both renders pages to pixmaps in a Callable task scheduled on
31 * a thread pool provided by ExecutorService. The number of threads in the
32 * thread pool is limited to four here as an example.
33 *
34 * To build this example in a source tree:
35 * make -C platform/java examples
36 *
37 * To render all page from a document and output PNGs, run:
38 * java -classpath build/java/debug -Djava.library.path=build/java/debug \
39 * example.MultiThreadedWithPool document.pdf
40 */
41
42 package example;
43
44 /* Import classes for scheduling on a thread pool. */
45 import java.util.*;
46 import java.util.concurrent.*;
47
48 /* Import all MuPDF java classes. */
49 import com.artifex.mupdf.fitz.*;
50
51 class MultiThreadedWithPool
52 {
53 public static void main(String args[])
54 {
55 /* Parse arguments. */
56 if (args.length < 1)
57 {
58 System.err.println("usage: MultiThreadedWithPool input-file");
59 System.err.println("\tinput-file: path of PDF, XPS, CBZ or EPUB document to open");
60 return;
61 }
62
63 /* Open the document and count its pages on the main thread. */
64 String filename = args[0];
65 Document doc;
66 int pageCount;
67 try {
68 doc = Document.openDocument(filename);
69 } catch (RuntimeException ex) {
70 System.err.println("cannot open document: " + ex.getMessage());
71 return;
72 }
73
74 try {
75 pageCount = doc.countPages();
76 } catch (RuntimeException ex) {
77 System.err.println("cannot count document pages: " + ex.getMessage());
78 return;
79 }
80
81 /* Create an ExecutorService with a thread pool of 4 threads. */
82 ExecutorService executor = Executors.newFixedThreadPool(4);
83
84 /* A list holding futures for the rendered images from each page. */
85 List renderingFutures = new LinkedList();
86
87 for (int i = 0; i < pageCount; ++i) {
88 final int pageNumber = i;
89 try {
90 Page page = doc.loadPage(pageNumber);
91 final Rect bounds = page.getBounds();
92 final DisplayList displayList = page.toDisplayList();
93
94 /* Append this callable to the list of page rendering futures above.
95 * It may not be scheduled to run by the executor until later when
96 * asking for the resulting pixmap.
97 */
98 renderingFutures.add(executor.submit(new Callable<Pixmap>() {
99 public Pixmap call() {
100 System.out.println(pageNumber + ": creating pixmap");
101
102 /* Create a white destination pixmap with correct dimensions. */
103 Pixmap pixmap = new Pixmap(ColorSpace.DeviceRGB, bounds);
104 pixmap.clear(0xff);
105
106 System.out.println(pageNumber + ": rendering display list to pixmap");
107
108 /* Run the display list through a DrawDevice which
109 * will render the requested area of the page to the
110 * given pixmap.
111 */
112 DrawDevice dev = new DrawDevice(pixmap);
113 displayList.run(dev, Matrix.Identity(), bounds, null);
114 dev.close();
115
116 /* Return the rendered pixmap to the future. */
117 return pixmap;
118 }
119 }));
120 } catch (RuntimeException ex) {
121 System.err.println(pageNumber + ": cannot load page, skipping render: " + ex.getMessage());
122 renderingFutures.add(ex);
123 }
124 }
125
126 /* Get the resulting pixmap from each page rendering future. */
127 System.out.println("awaiting " + pageCount + " futures");
128 for (int i = 0; i < pageCount; ++i) {
129 if (renderingFutures.get(i) instanceof Exception) {
130 Exception ex = (Exception) renderingFutures.get(i);
131 System.err.println(i + ": skipping save, page loading failed: " + ex.toString());
132 continue;
133 }
134
135 Future<Pixmap> future = (Future<Pixmap>) renderingFutures.get(i);
136 if (future == null) {
137 System.err.println(i + ": skipping save, page loading failed");
138 continue;
139 }
140
141 Pixmap pixmap;
142 try {
143 pixmap = future.get();
144 } catch (InterruptedException ex) {
145 System.err.println(i + ": interrupted while waiting for rendering result, skipping all remaining pages: " + ex.getMessage());
146 break;
147 } catch (ExecutionException ex) {
148 System.err.println(i + ": skipping save, page rendering failed: " + ex.getMessage());
149 continue;
150 }
151
152 /* Save destination pixmap to a PNG. */
153 String pngfilename = String.format("out-%04d.png", i);
154 System.out.println(i + ": saving rendered pixmap as " + pngfilename);
155 pixmap.saveAsPNG(pngfilename);
156 }
157
158 /* Stop all thread pool threads. */
159 executor.shutdown();
160
161 System.out.println("finally!");
162 }
163 }