IMagickImage.Crop() causes image to be blurry - c#

I have the following C# code:
MagickImage pdfPage = MyCodeToGetPage();
String barcodePng = "tmp.png"
MagickGeometry barcodeArea = new MagickGeometry(350, 153, 208, 36);
IMagickImage barcodeImg = pdfPage.Clone();
barcodeImg.Crop(barcodeArea);
barcodeImg.Write(barcodePng);
It creates a tmp.png file that is displayed in the lower barcode below:
The problem is that tmp.png file is fuzzy and my barcode detection logic will not detect the barcode. You can see the upper image is clear and the lines are not merged.
The title says that Crop() is causing the problem, but it could also be the Write().
How do I crop the barcode out of the pdf without making tmp.png fuzzy?
This was not a problem when the source document is a .tif. More precisely, if I convert the .pdf to a .tif and then crop it the .png is clear enough that the barcode can be detected. I want to eliminate the intermediate .tif as it used a clumsy printer driver to convert.

As you requested in your answer below:
Adding density on the read was what I had first suggested in my comment to your question. It increases the size of the rasterized version of the input. It is like scanning at a higher density. What I typically do in ImageMagick is to read the pdf at 4x nominal density, which is 4x72=288, then resize down by 1/4=25%. This will generally give a much better quality to your your result. So the command that I use in command line ImageMagick would be:
convert -density 288 input.pdf -resize 25% result.suffix
I would also add that Ghostscript cannot handle CMYK PDFs that have transparency. So one must change the colorspace to sRGB before reading the pdf file. So in this case, it would be:
convert -density 288 -colorspace sRGB input.pdf -resize 25% result.suffix
Sorry, I do not code C++, so perhaps I misunderstand, but I do not understand why increasing the density before reading in a TIFF would make any difference.

This URL had the answer:
http://www.jiajianhudong.com/question/642668.html
To fix it I changed my code to this:
MagickImage pdfPage = MyCodeToGetPage();
String barcodePng = "tmp.png"
MagickGeometry barcodeArea = new MagickGeometry(350, 153, 208, 36);
IMagickImage barcodeImg = pdfPage.Clone();
barcodeImg.ColorType = ColorType.Bilevel;
barcodeImg.Depth = 1;
barcodeImg.Alpha(AlphaOption.Off);
barcodeImg.Crop(barcodeArea);
barcodeImg.Write(barcodePng);
And the most critical part of fixing was to change:
using (MagickImageCollection tiffPageCollection = new MagickImageCollection())
{
tiffPageCollection.Read(tifName);
to
var settings = new MagickReadSettings { Density = new Density(200) };
using (MagickImageCollection tiffPageCollection = new MagickImageCollection())
{
tiffPageCollection.Read(tifName, settings);
If someone wants to copy my answer and add a clear reason why adding Density on the read fixes the problem I will give them the answer.

Related

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.

ImageMagick.NET PDF to JPG conversion - insufficient memory

I'm using ImageMagick.NET to convert PDFs to JPGs. Here's my code:
MagickReadSettings settings = new MagickReadSettings();
settings.Density = new MagickGeometry(300, 300);
using (MagickImageCollection images = new MagickImageCollection())
{
images.Read(pdfFilePathString, settings);
MagickImage image = images.AppendVertically();
image.Format = MagickFormat.Jpg;
//image.Quality = 70;
//if (image.Width > 1024)
//{
// int heightRatio = Convert.ToInt32(Math.Round((decimal)(image.Height / (image.Width / 1024)), 0));
// image.Resize(1024, heightRatio);
//}
image.Write(tempFilePathString);
image.Dispose();
}
The problem is, I keep getting insufficient memory exceptions, which occur on the image.Write(). It is obviously due to file size, as a small pdf will work, but not a multi page pdf. The particular file I'm trying to get it to run through is a 12 page text pdf. I can get it to work if I sent the density low, for example (100, 100) works, but the quality is terrible.
The commented out lines were some other solutions I was trying to implement, but it keeps running for a long time (several minutes) without end (at least as far as my patience is concerned) with those enabled. One of those is to reduce quality, and the other to reduce image size. The pdfs always come out very large, much larger than necessary.
If I could reduce image size and/or quality before the file is written, that would be great. Or at least I need to be able to be able to produce an image in a quality that is decent enough without having memory issues. It doesn't seem like it should be having memory issues here as its not as if the file size is ginormous, although it probably still is bigger than desired for an image. The 12 page pdf when I could get it to render came in at around 6-7 megs.
I'm using 32-bit ImageMagick - I wonder if 64-bit would solve the issue, but there have been issues trying to get that version to run on a local environment - which is another issue entirely.
Anybody have any thoughts on anything else I can try?
Thanks

PDFs are rendering fine, but printing with jagged edges - PDFSharp

I have a complex application producing PDFs via PDFSharp. I'm running into a problem which is proving very difficult to solve.
When rendering images (text is an image as well) rotated, the PDF produced looks fine, but when printed it has jagged edges and generally messed up -- see attachment.
Here is the relevant code:
// determine how big the image should be
double destinationWidth = Math.Round(pageWidth * imageInfo.WidthFactor);
double destinationHeight = destinationWidth;
// rescale the image to needed size
imageInfo.Image = ImageHelper.ResizeImage(imageInfo.Image, (int)(destinationWidth * 3), (int)(destinationHeight * 3));
// get image
XImage xImage = XImage.FromGdiPlusImage(imageInfo.Image);
// define fill area
XRect destination = new XRect();
destination.X = imageInfo.XFactor * pageWidth;
destination.Y = imageInfo.YFactor * pageHeight;
destination.Width = destinationWidth; //pageWidth * imageInfo.WidthFactor;
destination.Height = destinationHeight; //destination.Width; // shouldn't this use the page height and height factor?
// save state before rotate
XGraphicsState previousState = gfx.Save();
// rotate canvas
gfx.RotateAtTransform(imageInfo.RotationAngle, new XPoint(destination.X + destination.Width / 2, destination.Y + destination.Height / 2));
// render image
gfx.DrawImage(xImage, destination);
// undo transforms
gfx.Restore(previousState);
Please, please, help. It prints fine from Chrome's PDF viewer, for what it's worth.
I attempted converting the images to SVG (pixel by pixel) and rendering, which worked fine, but performance made it not feasible. I need to find a more elegant solution.
Thanks so much!
PDF:
https://dl.dropbox.com/u/49564994/PDF.pdf
Print-out:
https://dl.dropbox.com/u/49564994/Print.jpg
Almost two years ago I had a similar problem. A generated PDF was all garbled up when I printed it. It was just a report, did not contain any images, but several sentences or words were missing.
I used a Word template, replaced some placeholders to generate a report and then saved the Word document to PDF using the Office Save As PDF add-in.
There is a difference when you print the PDF with a PCL printer driver or a PostScript one. Check out if you get any difference between those. Might be a font problem. Check that the font encoding is set correctly.
At the time I did not find a solution. Finally resorted to converting the PDF to an image and sending that to the printer. Worked fine.
This should also be possible using PDFSharp by invoking GhostScript to create images from PDF pages.

iTextsharp - PDF file size after inserting image

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();

.NET Saving jpeg with the same quality as it was loaded

I have a cannon digital camera and I set it to take pictures with superfine quality and it outputs a .jpg file 3 mega in size.
If I load it like this in ASP.NET(this is useful to change it's dpi resolution or crop it or whaterver)
imgPicture = Image.FromFile(Config.WorkDirectory + this.TempPhotoName);
bmpPicture = new Bitmap(imgPicture);
and then I save it again like this:
bmpModified.Save(Config.WorkDirectory + this.TempPhotoName,System.Drawing.Imaging.ImageFormat.Jpeg);
it outputs a jpg that is only 700KB or so in size. There is a loss of quality.
I also tried saving it like this:
bmpPicture.Save(Config.WorkDirectory + this.TempPhotoName, codecJpeg, encparams);
where codecJpeg is
ImageCodecInfo codecJpeg = this.getEncoderInfo("image/jpeg");
private ImageCodecInfo getEncoderInfo(string mimeType)
{
// Get image codecs for all image formats
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
// Find the correct image codec
for (int i = 0; i < codecs.Length; i++)
if (codecs[i].MimeType == mimeType)
return codecs[i];
return null;
}
and encparams:
EncoderParameters encparams = new EncoderParameters(1);
encparams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 97L);
This way the size(and I suspect also the quality) is maintained but I am inputing the quality by hand.
I want to ask:
Is there a way to save the image with the same quality as it was loaded without hardcoding the quality value?
Thank you in advance
So it sounds like you know how to set the quality, you really just need to know how to fetch the quality from the original image?
I suspect that Image.PropertyItems is your friend, if the quality is in the metadata to start with. (I don't know if there's even a standard scale for quality within JPEG encoders.)
EDIT: I've just checked, and a jpeg I downloaded didn't have any tags for quality.
One option might be to work out how big the file should end up to have roughly the same quality, and then save it several times, doing a binary search to work out the most appropriate quality. Icky, but it might just work.
I have a sneaking suspicion that there isn't a way to just preserve the original quality setting, although I don't have very good grounds for that suspicion...
Read here how to save image without re-encoding image: How-to: Re-encode a JPEG Image with Metadata.
However, if you do cropping or another image manipulation it impossible to do it without quality loss (well technically it is possible to do loss-less crop, if you work with boundaries that multiply of 16, but AFAIK it is cannot be done with libraries available in .net).
You must use the additional parameters which tell GDI+ to detect the color scheme.
For instance:
using (var img = Image.FromStream(fileupload.InputStream, true,true))
{
img.Save(fileOnDisk, ImageFormat.Jpeg);
}
using (var img = Image.FromFile("yourimage", true))
{
img.Save(fileOnDisk, ImageFormat.Jpeg);
}

Categories

Resources