iText PDF; Javaを使ってjpeg2000をjpgに変換するhowto

I'm trying to solve a problem using java, iText, and the Java advanced imaging library. My software system uses ghostscript to create jpg thumbnail images etc... from PDF files. However on CentOS 5.x the highest version of ghostscript is 8.7 which has a known issue of not being able to handle PDF files containing JPEG 2000 images in them. My plan is to scan the file first and see if it contains jpeg2000 images (I've already got this part figured out); if so, then use iText and the Java Advanced Imaging library (contains the jpeg2000 read & write codecs) to convert the contained jpeg2000 files into regular jpeg files & then pass the new PDF file to ghostscript. The code below attempts this, but results in another file containing jpeg2000 files. Any help with this would be much appreciated.

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;
    }
}
0

3 答え

だから私は自分でこの問題を解決することができました(Bruno Lowagieの偉大な本であるiTextの助けを借りて)。 iTextを使ってPDFをスキャンして、JPEG2000画像が含まれているかどうか、同じPDFを出力するかどうか、内部のJPEG2000画像を通常のJPEG画像に置き換えて調べることです。これは、致命的なゴーストスクリプト8.7「JPXDecodeデータを処理できませんでした」エラーを解決しますが、PDFのiOSとの互換性を持たせるのにも役立ちます。

そうすることなく、子供たちはさらにそうすることができます。ここに行く...

ステップ1)iText 5.x .jarファイルをダウンロードし、jai_imageio-1.1.jar(JPEG2000ファイルを変換できるJava高度イメージングライブラリ)をダウンロードします。

ステップ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

ブヨヤ...

1
追加された

素晴らしいですが、GlassFish v3.1にいくつかの問題がありました。 GlassfishはClasspathにjai_imageio-1.1.jarがないかのように動作しました。私は "/ path/to/glassfish/domains/domain1/lib/ext /"フォルダにこのjai_imageio.jarを置くことを修正しました。

1
追加された

私のPDFには、 CentOS 5.3のGhostScript - 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
追加された