2013-12-16 123 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