logo
Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

2 Pages12>
Options
Go to last post Go to first unread
Paul Rayman  
#1 Posted : Tuesday, January 5, 2016 6:13:21 AM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 1,011

Thanks: 5 times
Was thanked: 121 time(s) in 118 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#post431

Question:
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

Paul Rayman  
#2 Posted : Sunday, January 17, 2016 3:16:13 AM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 1,011

Thanks: 5 times
Was thanked: 121 time(s) in 118 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

Guest  
#3 Posted : Thursday, January 21, 2016 4:18:02 PM(UTC)
Guest

Rank: Guest

Groups: Guests
Joined: 1/5/2016(UTC)
Posts: 158

Was thanked: 4 time(s) in 4 post(s)
Where does the GetRenderSize() method come from ?
Paul Rayman  
#4 Posted : Thursday, January 21, 2016 5:57:38 PM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 1,011

Thanks: 5 times
Was thanked: 121 time(s) in 118 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

Guest  
#5 Posted : Friday, January 22, 2016 10:47:13 AM(UTC)
Guest

Rank: Guest

Groups: Guests
Joined: 1/5/2016(UTC)
Posts: 158

Was thanked: 4 time(s) in 4 post(s)
Thanks!
Guest  
#6 Posted : Friday, January 22, 2016 3:09:18 PM(UTC)
Guest

Rank: Guest

Groups: Guests
Joined: 1/5/2016(UTC)
Posts: 158

Was thanked: 4 time(s) in 4 post(s)
Line 66 a bug, maybe, should default to false?
Paul Rayman  
#7 Posted : Friday, January 22, 2016 10:23:05 PM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 1,011

Thanks: 5 times
Was thanked: 121 time(s) in 118 post(s)
Yes, you're right. But it should be e.PageSettings.Landscape = pd.PrinterSettings.DefaultPageSettings.Landscape;
Guest  
#8 Posted : Monday, January 25, 2016 9:01:09 AM(UTC)
Guest

Rank: Guest

Groups: Guests
Joined: 1/5/2016(UTC)
Posts: 158

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.
Paul Rayman  
#9 Posted : Monday, January 25, 2016 5:28:37 PM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 1,011

Thanks: 5 times
Was thanked: 121 time(s) in 118 post(s)
Thanks
Guest  
#10 Posted : Friday, March 18, 2016 5:10:26 PM(UTC)
Guest

Rank: Guest

Groups: Guests
Joined: 1/5/2016(UTC)
Posts: 158

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!
Paul Rayman  
#11 Posted : Sunday, March 20, 2016 11:09:29 AM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 1,011

Thanks: 5 times
Was thanked: 121 time(s) in 118 post(s)
Originally Posted by: Guest Go to Quoted Post

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

nuander  
#12 Posted : Monday, March 21, 2016 12:59:21 PM(UTC)
nuander

Rank: Newbie

Groups: Registered
Joined: 3/18/2016(UTC)
Posts: 1
United States
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



Paul Rayman  
#13 Posted : Wednesday, March 23, 2016 6:22:07 AM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 1,011

Thanks: 5 times
Was thanked: 121 time(s) in 118 post(s)
I guess the PDF format does not provide such opportunities.
Paul Rayman  
#14 Posted : Sunday, July 17, 2016 9:33:26 AM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 1,011

Thanks: 5 times
Was thanked: 121 time(s) in 118 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

Guest  
#15 Posted : Wednesday, November 9, 2016 4:29:34 AM(UTC)
Guest

Rank: Guest

Groups: Guests
Joined: 1/5/2016(UTC)
Posts: 158

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?
Paul Rayman  
#16 Posted : Thursday, November 10, 2016 6:51:30 PM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 1,011

Thanks: 5 times
Was thanked: 121 time(s) in 118 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.
Guest  
#17 Posted : Sunday, October 22, 2017 7:08:34 PM(UTC)
Guest

Rank: Guest

Groups: Guests
Joined: 1/5/2016(UTC)
Posts: 158

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?
Paul Rayman  
#18 Posted : Monday, October 23, 2017 6:11:12 AM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 1,011

Thanks: 5 times
Was thanked: 121 time(s) in 118 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.
Guest  
#19 Posted : Monday, October 23, 2017 5:45:26 PM(UTC)
Guest

Rank: Guest

Groups: Guests
Joined: 1/5/2016(UTC)
Posts: 158

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

Paul Rayman  
#20 Posted : Tuesday, October 24, 2017 10:27:30 AM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 1,011

Thanks: 5 times
Was thanked: 121 time(s) in 118 post(s)
Originally Posted by: Guest Go to Quoted Post
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
Users browsing this topic
2 Pages12>
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.