[英]Compressing images in existing pdfs makes the resulting PDF file bigger (Lowagies resizing method and real compression method)
Im having a problem with image compression. 我在图像压缩方面遇到问题。 I used the answer described in this question compress pdf with large images via java if i set the FACTOR variable to 0.9f or 1f (original size) the resulting pdf file starts to get bigger than the ORIGINAL. 如果我将FACTOR变量设置为0.9f或1f(原始大小),则使用此问题中描述的答案通过Java将pdf压缩为大图像 ,结果pdf文件开始变得大于原始文件。 But that is not the case for all files. 但是,并非所有文件都如此。 Some files created by myself are getting smaller like planned but some just get bigger like +1/3rd and i get black backgrounds on some images ontop of it. 我自己创建的某些文件正像计划的那样变小,但有些文件却像+ 1 / 3rd一样变大,而我在其顶部的某些图像上得到黑色背景。 this is getting even worse when im using the normal image compression without resizing the image This is my test file. 当我使用正常的图像压缩而不调整图像大小时,情况变得更糟。 这是我的测试文件。
Lowagies method: (resize the images) Lowagies方法:(调整图像大小)
// TODO Auto-generated method stub
PdfName key = new PdfName("ITXT_SpecialId");
PdfName value = new PdfName("123456789");
// Read the file
PdfReader reader = new PdfReader(args[0]);
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() * 1f);
int height = (int)(bi.getHeight() * 1f);
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
AffineTransform at = AffineTransform.getScaleInstance(1f, 1f);
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("/Applications/XAMPP/xamppfiles/htdocs/pdf_compress/download/"+args[2]));
stamper.close();
reader.close();
My method (Using real compression by setting the quallity of the image instead of resizing it) 我的方法(通过设置图像的质量来使用实际压缩,而不是调整其大小)
PdfReader reader = new PdfReader(args[0]);
// Read the file
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;
PdfObject pdfsubtype = stream.get(PdfName.SUBTYPE);
if (pdfsubtype != null && pdfsubtype.toString().equals(PdfName.IMAGE.toString())) {
System.out.println(pdfsubtype.length());
PdfImageObject image = new PdfImageObject(stream);
BufferedImage bi = image.getBufferedImage();
if (bi == null) continue;
int width = (int)(bi.getWidth());
int height = (int)(bi.getHeight());
if(width <=30 || height <=30){
continue;
}
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
AffineTransform at = null;
Graphics2D g = img.createGraphics();
g.drawRenderedImage(bi, at );
ByteArrayOutputStream imgBytes = new ByteArrayOutputStream();
Iterator iter = ImageIO.getImageWritersByFormatName("JPG");
ImageWriter writer = (ImageWriter)iter.next();
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
// here goes the compression
iwp.setCompressionQuality(Float.valueOf(args[1]));
ImageOutputStream imageos = ImageIO.createImageOutputStream(imgBytes);
writer.setOutput(imageos);
IIOImage images = new IIOImage(img, null, null);
writer.write(null,images , iwp);
imageos.close();
writer.dispose();
stream.clear();
stream.setData(imgBytes.toByteArray(), false, PRStream.BEST_COMPRESSION);
stream.put(PdfName.TYPE, PdfName.XOBJECT);
stream.put(PdfName.SUBTYPE, PdfName.IMAGE);
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("/Applications/XAMPP/xamppfiles/htdocs/pdf_compress/download/"+args[2]));
stamper.setFullCompression();
stamper.close();
reader.close();
System.out.println("Done");
What is wrong with the code? 代码有什么问题? Should i use a different image compression method? 我应该使用其他图像压缩方法吗? Are there any others? 还有其他吗?
When I only replace JPEGs, I already get a lower file size. 当我仅替换JPEG时,我已经获得了较小的文件大小。 Removing the unused object also helps: 删除未使用的对象还有助于:
public class ReduceSize {
public static final String SRC = "resources/pdfs/annual_report_2009.pdf";
public static final String DEST = "results/images/annual_report_2009.pdf";
public static final float FACTOR = 0.5f;
public static void main(String[] args) throws DocumentException, IOException {
File file = new File(DEST);
file.getParentFile().mkdirs();
new ReduceSize().manipulatePdf(SRC, DEST);
}
public void manipulatePdf(String src, String dest) throws DocumentException, IOException {
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 (!PdfName.IMAGE.equals(stream.getAsName(PdfName.SUBTYPE)))
continue;
if (!PdfName.DCTDECODE.equals(stream.getAsName(PdfName.FILTER)))
continue;
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);
if (width <= 0 || height <= 0)
continue;
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(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);
}
reader.removeUnusedObjects();
// Save altered PDF
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
stamper.setFullCompression();
stamper.close();
reader.close();
}
}
This reduces the 10,510 KB file to 9,159 KB. 这样会将10,510 KB文件减少到9,159 KB。 Of course: fonts also take up quite some space. 当然:字体也占用相当大的空间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.