0

This is my model for document:

 public class PdfDocumentModel { private final PDDocument document; private float dpi = 110; // Constructor accepts InputStream public PdfDocumentModel(InputStream inputStream) throws IOException { this.document = PDDocument.load(inputStream); // Load PDF from InputStream } public int getPageCount() { return document.getNumberOfPages(); } public void close() throws IOException { document.close(); } public void setDpi(float dpi) { this.dpi = dpi; // Allow setting DPI dynamically for rendering } // Render page to temporary file with dynamic DPI control public synchronized File renderPageToTempFile(int pageIndex) throws IOException { if (pageIndex < 0 || pageIndex >= getPageCount()) { throw new IndexOutOfBoundsException("Invalid page index: " + pageIndex); } // Render the page to a BufferedImage with the current DPI setting PDFRenderer renderer = new PDFRenderer(document); BufferedImage image = renderer.renderImageWithDPI(pageIndex, dpi); // Use dynamic DPI // Convert BufferedImage to temporary PNG file Path tempFilePath = Files.createTempFile("page_" + pageIndex + "_", ".png"); File tempFile = tempFilePath.toFile(); try (OutputStream outputStream = Files.newOutputStream(tempFile.toPath())) { ImageIO.write(image, "PNG", outputStream); } return tempFile; } public void deleteTempFile(File tempFile) { if (tempFile != null && tempFile.exists()) { boolean deleted = tempFile.delete(); if (!deleted) { System.err.println("Failed to delete temporary file: " + tempFile.getAbsolutePath()); } } } } 
This is my View model: 
public class CenterViewModel { private PdfDocumentModel pdfDocument; private final ListProperty<BufferedImage> pages = new SimpleListProperty<>(FXCollections.observableArrayList()); private final IntegerProperty currentPage = new SimpleIntegerProperty(); private final ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); public CenterViewModel() { currentPage.addListener((obs, oldPage, newPage) -> { if (newPage.intValue() >= 0 && newPage.intValue() < pages.size()) { loadPage(newPage.intValue()); } }); } public void loadPdf(InputStream inputStream) throws IOException { // Close the existing PDF document if one is already loaded if (pdfDocument != null) { closePdf(); } // Create a new PdfDocumentModel using the InputStream pdfDocument = new PdfDocumentModel(inputStream); // Clear previous page list and prepare for new pages pages.clear(); int pageCount = pdfDocument.getPageCount(); // Add placeholders for each page for (int i = 0; i < pageCount; i++) { pages.add(null); // Placeholder for each page } // Load a subset of pages initially (e.g., first 100 pages) loadPages(0, Math.min(pageCount, 2000)); } public void setDpi(float dpi) { pdfDocument.setDpi(dpi); } public void loadPages(int startIndex, int endIndex) { for (int i = startIndex; i < endIndex; i++) { if (i >= pages.size() || pages.get(i) != null) { continue; } loadPage(i); } } public void loadPage(int pageIndex) { if (pageIndex < 0 || pageIndex >= pages.size()) { throw new IndexOutOfBoundsException("Invalid page index: " + pageIndex); } // Render page asynchronously Task<File> task = new Task<>() { @Override protected File call() throws Exception { return pdfDocument.renderPageToTempFile(pageIndex); } @Override protected void succeeded() { File tempFile = getValue(); try { BufferedImage image = ImageIO.read(tempFile); pages.set(pageIndex, image); // Update page image pdfDocument.deleteTempFile(tempFile); // Clean up temporary file } catch (IOException e) { System.err.println("Failed to read page " + pageIndex + ": " + e.getMessage()); } } @Override protected void failed() { System.err.println("Failed to render page " + pageIndex + ": " + getException().getMessage()); } }; executorService.submit(task); } public void shutdownExecutor() { if (!executorService.isShutdown()) { executorService.shutdown(); } } public int getTotalPages() { return pdfDocument != null ? pdfDocument.getPageCount() : 0; } public ListProperty<BufferedImage> pagesProperty() { return pages; } public IntegerProperty currentPageProperty() { return currentPage; } public void setCurrentPage(int pageIndex) { if (pageIndex >= 0 && pageIndex < pages.size()) { currentPage.set(pageIndex); } } public void closePdf() throws IOException { if (pdfDocument != null) { pdfDocument.close(); } pages.clear(); } } 

And this the View:

 public class CenterView { private final ListView<BufferedImage> listView; private final ListProperty<BufferedImage> pages = new SimpleListProperty<>(FXCollections.observableArrayList()); private final CenterViewModel centerViewModel = new CenterViewModel(); private final IntegerProperty currentPage = new SimpleIntegerProperty(); private final Label totalPagesLabel = new Label(); private final Button resetButton = new Button("Reset"); private final BorderPane mainLayout = new BorderPane(); public CenterView() { listView = new ListView<>(centerViewModel.pagesProperty()); listView.getStylesheets().add(Objects.requireNonNull(getClass().getResource("/style/listview-config.css")).toExternalForm()); initialize(); } private void initialize() { listView.setCellFactory(param -> new PdfPageCell()); currentPage.addListener((obs, oldVal, newVal) -> loadPagesAround(newVal.intValue())); listView.setOnDragOver(this::handleDragOver); listView.setOnDragDropped(this::handleDragDropped); resetButton.setOnAction(event -> { pages.clear(); totalPagesLabel.setText("Total Pages: 0"); }); listView.setOnScroll(event -> { int currentIndex = listView.getSelectionModel().getSelectedIndex(); if (event.getDeltaY() > 0 && currentIndex > 0) { loadPagesAround(currentIndex - 5); } else if (event.getDeltaY() < 0 && currentIndex < pages.size() - 1) { loadPagesAround(currentIndex + 5); } }); listView.getSelectionModel().selectedIndexProperty().addListener((obs, oldSelection, newSelection) -> { if (newSelection != null && newSelection.intValue() >= 0) { loadPagesAround(newSelection.intValue()); } }); mainLayout.setTop(resetButton); mainLayout.setCenter(listView); mainLayout.setBottom(totalPagesLabel); totalPagesLabel.setStyle("-fx-padding: 10px;"); } private class PdfPageCell extends ListCell<BufferedImage> { private final StackPane stackPane = new StackPane(); private final ImageView imageView = new ImageView(); private final DropShadow dropShadow = new DropShadow(); // DropShadow instance public PdfPageCell() { dropShadow.setOffsetX(0); dropShadow.setOffsetY(0); dropShadow.setRadius(7); dropShadow.setSpread(0.1); dropShadow.setColor(Color.gray(0.1)); imageView.setEffect(dropShadow); stackPane.getChildren().add(imageView); imageView.setPreserveRatio(true); imageView.setSmooth(true); } @Override protected void updateItem(BufferedImage item, boolean empty) { super.updateItem(item, empty); if (empty || item == null) { setGraphic(null); } else { // Convert the BufferedImage to JavaFX Image imageView.setImage(SwingFXUtils.toFXImage(item, null)); // Set the ImageView to fill the entire cell size imageView.fitWidthProperty().bind(stackPane.widthProperty()); imageView.fitHeightProperty().bind(stackPane.heightProperty()); setGraphic(stackPane); } } } public BorderPane getView() { updateTotalPages(); return mainLayout; } private void loadPagesAround(int currentIndex) { int totalPages = centerViewModel.getTotalPages(); int startIndex = Math.max(currentIndex - 5, 0); int endIndex = Math.min(currentIndex + 5, totalPages - 1); // Asynchronously preload pages new Thread(() -> { for (int i = startIndex; i <= endIndex; i++) { if (centerViewModel.pagesProperty().get(i) == null) { centerViewModel.loadPage(i); } } }).start(); } private void updateTotalPages() { int totalPages = centerViewModel.getTotalPages(); totalPagesLabel.setText("Total Pages: " + totalPages); } private void handleDragOver(DragEvent event) { Dragboard dragboard = event.getDragboard(); if (dragboard.hasFiles()) { event.acceptTransferModes(TransferMode.COPY); } event.consume(); } private void handleDragDropped(DragEvent event) { Dragboard dragboard = event.getDragboard(); boolean success = false; if (dragboard.hasFiles()) { List<File> files = dragboard.getFiles(); if (!files.isEmpty()) { File pdfFile = files.get(0); // Get the first file if (pdfFile.getName().endsWith(".pdf")) { try (InputStream inputStream = new FileInputStream(pdfFile)) { // Load the PDF using InputStream instead of File centerViewModel.loadPdf(inputStream); updateTotalPages(); success = true; } catch (Exception e) { e.printStackTrace(); } } } } event.setDropCompleted(success); event.consume(); } } 

My main issue is that I want to render a thounsand of pages or a large file with a 110 DPI. But currently what I can just rendered is about 500 pages with 110 DPI.

1
  • You haven't said what isn't working, presumably OutOfMemoryError. You only need to load image for visible cells. Commented Jan 21 at 11:25

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.