Jump to content
Server Maintenance This Week. ×

SM and iText to Compress PDF


This topic is 2958 days old. Please don't post here. Open a new topic instead.

Recommended Posts

Hello

I'm having major issues with FMP12 and large PDFs when printing to PDF so I tried Ocean West's suggestion of using ScriptMaster and iText to merge save as pdf pages, but the file size is still too large. I'd like to try to compress the pdf using iText, but I'm having problems making it work.

Using the example code from iText in Action:


/**

	 * Manipulates a PDF file src with the file dest as result

	 * @param src the original PDF

	 * @param dest the resulting PDF

	 * @param pow the PDF will be N-upped with N = Math.pow(2, pow);

	 * @throws IOException

	 * @throws DocumentException

	 */

public void compressPdf(String src, String dest) throws IOException, DocumentException {

	 PdfReader reader = new PdfReader(src);

	 PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest), PdfWriter.VERSION_1_5);

	 stamper.getWriter().setCompressionLevel(9);

	 int total = reader.getNumberOfPages() + 1;

	 for (int i = 1; i < total; i++) {

		 reader.setPageContent(i, reader.getPageContent(i));

	 }

	 stamper.setFullCompression();

	 stamper.close();

}







I tried to translate it as (as well as several other variations which also did not work):



RegisterGroovy( "compressPdf( src; dest)" ; "//compressPdf ( src; dest)¶¶

import com.itextpdf.text.pdf.PdfReader¶

import com.itextpdf.text.pdf.PdfStamper¶

import com.itextpdf.text.pdf.PdfWriter¶¶

	

reader = new PdfReader(src)¶

stamper = new PdfStamper(reader, new FileOutputStream(dest), PdfWriter.VERSION_1_5)¶

	 stamper.getWriter().setCompressionLevel(9)¶

	 int total = reader.getNumberOfPages() + 1¶

	 for (int i = 1; i < total; i++) {

		 reader.setPageContent(i, reader.getPageContent(i))¶

	 }

	 stamper.setFullCompression()¶

	 stamper.close()¶ ")

but that did not work.

Is there documentation on how to "translate" iText sample code when working in Filemaker?

Can someone let me know what is wrong with the above code?

Link to comment
Share on other sites

What do you mean - did not work??

Threw an errror or did not apprently change the size of your PDF?

It depends on lots of things. In particular what is inside your PDF and how it got there. The compression is like zip, it will compress the data that writes the file, but if it has a huge image inside iText does NOT change that by resampling or any other method that would significantly reduce the file size. Well not without looping through the dictionaries and finding the image, processing it with some other java class and theh re-inserting the bytes - there has been a discussion about this on their support list over the last few weeks.

From an old thread I saved

>>

You're mixing different concepts. When you set the compression for an

image in iText, you are talking about LOSSLESS compression. When you set

the compression for an image in ImageMagic, you're talking about LOSSY

compression.

In iText, the number of pixes (the resolution) isn't changed. I'm sure

that ImageMagic reduces the resolution.

Read section 10.2.6 of the second edition: "Lossless compression won't

result in dramatic file size reduction. However, if lossy compression is

acceptable, you could use the java.awt.Image to reduce the quality."

Listing 10.12 shows an example named CompressAwt that explains how to

reduce the resolution.

The code is fine, probably could be a bit more Groovy




import com.itextpdf.text.pdf.PdfReader

import com.itextpdf.text.pdf.PdfStamper

import com.itextpdf.text.pdf.PdfWriter



reader = new PdfReader(src)

stamper = new PdfStamper(reader, new FileOutputStream(dest), PdfWriter.VERSION_1_7)

stamper.getWriter().setCompressionLevel(9)

for (i in 1..reader.getNumberOfPages()){

reader.setPageContent(i, reader.getPageContent(i))

}

stamper.setFullCompression()

stamper.close()

return true



This might be helpful

http://www.javabeat.net/2011/05/resizing-an-image-in-an-existing-document-using-itext/

Link to comment
Share on other sites

By not working, I mean it was not registering as an external function.

I was looking to compress the images with a lossy compression to reduce the overall file size. Thank you very much for explaining. I will give the code a try and see if the file size comes down enough.

Thanks a lot.

Link to comment
Share on other sites

Thanks, it registered and worked now.

The file size is the same before and after compression, which is good to know.

Thank you very much for your explaination because at least I know why.

I'm going to use GetThumbnail on layouts that produce large PDFs, at least for now. It seems Save as PDF produces large PDFs on some layouts, but decent size PDFs on other layouts.

Thanks a lot.

Link to comment
Share on other sites

I am currently working on some iText code to loop through a pdf, extract images, reduce them in size, and then put them back.

The problem is getting it to work with CMYK images which are a lot more complicated than RGB.

Will update when I have made some progress

Link to comment
Share on other sites

This may not be the answer to your specific case but here is a proof-of-concept for reducing PDF file size

It takes all images and scales them down in size and then puts them back into the original pdf at the original size as an RGB jpg

The clever bit comes from Werner Randelshofer's Blog, http://www.randelsho...h-java-imageio/

which allows the reading of CMYK jpg files of several flavours

I haven't tested it extensively yet but seems to work OK on a selection from my Documents folder - example reduced 2.4MB to 768kb with a setting of 0.3 and 1MB with a setting of 0.7




// PDFreduceImages ( fm_fileIn ; fm_fileOut ; fm_icc ; factor ; invert )

// 12_06_28 JR

// v1.0

//

// requires :

// iText 5.3

// Xmlgraphics-Commons-1.4 -- http://xmlgraphics.apache.org/commons/

// Sanselan -- http://commons.apache.org/imaging/

// CMYKdemo -- http://www.randelshofer.ch/blog/2011/08/reading-cmyk-jpeg-images-with-java-imageio/

// some clever stuff by werner!!

//

// fm_fileIn is path to pdf to resize, fm_fileOut is output path

// fm_icc is optional path to a CMYK ICC profile - see http://www.adobe.com/support/downloads/detail.jsp?ftpID=3680

// factor is 0.0001 to 1 with relative compression, grayscale images are not reduced as much

// invert toggles the method from YCCK to CMYK if your images are inverted

// TODO find out how to automate this so it can be done on a case-by-case basis

//

// This works by reading the images in the XStream from a PDF, resizing each image down and then rewriting it at the orignal size as an RGB or GRAY jpg

// crude but effective as a way of reducing PDF file size



import java.awt.Graphics2D

import java.awt.geom.AffineTransform

import java.awt.image.BufferedImage

import java.io.ByteArrayOutputStream

import java.io.FileOutputStream

import javax.imageio.ImageIO

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

import org.monte.media.jpeg.*

import org.apache.sanselan.*

import java.awt.color.ICC_Profile



FACTOR = Math.min(1, factor.toFloat())

GFACTOR = Math.min(1, FACTOR * 1.6)

key = new PdfName('Subtype')

key2 = new PdfName('ColorSpace')

value = new PdfName('Image')

reader = new PdfReader(fm_fileIn)

n = reader.getXrefSize()

PdfObject object

PRStream stream



for ( i in 0..<n){

object = reader.getPdfObject(i)

if (object == null || !object.isStream()) continue

stream = (PRStream)object

if (value.equals(stream.get(key))){

// it is an image

image = new PdfImageObject(stream)

if (stream.get(key2).toString()[-4..-1]=='CMYK'){

//CMYK code

// find out if there is an embedded profile

icc_profile = Sanselan.getICCProfile(image.getImageAsBytes())

if (icc_profile == null){

// no there isnt so use the one I provide OR a defauilt

icc_profile = !fm_icc ? profile = ICC_Profile.getInstance(CMYKJPEGImageReader.class.getResourceAsStream("Generic CMYK Profile.icc")) : ICC_Profile.getInstance(fm_icc)

} //end if

c = new CMYKJPEGImageReader()

if(!invert || invert == '0'){

bi = c.readRGBImageFromYCCK(new ByteArrayInputStream(image.getImageAsBytes()), icc_profile)

} else {

bi = c.readRGBImageFromCMYK(new ByteArrayInputStream(image.getImageAsBytes()), icc_profile)

} //end if

int width = bi.getWidth() * FACTOR

int height = bi.getHeight() * FACTOR

img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)

} else if (stream.get(key2).toString()[-4..-1] == 'GRAY'){

//GRAY code

bi = image.getBufferedImage()

if (bi == null) continue

int width = (bi.getWidth() * GFACTOR);

	 int height = (bi.getHeight() * GFACTOR)

img = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY)

} else {

//RGB code

bi = image.getBufferedImage()

if (bi == null) continue

int width = (bi.getWidth() * FACTOR);

	 int height = (bi.getHeight() * FACTOR)

img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)

} //end if

// scale the image

at = AffineTransform.getScaleInstance(FACTOR, FACTOR)

g = img.createGraphics()

g.drawRenderedImage(bi, at)

imgBytes = new ByteArrayOutputStream()

ImageIO.write(img, "jpg", imgBytes)

// replace stream

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(img.getWidth()))

stream.put(PdfName.HEIGHT, new PdfNumber(img.getHeight()))

stream.put(PdfName.BITSPERCOMPONENT, new PdfNumber(8))

stream.put(PdfName.COLORSPACE, PdfName.DEVICERGB)

} //end if

} //end for

try{

stamper = new PdfStamper(reader, new FileOutputStream(fm_fileOut))

stamper.close()

} catch (e) {

//return 'ERROR'

return e.getMessage()

}

return true





Link to comment
Share on other sites

John,

Holy crow, this looks like it will solve a longstanding issue of mine. I can't install it for a couple week, but it looks pretty good.

Any way of converting images to grayscale? The images usually are in color but don't need to be and that would reduce the size too.

Contact me offline if you'd prefer: [email protected]

Thanks,

David

Link to comment
Share on other sites

  • 3 years later...

Just wanted to share an experience...

 

I know this is just a proof-of-concept, but I've been using this code for quite some time now for my own purposes, and mostly had really good results. I just tried it with a client of mine, who however got some interesting results recently.

They noticed that PDFs that actually grew in size with certain factors when the documents compressed contained grey placeholder images with a simple text, rather than actual complex images.

It looks like the algorithm used doesn't work well in this case - reminds me of my first image database in the mid 90s when somebody decided to save space when scanning images...

I did some testing, and got the following results:

Original file: 92 KB

0.1 76 KB
0.2 72 KB
0.3 79 KB
0.4 90 KB
0.5 98 KB
0.6 116 KB
0.7 136 KB
0.8 151 KB
0.9 174 KB
1.0 157 KB

It's actually only the uncompressed image that gives acceptable quality even for on-screen use.

I'll try to look around myself, but if somebody knows of a better compression algorithm, I'm interested!

Link to comment
Share on other sites

  • 7 months later...

Hello,

I found that discussion as I'm looking for a script compressing a pdf file generated by the plugin printswitch of myFMbutler. An A4 without only a little picture (logo of the society) has more than 300ko !

In  the scriptmaster sample file, after adding the iText library in jars, I pasted the script of nleon307 ; it runs without error but the dest file has the same weight !!!

Can you give me an indication or a sample file ?

Regards

Noël

Capture d’écran 2016-03-16 à 07.17.18.png

Link to comment
Share on other sites

Noel

if you read the comments further up, the compression is like zip, but it does not resample any images in the process. For that you need some of the other techniques.

Can you post an example of the file?

Link to comment
Share on other sites

Hello !

 
I had read but probably not enough ; that you were talking pictures took me back to my models that contain the logo of the association ... and then surprise it was very heavy! A reduction in gif later and my pdf is near 100kb Pomero_Nathalie2016.pdf, what seems better ! I join a sample pdf and if you think we can get lighter !

 

Link to comment
Share on other sites

Thanks ! I'll try it

But I'm surprised because even these 2 pictures reduced as gif (5ko for each) the layout generated is 583ko for an A4 vs 28ko if without pictures on the PC.  On the Mac with pictures the pdf is only 90ko

FmButler who distributes the PrinterSwitch plugin says that the problem comes from the Amuyi pdf driver they use on PC;

Have a good week

Noël

Link to comment
Share on other sites

This topic is 2958 days old. Please don't post here. Open a new topic instead.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.