Rank: Administration
Groups: Administrators
Joined: 1/5/2016(UTC) Posts: 936
Thanks: 3 times Was thanked: 112 time(s) in 109 post(s)
|
PLEASE NOTE: The printing subsystem has been optimized. Please find details here: http://forum.patagames.com/posts/m431-Print-functionality-in-Pdfium--NET-SDK#post431Question:I'm currently working on a C# application that uses PDF render features for my employer. Pdfium.Net does an excellent job of displaying the PDFs but the app must be able to print them as well. Anybody know a way to print the current PDF document through this API? I've checked in the likely places and I haven't found anything. Answer:To print a PDF document, you can use standard .Net Framework, like shown in the code below: Code:
public void PrintDocument(PdfDocument pdf)
{
//.Net Framework class from System.Drawing.Printing namespace
PrintDocument pd = new PrintDocument();
int pageForPrint = 0;
pd.PrintPage += (s, e) =>
{
//set paper size and orientation
e.PageSettings.PaperSize.RawKind = (int)PaperKind.A4;
e.PageSettings.Landscape = false;
//Calculate actual size in pixels that depends on current printer's DPI
int actualWidth = (int)(e.Graphics.DpiX * 210 / 25.4f); //210x297 - size of paper (A4) in millimeters
int actualHeight = (int)(e.Graphics.DpiY * 297 / 25.4f); //25.4f - millimeters per inch
//Render to PdfBitmap using page's Render method with FPDF_PRINTING flag
pdf.Pages[pageForPrint].Render
(e.Graphics,
0,
0,
actualWidth,
actualHeight,
Patagames.Pdf.Enums.PageRotate.Normal, Patagames.Pdf.Enums.RenderFlags.FPDF_PRINTING);
//Print next page
if (pageForPrint < pdf.Pages.Count - 1)
{
pageForPrint++;
e.HasMorePages = true;
}
};
//start printing routine
pd.Print();
}
Edited by user Sunday, July 17, 2016 9:50:17 AM(UTC)
| Reason: Not specified
|
|
|
|
Rank: Administration
Groups: Administrators
Joined: 1/5/2016(UTC) Posts: 936
Thanks: 3 times Was thanked: 112 time(s) in 109 post(s)
|
The code above illustrates the basic idea. Usually in real applications it a bit more complicated. Here's an code for printing, which is used in PdfViewer User Control (printing from tool strip). Code:
private PageRotate PageRotation(PdfPage pdfPage)
{
int rot = pdfPage.Rotation - pdfPage.OriginalRotation;
if (rot < 0)
rot = 4 + rot;
return (PageRotate)rot;
}
private SizeF GetRenderSize(Size pageSize, Size fitSize)
{
double w, h;
w = pageSize.Width;
h = pageSize.Height;
double nh = fitSize.Height;
double nw = w * nh / h;
if (nw > fitSize.Width)
{
nw = fitSize.Width;
nh = h * nw / w;
}
return new SizeF((float)nw, (float)nh);
}
/// <summary>
/// Occurs when the Print button is clicked
/// </summary>
/// <param name="item">The item that has been clicked</param>
protected virtual void OnPrintClick(ToolStripButton item)
{
//Set up PrintDocument object
PrintDocument pd = new PrintDocument();
pd.PrinterSettings.MinimumPage = 1;
pd.PrinterSettings.MaximumPage = PdfViewer.Document.Pages.Count;
pd.PrinterSettings.FromPage = pd.PrinterSettings.MinimumPage;
pd.PrinterSettings.ToPage = pd.PrinterSettings.MaximumPage;
int pageForPrint = 0;
pd.BeginPrint += (s, e) =>
{
//Calculate range of pages for print
switch(pd.PrinterSettings.PrintRange)
{
case PrintRange.Selection:
case PrintRange.CurrentPage: //Curent page
pd.PrinterSettings.FromPage = PdfViewer.Document.Pages.CurrentIndex+1;
pd.PrinterSettings.ToPage = PdfViewer.Document.Pages.CurrentIndex+1;
break;
case PrintRange.SomePages: //The range specified by the user
break;
default: //All pages
pd.PrinterSettings.FromPage = pd.PrinterSettings.MinimumPage;
pd.PrinterSettings.ToPage = pd.PrinterSettings.MaximumPage;
break;
}
pageForPrint = pd.PrinterSettings.FromPage-1;
};
pd.QueryPageSettings += (s, e) =>
{
//Set the paper orientation to Landscape if the page is rotated
e.PageSettings.Landscape = pd.PrinterSettings.DefaultPageSettings.Landscape;
if ((PdfViewer.Document.Pages[pageForPrint].Rotation == PageRotate.Rotate270
|| PdfViewer.Document.Pages[pageForPrint].Rotation == PageRotate.Rotate90
))
e.PageSettings.Landscape = true;
};
pd.PrintPage += (s, e) =>
{
//Calculate the size of the printable area in pixels
var fitSize = new Size(
(int)(e.Graphics.DpiX * e.PageSettings.PrintableArea.Width / 100),
(int)(e.Graphics.DpiY * e.PageSettings.PrintableArea.Height / 100)
);
//Get page's size
var pageSize = new Size(
(int)PdfViewer.Document.Pages[pageForPrint].Width / 72.0f * e.Graphics.DpiX,
(int)PdfViewer.Document.Pages[pageForPrint].Height / 72.0f * e.Graphics.DpiY);
//If page was rotated in original file, then we need to "rotate the paper in printer".
//For that just swap the width and height of the paper.
if (PdfViewer.Document.Pages[pageForPrint].OriginalRotation == PageRotate.Rotate270
|| PdfViewer.Document.Pages[pageForPrint].OriginalRotation == PageRotate.Rotate90)
fitSize = new Size(fitSize.Height, fitSize.Width);
//Calculate the page's size fitted to the paper's size.
var rSize = GetRenderSize(pageSize, fitSize);
using (PdfBitmap bmp = new PdfBitmap((int)rSize.Width, (int)rSize.Height, true))
{
//Render to PdfBitmap using page's Render method with FPDF_PRINTING flag.
PdfViewer.Document.Pages[pageForPrint].Render
(bmp,
0,
0,
(int)rSize.Width,
(int)rSize.Height,
PageRotate.Normal,
RenderFlags.FPDF_PRINTING | RenderFlags.FPDF_ANNOT);
//Rotates the PdfBitmap image depending on the orientation of the page
if (PageRotation(PdfViewer.Document.Pages[pageForPrint]) == PageRotate.Rotate270)
bmp.Image.RotateFlip(System.Drawing.RotateFlipType.Rotate270FlipNone);
else if (PageRotation(PdfViewer.Document.Pages[pageForPrint]) == PageRotate.Rotate180)
bmp.Image.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
else if (PageRotation(PdfViewer.Document.Pages[pageForPrint]) == PageRotate.Rotate90)
bmp.Image.RotateFlip(System.Drawing.RotateFlipType.Rotate90FlipNone);
//Set DPI of the image same as the printer's DPI
(bmp.Image as Bitmap).SetResolution(e.Graphics.DpiX, e.Graphics.DpiY);
//Draw rendered image to printer's graphics surface
e.Graphics.DrawImageUnscaled(bmp.Image, 0, 0);
}
//Print next page
if (pageForPrint < pd.PrinterSettings.ToPage-1)
{
pageForPrint++;
e.HasMorePages = true;
}
};
//Show standard print dilog
var dlg = new PrintDialog();
dlg.AllowCurrentPage = true;
dlg.AllowSomePages = true;
dlg.UseEXDialog = true;
dlg.Document = pd;
if(dlg.ShowDialog()== DialogResult.OK)
{
pd.Print();
}
}
Edited by user Tuesday, April 19, 2016 5:04:55 PM(UTC)
| Reason: Not specified
|
|
|
|
Rank: Guest
Groups: Guests
Joined: 1/5/2016(UTC) Posts: 153
Was thanked: 4 time(s) in 4 post(s)
|
Where does the GetRenderSize() method come from ?
|
|
|
|
Rank: Administration
Groups: Administrators
Joined: 1/5/2016(UTC) Posts: 936
Thanks: 3 times Was thanked: 112 time(s) in 109 post(s)
|
These methods can be found in source code: Code:
private PageRotate PageRotation(PdfPage pdfPage)
{
int rot = pdfPage.Rotation - pdfPage.OriginalRotation;
if (rot < 0)
rot = 4 + rot;
return (PageRotate)rot;
}
private SizeF GetRenderSize(Size pageSize, Size fitSize)
{
double w, h;
w = pageSize.Width;
h = pageSize.Height;
double nh = fitSize.Height;
double nw = w * nh / h;
if (nw > fitSize.Width)
{
nw = fitSize.Width;
nh = h * nw / w;
}
return new SizeF((float)nw, (float)nh);
}
Edited by user Wednesday, February 17, 2016 12:35:14 AM(UTC)
| Reason: Not specified
|
|
|
|
Rank: Guest
Groups: Guests
Joined: 1/5/2016(UTC) Posts: 153
Was thanked: 4 time(s) in 4 post(s)
|
|
|
|
|
Rank: Guest
Groups: Guests
Joined: 1/5/2016(UTC) Posts: 153
Was thanked: 4 time(s) in 4 post(s)
|
Line 66 a bug, maybe, should default to false?
|
|
|
|
Rank: Administration
Groups: Administrators
Joined: 1/5/2016(UTC) Posts: 936
Thanks: 3 times Was thanked: 112 time(s) in 109 post(s)
|
Yes, you're right. But it should be e.PageSettings.Landscape = pd.PrinterSettings.DefaultPageSettings.Landscape;
|
|
|
|
Rank: Guest
Groups: Guests
Joined: 1/5/2016(UTC) Posts: 153
Was thanked: 4 time(s) in 4 post(s)
|
Lines 15/16 in that sample with GetRenderSize() are also wrong/unnecessary--nw and nh always get overwritten.
|
|
|
|
Rank: Administration
Groups: Administrators
Joined: 1/5/2016(UTC) Posts: 936
Thanks: 3 times Was thanked: 112 time(s) in 109 post(s)
|
|
|
|
|
Rank: Guest
Groups: Guests
Joined: 1/5/2016(UTC) Posts: 153
Was thanked: 4 time(s) in 4 post(s)
|
I need a VB.Net version of this solution and there is a particular bit of this code that I don't know how to convert from c#.
specifically what does pd.PrintPage += (s, e) => {...} do and what would be the Vb.net equivalent. I notice that pd has not PrintPage method, it looks to me like you are adding an event listener? Can someone give me a quick VB.Net version of this?
Thanks for your help!
|
|
|
|
Rank: Administration
Groups: Administrators
Joined: 1/5/2016(UTC) Posts: 936
Thanks: 3 times Was thanked: 112 time(s) in 109 post(s)
|
Originally Posted by: Guest  specifically what does pd.PrintPage += (s, e) => {...} do and what would be the Vb.net equivalent.
I guess a VB.NET equivalent is a folowing: Code:
Dim pd as PrintDocument = New PrintDocument();
Dim pageForPrint as Integer = 0;
AddHandler pd.PrintPage, Sub(s, e)
'...
End Sub
'start printing routine
pd.Print();
Edited by user Sunday, March 20, 2016 11:14:09 AM(UTC)
| Reason: Not specified
|
|
|
|
Rank: Newbie
Groups: Registered
Joined: 3/18/2016(UTC) Posts: 1  Location: Houston Thanks: 1 times
|
Yes that did the trick thanks.
I'm trying to print using the code example at the top of this thread so that I don't have to implement the PDFViewer control. I don't want to display the PDF I just want to print it. After reviewing the code, testing it, and reviewing the SDK Reference, I have some questions about the page sizes and the Render method of the Page class.
There doesn't seem to be any property in the Page class indicating the Page Layout e.g. Portrait/Landscape. Which is odd because the PDF must contain that information on a page by page basis. The rotation property also does not indicate page layout. So I'm having to use some math to compare the printer paper size to the Page.Height and Page.Width. Now the reference says those are in Points (1/72 inch) so I can do the math. But it seems like it should easier.
Please advise. Thanks
|
|
|
|
Rank: Administration
Groups: Administrators
Joined: 1/5/2016(UTC) Posts: 936
Thanks: 3 times Was thanked: 112 time(s) in 109 post(s)
|
I guess the PDF format does not provide such opportunities.
|
|
|
|
Rank: Administration
Groups: Administrators
Joined: 1/5/2016(UTC) Posts: 936
Thanks: 3 times Was thanked: 112 time(s) in 109 post(s)
|
The printing subsystem has been optimized. Now it printing faster and consumes much less memory. To print the document to the default printer, you can write the following: Code:
var doc = PdfDocument.Load("c:\test.pdf");
var printDoc = new PdfPrintDocument(doc);
printDoc.Print();
The code above shows the standard printing dialog with printing progress. If you want to suppress it modify code like shown below: Code:
var doc = PdfDocument.Load("c:\test.pdf");
var printDoc = new PdfPrintDocument(doc);
PrintController printController = new StandardPrintController();
printDoc.PrintController = printController;
printDoc.Print();
Because the PdfPrintDocumentis derived from standard PrintDocument class you can use standard Microsoft Windows print dialog box ( PrinterDialog) that configures a PrintDocument according to user input and then prints a document. Please look at this code: Code:
public void OnPrintClick()
{
if (PdfViewer.Document.FormFill != null)
PdfViewer.Document.FormFill.ForceToKillFocus();
//create an instance of PrintDocument class
var printDoc = new PdfPrintDocument(PdfViewer.Document);
//Create a standard print dialog box
var dlg = new PrintDialog();
dlg.AllowCurrentPage = true;
dlg.AllowSomePages = true;
dlg.UseEXDialog = true;
//sets the PrintDocument used to obtain PrinterSettings.
dlg.Document = printDoc;
//show PrinterDialog and print pdf document
if (dlg.ShowDialog() == DialogResult.OK)
printDoc.Print();
}
Edited by user Sunday, July 17, 2016 9:47:33 AM(UTC)
| Reason: Not specified
|
|
|
|
Rank: Guest
Groups: Guests
Joined: 1/5/2016(UTC) Posts: 153
Was thanked: 4 time(s) in 4 post(s)
|
Is there any easy way to print four DIN A6 PDFs to one DIN A4 page using PDFIUM?
|
|
|
|
Rank: Administration
Groups: Administrators
Joined: 1/5/2016(UTC) Posts: 936
Thanks: 3 times Was thanked: 112 time(s) in 109 post(s)
|
Do you mean you need to print a four page on one sheet? The most pronters has this functionality in they settings which available through PrintDialog window. You can combine this option with the Collate option to achieve the desired result. Unfortunately there is no a simple way to do that if a printer's drivers does not support this feature. In this case you need manually render pages, combine and print them self as an image.
|
|
|
|
Rank: Guest
Groups: Guests
Joined: 1/5/2016(UTC) Posts: 153
Was thanked: 4 time(s) in 4 post(s)
|
Hi. I am using the following vb.net code Code:
Dim doc As PdfDocument = PdfDocument.Load(strPDF)
Dim printDoc As PdfPrintDocument = New PdfPrintDocument(doc)
printDoc.Print()
and line 2 gives me: Error BC30389 'PdfiumViewer.PdfPrintDocument' is not accessible in this context because it is 'Friend'. There is an Imports PDFiumViewer at the top of the module Where am I going wrong?
|
|
|
|
Rank: Administration
Groups: Administrators
Joined: 1/5/2016(UTC) Posts: 936
Thanks: 3 times Was thanked: 112 time(s) in 109 post(s)
|
WinForms, WPF, Console app? Looks like you did something wrong. But you have provided very little info about the usage, so it is really hard to make a specific statement. I have created an empty WPF app with your code and everything works fine.
|
|
|
|
Rank: Guest
Groups: Guests
Joined: 1/5/2016(UTC) Posts: 153
Was thanked: 4 time(s) in 4 post(s)
|
I have managed to solve the issue. Originally I had downloaded the NuGet package for PDFium viewer but not the full PDFium toolkit. I had a previous reference to PDFWriter.dll that also has a PDFPrintDocument object. Even qualifying the reference as PDFiumViewer.PDFPrintDocument didn't stop the 'Friend' error. After installing the full PDFium toolkit package and removing the PDFiumViewer qualification in line 2, I still got an error but now it was ambiguous name error saying that PdfDocument could be from PDFiumViewer, PDFWriter or Patagames.PDF.Net so I qualified the code as follows Code:
PdfCommon.Initialize("")
Dim doc As Patagames.Pdf.Net.PdfDocument = Patagames.Pdf.Net.PdfDocument.Load(strPDF)
Dim printDoc As New PdfPrintDocument(doc)
Dim PrintController As PrintController = New StandardPrintController()
printDoc.PrintController = PrintController
printDoc.Print()
And now it works. Does this mean that the viewer does not function as a stand-alone component without the full toolkit? Edited by moderator Monday, March 30, 2020 10:37:31 PM(UTC)
| Reason: Not specified
|
|
|
|
Rank: Administration
Groups: Administrators
Joined: 1/5/2016(UTC) Posts: 936
Thanks: 3 times Was thanked: 112 time(s) in 109 post(s)
|
Originally Posted by: Guest  Does this mean that the viewer does not function as a stand-alone component without the full toolkit? No, it does not. NuGet package contains all you need to develop using Pdfium.Net SDK
|
|
|
|
Forum Jump
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.
Important Information:
The Patagames Software Support Forum uses cookies. By continuing to browse this site, you are agreeing to our use of cookies.
More Details
Close