pdfbox - pdf увеличить размер после преобразования в оттенки серого - PullRequest
0 голосов
/ 13 февраля 2020

Мне нужно преобразовать отсканированный PDF в PDF в градациях серого. Я нашел 2 решения для этого.

Первое - просто использовать renderImage

private void convertToGray() throws IOException {
    File pdfFile = new File(PATH);
    try (PDDocument originalPdf = PDDocument.load(pdfFile);
         PDDocument doc = new PDDocument()) {
        LOGGER.info("Current heap after loading file: {}", Runtime.getRuntime().totalMemory());
        PDFRenderer pdfRenderer = new PDFRenderer(originalPdf);
        for (int pageNum = 0; pageNum < originalPdf.getNumberOfPages(); pageNum++) {
//          PDImageXObject pdImage = LosslessFactory.createFromImage(doc, bufferedImage);
            BufferedImage grayImage = pdfRenderer.renderImageWithDPI(pageNum, 300F, ImageType.GRAY);
            PDImageXObject pdImage = JPEGFactory.createFromImage(doc, grayImage);
            float pageWight = originalPdf.getPage(pageNum).getMediaBox().getWidth();
            float pageHeight = originalPdf.getPage(pageNum).getMediaBox().getHeight();
            PDPage page = new PDPage(new PDRectangle(pageWight, pageHeight));
            doc.addPage(page);
            try (PDPageContentStream contentStream = new PDPageContentStream(doc, page)) {
                contentStream.drawImage(pdImage, 0F, 0F, pageWight, pageHeight);
            }
        }
        doc.save(NEW_PATH);
    }
}

Но это приводит к увеличению размера файла (поскольку некоторые PDF-файлы имеют меньше DPI, чем 300.

Второй - просто заменить существующее изображение на серый аналог

private void convertByImageToGray() throws IOException {
    File pdfFile = new File(PATH);
    try (PDDocument document = PDDocument.load(pdfFile)) {
        List<COSObject> objects = document.getDocument().getObjectsByType(COSName.IMAGE);
        for (COSObject object : objects) {
            LOGGER.info("Class: {}; {}", object.getClass(), object.toString());
        }
        for (int pageNum = 0; pageNum < document.getNumberOfPages(); pageNum++) {
            PDPage page = document.getPage(pageNum);
            replaceImage(document, page);
        }
        document.save(NEW_PATH);
    }
}

private void replaceImage(PDDocument document, PDPage page) throws IOException {
    PDResources resources = page.getResources();
    Iterable<COSName> xObjectNames = resources.getXObjectNames();
    if (xObjectNames != null) {
        for (COSName xObjectName : xObjectNames) {
            PDXObject object = resources.getXObject(xObjectName);
            if (object instanceof PDImageXObject) {
                PDImageXObject img1 = (PDImageXObject) object;
                BufferedImage bufferedImage1 = img1.getImage();
                BufferedImage grayBufferedImage = convertBufferedImageToGray(bufferedImage1);
//                    PDImageXObject grayImage = JPEGFactory.createFromImage(document, grayBufferedImage);
                PDImageXObject grayImage = LosslessFactory.createFromImage(document, grayBufferedImage);
                resources.put(xObjectName, grayImage);
            }
        }
    }
}

private static BufferedImage convertBufferedImageToGray(BufferedImage sourceImg) {
    ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
    ColorConvertOp op = new ColorConvertOp(sourceImg.getColorModel().getColorSpace(), cs, null);
    op.filter(sourceImg, sourceImg);
    return sourceImg;
}

Но все же некоторые файлы увеличиваются в размере примерно в 3 раза (даже они уже были в оттенках серого; интересно, что в этом случае JPEGFactory создает файлы большего размера, чем LosslessFactory). Все изображения в формате PDF в градациях серого имеют такой же размер, что и исходные. И я не понимаю, почему.

Может быть есть лучший способ сделать PDF в градациях серого с предсказуемым размером (кроме ghostscript)?

ОБНОВЛЕНИЕ: Я только что понял, что проблема заключается в создании PDF из изображения. Он не сжимает а также.

Например, у меня есть фиктивный файл сканирования на 1 страницу размером менее 1 Мб. Но если я получаю из него изображение (напрямую копируемое через Acrobat Reader в Paint или через код выше), его размер ~ 8-10 Мб в зависимости от метода. И если я создаю новый PDF-файл из этого изображения, он почти не сжимается. Вот пример кода:

File pdfFile = new File(FULL_FILE);
try (PDDocument document = PDDocument.load(pdfFile)) {
    PDPage page = new PDPage();
    document.addPage(page);
    PDImageXObject pdImage = PDImageXObject.createFromFile("example.png", document);
    try (PDPageContentStream contents = new PDPageContentStream(document, page)) {
        contents.drawImage(pdImage, 0F, 0F);
    }
    document.save(FULL_FILE_NEW);
}

1 Ответ

2 голосов
/ 13 февраля 2020

Да LosslessFactory создает файлы меньшего размера по сравнению с JPEGFactory

В приведенной ниже ссылке есть разные методы для достижения одной и той же цели. В целом, серое изображение наилучшего качества было из Варианта 6, однако это было далеко не самое быстрое (я сам использовал Вариант 4). Для сравнения вы также можете выбрать

Эта ссылка содержит возможные способы преобразования цветных изображений в черный. Это мне очень помогло. Дайте мне знать, если это работает для вас, и утвердите мой ответ, если это помогло.

...