Anybody know how to get all of these in a C# app that leads the user to a print dialogue screen?
What I mean is this:
In the gui the user selects a document, right clicks on the doc, chooses Print. Instead of immediately printing out the doc, the print dialogue comes up.
Anybody know the syntax for all of this? I tried using all of the interops for the MS Office apps and trying the printdialogue method...but no such luck.
Can anybody provide me with some code? I've seriously been at this for HOURS and can't come up with a thing.
Maybe see this previous Q&A:
send-document-to-printer-with-c#
Or, for a WPF app that prints a FlowDocument :
private void DoThePrint(System.Windows.Documents.FlowDocument document)
{
// Clone the source document's content into a new FlowDocument.
// This is because the pagination for the printer needs to be
// done differently than the pagination for the displayed page.
// We print the copy, rather that the original FlowDocument.
System.IO.MemoryStream s = new System.IO.MemoryStream();
TextRange source = new TextRange(document.ContentStart, document.ContentEnd);
source.Save(s, DataFormats.Xaml);
FlowDocument copy = new FlowDocument();
TextRange dest = new TextRange(copy.ContentStart, copy.ContentEnd);
dest.Load(s, DataFormats.Xaml);
// Create a XpsDocumentWriter object, implicitly opening a Windows common print dialog,
// and allowing the user to select a printer.
// get information about the dimensions of the seleted printer+media.
System.Printing.PrintDocumentImageableArea ia = null;
System.Windows.Xps.XpsDocumentWriter docWriter = System.Printing.PrintQueue.CreateXpsDocumentWriter(ref ia);
if (docWriter != null && ia != null)
{
DocumentPaginator paginator = ((IDocumentPaginatorSource)copy).DocumentPaginator;
// Change the PageSize and PagePadding for the document to match the CanvasSize for the printer device.
paginator.PageSize = new Size(ia.MediaSizeWidth, ia.MediaSizeHeight);
Thickness t = new Thickness(72); // copy.PagePadding;
copy.PagePadding = new Thickness(
Math.Max(ia.OriginWidth, t.Left),
Math.Max(ia.OriginHeight, t.Top),
Math.Max(ia.MediaSizeWidth - (ia.OriginWidth + ia.ExtentWidth), t.Right),
Math.Max(ia.MediaSizeHeight - (ia.OriginHeight + ia.ExtentHeight), t.Bottom));
copy.ColumnWidth = double.PositiveInfinity;
//copy.PageWidth = 528; // allow the page to be the natural with of the output device
// Send content to the printer.
docWriter.Write(paginator);
}
}
Related
i have a netcore 3 app to read and split a PDF containing paychecks of some companies which i am working for.
This app ran pretty well since last builds... my the way, the PDF reader started to fail to parse the contents of any PDF.
PDF is built only with Italian words, no special chars. Few tables and a single logo. I'm not able to attach it due to privacy.
public PaycheckSplitter Read()
{
using (var reader = new PdfReader(new MemoryStream(this._stream)))
{
var doc = new PdfDocument(reader);
this.Paycheck = new PaychecksCollection();
for (int i = 1; i <= doc.GetNumberOfPages(); i++)
{
PdfPage page = doc.GetPage(i);
string text = PdfTextExtractor.GetTextFromPage(page, new LocationTextExtractionStrategy());
if (text.Contains(Consts.BpEnd)) break;
// trying to find something by regex... btw text contains only a sequence of \n\n\n\n...
string cf = Consts.CodFiscale.Match(text).Value;
this.Paychecks.Add(new Paycheck(cf), i);
}
doc.Close();
}
return this;
}
Anything i can do?
As far as i can see... the only and best way to have something to read a PDF text for free is iText7...
I was about to use iTextSharp to fill out PDF form, when I've found out, that there is new kid on the block: iText 7.0. Naturally I gave it a try and... it didn't go well, unfortunately. Here is an issue. I have editable PDF form, that's need to be filled out programmatically. I used following code to acomplished that:
string srcPdfFormPath = #"<Path to source pdf form>";
string destPdfFormPath = #"<Path to destination pdf form>";
using (PdfDocument pdfDocument = new PdfDocument(reader, new PdfWriter(destPdfFormPath)))
{
PdfAcroForm form = PdfAcroForm.GetAcroForm(pdfDocument, true);
var fieldName = "FullName";
var pdfField = form.GetField(fieldName);
if (pdfField != null)
pdfField.SetValue("John Doe", null);
else
Debug.WriteLine($"Cannot find following field {fieldName } on pdf form.");
pdfDocument.Close();
}
Though desired field has been populated, the form not only has been flattened(which, AFAIK is not expected behavior), but also when populated pdf would be opened in Acrobat reader it would produce following message:
"This document enabled extended features in Adobe Acrobat Reader DC.
The document has been changed since it was created and use of extended
features is no longer available. Please contact the author for the
original version of this document."
Those results are not what we have been shooting for. So in order to preserve the document editability and get rid of pesky message I've decided to open PDF form in "Append Mode". Here is a code I've used:
string srcPdfFormPath = #"<Path to source pdf form>";
string destPdfFormPath = #"<Path to destination pdf form>";
using (PdfDocument pdfDocument = new PdfDocument(reader, new PdfWriter(destPdfFormPath)
, new StampingProperties().UseAppendMode()))
{
PdfAcroForm form = PdfAcroForm.GetAcroForm(pdfDocument, true);
var fieldName = "FullName";
var pdfField = form.GetField(fieldName);
if (pdfField != null)
pdfField.SetValue("John Doe", null);
else
Debug.WriteLine($"Cannot find following field {fieldName } on pdf form.");
pdfDocument.Close();
}
And, alas, this attempt also failed on its mission. Though pesky message would no longer be seen, the form itself would not be populated, which is not acceptable. And for the life of me I could not figure out why those behaviors are persist and go together, like horse and carriage!
So question is: what am I missing here? Is there way to make it work using new version of iText?
I am generating a PDF from an HTML string.
When this string is really long, I would like to create a new page, split the text (without breaking the html) and so on.
Here is my code :
// instantiate Pdf object
Aspose.Pdf.Generator.Pdf pdf = new Aspose.Pdf.Generator.Pdf();
// specify the Character encoding for for HTML file
pdf.HtmlInfo.CharSet = "UTF-8";
pdf.HtmlInfo.Margin.Left = 10;
pdf.HtmlInfo.Margin.Right = 10;
pdf.HtmlInfo.PageHeight = 1050;
pdf.HtmlInfo.PageWidth = 730;
pdf.HtmlInfo.ShowUnknownHtmlTagsAsText = true;
pdf.HtmlInfo.TryEnlargePredefinedTableColumnWidthsToAvoidWordBreaking = true;
pdf.HtmlInfo.CharsetApplyingLevelOfForce = Aspose.Pdf.Generator.HtmlInfo.CharsetApplyingForceLevel.UseWhenImpossibleDetectFromContent;
// bind the source HTML
pdf.BindHTML("MyVeryVeryLongHTML");
MemoryStream stream = new MemoryStream();
pdf.Save(stream);
byte[] pdfBytes = stream.ToArray();
This code works for the HTML, but the overflow is not handled. The text continue after the page. Is it possible to set a max "height" of the page to not cross, and if it does, it recreates a new page ?
Hope it makes sense !
Thanks a lot
You can set the Page height by selecting type of PDF page you require like A1, A2, etc . Afterwords , your problem of page height will automatically be taken care by the Aspose. For more refer the link..
Aspose PDF Page Height
Update
update pdf.HtmlInfo to pdf.PageSetup (or pdf.PageInfo) and add bottom margin also.
I have an existing PDF document named as aa.pdf. This PDF document has 3 pages. I'd like to add a PDF form field (or a text) at the page bottom of the first page in aa.pdf using iTextSharp.
Meanwhile, I also hope that the PDF form field added (or the text added) can link into another page of aa.pdf. For example, after I click the PDF form field (or the text) located in the first page of aa.pdf,this PDF document skips into the second page.
How can I realize the aboved functionalities using iTextSharp?
Thanks.
To create links within a PDF you use a PdfAction which can be set on a Chunk which can optionally be added to a Paragraph. There are several different types of actions that you can choose from, the two that you are probably interested in are the NEXTPAGE action and/or the GotoLocalPage action. The first item does what it says and goes to the next page. This one is nice because you don't have to worry about figuring out what page number you are on. The second item allows you to specify the specific page number to go to. In its simplest form you can do:
Chunk ch = new Chunk("Go to next page").SetAction(new PdfAction(PdfAction.NEXTPAGE));
This creates a Chunk that you can add in whatever way you want. When working with an existing PDF there's several different ways to add text to a page. One way it to use a ColumnText object which has a method called SetSimpleColumn that allows you to define a simple rectangle that you can add elements to.
Lastly, PDF readers don't automatically treat links differently within a PDF except to give a different cursor when hovering. More specifically, unlike a webpage where hyperlinks are turned a different color, PDFs don't change the color of links unless you tell them to, so this should be kept in mind when creating them. Also, when modifying a PDF you generally never want to overwrite the existing PDF during the process because that would be writing to something that your reading from. Sometimes it works, more often then not it breaks, sometimes subtly. Instead, write to a second file and when you are completely done, erase the first file and rename the second file.
The code below is a full working C# 2010 WinForms app targeting iTextSharp 5.1.2.0. The first part of the code creates a sample PDF called "aa.pdf" on the desktop. If you already have that file you can comment this section out but its in here so others can reproduce this example. The second part creates a new file called "bb.pdf" based on "aa.pdf". It adds two text links to the bottom of the first page. The first link advances the PDF to just the next page while the second link advances the PDF to a specific page number. See the comments in the code for specific implementation details.
using System;
using System.IO;
using System.Windows.Forms;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
//Files that we'll be working with
string inputFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "aa.pdf");
string outputFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "bb.pdf");
//Create a standard PDF to test with, nothing special here
using (FileStream fs = new FileStream(inputFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (Document doc = new Document(PageSize.LETTER)) {
using (PdfWriter writer = PdfWriter.GetInstance(doc, fs)) {
doc.Open();
//Create 10 pages with labels on each page
for (int i = 1; i <= 10; i++) {
doc.NewPage();
doc.Add(new Paragraph(String.Format("This is page {0}", i)));
}
doc.Close();
}
}
}
//For the OP, this is where you would start
//Declare some variables to be used later
ColumnText ct;
Chunk c;
//Bind a reader to the input file
PdfReader reader = new PdfReader(inputFile);
//PDFs don't automatically make hyperlinks a special color so we're specifically creating a blue font to use here
iTextSharp.text.Font BlueFont = FontFactory.GetFont("Arial", 12, iTextSharp.text.Font.NORMAL, iTextSharp.text.BaseColor.BLUE);
//Create our new file
using (FileStream fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
//Bind a stamper to our reader and output file
using (PdfStamper stamper = new PdfStamper(reader, fs)) {
Chunk ch = new Chunk("Go to next page").SetAction(new PdfAction(PdfAction.NEXTPAGE));
//Get the "over" content for page 1
PdfContentByte cb = stamper.GetOverContent(1);
//This example adds a link that goes to the next page
//Create a ColumnText object
ct = new ColumnText(cb);
//Set the rectangle to write to
ct.SetSimpleColumn(0, 0, 200, 20);
//Add some text and make it blue so that it looks like a hyperlink
c = new Chunk("Go to next page", BlueFont);
//Set the action to go to the next page
c.SetAction(new PdfAction(PdfAction.NEXTPAGE));
//Add the chunk to the ColumnText
ct.AddElement(c);
//Tell the system to process the above commands
ct.Go();
//This example add a link that goes to a specific page number
//Create a ColumnText object
ct = new ColumnText(cb);
//Set the rectangle to write to
ct.SetSimpleColumn(200, 0, 400, 20);
//Add some text and make it blue so that it looks like a hyperlink
c = new Chunk("Go to page 3", BlueFont);
//Set the action to go to a specific page number. This option is a little more complex, you also have to specify how you want to "fit" the document
c.SetAction(PdfAction.GotoLocalPage(3, new PdfDestination(PdfDestination.FIT), stamper.Writer));
//Add the chunk to the ColumnText
ct.AddElement(c);
//Tell the system to process the above commands
ct.Go();
}
}
this.Close();
}
}
}
I'm having a somewhat odd print quality problem in my C# application. I have an XPS file (it's basically just a 1 page image, that was originally a scanned black and white image) that I'm trying to print to an IBM InfoPrint Mainframe driver via a C# application. I've printed to numerous other print drivers and never had a problem, but this driver gives me terrible quality with the AFP file it creates. If I open the same file in the Microsoft XPS viewer application and print to the same driver, the quality looks fine.
Trying to work though the problem I've tried 3 or 4 different approaches to printing in the C# app. The original code did something like this (trimmed for brevity):
System.Windows.Xps.XpsDocumentWriter writer = PrintQueue.CreateXpsDocumentWriter(mPrintQueue);
mCollator = writer.CreateVisualsCollator();
mCollator.BeginBatchWrite();
ContainerVisual v = getContainerVisual(xpsFilePath);
//tried all sorts of different options on the print ticket, no effect
mCollator.Write(v,mDefaultTicket);
That code (which I've truncated) certainly could have had some weird issues in it, so I tried something much simpler:
LocalPrintServer localPrintServer = new LocalPrintServer();
PrintQueue defaultPrintQueue = LocalPrintServer.GetDefaultPrintQueue();
PrintSystemJobInfo xpsPrintJob = defaultPrintQueue.AddJob("title", xpsDocPath, false);
Same results.
I even tried using the WCF print dialog, same poor quality (http://msdn.microsoft.com/en-us/library/ms742418.aspx).
One area I haven't tried yet, is using the old-school underlying print API's, but I'm not sure why that would behave differently. One other option I have, is my original document is a PDF, and I have a good 3rd party library that can make me an EMF file instead. However, every time I try to stream that EMF file to my printer, I get garbled text.
Any ideas on why this quality is lost, how to fix, or how to stream an EMF file to a print driver, would be much appreciated!
UPDATE:
One other note. This nice sample app: http://wrb.home.xs4all.nl/Articles_2010/Article_XPSViewer_01.htm experiences the same quality loss. I've also now performed tests where I open the PDF directly and render the Bitmaps to a Print Document, same fuzziness of the resulting images. If I open the PDFs in Acrobat and print they look fine.
So to close this issue, it seems that the IBM Infoprint driver (at least the way it's being used here) has quite different quality depending on how you print in C#.
In this question I was using:
System.Windows.Documents.Serialization.Write(Visual, PrintTicket);
I completely changed my approach, removing XPS entirely, and obtained an emf (windows metafile) rendition of my document, then sent that emf file to the Windows printer using the windows print event handler:
using (PrintDocument pd = new PrintDocument())
{
pd.DocumentName = this.mJobName;
pd.PrinterSettings.PrinterName = this.mPrinterName;
pd.PrintController = new StandardPrintController();
pd.PrintPage += new PrintPageEventHandler(DoPrintPage);
pd.Print();
}
(I've obviously omitted a lot of code here, but you can find examples of how to use this approach relatively easily)
In my testing, most print drivers were equally happy with either printing approach, but the IBM Infoprint driver was EXTREMELY sensitive to the quality. One possible explanation is that the Infoprint printer was required to be configured with a weird fixed DPI and it may be doing a relatively poor job converting.
EDIT: More detailed sample code was requested, so here ya go. Note that getting an EMF file is a pre-req for this approach. In this case I'm using ABC PDF, which lets you generate an EMF file from your PDF with a relatively simple call.
class AbcPrintEmf
{
private Doc mDoc;
private string mJobName;
private string mPrinterName;
private string mTempFilePath;
private bool mRenderTextAsPolygon;
public AbcPdfPrinterApproach(Doc printMe, string jobName, string printerName, bool debug, string tempFilePath, bool renderTextAsPolygon)
{
mDoc = printMe;
mDoc.PageNumber = 1;
mJobName = jobName;
mPrinterName = printerName;
mRenderTextAsPolygon = renderTextAsPolygon;
if (debug)
mTempFilePath = tempFilePath;
}
public void print()
{
using (PrintDocument pd = new PrintDocument())
{
pd.DocumentName = this.mJobName;
pd.PrinterSettings.PrinterName = this.mPrinterName;
pd.PrintController = new StandardPrintController();
pd.PrintPage += new PrintPageEventHandler(DoPrintPage);
pd.Print();
}
}
private void DoPrintPage(object sender, PrintPageEventArgs e)
{
using (Graphics g = e.Graphics)
{
if (mDoc.PageCount == 0) return;
if (mDoc.Page == 0) return;
XRect cropBox = mDoc.CropBox;
double srcWidth = (cropBox.Width / 72) * 100;
double srcHeight = (cropBox.Height / 72) * 100;
double pageWidth = e.PageBounds.Width;
double pageHeight = e.PageBounds.Height;
double marginX = e.PageSettings.HardMarginX;
double marginY = e.PageSettings.HardMarginY;
double dstWidth = pageWidth - (marginX * 2);
double dstHeight = pageHeight - (marginY * 2);
// if source bigger than destination then scale
if ((srcWidth > dstWidth) || (srcHeight > dstHeight))
{
double sx = dstWidth / srcWidth;
double sy = dstHeight / srcHeight;
double s = Math.Min(sx, sy);
srcWidth *= s;
srcHeight *= s;
}
// now center
double x = (pageWidth - srcWidth) / 2;
double y = (pageHeight - srcHeight) / 2;
// save state
RectangleF theRect = new RectangleF((float)x, (float)y, (float)srcWidth, (float)srcHeight);
int theRez = e.PageSettings.PrinterResolution.X;
// draw content
mDoc.Rect.SetRect(cropBox);
mDoc.Rendering.DotsPerInch = theRez;
mDoc.Rendering.ColorSpace = "RGB";
mDoc.Rendering.BitsPerChannel = 8;
if (mRenderTextAsPolygon)
{
//i.e. render text as polygon (non default)
mDoc.SetInfo(0, "RenderTextAsText", "0");
}
byte[] theData = mDoc.Rendering.GetData(".emf");
if (mTempFilePath != null)
{
File.WriteAllBytes(mTempFilePath + #"\" + mDoc.PageNumber + ".emf", theData);
}
using (MemoryStream theStream = new MemoryStream(theData))
{
using (Metafile theEMF = new Metafile(theStream))
{
g.DrawImage(theEMF, theRect);
}
}
e.HasMorePages = mDoc.PageNumber < mDoc.PageCount;
if (!e.HasMorePages) return;
//increment to next page, corrupted PDF's have occasionally failed to increment
//which would otherwise put us in a spooling infinite loop, which is bad, so this check avoids it
int oldPageNumber = mDoc.PageNumber;
++mDoc.PageNumber;
int newPageNumber = mDoc.PageNumber;
if ((oldPageNumber + 1) != newPageNumber)
{
throw new Exception("PDF cannot be printed as it is corrupt, pageNumbers will not increment properly.");
}
}
}
}