iTextsharp - PDF file size after inserting image - c#

I'm currently converting some legacy code to create PDF files using iTextSharp. We're creating a largish PDF file that contains a number of images, which I'm inserting like so:
Document doc = new Document(PageSize.A4, 50, 50, 25, 25);
PdfWriter writer = PdfWriter.GetInstance(doc, myStream);
writer.SetFullCompression();
doc.Open();
Image frontCover = iTextSharp.text.Image.GetInstance(#"C:\MyImage.png");
//Scale down from a 96 dpi image to standard itextsharp 72 dpi
frontCover.ScalePercent(75f);
frontCover.SetAbsolutePosition(0, 0);
doc.Add(frontCover);
doc.Close();
Inserting an image (20.8 KB png file) seems to increase the PDF file size by nearly 100 KB.
Is there a way of compressing the image before entry (bearing in mind that this needs to be of reasonable print quality), or of further compressing the entire PDF? Am I even performing any compression in the above example?

The answer appears to have been that you need to set an appropriate version of the PDF spec to target and then set the compression as follows:
PdfWriter writer = PdfWriter.GetInstance(doc, ms);
PdfContentByte contentPlacer;
writer.SetPdfVersion(PdfWriter.PDF_VERSION_1_5);
writer.CompressionLevel = PdfStream.BEST_COMPRESSION;
This has brought my file size down considerably. I also found that PNG's were giving me the best results as regards to final size of document.

I did some experiments this morning. My test image was 800x600 with a file size of 100.69K when saved as a PNG. I inserted this into a PDF (using iTextSharp and the usual GetInstance() method) and the file size increased from 301.71K to 402.63K. I then re-saved my test image as a raw bitmap with file size of 1,440,054. I inserted this into the PDF and the file size went DOWN to 389.81K. Interesting!
I did some research on the web for a possible explanation, and, based on what I found, it looks like iTextSharp does not compress images, but rather it compresses everything with some generic compression. So in other words, the BMP is not actually converted to another file type, it's just compressed very much like you would by ZIPping it. Whatever they're doing, it must be good, for it compressed better than the image with PNG compression. I assume iTextSharp woudld try to compress the PNG but would compress at 0% since it already is compressed. (This is inconsistent with the original author's observations, though... Paddy said his PDF size increased much more than the size of the PNG... not sure what to make of that. I can only go on my own experiments).
Conclusions:
1) I don't need to add some fancy library to my project to convert my (eventual dynamically-created) image to PNG; it actually does better to leave it totally uncompressed and let iTextSharp do all the compression work.
2) I also read stuff on the web about iTextSharp saving images at a certain DPI. I did NOT see this problem... I used ScalePercent() method to scale the bitmap to 1% and the file size was the same and there was no "loss" in the bitmap pixels in the bitmap... this confirms that iTextSharp is doing a simple, nice, generic lossless compression.

It seems that PDF requires the png to be transcoded to something else, jpeg, most probably.
see here: http://forums.adobe.com/message/2952201
The only thing I can think of is to convert png to smallest jpeg first, including scaling down 75%, then importing that file without scaling.

use:
var image = iTextSharp.text.Image.GetInstance(srcImage, ImageFormat.Jpeg);
image.ScaleToFit(document.PageSize.Width, document.PageSize.Height);
//image.ScalePercent(75f);
image.SetAbsolutePosition(0, 0);
document.Add(image);
document.NewPage();

Related

Image Quality Setting Not working in PNG and BMP Format Output

I'm using the following code to save image in different formats
public void saveJpeg(string path, Bitmap img, long quality)
{
System.Drawing.Imaging.EncoderParameter qualityParam = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
System.Drawing.Imaging.ImageCodecInfo Codec = this.getEncoderInfo(imgformat);
if (Codec == null)
return;
System.Drawing.Imaging.EncoderParameters encoderParams = new System.Drawing.Imaging.EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
img.Save(path + ext, Codec, encoderParams);
}
The quality setting works fine in case of JPEG Images.But when i set the quality to 20 and 100 for .bmp and .png formats i get files with the same size as output.
What is going wrong here?
Please advice.
"What is going wrong here?"
Nothing is going wrong here. The quality setting applies only to the JPEG encoder. PNG and BMP are both lossless, meaning that there's no quality/space trade-off to be made. You will always get exactly the same pixels out from those formats as went in.
Unfortunately, .NET does not offer much in the way of compression options for those formats, in any of its image-handling APIs. BMP does support a "run-length encoding" format, but to my knowledge there's no .NET API that will actually generate it. Likewise PNG, which actually has a lot more options that can be selected to tailor the compression used to the nature of the input image and the amount of time one wants to spend compressing the file.
But even if you had access to those options, they wouldn't affect the quality of the image. Just the final compressed size of the file (e.g. for PNG using the right compression algorithm and/or spending more time compressing the file will result in a smaller file, but still a file that is exactly the same as the image you started with).

PDFSharp compress filesize in c#

In my App i generate an PDF-File with PDFSharp.Xamarin which I got from this site:
https://github.com/roceh/PdfSharp.Xamarin
Everything is working fine.
In my PDF-Document I have many Images, which are compressed.
But the file size of my PDF-Document is too large.
Is there a possibility to compress my PDF-Document before saving it?
How can I work with the PdfSharp.SharpZipLib.Zip Namespace to deflate the file size?
UPDATE:
Here is my Code:
document = new PdfDocument();
document.Info.Title = nameDok.Replace(" ", "");
document.Info.Author = "---";
document.Info.CreationDate = DateTime.Now;
document.Info.Subject = nameDok.Replace(" ", "");
//That is how i add Images:
XImage image = XImage.FromStream(lstr);
gfx.DrawImage(image, 465, YPrev - 2, newimagewf, newimagehf);
document.CustomValues.CompressionMode = PdfCustomValueCompressionMode.Compressed;
document.Options.FlateEncodeMode = PdfFlateEncodeMode.BestCompression;
document.Save(speicherPfad);
Thanks for everyone.
I only know the original PDFsharp, not the Xamarin port: images are deflated automatically using SharpZipLib.
Make sure to use appropriate source images (e.g. JPEG or PNG, depending on the image).
On the project start page they write:
"Currently all images created via XGraphics are converted to jpegs with 70% quality."
This could mean that images are re-compressed, maybe leading to larger files than before.
Take one JPEG file, convert it to PDF, and check the size of the image (in bytes) in the PDF file.

Set image resolution

I have array of image bytes and I would like to set resolution. Original image can be JPEG, PNG, BMP. Output - PNG. I am using ImageMagic to convert image and do some manipulations.
using (var image = this.Convert(originalImage, height, width))
using (var stream = new MemoryStream())
{
image.Quality = 90;
image.Write(stream, MagickFormat.Png);
return stream.GetBuffer();
}
I tryed to modify image.GetExifProfile, but has no success (at least for PNG images).
I can't use any comandline tool (like ImageMagic or ExifTool) here.
There are 3 exiff tags I need to modify
XResolution
YResolution
ResolutionUnit
I can successfully achieve this with bitmap, but it also resource overhead (need to create MemoryStream ...).
I have found some Pdf specification, but it will consume time to make it all work.
Does any can point me to right direction?
Thanks.

.net compressing pdf generated with crystal reports

As of now, we are generating PDFs programmatically using crystal reports and saving it to database. The PDF document has barcode image in it. Each file is of size 120-150 KB.
Everything is running fine but lately we are facing problem with huge growth in database size and storage requirements. This is due to 100 - 1000 records being generated each day.
Is there any way to compress the PDF files and then store it. Any API/tools available that perform these without creating issue to the barcode.Can we gain much reduction in size after compression?
Or any alternative way of storing the data will be good?
Any suggestions on this would be highly appreciated.
Thanks,
Sveerap
Unfortunately, you won't gain much by compressing a PDF as it is already compressed.
Many compressed PDF files can be compressed further.
Size of a PDF file can usually be decreased by:
removing unused objects (if any)
removing extra whitespace characters from the file (not from the visual content)
using object streams (a PDF 1.5 feature)
I do not know how well Crystal Report compresses PDFs but you might want to try Docotic.Pdf library and the following code and see if your files can be compressed better.
public static void CompressExistingDocument(string original, string output)
{
using (PdfDocument pdf = new PdfDocument(original))
{
pdf.SaveOptions.Compression = PdfCompression.Flate;
pdf.SaveOptions.UseObjectStreams = true;
pdf.SaveOptions.RemoveUnusedObjects = true;
pdf.SaveOptions.WriteWithoutFormatting = true;
pdf.Save(output);
}
FileInfo originalFileInfo = new FileInfo(original);
FileInfo compressedFileInfo = new FileInfo(output);
MessageBox.Show(
String.Format("Original file size: {0} bytes;\r\nCompressed file size: {1} bytes",
originalFileInfo.Length, compressedFileInfo.Length));
System.Diagnostics.Process.Start(output);
}
Disclaimer: I work for the vendor of the library.

iTextSharp jbig2 encoder

string imgfile = #"C:\users\me\desktop\test.jpg";
Bitmap bmp = new Bitmap(imgfile);
Bitmap bw = ConvertTo1Bpp(bmp); //make b+w
Document doc =
new Document(new iTextSharp.text.Rectangle(bmp.Width, bmp.Height));
PdfWriter.GetInstance(doc,
new System.IO.FileStream(
#"C:\users\me\desktop\test.pdf",
System.IO.FileMode.Create,
System.IO.FileAccess.ReadWrite));
iTextSharp.text.ImgJBIG2 i =
((iTextSharp.text.ImgJBIG2)iTextSharp.text.ImgJBIG2.GetInstance(
bmp, System.Drawing.Imaging.ImageFormat.Bmp));
doc.Open();
doc.Add(i);
doc.Close();
I cant find any good documentation for this with iTextSharp. What I am trying to do is take a Jpeg file and convert it into a pdf embedded as a black and white JBig2 image. The error I get is an InvalidCastException between "iTextSharp.text.ImageRaw" and "iTextSharp.text.ImageJBig2"... is there an alternative to what I have above?
EDIT
ImgJBig2 just represents an image already encoded in JBig2 I believe now. What I am looking for is something that will take a Bitmap and encode it into a BW JBig2 Bitmap that I can put into a Pdf.
As far as I can tell there's not a lot of options for encoding JBig2 and no native free ones.
Windows Imaging SDK ($2500+)
JBIG2 Compression Codec SDK for .NET ($1,800)
jbig2enc (free but c code only)
The last creates a CLI program that you might be able to P/Invoke into or at worst script against so I think that's your best option if you don't want to pay. Does JBIG2 offer such greater compression over other formats?

Categories

Resources