iText PDF; Как конвертировать JPEG в 2000 JPG с помощью Java - PullRequest
0 голосов
/ 19 декабря 2011

Я пытаюсь решить проблему с помощью Java, iText и расширенной библиотеки изображений Java. Моя система использует ghostscript для создания миниатюрных изображений jpg и т. Д. Из файлов PDF. Однако в CentOS 5.x самая высокая версия ghostscript - это 8.7, в которой есть известная проблема, заключающаяся в невозможности обрабатывать файлы PDF, содержащие в себе изображения JPEG 2000. Мой план состоит в том, чтобы сначала отсканировать файл и посмотреть, содержит ли он изображения в формате jpeg2000 (я уже разобрался с этой частью); если это так, то используйте iText и библиотеку Java Advanced Imaging (содержит кодеки jpeg2000 для чтения и записи), чтобы преобразовать содержащиеся файлы jpeg2000 в обычные файлы jpeg, а затем передать новый файл PDF в ghostscript. Приведенный ниже код пытается это сделать, но в результате получается другой файл, содержащий файлы jpeg2000. Любая помощь с этим будет высоко ценится.

public class ImageReplacer{
    public static void main(String [] args){
        try{
            String RESULT = "";
            PdfReader reader = new PdfReader("pdf_containing_jpeg2000_images.pdf");
            PdfReaderContentParser parser = new PdfReaderContentParser(reader);
            MyImageRenderListener listener = new MyImageRenderListener(RESULT);
            MyImageConverterListener clistener = new MyImageConverterListener(RESULT);
            clistener.setReader(reader);
            for (int i = 1; i <= reader.getNumberOfPages(); i++) {
                parser.processContent(i, clistener);
            }   
            PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("out.pdf"));
            stamper.close();            
        }catch(Exception e){
            e.printStackTrace();    
        }
    }
}
class MyImageConverterListener implements RenderListener {
    protected String path = "";
    protected PdfReader reader;
    public MyImageConverterListener(String path) {
        this.path = path;
    }
    public void beginTextBlock() { }
    public void endTextBlock() { }
    public void renderImage(ImageRenderInfo renderInfo) {
        try {
            PdfImageObject image = renderInfo.getImage();
            PdfName filter = (PdfName)image.get(PdfName.FILTER);
            if (PdfName.JPXDECODE.equals(filter)) {
                if(image.getDictionary().isStream()){
                    BufferedImage bi = image.getBufferedImage();
                    if (bi == null) return; 
                    int width = (int)bi.getWidth();
                    int height = (int)bi.getHeight();
                    ByteArrayOutputStream imgBytes = new ByteArrayOutputStream(); 
                    ImageIO.write(bi, "JPG", imgBytes);
                    PRStream stream = new PRStream(reader,imgBytes.toByteArray());
                    stream.clear();
                    stream.setData(imgBytes.toByteArray(), false, PRStream.NO_COMPRESSION);
                    stream.put(PdfName.TYPE, PdfName.XOBJECT);
                    stream.put(PdfName.SUBTYPE, PdfName.IMAGE);
                    stream.put(new PdfName("foo"+Math.random()), new PdfName("bar"+Math.random()));
                    stream.put(PdfName.FILTER, PdfName.DCTDECODE);
                    stream.put(PdfName.WIDTH, new PdfNumber(width));
                    stream.put(PdfName.HEIGHT, new PdfNumber(height));
                    stream.put(PdfName.BITSPERCOMPONENT, new PdfNumber(8));
                    stream.put(PdfName.COLORSPACE, PdfName.DEVICERGB);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void renderText(TextRenderInfo renderInfo) { }
    public void setReader(PdfReader r){
        reader = r;
    }
}

Ответы [ 3 ]

1 голос
/ 07 октября 2013

Прекрасно работает, но у меня были некоторые проблемы с GlassFish v3.1.Glassfish действовал так, как будто в Classpath не было jai_imageio-1.1.jar.Я исправил это, поместив jai_imageio.jar в мою папку "/ path / to / glassfish / domains / domain1 / lib / ext /".

1 голос
/ 08 апреля 2016

У меня были некоторые проблемы с NullPointer с PDFConverter от Reece, потому что в моем PDF были разные типы встроенных элементов внутри GhostScript в CentOS 5.3 - Невозможно обработать данные JPXDecode . Поэтому я сделал несколько проверок Object / Type и добавил имя выходного файла в командную строку.

Все остальное замечательно и отлично работает с проблемой изображения jpeg2000. Спасибо Рису:)

import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfObject;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.PRStream;
import com.itextpdf.text.pdf.parser.PdfImageObject;
import com.itextpdf.text.pdf.PdfNumber;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import com.itextpdf.text.pdf.PdfStamper;
import java.io.*;

public class PDFConverter{

    public static void main(String [] args){
        if(args.length==2){
            if(hasJpeg2000(args[0])){
                System.out.println("Contains JPEG2000 images: Converting them to JPEG..."); 
                convertPDF(args[0], args[1]);
                System.out.println("Done...");
            }else{
                System.out.println("Doesn't contain any JPEG2000 images: Nothing to be done...");
            }
        }else{
            System.out.println("Please specify a PDF filename and a output filename as a command line arguments!");
        }
    }

    public static boolean hasJpeg2000(String s){
        try{
            PdfReader reader = new PdfReader(s); 
            int n = reader.getXrefSize();
            PdfObject object; 
            PRStream stream; 
            for (int i = 0; i < n; i++) {
                object = reader.getPdfObject(i); 
                if (object == null || !object.isStream())continue; 
                stream = (PRStream)object; 
                PdfObject pdfsubtype = stream.get(PdfName.SUBTYPE);
                System.out.println(pdfsubtype);
                if (pdfsubtype != null && pdfsubtype.toString().equals(PdfName.IMAGE.toString())) {
                    PdfImageObject image = new PdfImageObject(stream);
                    PdfName filter = (PdfName)image.get(PdfName.FILTER);
                    if (PdfName.JPXDECODE.equals(filter)) {
                        return true;
                    }
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return false;
    }

    private static void filterObject(PdfImageObject image,PdfName filter,PRStream stream) throws java.io.IOException {
        if (PdfName.JPXDECODE.equals(filter)) {
            BufferedImage bi = image.getBufferedImage();
            if (bi == null) return;
            int width = (int)(bi.getWidth());
            int height = (int)(bi.getHeight());
            ByteArrayOutputStream imgBytes = new ByteArrayOutputStream();
            ImageIO.write(bi, "JPG", imgBytes);
            stream.clear();
            stream.setData(imgBytes.toByteArray(),false, PRStream.NO_COMPRESSION);
            stream.put(PdfName.TYPE, PdfName.XOBJECT);
            stream.put(PdfName.SUBTYPE, PdfName.IMAGE);
            stream.put(new PdfName("foo"+Math.random()), new PdfName("bar"+Math.random()));
            stream.put(PdfName.FILTER, PdfName.DCTDECODE);
            stream.put(PdfName.WIDTH, new PdfNumber(width));
            stream.put(PdfName.HEIGHT, new PdfNumber(height));
            stream.put(PdfName.BITSPERCOMPONENT,new PdfNumber(8));
            stream.put(PdfName.COLORSPACE, PdfName.DEVICERGB);
        }
    }

    public static void convertPDF(String s, String out){
        try{
            PdfReader reader = new PdfReader(s); 
            int n = reader.getXrefSize();
            PdfObject object; 
            PRStream stream; 
            for (int i = 0; i < n; i++) {
                object = reader.getPdfObject(i); 
                if (object == null || !object.isStream())continue; 
                stream = (PRStream)object; 
                PdfObject pdfsubtype = stream.get(PdfName.SUBTYPE);
                if (pdfsubtype != null && pdfsubtype.toString().equals(PdfName.IMAGE.toString())) {
                    PdfImageObject image = new PdfImageObject(stream);
                    Object listOrName = image.get(PdfName.FILTER);
                    if (listOrName instanceof PdfName) {
                        PdfName filter = (PdfName)image.get(PdfName.FILTER);
                        filterObject(image, filter, stream);
                    }
                    else if (listOrName instanceof PdfArray) {
                        PdfArray list = (PdfArray)image.get(PdfName.FILTER);
                        for (int j = 0; j < list.size(); j++) {
                            PdfName filter = list.getAsName(j);
                            filterObject(image, filter, stream);
                        }
                    }
                    else {
                        System.err.println("Unknown Obejcttype: " + listOrName);
                    }
                }
            }
            PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(out)); stamper.close();
        } catch(Exception e){
            e.printStackTrace();
        }
    }

} 
1 голос
/ 20 декабря 2011

Так что мне удалось решить это самостоятельно (с небольшой помощью iText в действии Бруно Лоуаги - отличная книга). Просто для повторения, я собираюсь отсканировать PDF, используя iText, чтобы увидеть, содержит ли он какие-либо изображения JPEG2000 и выводит ли он тот же PDF, но с внутренними изображениями JPEG2000, замененными обычными изображениями JPEG. Это решает фатальную ошибку ghostscript 8.7 «Невозможно обработать данные JPXDecode», но также может пригодиться для обеспечения совместимости PDF с iOS.

Так что, без дальнейших усилий, дети; здесь идет ...

Шаг 1) Загрузите файл iText 5.x .jar и загрузите jai_imageio-1.1.jar (расширенная библиотека изображений Java, которая позволяет конвертировать файлы JPEG2000)

Шаг 2) Создайте файл с именем PDFConverter.java и поместите в него этот код:

import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfObject;
import com.itextpdf.text.pdf.PRStream;
import com.itextpdf.text.pdf.parser.PdfImageObject;
import com.itextpdf.text.pdf.PdfNumber;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import com.itextpdf.text.pdf.PdfStamper;
import java.io.*;

public class PDFConverter{
    public static void main(String [] args){
        if(args.length==1){
            if(hasJpeg2000(args[0])){
                System.out.println("Contains JPEG2000 images: Converting them to JPEG..."); 
                convertPDF(args[0]);
                System.out.println("Done...");
            }else{
                System.out.println("Doesn't contain any JPEG2000 images: Nothing to be done...");   
            }
        }else{
            System.out.println("Please specify a PDF filename as a command line argument!");    
        }
    }
    public static boolean hasJpeg2000(String s){
        try{
            PdfReader reader = new PdfReader(s); 
            int n = reader.getXrefSize();
            PdfObject object; 
            PRStream stream; 
            for (int i = 0; i < n; i++) {
                object = reader.getPdfObject(i); 
                if (object == null || !object.isStream())continue; 
                stream = (PRStream)object; 
                PdfImageObject image = new PdfImageObject(stream);
                PdfName filter = (PdfName)image.get(PdfName.FILTER);
                if (PdfName.JPXDECODE.equals(filter)) {
                    return true;
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return false;
    }
    public static void convertPDF(String s){
        try{
            PdfReader reader = new PdfReader(s); 
            int n = reader.getXrefSize();
            PdfObject object; 
            PRStream stream; 
            for (int i = 0; i < n; i++) {
                object = reader.getPdfObject(i); 
                if (object == null || !object.isStream())continue; 
                stream = (PRStream)object; 
                PdfImageObject image = new PdfImageObject(stream);
                PdfName filter = (PdfName)image.get(PdfName.FILTER);
                if (PdfName.JPXDECODE.equals(filter)) {
                    BufferedImage bi = image.getBufferedImage(); 
                    if (bi == null) continue; 
                    int width = (int)(bi.getWidth());
                    int height = (int)(bi.getHeight());
                    ByteArrayOutputStream imgBytes = new ByteArrayOutputStream(); 
                    ImageIO.write(bi, "JPG", imgBytes); 
                    stream.clear(); 
                    stream.setData(imgBytes.toByteArray(),false, PRStream.NO_COMPRESSION); 
                    stream.put(PdfName.TYPE, PdfName.XOBJECT); 
                    stream.put(PdfName.SUBTYPE, PdfName.IMAGE); 
                    stream.put(new PdfName("foo"+Math.random()), new PdfName("bar"+Math.random())); 
                    stream.put(PdfName.FILTER, PdfName.DCTDECODE); 
                    stream.put(PdfName.WIDTH, new PdfNumber(width)); 
                    stream.put(PdfName.HEIGHT, new PdfNumber(height)); 
                    stream.put(PdfName.BITSPERCOMPONENT,new PdfNumber(8)); 
                    stream.put(PdfName.COLORSPACE, PdfName.DEVICERGB);
                }
            }
            PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("out.pdf")); stamper.close();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
} 

Шаг 3) Скомпилируйте вышеуказанный файл следующим образом:

javac -cp.: IText-5.0.4.jar: jai_imageio-1.1.jar PDFConverter.java

Шаг 4) Запустить программу с PDF ...

java -cp.: IText-5.0.4.jar: jai_imageio-1.1.jar PDFConverter PDFFileName.pdf

Буйя ...

...