Reputation: 19
I'm trying to insert an image with id into a PDF document and allow to replace it later with another image. My process is as follows:
I use code from Bruno Lowagie book:
The problem is that whenever I delete an existing image or replace it my document gets corrupted. What am I doing wrong? This is the code:
public static bool PdfInsertSignature(string path, string fileName, string signatureName, byte[] imageBytes)
{
bool resultOk = true;
string tmpFilename = string.Concat("tmp_", Guid.NewGuid().ToString(), ".pdf");
// get file, copy to new file with signature
using (Stream inputPdfStream = new FileStream(path + fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
using (Stream outputPdfStream = new FileStream(path + tmpFilename, FileMode.Create, FileAccess.Write, FileShare.None))
{
using (var reader = new PdfReader(inputPdfStream))
using (PdfStamper stamper = new PdfStamper(reader, outputPdfStream, '\0', false))
{
var img = System.Drawing.Image.FromStream(new MemoryStream(imageBytes));
Image image = Image.GetInstance(img, BaseColor.WHITE);
img.Dispose();
var positions = stamper.AcroFields.GetFieldPositions(signatureName)[0];
if (positions != null)
{
//DeleteExistingSignatureImage(reader, stamper, signatureName);
image.SetAbsolutePosition(positions.position.Left + 20, positions.position.Top - 15);
image.ScalePercent(0.2f * 100);
image.BorderWidth = 0;
PdfImage pdfImg = new PdfImage(image, "", null);
pdfImg.Put(new PdfName("ITXT_SigImageId"), new PdfName(signatureName + "_img"));
if (!ReplaceImage(reader, stamper, signatureName, pdfImg))
{
PdfIndirectObject objRef = stamper.Writer.AddToBody(pdfImg);
image.DirectReference = objRef.IndirectReference;
PdfContentByte pdfContentByte = stamper.GetOverContent(positions.page);
pdfContentByte.AddImage(image);
}
}
else
{
resultOk = false;
logger.Error($"No matching Signature found for signatureName: {signatureName} in fileName: {fileName}.");
}
}
}
if (resultOk)
{
// delete old file and rename new file to old file's name
File.Delete(path + fileName);
File.Move(path + tmpFilename, path + fileName);
}
else
{
File.Delete(path + tmpFilename);
}
return resultOk;
}
private static bool ReplaceImage(PdfReader reader, PdfStamper stamper, string signatureName, PdfStream newImgStream)
{
PdfName key = new PdfName("ITXT_SigImageId");
PdfName value = new PdfName(signatureName + "_img");
PdfObject obj;
PRStream stream;
for (int i = 1; i < reader.XrefSize; i++)
{
obj = reader.GetPdfObject(i);
if (obj == null || !obj.IsStream())
{
continue;
}
stream = (PRStream)obj;
PdfObject pdfSubtype = stream.Get(PdfName.SUBTYPE);
if (pdfSubtype != null && pdfSubtype.ToString().Equals(PdfName.IMAGE.ToString()))
{
var streamVal = stream.Get(key);
if (streamVal != null && value.Equals(streamVal))
{
stream.Clear();
var ms = new MemoryStream();
stream.WriteContent(ms);
stream.SetData(ms.ToArray(), false);
foreach (PdfName name in newImgStream.Keys)
{
stream.Put(name, stream.Get(name));
}
return true;
}
}
}
return false;
}
private static void DeleteExistingSignatureImage(PdfReader reader, PdfStamper stamper, string signatureName)
{
PdfName key = new PdfName("ITXT_SigImageId");
PdfName value = new PdfName(signatureName + "_img");
PdfObject obj;
PRStream stream;
for (int i = 1; i < reader.XrefSize; i++)
{
obj = reader.GetPdfObject(i);
if (obj == null || !obj.IsStream())
{
continue;
}
stream = (PRStream)obj;
PdfObject pdfSubtype = stream.Get(PdfName.SUBTYPE);
if (pdfSubtype != null && pdfSubtype.ToString().Equals(PdfName.IMAGE.ToString()))
{
var streamVal = stream.Get(key);
if (streamVal != null && value.Equals(streamVal))
{
stream.Clear();
PdfReader.KillIndirect(stream);
//PdfReader.KillIndirect(obj);
//reader.RemoveUnusedObjects();
}
}
}
}
Upvotes: 0
Views: 3084
Reputation: 61
This is the code i've used to replace a 'ButtonField' on my PDF template with a signature image :
string TempStampPath = Server.MapPath(TempPath + "BookingConfirmation.pdf");
PdfReader pdfReader = new PdfReader(TempStampPath);
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(LocalFileName, FileMode.Create));
AcroFields pdfFormFields = pdfStamper.AcroFields;
try
{
pdfFormFields.SetField("NameSurname", NameSurname);
pdfFormFields.SetField("IdNumber", IDNumber);
pdfFormFields.SetField("CourseName", CourseName);
pdfFormFields.SetField("Location", Venue);
pdfFormFields.SetField("DateCompleted", CourseDate);
pdfFormFields.SetField("FacilitatorName", Facilitator);
try
{
iTextSharp.text.Image signature = iTextSharp.text.Image.GetInstance(image, System.Drawing.Imaging.ImageFormat.Png);
PushbuttonField ad = pdfStamper.AcroFields.GetNewPushbuttonFromField("btnFacilitatorSignature");
ad.Layout = PushbuttonField.LAYOUT_ICON_ONLY;
ad.ProportionalIcon = true;
ad.Image = signature;
ad.BackgroundColor = iTextSharp.text.BaseColor.WHITE;
pdfFormFields.ReplacePushbuttonField("btnFacilitatorSignature", ad.Field);
}
catch (Exception ex)
{ }
pdfStamper.FormFlattening = true;
pdfStamper.Close();
pdfStamper.Dispose();
pdfReader.Close();
}
catch (Exception ex)
{
pdfStamper.Close();
pdfStamper.Dispose();
pdfReader.Close();
}
Upvotes: 0
Reputation: 2066
The purpose of signing a PDF file is to prevent further changes without notice. You need to sign the document after you swap the image, or it will be corrupted.
Just do make it easier to find: This is Solution provided by amira.
Upvotes: 1