繁体   English   中英

如何在不调整图像大小的情况下压缩PDF?

[英]How to compress PDF without resizing image?

我正在使用iText压缩现有的pdf。 我正在使用《 iText in Action》 (第二版)中的示例:

package part4.chapter16;

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(SpecialId.RESULT);
        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))) {
                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.NO_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(RESULT));
        stamper.close();
        reader.close();
    }

    /**
     * Main method.
     *
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args) throws IOException, DocumentException {

        new ResizeImage().manipulatePdf(src, dest);
    }
}

以上代码基于FACTOR减小了图像的大小。 我不想减小尺寸,而是更改DPI以减小图像尺寸。 任何帮助将不胜感激。 我是Java新手。 还有其他可用于压缩PDF的开源工具吗?

您已经从我的书中复制/粘贴了一个示例,但似乎您没有读过这本书,也没有真正尝试过该示例。 您说:“我不想减小尺寸,但是要更改DPI。”

好吧……这正是我书中的例子所要做的! SpecialID示例中,我创建一个PDF,其PDF文件使用此矩形定义: new Rectangle(400, 300) 这意味着我们有一个页面,该页面的大小为400 x 300点(请参见下面的屏幕截图中的蓝点)。 在此页面上,我添加了500 x 332像素的JPG(请参见红点)。 使用以下方法将此图像缩放为400 x 300点:

img.scaleAbsolute(400, 300);

该图像占用55332字节(绿点)。

在此处输入图片说明

请注意,我们可以轻松计算DPI:图像的宽度为400点; 即5.555英寸。 图像的高度为300点; 那是4.166英寸 宽度的像素数为500,因此X方向上的DPI为500 x 72/400或90 DPI。 高度的像素数为332,因此DPI为332 x 72/300或79.68 DPI。

您想通过降低分辨率来缩小JPG的字节数。 但是:您希望图像的大小保持不变:它仍然必须覆盖400 x 300点。

正是您在问题中复制/粘贴的ResizeImage示例中完成的操作。 让我们不要看里面:

在此处输入图片说明

图像仍然可以测量400 x 300点(这就是您想要的,不是吗?),但是分辨率却急剧下降:图像现在是250 x 166像素,而不是500 x 332像素,而无需更改页面大小!

现在让我们计算新的DPI:在X方向上,我们有250 x 72 /400。这就是45 DPI。 在Y方向上,我们有166 x 72 /300。即39.84 DPI。 这恰好是我们以前拥有的DPI的一半! 这是巧合吗? 当然不是! 那就是我们使用的FACTOR (这只是简单的数学问题。)

由于降低分辨率,图像现在仅占用5343字节(而不是原始的55332字节)。 您已成功压缩图像。

简而言之:您误解了所使用的示例。 您说它无法实现您想要的。 我可以证明是的;-)

从您对此答案发表的评论看来,您正在混淆诸如图像分辨率,图像压缩等概念。要消除这种混乱,您应该阅读以下问题和解答:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM