我正在使用iTextSharp将Typewriter注释替换为具有相同内容和位置的Textbox,但是尽管它们中似乎有完全相同的数据,但某些生成的Textbox最终以不同的文本大小位于不同的位置hashMap
。
问题是,当我在此样本PDF上创建这些新的注释,然后在Adobe Acrobat XI中查看PDF时,新的文本框具有以下问题:
他们已从其原始位置(与箭头相邻)移至页面下部
文字大小已更改
右键单击新的文本框时,没有属性可用
我怀疑所有3个问题都是由于我如何创建新的文本框而导致的一个基本问题。
当我检查for中的/Rect
键时,它具有与原始键相同的矩形坐标,并且顺序相同,因此我不明白为什么某些注释最终会移位。hashMap
annot
freeTextAnnot
这是我的代码,用于使用现有的打字机注释数据创建新的文本框。请注意,您需要设置inputPath
并outputPath
以PDF和它的目标路径的实际位置:
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());
}
}
}
编辑:似乎部分问题可能在对的调用中pdfStamper.AddAnnotation(annot,1)
,因为在进行此调用后annot
,的/Rect
键值更改了。例如:
AddAnnotation()
致电前:
{[2401, 408.56, 2445.64, 693]}
通话后:
{[1899, 2445.64, 2183.44, 2401]}
因此,也许下面的代码PdfStamper.AddAnnotation()
(从链接到源代码)第1463-1493行负责,我目前正在研究这种可能性:
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;
}
}
}
}
您已经找到了更改注释的位置和尺寸的原因:
看来部分问题可能在于对的调用
pdfStamper.AddAnnotation(annot,1)
,因为在此调用之后annot
,/Rect
键的值会更改。...
PdfStamper.AddAnnotation()
(从链接到源代码)行1463-1493中的代码负责
确实,如果旋转页面,该代码将更改注释矩形。
这样做的基本原理是,对于旋转的页面,iText尝试减轻将旋转和平移添加到绘制直立文本所需的页面内容的负担,并使坐标系原点位于用户肩膀页面的左下角,以便用户根本不需要处理页面旋转。因此,它对于注释也是如此。
对于页面内容,有一个默认的PdfStamper
属性,如果一个人明确不希望这种旋转和平移,则可以将其关闭。不幸的是,注释没有类似的属性,它们的位置和大小总是得到“校正”,即旋转和平移。RotateContents
true
由于页面旋转是iText旋转和转换矩形的触发条件,因此可以在操作注释之前简单地删除页面旋转并在以后再次添加它:
PdfDictionary pageDict = pdfReader.GetPageN(1);
// hide the page rotation
PdfNumber rotation = pageDict.GetAsNumber(PdfName.ROTATE);
pageDict.Remove(PdfName.ROTATE);
//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--)
{
...
}
// add page rotation again if required
if (rotation != null)
pageDict.Put(PdfName.ROTATE, rotation);
pdfStamper.Close();
通过此添加,注释将保留在原位。
您还观察到:
右键单击新的文本框时,没有属性可用
这是因为您尚未更改Intent(IT)条目,因此它们仍包含FreeTextTypewriter,因此Adobe Reader不确定是哪种对象,因此不提供“属性”对话框。如果您还更改了意图:
//change annotation type to Textbox
annot.Put(PdfName.SUBTYPE, PdfName.FREETEXT);
annot.Put(new PdfName("IT"), PdfName.FREETEXT); // <======
annot.Put(new PdfName("Subj"), new PdfString("Textbox"));
您将看到“属性”对话框。
您的方法getFloat
首先导致我的坐标系发生最奇怪的变化,因为我的语言环境不使用点作为小数点分隔符。
我将其更改为此,使其与语言环境无关:
private float getFloat(PdfArray arr, int index)
{
return arr.GetAsNumber(index).FloatValue;
}
是否有特定原因为什么需要替换原始注释而不是简单地对其进行编辑?例如:
public void AlternativeReplaceFreetextByTextbox(string InputPath, string OutputPath)
{
PdfName IT = new PdfName("IT");
PdfName FREETEXTTYPEWRITER = new PdfName("FreeTextTypewriter");
using (PdfReader Reader = new PdfReader(InputPath))
{
PdfDictionary Page = Reader.GetPageN(1);
PdfArray Annotations = Page.GetAsArray(PdfName.ANNOTS);
foreach (PdfObject Object in Annotations)
{
PdfDictionary Annotation = (PdfDictionary)PdfReader.GetPdfObject(Object);
PdfName Intent = Annotation.GetAsName(IT);
if (FREETEXTTYPEWRITER.Equals(Intent))
{
// change annotation type to Textbox
Annotation.Put(IT, PdfName.FREETEXT);
}
}
using (PdfStamper Stamper = new PdfStamper(Reader, new FileStream(OutputPath, FileMode.Create)))
{ }
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句