I have been searching a lot on Google about how to compress existing pdf
(size). My problem is
I can't use any application, because it needs to be done by a C# program.
I can't use any paid library as my clients don't want to go out of Budget. So a PAID library is certainly a NO
I did my home-work for last 2 days and came upon a solution using iTextSharp, BitMiracle but to no avail as the former decrease just 1% of a file and later one is a paid.
I also came across PDFcompressNET and pdftk but i wasn't able to find their .dll.
Actually the pdf is insurance policy with 2-3 images (black and white) and around 70 pages accounting to size of 5 MB.
I need the output in pdf only(can't be in any other format)
Here's an approach to do this (and this should work without regard to the toolkit you use):
If you have a 24-bit rgb or 32 bit cmyk image do the following:
That said, if you do can do all of this well in an unsupervised manner, you have a commercial product in its own right.
I will say that you can do most of this with Atalasoft dotImage (disclaimers: it's not free; I work there; I've written nearly all the PDF tools; I used to work on Acrobat).
One particular way to that with dotImage is to pull out all the pages that are image only, recompress them and save them out to a new PDF then build a new PDF by taking all the pages from the original document and replacing them the recompressed pages, then saving again. It's not that hard.
List<int> pagesToReplace = new List<int>(); PdfImageCollection pagesToEncode = new PdfImageCollection(); using (Document doc = new Document(sourceStream, password)) { for (int i=0; i < doc.Pages.Count; i++) { Page page = doc.Pages[i]; if (page.SingleImageOnly) { pagesToReplace.Add(i); // a PDF image encapsulates an image an compression parameters PdfImage image = ProcessImage(sourceStream, doc, page, i); pagesToEncode.Add(i); } } PdfEncoder encoder = new PdfEncoder(); encoder.Save(tempOutStream, pagesToEncode, null); // re-encoded pages tempOutStream.Seek(0, SeekOrigin.Begin); sourceStream.Seek(0, SeekOrigin.Begin); PdfDocument finalDoc = new PdfDocument(sourceStream, password); PdfDocument replacementPages = new PdfDocument(tempOutStream); for (int i=0; i < pagesToReplace.Count; i++) { finalDoc.Pages[pagesToReplace[i]] = replacementPages.Pages[i]; } finalDoc.Save(finalOutputStream);
What's missing here is ProcessImage(). ProcessImage will rasterize the page (and you wouldn't need to understand that the image might have been scaled to be on the PDF) or extract the image (and track the transformation matrix on the image), and go through the steps listed above. This is non-trivial, but it's doable.
I think you might want to make your clients aware that any of the libraries you mentioned is not completely free:
Given all of the above I assume I can drop freeware requirement.
Docotic.Pdf can reduce size of compressed and uncompressed PDFs to different degrees without introducing any destructive changes.
Gains depend on the size and structure of a PDF: For small files or files that are mostly scanned images the reduction might not be that great, so you should try the library with your files and see for yourself.
If you are most concerned about size and there are many images in your files and you are fine with loosing some of the quality of those images then you can easily recompress existing images using Docotic.Pdf.
Here is the code that makes all images bilevel and compressed with fax compression:
static void RecompressExistingImages(string fileName, string outputName) { using (PdfDocument doc = new PdfDocument(fileName)) { foreach (PdfImage image in doc.Images) image.RecompressWithGroup4Fax(); doc.Save(outputName); } }
There are also RecompressWithFlate
, RecompressWithGroup3Fax
and RecompressWithJpeg
methods.
The library will convert color images to bilevel ones if needed. You can specify deflate compression level, JPEG quality etc.
Docotic.Pdf can also resize big images (and recompress them at the same time) in PDF. This might be useful if images in a document are actually bigger then needed or if quality of images is not that important.
Below is a code that scales all images that have width or height greater or equal to 256. Scaled images are then encoded using JPEG compression.
public static void RecompressToJpeg(string path, string outputPath) { using (PdfDocument doc = new PdfDocument(path)) { foreach (PdfImage image in doc.Images) { // image that is used as mask or image with attached mask are // not good candidates for recompression if (!image.IsMask && image.Mask == null && (image.Width >= 256 || image.Height >= 256)) image.Scale(0.5, PdfImageCompression.Jpeg, 65); } doc.Save(outputPath); } }
Images can be resized to specified width and height using one of the ResizeTo
methods. Please note that ResizeTo
method won't try to preserve aspect ratio of images. You should calculate proper width and height yourself.
Disclaimer: I work for Bit Miracle.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With