We are using Pdf library to generate some dynamic contracts, where the initial pdf has some text placeholders, then after collecting data form the user we generate the end contract.
While doing this, we discovered a very strange issue. See the code below.
Basically finding all the needed text using the Regex and TextAbsorber, then having the position of the fragments, I place an ImageStamp. What is strange is, the Signature field I can see it 3 times as needed, but the checkboxes only the last one. The funny thing is, if I reverse the order of the fields in the list, then I see the last Signature, and all checkboxes.
Can you please tell me what is wrong here?
For your convenience, I attached the full project.
Thank you.
AsposeReplaceTextWithImage.zip (70.3 KB)
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using Aspose.Pdf;
using Aspose.Pdf.Text;
namespace AsposeReplaceTextWithImage
{
class Program
{
static Random R = new Random();
static void Main(string[] args)
{
List<Field> fields = new List<Field>()
{
new Field(){IsCustom = true, Name = "custom"},
new Field(){IsSignature = true, Name = "t"},
new Field(){IsCheckBox = true, Name = "c"}
};
Document pdfDocument = new Document(new FileStream("QC simple contract.pdf", FileMode.Open));
int customCnt = 1;
foreach (var field in fields)
{
var regex = CreateFieldRg(field.Name);
var textFragmentAbsorber = new TextFragmentAbsorber(regex, new TextSearchOptions(true));
foreach (var page in pdfDocument.Pages) page.Annotations.Clear();
pdfDocument.Pages.Accept(textFragmentAbsorber);
var textFragmentCollection = textFragmentAbsorber.TextFragments;
foreach (var fragment in textFragmentCollection)
{
if (field.IsCustom)
{
fragment.Text = $"Custom_{customCnt++}";
}
else if (field.IsSignature)
{
fragment.Text = GetEmptyTextToFitWidth(fragment);
var w = fragment.Rectangle.Width;
var h = fragment.Rectangle.Height;
var ms = new MemoryStream(File.ReadAllBytes("signature.png")); // in real project it comes from a web-request
var imageStamp = new ImageStamp(ms)
{
Background = false,
Width = w,
Height = h,
XIndent = fragment.Position.XIndent,
YIndent = fragment.Position.YIndent,
OutlineOpacity = 0.5,
};
fragment.Page.AddStamp(imageStamp);
}
else if (field.IsCheckBox)
{
fragment.Text = GetEmptyTextToFitWidth(fragment);
var w = Math.Min(fragment.Rectangle.Width, fragment.Rectangle.Height);
var bitmap = R.Next(4) == 2
? File.ReadAllBytes("CheckBox-checked-512.png")
: File.ReadAllBytes("CheckBox-empty-512.png");
var ms = new MemoryStream(bitmap);
var imageStamp = new ImageStamp(ms)
{
Background = false,
Width = w,
Height = w,
XIndent = fragment.Position.XIndent,
YIndent = fragment.Position.YIndent,
OutlineOpacity = 0.5,
};
fragment.Page.AddStamp(imageStamp);
}
}
}
pdfDocument.Save("result.pdf");
}
private static string GetEmptyTextToFitWidth(TextFragment textFragment)
{
var text = new string(' ', textFragment.Text.Length);
var width = textFragment.TextState.Font.MeasureString(text, textFragment.TextState.FontSize);
var widthCustom =
textFragment.TextState.Font.MeasureString(textFragment.Text, textFragment.TextState.FontSize);
if (width < widthCustom)
while (width < widthCustom)
{
text += " ";
width = textFragment.TextState.Font.MeasureString(text, textFragment.TextState.FontSize);
}
else
while (text.Length > 0 && width > textFragment.Rectangle.Width)
{
text = text.Remove(0, 1);
width = textFragment.TextState.Font.MeasureString(text, textFragment.TextState.FontSize);
}
return text;
}
private static Regex CreateFieldRg(string fieldName)
{
//return new Regex(@"<([\$\@])\s*(" + fieldName + @")([0-9]*)\s*>", RegexOptions.IgnoreCase);
return new Regex(@"<([\$\@]{1})\s*(" + fieldName + @")\s*>", RegexOptions.IgnoreCase);
}
}
public class Field
{
public bool IsCustom { get; set; }
public bool IsSignature { get; set; }
public bool IsCheckBox { get; set; }
public string Name { get; set; }
}
}