Reputation: 1477
I think this might be a bug, but if anyone can help I'd appreciate it. I currently have another question open that deals with a similar issue, but I think this question better exemplifies the problem, and more simply too. That being said I don't want to delete the old one in case it increases my wait time. I yield to the mods to decide which question is better.
Here's a sample application that creates a pdf, then a table. It adds a cell to the table and then ties a fieldpositioningevent to the cell event.
using System;
using System.Diagnostics;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace iTextSharpTextBoxInTableCell
{
class Program
{
static void Main(string[] args)
{
// Create a PDF with a TextBox in a table cell
BaseFont bfHelvetica = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1250, false);
Font helvetica12 = new Font(bfHelvetica, 12, Font.NORMAL, BaseColor.BLACK);
Document doc = new Document(PageSize.LETTER, 18f, 18f, 18f, 18f);
FileStream fs = new FileStream("TextBoxInTableCell.pdf", FileMode.Create);
PdfWriter writer = PdfWriter.GetInstance(doc, fs);
doc.Open();
PdfPTable myTable = new PdfPTable(1);
myTable.TotalWidth = 568f;
myTable.LockedWidth = true;
myTable.HorizontalAlignment = 0;
TextField tf = new TextField(writer, new iTextSharp.text.Rectangle(67, 585, 140, 800), "cellTextBox");
tf.Text = "test";
PdfPCell tbCell = new PdfPCell(new Phrase(" ", helvetica12));
iTextSharp.text.pdf.events.FieldPositioningEvents events =
new iTextSharp.text.pdf.events.FieldPositioningEvents(writer, tf.GetTextField());
tbCell.CellEvent = events;
myTable.AddCell(tbCell);
doc.Add(myTable);
doc.Close();
fs.Close();
Process.Start("TextBoxInTableCell.pdf");
Console.WriteLine("End Of Program Execution");
Console.ReadLine();
}
}
}
Here's what this field looks like when it's generated:
As you can see, the text is squashed. I've published the generated pdf here.
Upvotes: 0
Views: 3866
Reputation: 55427
I'm definitely seeing what you're seeing and as @mkl said in your other post, the problem comes down to the appearance's BBOX
entry not being set to the same size as the field. I can't really find too many examples of FieldPositioningEvents
in the wild and the ones that do exist appear to be copy-and-paste's of each other for the most part.
Anyway, if you read the actual code for FieldPositioningEvents
you'll see that it can be used for both page events as well as cell events which makes me think it was intended for broader purposes possibly, but that's just a guess on my part.
One solution is to just write your own subclass of IPdfPCellEvent
. Below is an example of that that follows the example provided by FieldPositioningEvents
however it is specific to TextFields
since we're interested in setting the /BBOX
entry. It has two constructors, one that works very similar to FieldPositioningEvents
that takes a PdfWriter
and a TextField
and one that just takes the most commonly set properties of a TextFields
and actually creates it for you. The CellLayout
is part of the interface contract and actually figures out where the annotation should be drawn.
public class SingleCellFieldPositioningEvent : IPdfPCellEvent {
public TextField Field { get; set; }
public PdfWriter Writer { get; set; }
public float Padding { get; set; }
public SingleCellFieldPositioningEvent(PdfWriter writer, TextField field) {
this.Field = field;
this.Writer = writer;
}
public SingleCellFieldPositioningEvent(PdfWriter writer, string fieldName, string text = "", BaseFont font = null, float fontSize = 14 ) {
//The rectangle gets changed later so it doesn't matter what we use
var rect = new iTextSharp.text.Rectangle(1, 1);
//Create the field and set various properties
this.Field = new TextField(writer, rect, fieldName);
this.Field.Text = text;
if (null == font) {
font = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED);
}
this.Field.Font = font;
this.Field.FontSize = fontSize;
this.Writer = writer;
}
public void CellLayout(PdfPCell cell, iTextSharp.text.Rectangle rect, PdfContentByte[] canvases) {
//Create the field's rectangle based on the current cell and requested padded
var newRect = new PdfRectangle(rect.GetLeft(Padding), rect.GetBottom(Padding), rect.GetRight(Padding), rect.GetTop(Padding));
//Set the appearance's rectangle to the same as the box
Field.Box = newRect.Rectangle;
//Get the raw field
var tf = this.Field.GetTextField();
//Change the field's rectangle
tf.Put(PdfName.RECT, newRect);
//Add the annotation to the writer
Writer.AddAnnotation(tf);
}
}
You can use this in two different ways. Either manually create a field and set various properties:
//The rectangle is actually changed in the cell event so it doesn't matter what we use
TextField tf = new TextField(writer, new iTextSharp.text.Rectangle(1, 1), "cellTextBox");
tf.Text = "test";
tf.Font = bfHelvetica;
tf.FontSize = 14;
PdfPCell tbCell = new PdfPCell(new Phrase(" ", helvetica12));
tbCell.CellEvent = new SingleCellFieldPositioningEvent(writer, tf);
Or just pass the properties in:
PdfPCell tbCell = new PdfPCell(new Phrase(" ", helvetica12));
tbCell.CellEvent = new SingleCellFieldPositioningEvent(writer, "cellTextBox", "test", bfHelvetica, 14);
myTable.AddCell(tbCell);
Upvotes: 2