2011-12-19 123 views
0

我試圖解決使用java,iText和Java高級圖像庫的問題。我的軟件系統使用ghostscript來創建PDF文件中的JPG縮略圖等。然而,在CentOS 5.x上,ghostscript的最高版本是8.7,其中有一個已知問題,即無法處理包含JPEG 2000圖像的PDF文件。我的計劃是首先掃描文件,看它是否包含jpeg2000圖像(我已經找出了這部分);如果是,則使用iText和Java Advanced Imaging庫(包含jpeg2000讀取&編寫編解碼器)將包含的jpeg2000文件轉換爲常規jpeg文件&,然後將新的PDF文件傳遞給ghostscript。下面的代碼試圖這樣做,但會導致另一個包含jpeg2000文件的文件。任何幫助,將不勝感激。iText PDF;如何將jpeg2000轉換爲使用Java的jpg

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

回答

1

所以我設法自己解決這個問題(在Bruno Lowagie的行動中,iText的一些幫助 - 很棒的書)。爲了重新進行迭代,我的意圖是使用iText掃描PDF以查看它是否包含任何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命令:iText的 - 5.0.4.jar:jai_imageio-1.1.jar PDFConverter PDFFileName.pdf

Booyah ......

1

工程很好,但我在GlassFish v3.1中遇到了一些問題。 Glassfish的行爲好像在Classpath中沒有jai_imageio-1.1.jar。我在我的「/ path/to/glassfish/domains/domain1/lib/ext /」文件夾中修復了這個問題。

1

我從Reece的PDFConverter中遇到了一些NullPointer問題,因爲我的PDF在GhostScript on CentOS 5.3 - Unable to process JPXDecode data中有不同類型的嵌入元素。所以我做了一些對象/類型檢查,並將輸出文件名添加到命令行。

其他一切都很棒,對圖像jpeg2000問題非常完美。感謝Reece :)

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(); 
     } 
    } 

}