I'm making a simple program with .NET and iText7
Inserting a signature image in a PDF document is one of the functions under production.
It has been implemented until the image is inserted into the PDF and newly saved, but I don't know if the image goes behind the text.
The Canvas function seems to be possible, but no matter how many times I look at the example, I can't see any parameters related to the placement.
It would be nice to present a keyword that can implement the function.
The sample results are attached to help understanding. In the figure, the left is the capture of the PDF in which I inserted my signature using a word processor, and the right is the capture of the PDF generated through IText.
My iText version is .Net 7.2.1.
I attached the code below just in case it was necessary.
Thank you.
public void PDF_SIGN(FileInfo old_fi)
{
string currentPath = System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
String imageFile = currentPath + "\\sign.jpg";
ImageData data = ImageDataFactory.Create(imageFile);
string source = old_fi.FullName;
string sourceFileName = System.IO.Path.GetFileNameWithoutExtension(source);
string sourceFileExtenstion = System.IO.Path.GetExtension(source);
string dest = old_fi.DirectoryName + "\\" + sourceFileName + "(signed)" + sourceFileExtenstion;
PdfDocument pdfDoc = new PdfDocument(new PdfReader(source), new PdfWriter(dest));
Document document = new Document(pdfDoc);
iText.Layout.Element.Image image = new iText.Layout.Element.Image(data);
image.ScaleAbsolute(Xsize, Ysize);
image.SetFixedPosition(1, Xaxis, Yaxis);
document.Add(image);
document.Close();
pdfDoc.Close();
}
Sample Result (Left: Gaol, Right: Current result):
You can organize content you add using iText in the same pass before or behind each other simply by the order of adding, and layout elements may have background images or colors.
The previously existing content of the source document, consequentially, usually serves as a mere background of everything new. Except, that is, if you draw to a page in a content stream that precedes earlier content.
Unfortunately you cannot use the Document class for this as its renderer automatically works in the foreground. But you can use the Canvas class here; this class only works on a single object (e.g. a single page) but it can be initialized in a far more flexible way.
In your case, therefore, replace
Document document = new Document(pdfDoc);
iText.Layout.Element.Image image = new iText.Layout.Element.Image(data);
image.ScaleAbsolute(Xsize, Ysize);
image.SetFixedPosition(1, Xaxis, Yaxis);
document.Add(image);
document.Close();
by
iText.Layout.Element.Image image = new iText.Layout.Element.Image(data);
image.ScaleAbsolute(Xsize, Ysize);
image.SetFixedPosition(1, Xaxis, Yaxis);
PdfPage pdfPage = pdfDoc.GetFirstPage();
PdfCanvas pdfCanvas = new PdfCanvas(pdfPage.NewContentStreamBefore(), pdfPage.GetResources(), pdfDoc);
using (Canvas canvas = new Canvas(pdfCanvas, pdfPage.GetCropBox()))
{
canvas.Add(image);
}
and you should get the desired result.
(Actually I tested that using Java and ported it to C# in writing this answer. I hope it's ported all right.)
As an aside, if you only want to put an image on the page, you don't really need the Canvas, you can directly use one of the AddImage* methods of PdfCanvas. For multiple elements to be automatically arranged, though, using the Canvas is a good idea.
Also I said above that you cannot use Document here. Actually you can if you replace the document renderer that class uses. For the task at hand that would have been an overkill, though.
Related
I'm using MigraDoc to programatically generate a PDF file with text, images and tables.
I need to set Document Orientation (for all pages) in the document object to Landscape.
So I tried the following.
document.DefaultPageSetup.Orientation = Orientation.Landscape;
But I get the following debug assertion error.
---------------------------
Assertion Failed: Abort=Quit, Retry=Debug, Ignore=Continue
---------------------------
DefaultPageSetup must not be modified
If I click Ignore, it goes through and the Orientation is indeed Landscape.
However, I want to make sure I am doing this the right way.
So the question is, how do I set the document orientation for all pages in a Document using the MigraDoc library?
Here's the rest of the code (so it helps you get the context)
using System.Runtime.Remoting.Messaging;
using MigraDoc.DocumentObjectModel;
namespace MyNamespace.PdfReports
{
class Documents
{
public static Document CreateDocument()
{
// Create a new MigraDoc document
Document document = new Document();
document.Info.Title = "The Title";
document.Info.Subject = "The Subject";
document.Info.Author = "Shiva";
document.DefaultPageSetup.Orientation = Orientation.Landscape;
Many thanks!
-Shiva
UPDATE:
SOLUTION: Here's the working code, based on Thomas' answer below (for the benefit of others who maybe looking for this solution).
// Create a new MigraDoc document
Document document = new Document();
//...
//......
PageSetup pageSetup = document.DefaultPageSetup.Clone();
// set orientation
pageSetup.Orientation = Orientation.Landscape;
// ... set other page setting you want here...
Assign DefaultPageSetup.Clone() to the PageFormat of your section and modify that.
Then you modify a copy of the default settings and no assertion will fail.
With your approach, all documents would default to landscape - not just the document you set it for.
This answer applies to MigraDoc only as only MigraDoc uses DefaultPageSetup.
See this post in the PDFsharp forum where Clone() is used to create a copy of the DefaultPageSetup:
I am generating collections (Acrobat Portfolios) via iTextSharp. I would like to assign an existing custom navigator (custom layout) to the generated collection. I believe iTextSharp allows for the CUSTOM parameter to define a custom navigator, as in the last code line of this block:
Document document = new Document();
FileStream stream = new FileStream(portfolioPath, FileMode.Create);
PdfWriter writer = PdfWriter.GetInstance(document, stream);
document.Open();
document.Add(new Paragraph(" "));
PdfCollection collection = new PdfCollection(PdfCollection.CUSTOM);
//The integer 3 can also substitute for PdfCollection.CUSTOM
However, when the collection/portfolio is generated the CUSTOM parameter inserts the TILE layout within the generated collection. I want to have the CUSTOM parameter use a custom .nav navigator I developed to insert a custom layout.
I located this post on SO:
How to embed a .nav file into pdf portfolio?
which lead to:
Adobe® Supplement to the
ISO 32000
BaseVersion: 1.7
ExtensionLevel: 3e
Pages 34 - 37 of this document says it is possible to have the collection access the custom navigator by adjusting the Navigator entry in the collection dictionary and the navigator dictionary itself. Additionally, page 541 of the Second Edition of iText in Action implies this is possible (and it is my hope what is possible in iText is also possible in iTextSharp).
So is it possible -- using iTextSharp -- to have a generated collection/portfolio access and implement a custom layout/navigator? If so, how? Or is there another way to do this via C# and/or through some workaround? All help is greatly appreciated.
I found a different way to dictate the custom layout/navigator using iTextSharp. Instead of defining the custom layout during or after
PdfCollection collection = new PdfCollection(PdfCollection.CUSTOM);
I threw out the code listed in my question and used the iTextSharp stamper.
First, I created an empty portfolio file. Within this file I assigned the custom layout that I wanted to use. When opened the file displays the layout, but contains no attached files. This file will serve as a template and assign it's navigator to each newly created iTextSharp PDF using this code:
const string templatePath = #"C:\PortfolioTemplate\PortfolioTemplate.pdf"; //this file will contain the custom navigator/layout for the new pdf
const string portfolioPath = #"C:\OutputFile\NewPortfolio.pdf";
string[] packageitems = { file-to-add-to-collection };
PdfReader reader = new PdfReader(templatePath);
FileStream outputstream = new FileStream(portfolioPath, FileMode.Create);
PdfStamper stamp = new PdfStamper(reader, outputstream);
PdfFileSpecification fs = PdfFileSpecification.FileEmbedded(stamp.Writer, packageitems[0], packageitems[0], null);
stamp.AddFileAttachment(packageitems[0], fs);
stamp.Close();
I used the above proof of concept to loop through all the files in a directory folder and I have created large portfolios without issue that are styled using the custom navigator/layout I wanted.
After coming up with the idea of using a template to pass the navigator into a newly created portfolio, I used the code in the below link to guide me to the above conclusion:
http://itextsharp.10939.n7.nabble.com/Attach-file-td3812.html
I am looking for a way to merge the content of two pdf pages.
It could be a watermark, an image or whatever.
The scenario is as follows:
I have a Word-addin that allows the user to create different templates for different customers based on several template forms. For each new customer, the user can provide a new letter paper containing header image / logos and footer. This shall be applied anyhow at runtime. Could be an image that is loaded directly into the header of the template (then I would need to render pdf to image, for the letter paper will mostly be provided as pdf-file) or when exporting the document (merging letter paper as background).
But the template shall not be accessible by the user, so this must be done programmatically.
So far, I tried Pdfsharp library, which does not support neither the version of my provided backpapers, nor the version of my documents created in Word 2007.
iTextSharp seemed very promising, but I could not manage to merge the contents so far.
I also tried pdftk.exe, but even when i ran it manually from command line, I got the error: "Done. Input errors, so no output created."
It does not matter how it is handled, but the output matters.
I forgot to mention, there is a whiteline created in the Word-template for archiving purposes, so this part may not be added as image or it has to be added afterwords into the output document.
Thanks in advance!
StampStationery.cs, a sample from the Webified iTextSharp Examples which essentially are the C#/iTextSharp versions of the Java/iText samples from the book iText in Action — 2nd Edition, does show how to add the contents of a page from one PDF document as stationery behind the content of each page of another PDF.
The central method is this:
public byte[] ManipulatePdf(byte[] src, byte[] stationery)
{
// Create readers
PdfReader reader = new PdfReader(src);
PdfReader s_reader = new PdfReader(stationery);
using (MemoryStream ms = new MemoryStream())
{
// Create the stamper
using (PdfStamper stamper = new PdfStamper(reader, ms))
{
// Add the stationery to each page
PdfImportedPage page = stamper.GetImportedPage(s_reader, 1);
int n = reader.NumberOfPages;
PdfContentByte background;
for (int i = 1; i <= n; i++)
{
background = stamper.GetUnderContent(i);
background.AddTemplate(page, 0, 0);
}
}
return ms.ToArray();
}
}
This method returns the manipulated PDF as a byte[].
I need to insert an image based on a generated barcode file.
The problem I'm having is when using the iTextSharp library I can normally fill in text such as
PdfReader pdfReader = new PdfReader(oldFile);
PdfStamper pdfStamper = new PdfStamper(pdfReader, outFile);
AcroFields fields = pdfStamper.AcroFields;
fields.SetField("topmostSubform[0].Page1[0].BARCODE[0]", "X974005-1");
though there's one field where in pdf if I click onto it it prompts me for an image to insert into field, but I can't seem to programmatically accomplish this. Based on some google searches and stumbling upon a stackoverflow page, I inserted the following code expecting it to work as desired:
string fieldName = "topmostSubform[0].Page1[0].BARCODE[0]";
string imageFile = "test-barcode.jpg";
AcroFields.FieldPosition fieldPosition = pdfStamper.AcroFields.GetFieldPositions(fieldName)[0];
PushbuttonField imageField = new PushbuttonField(pdfStamper.Writer, fieldPosition.position, fieldName);
imageField.Layout = PushbuttonField.LAYOUT_ICON_ONLY;
imageField.Image = iTextSharp.text.Image.GetInstance(imageFile);
imageField.ScaleIcon = PushbuttonField.SCALE_ICON_ALWAYS;
imageField.ProportionalIcon = false;
imageField.Options = BaseField.READ_ONLY;
pdfStamper.AcroFields.RemoveField(fieldName);
pdfStamper.AddAnnotation(imageField.Field, fieldPosition.page);
The problem I am having is while it removes the existing field as intended, when I open the newly created PDF file I don't see this new push button field with the intended image file but rather as a blank but when I perform this through debug mode I can see that it's at least picking up the correct dimensions of the image file, so I don't know what I'm doing wrong here.
Please advise, thanks.
If you read the official documentation (that is: my book), you'll find this example: ReplaceIcon.cs
You're removing the field using pdfStamper.AcroFields.RemoveField(fieldName); and subsequently you try adding the new field using pdfStamper.AddAnnotation(imageField.Field, fieldPosition.page);
That's wrong. You should replace the field using pdfStamper.AcroFields.ReplacePushbuttonField(fieldname, imageField.Field);
The ReplacePushbuttonField() method copies plenty of settings behind the scenes.
We have a .NET app which prints to both real printers and PDF, currently using PDFsharp, although that part can be changed if there's a better option. Most of the output is generated text or images, but there can be one or more pages that get appended to the end. That page(s) are provided by the end-user in PDF format.
When printing to paper, our users use pre-printed paper, but in the case of an exported PDF, we concatenate those pages to the end, since they're already in PDF format.
We want to be able to embed those PDFs directly into the print stream so they don't need pre-printed paper. However, there aren't really any good options for rendering a PDF to a GDI page (System.Drawing.Graphics).
Is there a vector format the PDF could be converted to by some external program, that could rendered to a GDI+ page without being degraded by conversion to a bitmap first?
In an article titled "How To Convert PDF to EMF In .NET," I have shown how to do this using our PDFOne .NET product. EMFs are vector graphics and you can render them on the printer canvas.
A simpler alternative for you is PDF overlay explained in another article titled "PDF Overlay - Stitching PDF Pages Together in .NET." PDFOne allows x-y offsets in overlays that allows you stitch pages on the edges. In the article cited here, I have overlaid the pages one over another by setting the offsets to zero. You will have set it to page width and height.
DISCLAIMER: I work for Gnostice.
Ghostscript can output PostScript (which is a vector file) which can be directly sent to some types of printers. For example, if you're using an LPR capable printer, the PS file can be directly set to that printer using something like this project: http://www.codeproject.com/KB/printing/lpr.aspx
There are also some commercial options which can print a PDF (although I'm not sure if the internal mechanism is vector or bitmap based), for example http://www.tallcomponents.com/pdfcontrols2-features.aspx or http://www.tallcomponents.com/pdfrasterizer3.aspx
I finally figured out that there is an option that addresses my general requirement of embedding a vector format into a print job, but it doesn't work with GDI based printing.
The XPS file format created by Microsoft XPS Writer print driver can be printed from WPF, using the ReachFramework.dll included in .NET. By using WPF for printing instead of GDI, it's possible to embed an XPS document page into a larger print document.
The downside is, WPF printing works quite a bit different, so all the support code that directly uses stuff in the Sytem.Drawing namespace has to be re-written.
Here's the basic outline of how to embed the XPS document:
Open the document:
XpsDocument xpsDoc = new XpsDocument(filename, System.IO.FileAccess.Read);
var document = xpsDoc.GetFixedDocumentSequence().DocumentPaginator;
// pass the document into a custom DocumentPaginator that will decide
// what order to print the pages:
var mypaginator = new myDocumentPaginator(new DocumentPaginator[] { document });
// pass the paginator into PrintDialog.PrintDocument() to do the actual printing:
new PrintDialog().PrintDocument(mypaginator, "printjobname");
Then create a descendant of DocumentPaginator, that will do your actual printing. Override the abstract methods, in particular the GetPage should return DocumentPages in the correct order. Here's my proof of concept code that demonstrates how to append custom content to a list of Xps documents:
public override DocumentPage GetPage(int pageNumber)
{
for (int i = 0; i < children.Count; i++)
{
if (pageNumber >= pageCounts[i])
pageNumber -= pageCounts[i];
else
return FixFixedPage(children[i].GetPage(pageNumber));
}
if (pageNumber < PageCount)
{
DrawingVisual dv = new DrawingVisual();
var dc = dv.Drawing.Append();
dc = dv.RenderOpen();
DoRender(pageNumber, dc); // some method to render stuff to the DrawingContext
dc.Close();
return new DocumentPage(dv);
}
return null;
}
When trying to print to another XPS document, it gives an exception "FixedPage cannot contain another FixedPage", and a post by H.Alipourian demonstrates how to fix it: http://social.msdn.microsoft.com/Forums/da/wpf/thread/841e804b-9130-4476-8709-0d2854c11582
private DocumentPage FixFixedPage(DocumentPage page)
{
if (!(page.Visual is FixedPage))
return page;
// Create a new ContainerVisual as a new parent for page children
var cv = new ContainerVisual();
foreach (var child in ((FixedPage)page.Visual).Children)
{
// Make a shallow clone of the child using reflection
var childClone = (UIElement)child.GetType().GetMethod(
"MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic
).Invoke(child, null);
// Setting the parent of the cloned child to the created ContainerVisual
// by using Reflection.
// WARNING: If we use Add and Remove methods on the FixedPage.Children,
// for some reason it will throw an exception concerning event handlers
// after the printing job has finished.
var parentField = childClone.GetType().GetField(
"_parent", BindingFlags.Instance | BindingFlags.NonPublic);
if (parentField != null)
{
parentField.SetValue(childClone, null);
cv.Children.Add(childClone);
}
}
return new DocumentPage(cv, page.Size, page.BleedBox, page.ContentBox);
}
Sorry that it's not exactly compiling code, I just wanted to provide an overview of the pieces of code necessary to make it work to give other people a head start on all the disparate pieces that need to come together to make it work. Trying to create a more generalized solution would be much more complex than the scope of this answer.
While not open source and not .NET native (Delphi based I believe, but offers a precompiled .NET library), Quick PDF can render a PDF to an EMF file which you could load into your Graphics object.