nleon307 Posted June 26, 2012 Posted June 26, 2012 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?
john renfrew Posted June 26, 2012 Posted June 26, 2012 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/
nleon307 Posted June 27, 2012 Author Posted June 27, 2012 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.
nleon307 Posted June 28, 2012 Author Posted June 28, 2012 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.
john renfrew Posted June 28, 2012 Posted June 28, 2012 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
john renfrew Posted June 28, 2012 Posted June 28, 2012 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
nleon307 Posted June 29, 2012 Author Posted June 29, 2012 Wow, I will absolutely give this a try this weekend. It sounds like exactly what I am trying to do. Thank you so much for posting it.
David Jondreau Posted June 30, 2012 Posted June 30, 2012 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
john renfrew Posted June 30, 2012 Posted June 30, 2012 My error.. Missed out one line in the header, this also needs Sanselan from http://commons.apache.org/imaging/
David Wikström Posted August 5, 2015 Posted August 5, 2015 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 KB0.2 72 KB0.3 79 KB0.4 90 KB0.5 98 KB0.6 116 KB0.7 136 KB0.8 151 KB0.9 174 KB1.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!
Noél Dubau Posted March 16, 2016 Posted March 16, 2016 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
john renfrew Posted March 16, 2016 Posted March 16, 2016 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?
Noél Dubau Posted March 17, 2016 Posted March 17, 2016 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 !
john renfrew Posted March 17, 2016 Posted March 17, 2016 here's two goes, one of which is unacceptable in terms of quality It's not just the logo but the signature, and to be fair a 100k PDF is hardly heavyweight. and taking both logos out it is 66k... doc_small.pdf doc_small_85.pdf
Noél Dubau Posted March 18, 2016 Posted March 18, 2016 Thanks for that return and the samples added... but how did you get that result ? Thanks Noel
john renfrew Posted March 18, 2016 Posted March 18, 2016 Using the PDFreduceImages function from the middle of the post, or at least my latest dev function based on that..
Noél Dubau Posted March 21, 2016 Posted March 21, 2016 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
Recommended Posts
This topic is 3238 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 accountSign in
Already have an account? Sign in here.
Sign In Now