PDFBox PDFMergerUtility нестабильно в приложении JavaFX - PullRequest
0 голосов
/ 06 июля 2018

Мое приложение JavaFX загружало PDF-файлы с сервера, поверните в книжную ориентацию, если PDF имеет альбомную ориентацию, а затем объедините все PDF-файлы в один PDF-файл, чтобы распечатать его.

Все прошло нормально, за исключением того, что программа случайно зависла при выводе объединенного PDF или при добавлении одного из файлов PDF в PDFMergerUtility (который я использую PDFBox 2.0.11 и также пробовал 2.0.9). Поскольку моему приложению требуются ProgressBar и TextArea для отображения текущего действия или состояния, я использовал Задачу на своей странице контроллера. Когда программа зависает, она не вводит никаких исключений и не печатает никаких сообщений, но полностью останавливает фоновое действие. Я пробовал небольшое количество файлов (<50 файлов) и тесты больших файлов (> 1000), но все они имеют одинаковые результаты абсолютно обычных или случайных зависаний.

Ниже приведен код моей программы контроллера:

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, возможно, из-за того, что я использовал Задачу снаружи или из-за того, что я пропустил что-то важное?

1 Ответ

0 голосов
/ 09 июля 2018

Бинго!Исключением был OutOfMemoryError, и Task из JavaFX заставил его замолчать.

Я добавил следующий код при запуске задачи, и он будет обрабатывать исключения:

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.

...