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

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.

Related

Exporting WPF Canvas to PDF

I've been attempting to find an easy solution to exporting a Canvas in my WPF Application to a PDF Document.
So far, the best solution has been to use the PrintDialog and set it up to automatically use the Microsoft Print the PDF 'printer'. The only problem I have had with this is that although the PrintDialog is skipped, there is a FileDialog to choose where the file should be saved.
Sadly, this is a deal-breaker because I would like to run this over a large number of canvases with automatically generated PDF names (well, programitically provided anyway).
Other solutions I have looked at include:
Using PrintDocument, but from my experimentation I would have to manually iterate through all my Canveses children and manually invoke the correct Draw method (of which a lot of my custom elements with transformation would be rather time consuming to do)
Exporting as a PNG image and then embedding that in a PDF. Although this works, TextBlocks within my canvas are no longer text. So this isn't an ideal situation.
Using the 3rd party library PDFSharp has the same downfall as the PrintDocument. A lot of custom logic for each element.
With PDFSharp. I did find a method fir generating the XGraphics from a Canvas but no way of then consuming that object to make a PDF Page
So does anybody know how I can skip or automate the PDF PrintDialog, or consume PDFSharp XGraphics to make
A page. Or any other ideas for directions to take this besides writing a whole library to convert each of my Canvas elements to PDF elements.
If you look at the output port of a recent windows installation of Microsoft Print To PDF
You may note it is set to PORTPROMP: and that is exactly what causes the request for a filename.
You might note lower down, I have several ports set to a filename, and the fourth one down is called "My Print to PDF"
So very last century methodology; when I print with a duplicate printer but give it a different name I can use different page ratios etc., without altering the built in standard one. The output for a file will naturally be built:-
A) Exactly in one repeatable location, that I can file monitor and rename it, based on the source calling the print sequence, such that if it is my current default printer I can right click files to print to a known \folder\file.pdf
B) The same port can be used via certain /pt (printto) command combinations to output, not just to that default port location, but to a given folder\name such as
"%ProgramFiles%\Windows NT\Accessories\WORDPAD.EXE" /pt listIN.doc "My Print to PDF" "My Print to PDF" "listOUT.pdf"
Other drivers usually charge for the convenience of WPF programmable renaming, but I will leave you that PrintVisual challenge for another of your three wishes.
MS suggest XPS is best But then they would be promoting it as a PDF competitor.
It does not need to be Doc[X]2PDF it could be [O]XPS2PDF or aPNG2PDF or many pages TIFF2PDF etc. etc. Any of those are Native to Win 10 also other 3rd party apps such as [Free]Office with a PrintTo verb will do XLS[X]2PDF. Imagination becomes pagination.
I had a great success in generating PDFs using PDFSharp in combination with SkiaSharp (for more advanced graphics).
Let me begin from the very end:
you save the PdfDocument object in the following way:
PdfDocument yourDocument = ...;
string filename = #"your\file\path\document.pdf"
yourDocument.Save(filename);
creating the PdfDocument with a page can be achieved the following way (adjust the parameters to fit your needs):
PdfDocument yourDocument = new PdfDocument();
yourDocument.PageLayout = PdfPageLayout.SinglePage;
yourDocument.Info.Title = "Your document title";
PdfPage yourPage = yourDocument.AddPage();
yourDocument.Orientation = PageOrientation.Landscape;
yourDocument.Size = PageSize.A4;
the PdfPage object's content (as an example I'm putting a string and an image) is filled in the following way:
using (XGraphics gfx = XGraphics.FromPdfPage(yourPage))
{
XFont yourFont = new XFont("Helvetica", 20, XFontStyle.Bold);
gfx.DrawString(
"Your string in the page",
yourFont,
XBrushes.Black,
new XRect(0, XUnit.FromMillimeter(10), page.Width, yourFont.GetHeight()),
XStringFormats.Center);
using (Stream s = new FileStream(#"path\to\your\image.png", FileMode.Open))
{
XImage image = XImage.FromStream(s);
var imageRect = new XRect()
{
Location = new XPoint() { X = XUnit.FromMillimeter(42), Y = XUnit.FromMillimeter(42) },
Size = new XSize() { Width = XUnit.FromMillimeter(42), Height = XUnit.FromMillimeter(42.0 * image.PixelHeight / image.PixelWidth) }
};
gfx.DrawImage(image, imageRect);
}
}
Of course, the font objects can be created as static members of your class.
And this is, in short to answer your question, how you consume the XGraphics object to create a PDF page.
Let me know if you need more assistance.

IMagickImage.Crop() causes image to be blurry

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.

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.

Resize page with ABCPdf before rendering (huge images in the pdf)

I have a problem with ABCPdf, when I try to convert a pdf files into seperate image files as fallbacks for old browsers.
I have some working code that perfectly renders the page and resizes the rendering into the wanted size. Now my problem occurs when the pdf page is huge w7681px x h10978px. It nearly kills my development machine and the deployment machine cannot even chew the file.
I normally just render the page 1-to-1 as the pdf page and then uses other algorithms to resize this image. This is not efficient since ABCPdf takes alot of power to output this image.
I have the following code:
private byte[] GeneratePng(Doc pdfDoc, int dpi)
{
var useDpi = dpi;
pdfDoc.Rendering.DotsPerInch = useDpi;
pdfDoc.Rendering.SaveQuality = 100;
pdfDoc.Rect.String = pdfDoc.CropBox.String;
pdfDoc.Rendering.ResizeImages = true;
int attemptCount = 0;
for (;;)
{
try
{
return pdfDoc.Rendering.GetData("defineFileTypeDummyString.png");
}
catch
{
if (++attemptCount == 3) throw;
}
}
}
I have tried the following solutions:
Resizing the page
pdfDoc.SetInfo(pdfDoc.Page, "/MediaBox:Rect", "0 0 200 300");
Resizing the page and outputting it. Which doesn't seem to make any changes at all.
Resizing the images before rendering it:
foreach (IndirectObject io in pdfDoc.ObjectSoup) {
if (io is PixMap) {
PixMap pm = (PixMap)io;
pm.Realize(); // eliminate indexed color images
pm.Resize(pm.Width / 4, pm.Height / 4);
}
}
Didn't do anything either and still resulted in a long load time.
Running the reduzed size operation before rendering:
using (ReduceSizeOperation op = new ReduceSizeOperation(pdfDoc))
op.Compact(true);
Didn't do anything either. Just went directly to rendering and took a long time.
Can anyone help me here? Maybe point me to some ABCPdf resizing algorithm or something.
Ok so I talked to the customer support at ABCPdf and they gave me the following.
doc1.Read(originalPDF);
// Specify size of output page. (This example scales the page, maintaining the aspect ratio,
// but you could set the MediaBox Height and Width to any desired value.)
doc2.MediaBox.Height = doc1.MediaBox.Height / 8;
doc2.MediaBox.Width = doc1.MediaBox.Width / 8;
doc2.Rect.SetRect(doc2.MediaBox);
doc2.Page = doc2.AddPage();
// Create the output image
doc2.AddImageDoc(doc1, 1, null);
doc2.Rendering.Save(savePath);
Which is supposed to be used with single page PDFs, so if you have a pdf full of large pictures, then you should chop it up. Which you can do following my other Q/A: Chop PDFs into single pages
The rendering algorithm they use in the above code is auto detected by ABCPdf and you cannot control it yourself (and they told me that I didn't want to). So I put my faith in their code. At least I did a test and the quality looks quite similar to a InterpolationMode.HighQualityBicubic and only differed when zoomed. So I wouldn't be too concerned with it either.
At last the above code gave me a speed boost compared to rendering and then resizing of about 10x faster. So it is really worth something if you do this operation a lot.

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

Categories

Resources