2013-12-16 149 views
6

尋找一種方式來壓縮PDF格式的圖像和輸出PDF格式的歸檔。我無法在創建之前壓縮圖像,因爲這會影響打印質量。通過java壓縮pdf與大圖像

每個pdf的大小約爲8MB,其中大部分由2個圖像組成。圖像是在PNG格式,並在生成期間帶入pdf(使用第三方發生器)

有沒有辦法在java中壓縮這些沒有使用第三方工具。我已經嘗試過使用pdfbox,itext和第三方exe(neevia),第三方工具是目前爲止唯一給我任何結果的第三方工具(低至約半MB),但我不想將控制權交給exe 。 示例代碼如下。

import java.io.BufferedReader; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.util.Arrays; 

import org.apache.pdfbox.exceptions.COSVisitorException; 
import org.apache.pdfbox.pdmodel.PDDocument; 
import org.apache.pdfbox.pdmodel.common.PDStream; 

import com.itextpdf.text.DocumentException; 
import com.itextpdf.text.pdf.PdfReader; 
import com.itextpdf.text.pdf.PdfStamper; 
import com.itextpdf.text.pdf.PdfWriter; 

public class compressPDF { 

public static void main (String[] args) throws IOException, DocumentException, COSVisitorException { 


    /* 
    * Using PDF Box 
    */ 

    PDDocument doc; // = new PDDocument(); 

    doc = PDDocument.load("C:/_dev_env_/TEMP/compressPDF/TRPT_135002_1470_20131212_121423.PDF"); 

    PDStream stream= new PDStream(doc); 
    stream.addCompression(); 

    doc.save("C:/_dev_env_/TEMP/compressPDF/compressed_pdfBox.pdf"); 

    doc.close(); 

    /* 
    * Using itext 
    */ 

    PdfReader reader = new PdfReader("C:/_dev_env_/TEMP/compressPDF/TRPT_135002_1470_20131212_121423.PDF"); 

    PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("C:/_dev_env_/TEMP/compressPDF/compressed_Itext.pdf"), PdfWriter.VERSION_1_5); 
    stamper.setFullCompression(); 
    stamper.getWriter().setCompressionLevel(50); 
    int total = reader.getNumberOfPages() + 1; 
    for (int i = 1; i < total; i++) { 
     reader.setPageContent(i, reader.getPageContent(i)); 
    } 
    stamper.close(); 
    reader.close(); 

    /* 
    * Using 3rd party - Neevia 
    */ 
    try { 
    Process process = new ProcessBuilder("C:/Program Files (x86)/neeviaPDF.com/PDFcompress/cmdLine/CLcompr.exe","C:/_dev_env_/TEMP/compressPDF/TRPT_135002_1470_20131212_121423.PDF", "C:/_dev_env_/TEMP/compressPDF/compressed_Neevia.pdf").start(); 
    InputStream is = process.getInputStream(); 
    InputStreamReader isr = new InputStreamReader(is); 
    BufferedReader br = new BufferedReader(isr); 
    String line; 

    System.out.printf("Output of running %s is:", Arrays.toString(args)); 

    while ((line = br.readLine()) != null) { 
     System.out.println(line); 
    } 
    } catch (Exception e) { 
     System.out.println(e); 
    } finally { 
     System.out.println("Created!!"); 
    } 

} 

} 
+0

你在保存的圖像上?你有沒有考慮像png這樣的無損格式? – Taylor

+0

圖像以png格式存儲,並使用名爲doc1(第三方)的生成器引入到文檔中。感謝您的快速回復:) –

+1

如果pdf大小的大部分是這些圖像,並且它們已經被壓縮,那麼您可能處於僵局。我在臨時中進行了一些研究,PDF將壓縮存儲圖像:https://en.wikipedia.org/wiki/Pdf#Raster_images,因此您可能需要調整pdf的組裝方式。除非您刪除並重新添加圖像,否則一旦PDF已經組裝完畢,就不能確定可以做多少事情。 – Taylor

回答

16

我用下面的代碼進行概念證明...作品一種享受:)感謝布魯諾設置我在正確的道路:)

package compressPDF; 

import java.awt.Graphics2D; 
import java.awt.geom.AffineTransform; 
import java.awt.image.BufferedImage; 
import java.io.ByteArrayOutputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 

import javax.imageio.ImageIO; 

import com.itextpdf.text.DocumentException; 
import com.itextpdf.text.pdf.PRStream; 
import com.itextpdf.text.pdf.PdfName; 
import com.itextpdf.text.pdf.PdfNumber; 
import com.itextpdf.text.pdf.PdfObject; 
import com.itextpdf.text.pdf.PdfReader; 
import com.itextpdf.text.pdf.PdfStamper; 
import com.itextpdf.text.pdf.parser.PdfImageObject; 

public class ResizeImage { 

/** The resulting PDF file. */ 
//public static String RESULT = "results/part4/chapter16/resized_image.pdf"; 
/** The multiplication factor for the image. */ 
public static float FACTOR = 0.5f; 

/** 
* Manipulates a PDF file src with the file dest as result 
* @param src the original PDF 
* @param dest the resulting PDF 
* @throws IOException 
* @throws DocumentException 
*/ 
public void manipulatePdf(String src, String dest) throws IOException, DocumentException { 
    PdfName key = new PdfName("ITXT_SpecialId"); 
    PdfName value = new PdfName("123456789"); 
    // Read the file 
    PdfReader reader = new PdfReader(src); 
    int n = reader.getXrefSize(); 
    PdfObject object; 
    PRStream stream; 
    // Look for image and manipulate image stream 
    for (int i = 0; i < n; i++) { 
     object = reader.getPdfObject(i); 
     if (object == null || !object.isStream()) 
      continue; 
     stream = (PRStream)object; 
     // if (value.equals(stream.get(key))) { 
     PdfObject pdfsubtype = stream.get(PdfName.SUBTYPE); 
     System.out.println(stream.type()); 
     if (pdfsubtype != null && pdfsubtype.toString().equals(PdfName.IMAGE.toString())) { 
      PdfImageObject image = new PdfImageObject(stream); 
      BufferedImage bi = image.getBufferedImage(); 
      if (bi == null) continue; 
      int width = (int)(bi.getWidth() * FACTOR); 
      int height = (int)(bi.getHeight() * FACTOR); 
      BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 
      AffineTransform at = AffineTransform.getScaleInstance(FACTOR, FACTOR); 
      Graphics2D g = img.createGraphics(); 
      g.drawRenderedImage(bi, at); 
      ByteArrayOutputStream imgBytes = new ByteArrayOutputStream(); 
      ImageIO.write(img, "JPG", imgBytes); 
      stream.clear(); 
      stream.setData(imgBytes.toByteArray(), false, PRStream.BEST_COMPRESSION); 
      stream.put(PdfName.TYPE, PdfName.XOBJECT); 
      stream.put(PdfName.SUBTYPE, PdfName.IMAGE); 
      stream.put(key, value); 
      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); 
     } 
    } 
    // Save altered PDF 
    PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest)); 
    stamper.close(); 
    reader.close(); 
} 

/** 
* Main method. 
* 
* @param args no arguments needed 
* @throws DocumentException 
* @throws IOException 
*/ 
public static void main(String[] args) throws IOException, DocumentException { 
    //createPdf(RESULT); 
    new ResizeImage().manipulatePdf("C:/_dev_env_/TEMP/compressPDF/TRPT_135002_1470_20131212_121423.PDF", "C:/_dev_env_/TEMP/compressPDF/compressTest.pdf"); 
} 

} 
+1

(備註:你實際上可以通過點擊你自己答案的投票數下面的勾號來接受你自己的答案。) – rwong

+0

我無法找到這兩個類BufferedImage,Graphics2D – Erum