compress pdf with large images via java

后端 未结 2 1473
梦谈多话
梦谈多话 2020-12-03 06:02

Looking for a way to compress images in a pdf and to output a pdf for archiving. I cannot compress the images before creation as it would compromise the quality of the print

相关标签:
2条回答
  • 2020-12-03 06:25

    I used code below for a proof of concept... Works a treat :) Thanks to Bruno for setting me on the right path :)

    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");
    }
    
    }
    
    0 讨论(0)
  • 2020-12-03 06:28

    Just to update the excellent answer from @Daniel, I update his code to be compatible with iText7.

    package opencde.builder.compresspdf;
    
    import java.awt.Graphics2D;
    import java.awt.geom.AffineTransform;
    import java.awt.image.BufferedImage;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.util.Iterator;
    
    import javax.imageio.ImageIO;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.itextpdf.io.image.ImageDataFactory;
    import com.itextpdf.kernel.pdf.PdfDictionary;
    import com.itextpdf.kernel.pdf.PdfDocument;
    import com.itextpdf.kernel.pdf.PdfName;
    import com.itextpdf.kernel.pdf.PdfPage;
    import com.itextpdf.kernel.pdf.PdfReader;
    import com.itextpdf.kernel.pdf.PdfStream;
    import com.itextpdf.kernel.pdf.PdfWriter;
    import com.itextpdf.kernel.pdf.xobject.PdfImageXObject;
    import com.itextpdf.layout.element.Image;
    
    public class ResizeImageV7 {
        
        // Logging
        private static Logger logger = LoggerFactory.getLogger(ResizeImageV7.class);
    
        /**
         * Manipulates a PDF file src with the file dest as result
         * 
         * @param src  the original PDF
         * @param dest the resulting PDF
         * @param resizeFactor factor to multiplicate to resize image
         * @throws IOException
         */
        public void manipulatePdf(String src, String dest,Float resizeFactor) throws IOException {
            
            //Get source pdf
            PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));
    
            // Iterate over all pages to get all images.
            for (int i = 1; i <= pdfDoc.getNumberOfPages(); i++)
            {
                PdfPage page = pdfDoc.getPage(i);
                PdfDictionary pageDict = page.getPdfObject();
                PdfDictionary resources = pageDict.getAsDictionary(PdfName.Resources);
                // Get images
                PdfDictionary xObjects = resources.getAsDictionary(PdfName.XObject);
                for (Iterator<PdfName> iter = xObjects.keySet().iterator() ; iter.hasNext(); ) {
                    // Get image
                    PdfName imgRef = iter.next();
                    PdfStream stream = xObjects.getAsStream(imgRef);
                    PdfImageXObject image = new PdfImageXObject(stream);
                    BufferedImage bi = image.getBufferedImage();
                    if (bi == null)
                        continue;
                    
                    // Create new image
                    int width = (int) (bi.getWidth() * resizeFactor);
                    int height = (int) (bi.getHeight() * resizeFactor);
                    BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                    AffineTransform at = AffineTransform.getScaleInstance(resizeFactor, resizeFactor);
                    Graphics2D g = img.createGraphics();
                    g.drawRenderedImage(bi, at);
                    ByteArrayOutputStream imgBytes = new ByteArrayOutputStream();
                    
                    // Write new image
                    ImageIO.write(img, "JPG", imgBytes);
                    Image imgNew =new Image(ImageDataFactory.create(imgBytes.toByteArray()));
                    
                    // Replace the original image with the resized image
                    xObjects.put(imgRef, imgNew.getXObject().getPdfObject());
                }          
            }
            
            pdfDoc.close();
        }
    
        /**
         * Main method.
         *
         * @param src  the original PDF
         * @param dest the resulting PDF
         * @param resizeFactor factor to multiplicate to resize image
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            //Get input parametres
            if (args.length<3 ) {
                System.out.println("Source PDF, Destination PDF and Resize Factor must be provided as parametres");
            } else {
                String sourcePDF=args[0];
                String destPDF=args[1];
                Float resizeFactor=Float.valueOf(new String(args[2]));
                logger.info("Inovking Resize with args, source:" + sourcePDF
                        + " destination:" + destPDF 
                        + " factor:" + resizeFactor);
                //Call method to resize images
                new ResizeImageV7().manipulatePdf(sourcePDF,destPDF,resizeFactor);
                logger.info("PDF resized");
            }
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题