iTextSharp PdfStamper.PartialFormFlattening flattening only some, not all, of the fields - itext

The code below is correctly assigning the value "foo" to the named field, but the field is not being "flattened". I must be neglecting a step, but I don't know what it is. Please advise. Thanks.
public byte[] FlattenSpecifiedFormFields(byte[] b, List<string> fieldNames2Flatten)
{
PdfReader reader = new PdfReader(b);
using (var ms = new MemoryStream())
{
var stamper = new iTextSharp.text.pdf.PdfStamper(reader, ms);
foreach (string name in fieldNames2Flatten)
{
stamper.AcroFields.SetField(name, "foo");
stamper.PartialFormFlattening(name);
}
stamper.Close();
return ms.ToArray();
};
}

Even when partially flattening a form, the PdfStamper FormFlattening property must be set to true. I.e.:
var stamper = new PdfStamper(reader, ms);
stamper.FormFlattening = true;
foreach (string name in fieldNames2Flatten)
{
stamper.AcroFields.SetField(name, "foo");
stamper.PartialFormFlattening(name);
}

Related

Duplicate Fields using itextsharp

I have this code to create TextFields
public void MssCreateTextField(byte[] ssPdf, RCRectangleRecord ssRectangle, string ssName, int ssFontSize, string ssValue, int ssPage, out byte[] ssPdfOut, bool ssIsMultiline) {
PdfReader reader = new PdfReader(ssPdf);
ssPdfOut = null;
var output = new MemoryStream();
var stamper = new PdfStamper(reader, output);
/*TextField tField = new TextField(stamper.Writer, new iTextSharp.text.Rectangle((float)ssRectangle.ssSTRectangle.ssllx, (float)ssRectangle.ssSTRectangle.sslly, (float)ssRectangle.ssSTRectangle.ssurx, (float)ssRectangle.ssSTRectangle.ssury), ssName);
if (ssValue!="")
tField.Text = ssValue;
if (ssIsMultiline)
tField.Options = TextField.MULTILINE;
tField.FontSize = ssFontSize;*/
PdfFormField tField = PdfFormField.CreateTextField(stamper.Writer, ssIsMultiline, false, 50);
tField.FieldName = ssName;
tField.SetWidget(new iTextSharp.text.Rectangle((float)ssRectangle.ssSTRectangle.ssllx, (float)ssRectangle.ssSTRectangle.sslly, (float)ssRectangle.ssSTRectangle.ssurx, (float)ssRectangle.ssSTRectangle.ssury), PdfAnnotation.HIGHLIGHT_TOGGLE);
stamper.FormFlattening = false;
stamper.AddAnnotation(tField, ssPage);
stamper.Close();
reader.Close();
ssPdfOut = output.ToArray();
}
As you can see i have some code commented as an alternative but the two different ways are producing the same result.
What i am trying to achieve is create two textfields with the same name to when editing one it edits the others two. This two codes do that (in the browsers and pdfescape site) excepting in the adobe acrobat reader. In the acrobat reader i get just the first field visible and the others hidden i dont know why...
If you want to add two text field visualizations which represent the same content, you have to add them as two widgets of the same field and not two distinct fields, e.g. like this:
public void CreateDoubleTextField(byte[] ssPdf, Rectangle ssRectangle1, Rectangle ssRectangle2, string ssName, int ssFontSize, string ssValue, int ssPage, out byte[] ssPdfOut, bool ssIsMultiline)
{
PdfReader reader = new PdfReader(ssPdf);
ssPdfOut = null;
var output = new MemoryStream();
var stamper = new PdfStamper(reader, output);
PdfFormField tField = PdfFormField.CreateTextField(stamper.Writer, ssIsMultiline, false, 50);
tField.FieldName = ssName;
PdfFormField widget1 = PdfFormField.CreateEmpty(stamper.Writer);
widget1.SetWidget(ssRectangle1, PdfAnnotation.HIGHLIGHT_TOGGLE);
PdfFormField widget2 = PdfFormField.CreateEmpty(stamper.Writer);
widget2.SetWidget(ssRectangle2, PdfAnnotation.HIGHLIGHT_TOGGLE);
tField.AddKid(widget1);
tField.AddKid(widget2);
stamper.FormFlattening = false;
stamper.AddAnnotation(tField, ssPage);
stamper.Close();
reader.Close();
ssPdfOut = output.ToArray();
}
(As I don't have that RCRectangleRecord, I use the iTextSharp Rectangle class as argument.)
This gives you two field visualizations in Adobe Acrobat Reader; after editing one of them and switching focus (e.g. clicking somewhere outside that visualization), the other visualization duplicates the content.
Now i have this and i can create two fields when the list has more than one Rectangle but for some reason i dont know how the two fields appears without the name!!
PdfReader reader = new PdfReader(ssPdf);
ssPdfOut = null;
var output = new MemoryStream();
var stamper = new PdfStamper(reader, output);
TextField tField;
if (ssRectangle.Count==1){
tField= new TextField(stamper.Writer, new iTextSharp.text.Rectangle((float)ssRectangle[0].ssSTRectangle.ssllx, (float)ssRectangle[0].ssSTRectangle.sslly, (float)ssRectangle[0].ssSTRectangle.ssurx, (float)ssRectangle[0].ssSTRectangle.ssury), ssName);
if (ssValue!="")
tField.Text = ssValue;
if (ssIsMultiline)
tField.Options = TextField.MULTILINE;
tField.FontSize = ssFontSize;
tField.FieldName = ssName;
stamper.AddAnnotation(tField.GetTextField(), ssPage);
}
else
{
PdfFormField PtField = PdfFormField.CreateTextField(stamper.Writer, ssIsMultiline, false, 250);
PtField.Name=ssName;
foreach (RCRectangleRecord item in ssRectangle)
{
/*
tField=new TextField(stamper.Writer, new iTextSharp.text.Rectangle((float)ssRectangle[0].ssSTRectangle.ssllx, (float)ssRectangle[0].ssSTRectangle.sslly, (float)ssRectangle[0].ssSTRectangle.ssurx, (float)ssRectangle[0].ssSTRectangle.ssury), ssName);
tField.FieldName = ssName;
PtField.AddKid(tField.GetTextField());*/
PdfFormField widget = PdfFormField.CreateEmpty(stamper.Writer);
widget.SetWidget(new Rectangle((float)item.ssSTRectangle.ssllx, (float)item.ssSTRectangle.sslly, (float)item.ssSTRectangle.ssurx, (float)item.ssSTRectangle.ssury), PdfAnnotation.HIGHLIGHT_TOGGLE);
widget.Name = ssName;
PtField.AddKid(widget);
}
stamper.AddAnnotation(PtField, ssPage);
}
stamper.FormFlattening = false;
stamper.Close();
reader.Close();
ssPdfOut = output.ToArray();

I cannot write into specific location in pdf

Trying to manipulate pdf with using pdfstamper I don't know what's wrong in the code it doesn't print textfield in output file. Thanks in advance
PdfReader reader = new PdfReader("Players.pdf");
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(Result));
AcroFields form = stamper.getAcroFields(); // using acro fields to fill out the pdf
form.setGenerateAppearances(true);
rs = statement.executeQuery("SELECT * from Players");
while ( rs.next() ) {
String Country = null;
Country = rs.getString("CName");
System.out.println(Country);
if (rs != null)
Country = rs.getString("CName");
form.setField("Country",Country);
}
stamper.setFormFlattening(true);
stamper.close();
connection.close();

iTextSharp - Create new document as Byte[]

Have a little method which goes to the database and retrieves a pdf document from a varbinary column and then adds data to it. I would like to add code so that if this document (company stationery ) is not found then a new blank document is created and returned. The method could either return a Byte[] or a Stream.
Problem is that the variable "bytes" in the else clause is null.
Any ideas what's wrong?
private Byte[] GetBasePDF(Int32 AttachmentID)
{
Byte[] bytes = null;
DataTable dt = ServiceFactory
.GetService().Attachments_Get(AttachmentID, null, null);
if (dt != null && dt.Rows.Count > 0)
{
bytes = (Byte[])dt.Rows[0]["Data"];
}
else
{
// Create a new blank PDF document and return it as Byte[]
ITST.Document doc =
new ITST.Document(ITST.PageSize.A4, 50f, 50f, 25f, 25f);
MemoryStream ms = new MemoryStream();
PdfCopy copy = new PdfCopy(doc, ms);
ms.Position = 0;
bytes = ms.ToArray();
}
return bytes;
}
You are trying to use PdfCopy but that's intended for existing documents, not new ones. You just need to create a "blank" document using PdfWriter and Document. iText won't let you create a 100% empty document but the code below essentially does that by just adding a space.
private static Byte[] CreateEmptyDocument() {
using (var ms = new System.IO.MemoryStream()) {
using (var doc = new Document()) {
using (var writer = PdfWriter.GetInstance(doc, ms)) {
doc.Open();
doc.Add(new Paragraph(" "));
doc.Close();
}
}
return ms.ToArray();
}
}
I think you may need to use
bytes = ms.GetBuffer();
not
bytes = ms.ToArray();

Use External Css to parse XML

OK i am parsing HTML from a string into a PDFCEll.
It works great thanks to some help from here.
Here is how i am doing it.
How do i use an external css file so i can use class's and not STYLE=""
public class XhtmlToListHelper : IElementHandler
{
// Generic list of elements
public List<IElement> elements = new List<IElement>();
// Add the item to the list
public void Add(IWritable w)
{
if (w is WritableElement)
{
elements.AddRange(((WritableElement)w).Elements());
}
}
string html = "<ul class=\"list\"><li>html 1</li><li>html 2</li><li>html 3</li></ul>";
using (TextReader sr = new StringReader(html))
{
XMLWorkerHelper.GetInstance().ParseXHtml(XhtmlHelper, sr);
}
foreach (var element in XhtmlHelper.elements)
{
if (element.IsContent())
{
PDFCell.AddElement(element);
}
}
Now i have got this far, but how to tye it all in evades me. Any help would be much apreacheted.
HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
htmlContext.SetTagFactory(iTextSharp.tool.xml.html.Tags.GetHtmlTagProcessorFactory());
ICSSResolver cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(false);
cssResolver.AddCssFile(HttpContext.Current.Server.MapPath("~/Templates/css/core.css"), true);
If you poke around the source here and you should see how to implement it. Basically, your three line using block quadruples in size and complexity:
var XhtmlHelper = new XhtmlToListHelper();
var htmlContext = new HtmlPipelineContext(null);
htmlContext.SetTagFactory(iTextSharp.tool.xml.html.Tags.GetHtmlTagProcessorFactory());
var cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(false);
cssResolver.AddCssFile(#"c:\test.css", true);
var pipeline = new CssResolverPipeline(cssResolver, new HtmlPipeline(htmlContext, new ElementHandlerPipeline(XhtmlHelper, null)));//Here's where we add our IElementHandler
var worker = new XMLWorker(pipeline, true);
var parser = new XMLParser();
parser.AddListener(worker);
using (TextReader sr = new StringReader(html)) {
parser.Parse(sr);
}

Open Xml: Word Create a new Document and add a paragraph from another document

I have a document that I am iterating thru getting the paragraphs. For each of these paragraphs I need to create a new document and save it. I can't figure out how to add a Paragraph from the source document to the new one.
foreach (var p in paragraphsFromSourceDocument)
{
using (var memoryStream = new MemoryStream())
{
var doc = WordprocessingDocument.Create(memoryStream, WordprocessingDocumentType.Document);
doc.AddMainDocumentPart();
// Create the Document DOM.
doc.MainDocumentPart.Document = new Document();
doc.MainDocumentPart.Document.Body = new Body();
//Add the paragraph 'p' to the Body here:
// HOW ?????????
doc.MainDocumentPart.Document.Save();
}
}
// Open the file read-only since we don't need to change it.
using (var wordprocessingDocument = WordprocessingDocument.Open(documentFileName, true))
{
paragraphs = wordprocessingDocument.MainDocumentPart.Document.Body
.OfType<Paragraph>().ToList();
styles = wordprocessingDocument.MainDocumentPart.StyleDefinitionsPart;
foreach (var p in paragraphs)
{
using (var memoryStream = new MemoryStream())
{
var doc = WordprocessingDocument.Create(memoryStream, WordprocessingDocumentType.Document);
doc.AddMainDocumentPart().AddPart(styles);
doc.MainDocumentPart.Document = new Document();
doc.MainDocumentPart.Document.Body = new Body();
doc.MainDocumentPart.Document.Body.Append(p.CloneNode(true));
doc.MainDocumentPart.Document.Save();
Console.WriteLine(GetHTMLOfDoc(doc));
}
}
}