Is it possible to convert an HTML string to a PDF file in a UWP app?
I've seen lots of different ways it can be done in regular .NET apps (there seem to be plenty of third party libraries), but I've yet to see a way it can be done in a Universal/UWP app. Does anyone know how it can be done?
Perhaps there is some way to hook into the "Microsoft Print to PDF" option, if there is no pure code solution?
Or is there a roundabout way of doing it, maybe like somehow using Javascript and https://github.com/MrRio/jsPDF inside a C# UWP app? I'm not sure, clutching at straws...
EDIT
I have marked the solution provided by Grace Feng - MSFT as correct for proving that it IS possible to convert HTML to PDF, through the use of the Microsoft Print to PDF option in the print dialog. Thank you
Perhaps there is some way to hook into the "Microsoft Print to PDF" option, if there is no pure code solution?
Yes, but using this way, you will need to firstly show your HTML string in controls like RichEditBox or TextBlock, only UIElement can be printable content.
You can also create PDF file by yourself, here is basic syntax used in PDF:
You can use BT and ET to create paragraph:
Here is sample in C#:
StringBuilder sb = new StringBuilder();
sb.AppendLine("BT"); // BT = begin text object, with text-units the same as userspace-units
sb.AppendLine("/F0 40 Tf"); // Tf = start using the named font "F0" with size "40"
sb.AppendLine("40 TL"); // TL = set line height to "40"
sb.AppendLine("230.0 400.0 Td"); // Td = position text point at coordinates "230.0", "400.0"
sb.AppendLine("(Hello World)'");
sb.AppendLine("/F2 20 Tf");
sb.AppendLine("20 TL");
sb.AppendLine("0.0 0.2 1.0 rg"); // rg = set fill color to RGB("0.0", "0.2", "1.0")
sb.AppendLine("(This is StackOverflow)'");
sb.AppendLine("ET");
Then you can create a PDF file and save this into this file. But since you want to convert the HTML to PDF, it could be a hard work and I think you don't want to do this.
Or is there a roundabout way of doing it, maybe like somehow using Javascript and https://github.com/MrRio/jsPDF inside a C# UWP app? I'm not sure, clutching at straws...
To be honestly, using Libs or Web service to convert HTML to PDF is also a method, there are many and I just searched for them, but I can't find any free to be used in WinRT. So I think the most practicable method here is the first one, hooking into Microsoft Print to PDF. To do this, you can check the official Printing sample.
Update:
Used #Jerry Nixon - MSFT's code in How do I print WebView content in a Windows Store App?, this is a great sample. I just added some code for add pages for printing, in the NavigationCompleted event of WebView:
private async void webView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
MyWebViewRectangle.Fill = await GetWebViewBrush(webView);
MyPrintPages.ItemsSource = await GetWebPages(webView, new Windows.Foundation.Size(842, 595));
}
Then in the printDoc.AddPages += PrintDic_AddPages; event (printDoc is instance of PrintDocument):
private void PrintDic_AddPages(object sender, AddPagesEventArgs e)
{
foreach (var item in MyPrintPages.Items)
{
var rect = item as Rectangle;
printDoc.AddPage(rect);
}
printDoc.AddPagesComplete();
}
For other code you can refer to the official printing sample.
Related
A want to write text to a Win2d CanvasSvg document however I am unable to find any example at all on how to to this. I have already drawn some basic shapes but I'm stuck on text. The Class is described at:
https://microsoft.github.io/Win2D/WinUI3/html/T_Microsoft_Graphics_Canvas_Svg_CanvasSvgTextElement.htm
I'm not sure if the Win2d CanvasSvg even supports normal Svg text as an attempt to load a simple text file in svg (which worked ok with Chrome) failed to show anything when loaded (using the Win2D sample on the GitHub site & swapping the file for loading).
A google search for CanvasSvgTextElement gives only 7 results! As you can in the bit of code below, I am out of my depth!
string myTest = "<text x=\"100\" y=\"100\" text=\"Hello World\" />";
CanvasSvgTextElement testElement = new CanvasSvgTextElement( //something goes here - how to find?// );
svgDocument.Root.CreateAndAppendTextChildElement( //what to put here ?//);
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.
I am using iTextSharp for reading and managing PDF documents. Things such as stamping overlays for the background or logos and backers. The PDF's are statement files, so I cannot give an example. I am wondering how to view the settings of the PDF to see if the PDF file is Simplex or Duplex, and that sort of information. Any help or suggestions would be appreciated. At the moment I test for certain criteria of second page, and this is a poor and bad way to do this. Thanks in advance, and happy coding!
The duplex mode is stored in the document's /ViewerPreferences dictionary under the /Duplex key. It supports three values, /DuplexFlipLongEdge, /DuplexFlipShortEdge, and /Simplex. You can use the code below to inspect this:
//Assume false by default since this was introduced in PDF 1.7
Boolean isDuplex = false;
//Bind a reader to our file
using (var r = new PdfReader(testFile)) {
//Get the view preferences
var prefs = r.Catalog.GetAsDict(PdfName.VIEWERPREFERENCES);
//Make sure we found something
if (prefs != null) {
//Get the duplex key
var duplex = prefs.Get(PdfName.DUPLEX);
//Make sure we got something and it is one of the duplex modes
isDuplex = (duplex != null && (duplex.Equals(PdfName.DUPLEXFLIPLONGEDGE) || duplex.Equals(PdfName.DUPLEXFLIPSHORTEDGE)));
}
}
I know its 2 years later but I just spent hours searching, found this... but eventually found...
I create a button that runs this script (that pops up the printer dialogue with duplex pre selected if available... note that selecting another printer erases this pre selection.. also change "Long" for "Short" if you flip that way... q8)
var pp = this.getPrintParams();
pp.DuplexType = pp.constants.duplexTypes.DuplexFlipLongEdge;
this.print(pp);
I have a C# application that When the user clicks Print the application creates a PDF in memorystream using ITextSharp. I need to print this PDF automatically to a specific printer and tray.
I have searched for this but all i can find is using javascript, but it doesn't print to a specific tray.
Does anyone have an examples of doing this?
Thank you.
You can change printer tray with this code.
string _paperSource = "TRAY 2"; // Printer Tray
string _paperName = "8x17"; // Printer paper name
//Tested code comment. The commented code was the one I tested, but when
//I was writing the post I realized that could be done with less code.
//PaperSize pSize = new PaperSize() //Tested code :)
//PaperSource pSource = new PaperSource(); //Tested code :)
/// Find selected paperSource and paperName.
foreach (PaperSource _pSource in printDoc.PrinterSettings.PaperSources)
if (_pSource.SourceName.ToUpper() == _paperSource.ToUpper())
{
printDoc.DefaultPageSettings.PaperSource = _pSource;
//pSource = _pSource; //Tested code :)
break;
}
foreach (PaperSize _pSize in printDoc.PrinterSettings.PaperSizes)
if (_pSize.PaperName.ToUpper() == _paperName.ToUpper())
{
printDoc.DefaultPageSettings.PaperSize = _pSize;
//pSize = _pSize; //Tested code :)
break;
}
//printDoc.DefaultPageSettings.PaperSize = pSize; //Tested code :)
//printDoc.DefaultPageSettings.PaperSource = pSource; //Tested code :)
in the past I spent a lot of time searching the web for solutions to print pdf files to specific printer trays.
My requirement was: collect several pdf files from server directory and send each file to a different printer tray in a loop.
So I have tested a lot of 3rd party tools (trials) and best practices found in web.
Generally all theese tools can be divide into two classifications: a) send pdf files to printer in a direct way (silent in UI) or b) open pdf files in UI using a built-in pdf previewer working with .Net-PrintDocument.
The only solution that fix my requirement was PDFPrint from veryPdf (drawback: it´s not priceless, but my company bought it). All the other tools and solutions didn´t work reliable, that means: calling their print-routines with parameter e.g. id = 258 (defines tray 2; getting from installed printer) but printing the pdf file in tray 3 or pdf was opened in print previewer (UI) with lost images or totally blank content and so on..
Hope that helps a little bit.
There is a tool called pdfprint:
http://www.verypdf.com/pdfprint/index.html
And here they discuss some solutions:
http://social.msdn.microsoft.com/forums/en-US/csharpgeneral/thread/da99765f-2706-4bb6-aa0e-b90730294cb4
If I have an existing PDF that has a graphic on it, and I simple want a user to be able to click a point on the pdf, and drop a letter at the point the click, like A... B... etc. I'm thinking that ITextSharp could handle something like this, but frankly, I'm not sure how to accomplish it. Can you offer some guidance?
Here's a C# example using the commercial Quick PDF Library.
using System;
using System.IO;
using System.Drawing;
using System.Windows.Forms;
using QuickPDFAX0714;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private string LicenseKey = " your key here ";
private string OriginalFileName = "D:\\QuickPDFLibrary\\hello1.pdf";
private string NewFileName = "D:\\QuickPDFLibrary\\hello2.pdf";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
ShowPDF(OriginalFileName);
}
private void ShowPDF(string fileName)
{
PDFLibrary qp = new PDFLibrary();
qp.UnlockKey(LicenseKey);
qp.LoadFromFile(fileName);
// Fit width of PDF to width of picture box
int dpi = Convert.ToInt32((pictureBox1.Width * 72) / qp.PageWidth());
byte[] bmpData = (byte[])qp.RenderPageToVariant(dpi, 1, 0);
MemoryStream ms = new MemoryStream(bmpData);
Bitmap bmp = new Bitmap(ms);
pictureBox1.Image = bmp;
ms.Dispose();
}
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
PDFLibrary qp = new PDFLibrary();
qp.UnlockKey(LicenseKey);
qp.LoadFromFile(OriginalFileName);
// Calculate co-ordinates, width of PDF fitted to width of PictureBox
double xpos = ((double)e.X / (double)pictureBox1.Width) * qp.PageWidth();
double ypos = qp.PageHeight() - ((double)e.Y / (double)pictureBox1.Width) * qp.PageWidth();
qp.SetTextSize(24);
qp.SetTextColor(1, 0, 0);
qp.DrawText(xpos, ypos, "A");
qp.SaveToFile(NewFileName);
ShowPDF(NewFileName);
}
}
}
Wouldn't you probably want to load the PDF, turn it into something that you can render in your app (ie, some editable document object), make changes, and then write it back out to PDF?
Granted, that's probably a lot of work for what you are trying to accomplish, but most PDF tools I am aware of don't actually edit the .PDF directly.
iTextSharp may have the ability to load .PDF files into some sort of document tree that you can then manipulate. I would start by seeing if it does such a thing, and then try to change some of the nodes, or perhaps add nodes corresponding to your annotations.
It may not be possible to see your changes reflected in real time, so you probably will want to "fake" the changes by layering them over your render of the .PDF file as simple lable objects. That's probably the easiest way to start.
No, itextsharp can not do that, since itextsharp can manipulate pdf-files, but there's no way of rendering a pdf in itextsharp.
You can certainly use ITextSharp to add content to an existing PDF. There are samples on the web that can show you how. (It's been a while since I've done this, and my needs were to add watermark images to existing PDFs.)
ITextSharp doesn't read PDFs well, so you'll probably want to find something else to display the PDF. You may need to overlay a transparent window over whatever displays the PDF so you can catch the click, but that all depends upon the viewer you find.
Bearing in mind that I have only ever used PDFNet SDK for PDF manipulation tasks, I believe everything you are asking about can be achieved with that library, although you may have to deal with some complexity with coordinate conversion from the click to the location in the document, and again to building the matrix that locates the text where you need it on the write.
They do provide a simple WinForms sample PDF viewer application that might serve as a good starting point for your experimentation.
I haven't needed to go this deep into editing, myself. The starting points for documentation are in the FAQ (How to add a watermark to a page) and the knowledge base. The API documentation is also quite extensive and publicly available on the website.