Como impedir que a anotação de substituição altere a posição e o tamanho do texto?
Estou usando o iTextSharp para substituir anotações da máquina de escrever por caixas de texto com o mesmo conteúdo e posição, mas algumas das caixas de texto resultantes acabam em posições diferentes com tamanhos de texto diferentes, apesar de aparentemente terem exatamente os mesmos dados em suashashMap
.
O problema é que, quando crio essas novas anotações emeste exemplo de PDFe, em seguida, visualize o PDF no Adobe Acrobat XI, as novas caixas de texto têm os seguintes problemas:
Eles foram movidos de suas posições originais (adjacentes às setas) para baixo na página
O texto mudou de tamanho
Não háPropriedades disponível quando a nova caixa de texto é clicada com o botão direito do mouse
Eu suspeito que todos os três problemas se devam a um único problema subjacente na maneira como estou criando a nova caixa de texto.
Quando eu checo o/Rect
chave nohashMap
paraannot
, ele tem as mesmas coordenadas retangulares na mesma ordem que o originalfreeTextAnnot
, então não entendo por que algumas das anotações acabam sendo deslocadas.
Aqui está o meu código para criar as novas caixas de texto com os dados de anotação da máquina de escrever existentes. Observe que você precisará definirinputPath
eoutputPath
para o local real do PDF e seu caminho de destino:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using iTextSharp;
using iTextSharp.text.pdf;
using System.IO;
namespace PDFConverterTester
{
public class PdfModifierTester
{
public void testWithPaths()
{
//set to location of test PDF
string inputPath = @"C:\InputPath\Before Conversion Dummy.pdf";
//set to destination of new PDF
string outputPath = @"C:\OutputPath\Before Conversion Dummy.pdf";
test(inputPath, outputPath);
}
public void test(string inputPath, string outputPath)
{
PdfReader pdfReader = new PdfReader(inputPath);
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(outputPath, FileMode.Create));
//get the PdfDictionary of the 1st page
PdfDictionary pageDict = pdfReader.GetPageN(1);
//get annotation array
PdfArray annotArray = pageDict.GetAsArray(PdfName.ANNOTS);
//iterate through annotation array
int size = annotArray.Size;
for (int i = size - 1; i >= 0; i--)
{
PdfDictionary dict = annotArray.GetAsDict(i);
PdfName ITName = dict.GetAsName(new PdfName("IT"));
if (ITName != null)
{
if (ITName.Equals(new PdfName("FreeTextTypewriter")))
{
PdfAnnotation annot = copyToNewAnnotation_SSCCE(dict,pdfStamper);
pdfStamper.AddAnnotation(annot, 1);
annotArray.Remove(i);
}
}
}
pdfStamper.Close();
pdfReader.Close();
}
private PdfAnnotation copyToNewAnnotation_SSCCE(PdfDictionary freeTextAnnot,PdfStamper pdfStamper)
{
//need Rectangle for CreateFreeText()
iTextSharp.text.Rectangle rect;
PdfArray rectArray = freeTextAnnot.GetAsArray(PdfName.RECT);
if (rectArray == null)
{
rect = null;
}
else
{
rect = new iTextSharp.text.Rectangle(getFloat(rectArray, 0),
getFloat(rectArray, 1),
getFloat(rectArray, 2),
getFloat(rectArray, 3));
}
//create new annotation
PdfContentByte pcb = new PdfContentByte(pdfStamper.Writer);
PdfAnnotation annot = PdfAnnotation.CreateFreeText(pdfStamper.Writer, rect, "", pcb);
//make array of all possible PdfName keys in dictionary for freeTextAnnot
string pdfNames = "AP,BS,C,CA,CL,CONTENTS,CREATIONDATE,DA,DS,F,IT,LE,M,NM,P,POPUP,Q,RC,RD,ROTATE,SUBJ,SUBTYPE,T,TYPE";
string[] pdfNameArray = pdfNames.Split(',');
//iterate through key array copying key-value pairs to new annotation
foreach (string pdfName in pdfNameArray)
{
//get value for this PdfName
PdfName key = new PdfName(pdfName);
PdfObject obj = freeTextAnnot.Get(key);
//if returned value is null, maybe key is case-sensitive
if (obj == null)
{
//try with first letter only capitalized, e.g. "Contents" instead of "CONTENTS"
string firstCappdfName = char.ToUpper(pdfName[0]) + pdfName.Substring(1);
key = new PdfName(firstCappdfName);
obj = freeTextAnnot.Get(key);
}
//set key-value pair in new annotation
annot.Put(key, obj);
}
//change annotation type to Textbox
annot.Put(PdfName.SUBTYPE, PdfName.FREETEXT);
annot.Put(new PdfName("Subj"), new PdfString("Textbox"));
//set a default blank border
annot.Put(PdfName.BORDER, new PdfBorderArray(0, 0, 0));
return annot;
}
private float getFloat(PdfArray arr, int index)
{
return float.Parse(arr[index].ToString());
}
}
}
EDIT: Parece que parte do problema pode estar na chamada parapdfStamper.AddAnnotation(annot,1)
, Porqueannot
valores de para/Rect
mudança de tecla após esta ligação. Por exemplo.:
antesAddAnnotation()
ligar:
{[2401, 408.56, 2445.64, 693]}
após a chamada:
{[1899, 2445.64, 2183.44, 2401]}
Talvez o código a seguir dePdfStamper.AddAnnotation()
(link para fonte), linhas 1463-1493, é responsável, atualmente estou investigando esta possibilidade:
if (!annot.IsUsed()) {
PdfRectangle rect = (PdfRectangle)annot.Get(PdfName.RECT);
if (rect != null && (rect.Left != 0 || rect.Right != 0 || rect.Top != 0 || rect.Bottom != 0)) {
int rotation = reader.GetPageRotation(pageN);
Rectangle pageSize = reader.GetPageSizeWithRotation(pageN);
switch (rotation) {
case 90:
annot.Put(PdfName.RECT, new PdfRectangle(
pageSize.Top - rect.Top,
rect.Right,
pageSize.Top - rect.Bottom,
rect.Left));
break;
case 180:
annot.Put(PdfName.RECT, new PdfRectangle(
pageSize.Right - rect.Left,
pageSize.Top - rect.Bottom,
pageSize.Right - rect.Right,
pageSize.Top - rect.Top));
break;
case 270:
annot.Put(PdfName.RECT, new PdfRectangle(
rect.Bottom,
pageSize.Right - rect.Left,
rect.Top,
pageSize.Right - rect.Right));
break;
}
}
}
}