java - PDFBox PDFMergerUtility 在 JavaFX 应用程序上不稳定

标签 java javafx pdfbox

我的 JavaFX 应用程序从服务器下载 PDF,如果 PDF 是横向的,则旋转为纵向,然后将所有 PDF 文件合并为一个 PDF 文件以将其打印出来。

一切都很顺利,除了程序会随机卡在输出合并的 PDF 或将 PDF 文件之一添加到 PDFMergerUtility(我正在使用 PDFBox 2.0.11 并尝试过 2.0.9)。因为我的应用程序需要 ProgressBar 和 TextArea 来显示当前操作或状态,所以我在 Controller 页面中使用了任务。当程序挂起时,它没有输入任何异常或打印任何消息,而是完全停止后台操作。我尝试过少量文件(<50 个文件)和大文件测试(>1000 个),但它们都具有绝对正常或随机挂起的相同结果。

下面是我的 Controller 程序的代码:

public class ReadDataPageController implements Initializable {
    public long startTime;
    public long stopTime;
    @FXML
    private Button btnNext, btnCancel, btnPrevious;
    @FXML
    private Label infoLabel, time, total;
    @FXML
    private ProgressBar progBar;
    @FXML
    private TextArea textArea;

    public Task<String> dlTask() {
        return new Task<String>() {

            @Override
            protected String call() throws Exception {
                DownloadUtil dlutil = new DownloadUtil();
                StringBuilder textStr = new StringBuilder();
                List<String> dlList = mainApp.DL_LIST;

                // Download PDF files from FTP
                super.updateValue(textStr.append("Preparing files for download...\n").toString());
                for (int count = 0; count < dlList.size(); count++) {
                    String PDFLink = dlList.get(count).getPDFLink();
                    super.updateTitle("Downloading file" + PDFLink + " ...");
                    super.updateValue(textStr.append("Got " + PDFLink + "\n").toString());

                    try {
                        dlutil.exec(PDFLink);
                        // downloaded location will be stored inside List DownloadUtil.pdfList
                    } catch (IndexOutOfBoundsException ex) {
                        super.updateValue(textStr.append("Link not found for " + PDFLink + "\n").toString());
                    } catch (Exception ex) {
                        super.updateValue(textStr.append("Error while downloading " + PDFLink + " :" + ex.getMessage() + "\n").toString());
                    }
                    super.updateProgress(count + 1, dlList.size() * 3);
                }
                super.updateProgress(dlList.size(), dlList.size() * 3);
                super.updateTitle("Download action has finished.");
                super.updateValue(textStr.append("Download action has finished.\n").toString());

                // Rotate downloaded PDFs
                super.updateTitle("Preparing files for PDF rotation...");
                super.updateValue(textStr.append("Preparing files for PDF rotation...\n").toString());
                for (int i = 0; i < dlutil.pdfList.size(); i++) {
                    try {
                        String fileName = dlutil.pdfList.get(i);
                        rotatePDF(new File(fileName));
                        super.updateValue(textStr.append("Rotating PDF ("+(i+1)+" of "+dlutil.pdfList.size()+")...\n").toString());
                    } catch (Exception ex) {
                        super.updateValue(textStr.append("Error:" + ex.getMessage() + "...\n").toString());
                        ex.printStackTrace();
                    }
                    super.updateProgress(dlutil.pdfList.size() + i + 1, dlutil.pdfList.size() * 3);
                }

                if (PRINT_OPTION == PrintType.PRINT) {
                    // Merge downloaded PDFs
                    super.updateValue(textStr.append("Preparing files for PDF merging action...\n").toString());
                    PDFMergerUtility pdfutil = new PDFMergerUtility();
                    for (int i = 0; i < dlutil.pdfList.size(); i++) {
                        try {
                            String fileName = dlutil.pdfList.get(i);
                            pdfutil.addSource(fileName);
                            super.updateTitle("Adding files (" + (i + 1) + "/" + dlutil.pdfList.size() + ")");
                        } catch (Exception ex) {
                            super.updateValue(textStr.append("Error:" + ex.getMessage() + "...\n").toString());
                            ex.printStackTrace();
                        }
                        super.updateProgress(dlutil.pdfList.size()*2 + i + 1, dlutil.pdfList.size() * 3);
                    }
                    // Output merged pdf
                    try {
                        pdfutil.setDestinationFileName("../odt/merge.pdf");
                        pdfutil.mergeDocuments();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                    super.updateTitle("Merged all PDFs.");
                }

                super.updateProgress(100, 100);
                super.updateTitle("All action has been finished.");
                super.updateValue(textStr.append("All action has been finished, press Next to choose your printing option.\n").toString());
                return textStr.toString();
            }
        };
    }

    /**
     * Rotates PDF images 90 degree if the PDF is portrait
     * @param resource the PDF file path
     * @throws InvalidPasswordException
     * @throws IOException
     */
    public void rotatePDF(File resource) throws InvalidPasswordException, IOException {
        try {
            PDDocument document = PDDocument.load(resource);
            int pageCount = document.getNumberOfPages();
            System.out.println("Reading file: "+resource+", total page="+pageCount);
            for (int i = 0; i < pageCount; i++) {
                PDPage page = document.getDocumentCatalog().getPages().get(i);
                PDPageContentStream cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND,
                        false, false);
                Matrix matrix = Matrix.getRotateInstance(Math.toRadians(90), 0, 0);
                cs.transform(matrix);
                cs.close();

                PDRectangle cropBox = page.getCropBox();
                if (cropBox.getWidth() > cropBox.getHeight()) {
                    System.out.println("ROTATE "+i+"th");
                    Rectangle rectangle = cropBox.transform(matrix).getBounds();
                    PDRectangle newBox = new PDRectangle((float) rectangle.getX(), (float) rectangle.getY(),
                            (float) rectangle.getWidth(), (float) rectangle.getHeight());
                    page.setCropBox(newBox);
                    page.setMediaBox(newBox);
                    document.save(resource);
                }
            }
            document.close();
        } catch (Exception ex) {
            ex.printStackTrace();
            throw ex;
        }
    }
}

是否有任何原因可能导致 PDFMergerUtility 不稳定,可能是因为我在外面使用了任务,或者因为我错过了一些重要的东西?

最佳答案

宾果!异常是 OutOfMemoryError,JavaFX 的 Task 使其保持沉默。

我在启动任务时添加了以下代码,它将处理异常:

task.setOnFailed(new EventHandler<WorkerStateEvent>(){
    @Override
    public void handle(WorkerStateEvent event) {
        Throwable th = task.getException();
        System.out.println("Error on Task:"+th.getMessage());
        th.printStackTrace();
    }
});

为了避免 OutOfMemoryError,我将合并作业拆分为每个合并作业 100 个页面,并另存为多个合并的 PDF 文件。

关于java - PDFBox PDFMergerUtility 在 JavaFX 应用程序上不稳定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51204457/

相关文章:

java - 找不到符号方法 getcontext

java - JFileChooser 检查是否确实选择了文件?

css - 获取场景图中具有 styleClass 的所有节点

java - 为什么这个javafx fxml不调整大小?

java - PDF 文本注释样式 应用

java - Spring JPA 存储库仅在结果已存在时获取 id 而不是完整对象

java - WebServiceContext 保持为空

javafx:如何创建一个 cellFactory 来考虑一个对象的两个属性?

java - 在使用 PDFBox 的 java 中,如何使用文本创建可见的数字签名

java - 使用 PDFBox 获取 PDF 文本的字体信息