diff mupdf-source/platform/java/example/MultiThreadedWithPool.java @ 3:2c135c81b16c

MERGE: upstream PyMuPDF 1.26.4 with MuPDF 1.26.7
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:44:09 +0200
parents b50eed0cc0ef
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mupdf-source/platform/java/example/MultiThreadedWithPool.java	Mon Sep 15 11:44:09 2025 +0200
@@ -0,0 +1,163 @@
+// Copyright (C) 2022 Artifex Software, Inc.
+//
+// This file is part of MuPDF.
+//
+// MuPDF is free software: you can redistribute it and/or modify it under the
+// terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option)
+// any later version.
+//
+// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
+//
+// Alternative licensing terms are available from the licensor.
+// For commercial licensing, see <https://www.artifex.com/> or contact
+// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
+// CA 94129, USA, for further information.
+
+/**
+ * Multi-threaded rendering using a thread pool.
+ *
+ * First look at MultiThreaded.java and make sure you understand it.
+ * The caution at the top of the file mentions that creating one thread
+ * per page in a document with many pages may create performance issues.
+ *
+ * The code below both renders pages to pixmaps in a Callable task scheduled on
+ * a thread pool provided by ExecutorService. The number of threads in the
+ * thread pool is limited to four here as an example.
+ *
+ * To build this example in a source tree:
+ * make -C platform/java examples
+ *
+ * To render all page from a document and output PNGs, run:
+ * java -classpath build/java/debug -Djava.library.path=build/java/debug \
+ *         example.MultiThreadedWithPool document.pdf
+ */
+
+package example;
+
+/* Import classes for scheduling on a thread pool. */
+import java.util.*;
+import java.util.concurrent.*;
+
+/* Import all MuPDF java classes. */
+import com.artifex.mupdf.fitz.*;
+
+class MultiThreadedWithPool
+{
+	public static void main(String args[])
+	{
+		/* Parse arguments. */
+		if (args.length < 1)
+		{
+			System.err.println("usage: MultiThreadedWithPool input-file");
+			System.err.println("\tinput-file: path of PDF, XPS, CBZ or EPUB document to open");
+			return;
+		}
+
+		/* Open the document and count its pages on the main thread. */
+		String filename = args[0];
+		Document doc;
+		int pageCount;
+		try {
+			doc = Document.openDocument(filename);
+		} catch (RuntimeException ex) {
+			System.err.println("cannot open document: " + ex.getMessage());
+			return;
+		}
+
+		try {
+			pageCount = doc.countPages();
+		} catch (RuntimeException ex) {
+			System.err.println("cannot count document pages: " + ex.getMessage());
+			return;
+		}
+
+		/* Create an ExecutorService with a thread pool of 4 threads. */
+		ExecutorService executor = Executors.newFixedThreadPool(4);
+
+		/* A list holding futures for the rendered images from each page. */
+		List renderingFutures = new LinkedList();
+
+		for (int i = 0; i < pageCount; ++i) {
+			final int pageNumber = i;
+			try {
+				Page page =  doc.loadPage(pageNumber);
+				final Rect bounds = page.getBounds();
+				final DisplayList displayList = page.toDisplayList();
+
+				/* Append this callable to the list of page rendering futures above.
+				 * It may not be scheduled to run by the executor until later when
+				 * asking for the resulting pixmap.
+				 */
+				renderingFutures.add(executor.submit(new Callable<Pixmap>() {
+					public Pixmap call() {
+						System.out.println(pageNumber + ": creating pixmap");
+
+						/* Create a white destination pixmap with correct dimensions. */
+						Pixmap pixmap = new Pixmap(ColorSpace.DeviceRGB, bounds);
+						pixmap.clear(0xff);
+
+						System.out.println(pageNumber + ": rendering display list to pixmap");
+
+						/* Run the display list through a DrawDevice which
+						 * will render the requested area of the page to the
+						 * given pixmap.
+						 */
+						DrawDevice dev = new DrawDevice(pixmap);
+						displayList.run(dev, Matrix.Identity(), bounds, null);
+						dev.close();
+
+						/* Return the rendered pixmap to the future. */
+						return pixmap;
+					}
+				}));
+			} catch (RuntimeException ex) {
+				System.err.println(pageNumber + ": cannot load page, skipping render: " + ex.getMessage());
+				renderingFutures.add(ex);
+			}
+		}
+
+		/* Get the resulting pixmap from each page rendering future. */
+		System.out.println("awaiting " + pageCount + " futures");
+		for (int i = 0; i < pageCount; ++i) {
+			if (renderingFutures.get(i) instanceof Exception) {
+				Exception ex  = (Exception) renderingFutures.get(i);
+				System.err.println(i + ": skipping save, page loading failed: " + ex.toString());
+				continue;
+			}
+
+			Future<Pixmap> future = (Future<Pixmap>) renderingFutures.get(i);
+			if (future == null) {
+				System.err.println(i + ": skipping save, page loading failed");
+				continue;
+			}
+
+			Pixmap pixmap;
+			try {
+				pixmap = future.get();
+			} catch (InterruptedException ex) {
+				System.err.println(i + ": interrupted while waiting for rendering result, skipping all remaining pages: " + ex.getMessage());
+				break;
+			} catch (ExecutionException ex) {
+				System.err.println(i + ": skipping save, page rendering failed: " + ex.getMessage());
+				continue;
+			}
+
+			/* Save destination pixmap to a PNG. */
+			String pngfilename = String.format("out-%04d.png", i);
+			System.out.println(i + ": saving rendered pixmap as " + pngfilename);
+			pixmap.saveAsPNG(pngfilename);
+		}
+
+		/* Stop all thread pool threads. */
+		executor.shutdown();
+
+		System.out.println("finally!");
+	}
+}