我有AcroFields的PDF。某些字段是多行字段。我需要使用给定的文本填充AcroFields并使用" *"填充字段中的任何剩余空间。 (或预定义的字符/字符串)。我可以使用iText添加文字,但不知道如何计算要添加的适量填充物。
请你能建议我这样做。谢谢。
我写的代码是:
public string CreatePdf(IDictionary<FieldKey, string> dictionary, string template, string saveAs)
{
// Create new PDF from template
using (PdfReader reader = new PdfReader(template))
using (FileStream stream = new FileStream(saveAs, FileMode.Create, FileAccess.ReadWrite))
using (PdfStamper stamper = new PdfStamper(reader, stream))
{
// Populate PDF fields from dictionary
AcroFields formFields = stamper.AcroFields;
foreach (KeyValuePair<FieldKey, string> dataField in dictionary)
{
switch (dataField.Key.FieldType)
{
case FieldType.Text:
string fieldValue = dataField.Value;
// Add filler if a filler is set
if (!String.IsNullOrWhiteSpace(dataField.Key.FillRight))
{
fieldValue = GetTextWithFiller(formFields, dataField.Key.FieldName, fieldValue, dataField.Key.FillRight);
}
// Text field
if (!formFields.SetField(dataField.Key.FieldName, fieldValue))
throw new InvalidDataException(String.Format("Invalid Template Field: {0} in Template: {1}", dataField.Key.FieldName, template));
break;
case FieldType.Image:
// Image field
PlaceImage(formFields, dataField);
break;
case FieldType.Barcode2Of5:
// 2 of 5 Barcode
PlaceBarcode2Of5(dataField.Value, stamper);
break;
case FieldType.Barcode128:
// 2 of 5 Barcode
PlaceBarcode128(dataField.Value, stamper);
break;
default:
throw new InvalidDataException(String.Format("Invalid data filed type : {0}", dataField.Key.FieldType));
}
}
// Save PDF
reader.RemoveUnusedObjects();
stamper.FormFlattening = true;
stamper.Close();
}
return saveAs;
}
获取填充程序的方法,它没有按预期工作:
private static string GetTextWithFiller(AcroFields fields, string fieldName, string text, string filler)
{
// Get the size of the rectangle that defines the field
AcroFields.FieldPosition fieldPosition = fields.GetFieldPositions(fieldName)[0];
Rectangle rect = fieldPosition.position;
// Get field font
PdfDictionary merged = fields.GetFieldItem(fieldName).GetMerged(0);
TextField textField = new TextField(null, null, null);
fields.DecodeGenericDictionary(merged, textField);
Font fieldFont = new Font(textField.Font);
Chunk whatWeHave = new Chunk(text, fieldFont);
float textWidth = whatWeHave.GetWidthPoint();
// See how far the text field is filled with give text
float textEndPoint = rect.Left + textWidth;
float rectBottom = rect.Bottom;
float rectRight = rect.Right;
float rectTop = rect.Top;
// How many rows to fill
int textRows = Convert.ToInt32(rect.Height / fieldFont.CalculatedSize);
float totalCharactersWeCanFit = rect.Width * textRows;
if (textWidth < totalCharactersWeCanFit)
{
// Get the width of filler character
Chunk fillCharWidth = new Chunk(filler, fieldFont);
// Available gap
float gap = totalCharactersWeCanFit - textWidth;
// How much filler required
int fillAmount = Convert.ToInt32(gap / fillCharWidth.GetWidthPoint());
// Fill with filler
StringBuilder tempString = new StringBuilder();
tempString.Append(text);
for (int n = 0; n < fillAmount; ++n)
{
tempString.Append(filler);
}
text = tempString.ToString();
}
return text;
}
答案 0 :(得分:2)
考虑一个包含三个多行文本字段的表单:
对于第一个字段,我们定义了字体大小0(这也是你所做的);对于第二个字段,我们定义一个字体12;对于第三个字段,我们定义一个字体6。
现在让我们填写并展平表单:
public void manipulatePdf(String src, String dest) throws DocumentException, IOException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
AcroFields form = stamper.getAcroFields();
StringBuilder sb = new StringBuilder();
for (String name : form.getFields().keySet()) {
int n = getInformation(form, name);
for (int i = 0; i < n; i++) {
sb.append(" *");
}
String filler = sb.toString();
form.setField(name, name + filler);
}
stamper.setFormFlattening(true);
stamper.close();
reader.close();
}
结果如下:
如您所见,我们添加的填充*
的数量取决于字段级别定义的字体大小。如果字体大小为0,则将调整字体以使文本始终适合。如果字体具有实际值,我们可以或多或少地计算行数和&#34;列&#34;我们需要:
public int getInformation(AcroFields form, String name) {
form.getFieldItem(name);
AcroFields.Item item = form.getFieldItem(name);
PdfDictionary dict = item.getMerged(0);
PdfString da = dict.getAsString(PdfName.DA);
Object[] da_values = AcroFields.splitDAelements(da.toUnicodeString());
if (da_values == null) {
System.out.println("No default appearance");
}
BaseFont bf = null;
String font = (String)da_values[AcroFields.DA_FONT];
if (font != null) {
PdfDictionary dr = dict.getAsDict(PdfName.DR);
if (dr != null) {
PdfDictionary fontDict = dr.getAsDict(PdfName.FONT);
bf = BaseFont.createFont((PRIndirectReference)fontDict.get(new PdfName(font)));
}
}
if (bf == null) {
System.out.println("No BaseFont");
}
else {
System.out.println("Basefont: " + bf.getPostscriptFontName());
System.out.println("Size: " + da_values[AcroFields.DA_SIZE]);
Float size = (Float)da_values[AcroFields.DA_SIZE];
if (size == 0)
return 1000;
Rectangle rect = form.getFieldPositions(name).get(0).position;
float factor = bf.getFontDescriptor(BaseFont.BBOXURY, 1) - bf.getFontDescriptor(BaseFont.BBOXLLY, 1);
int rows = Math.round(rect.getHeight() / (size * factor) + 0.5f);
int columns = Math.round(rect.getWidth() / bf.getWidthPoint(" *", size) + 0.5f);
System.out.println("height: " + rect.getHeight() + "; width: " + rect.getWidth());
System.out.println("rows: " + rows + "; columns: " + columns);
return rows * columns;
}
return 1000;
}
首先我们得到字体,以便我们可以创建一个BaseFont
对象。然后我们得到字体大小并使用BaseFont
中存储的信息,我们将定义用于计算前导的因子(即两行之间的空间)。
我们也询问该领域的规模。然后我们计算出我们可以在高度(rows
)中放入多少行以及我们可以将String " *"
放入字段矩形的宽度(columns
)中的次数。如果我们将columns
和rows
相乘,我们会得到一个近似值,即我们必须添加" *"
以获得适当填充的次数。如果我们有太多的填充物并不重要:如果定义了字体,那么所有不适合的文本都将被删除。
您可以在此处找到完整示例:MultiLineFieldCount
我们采用multiline.pdf形式,getInformation()
方法返回此信息:
Basefont: Helvetica
Size: 0.0
Basefont: Helvetica
Size: 6.0
height: 86.0; width: 108.0
rows: 13; columns: 27
Basefont: Helvetica
Size: 12.0
height: 86.0; width: 107.999985
rows: 7; columns: 14
我们无法详细说明第一个字段,因为字体大小为0.在您的示例中也是如此。如果字体为0,则您的问题无法解决。您无法计算出*
适合该字段的数量,因为您不知道将用于呈现*
的字体大小。
如果字体大小为12,我们可以容纳7行和14列(我们在屏幕截图中看到7行和13列)。如果字体大小为6,我们可以容纳14行和27列(我们在屏幕截图中看到14行和26列)。
额外的列是由于我们使用了ceil()
方法。最好过高估计列数而不是低估它......