如何防止替换注释更改位置和文本大小?

锡吉尔

我正在使用iTextSharp将Typewriter注释替换为具有相同内容和位置的Textbox,但是尽管它们中似乎有完全相同的数据,但某些生成的Textbox最终以不同的文本大小位于不同的位置hashMap

问题是,当我在此样本PDF上创建这些新的注释,然后在Adobe Acrobat XI中查看PDF时,新的文本框具有以下问题:

  • 他们已从其原始位置(与箭头相邻)移至页面下部

  • 文字大小已更改

  • 右键单击新的文本框时,没有属性可用

我怀疑所有3个问题都是由于我如何创建新的文本框而导致的一个基本问题。

当我检查for中/Rect键时,它具有与原始相同的矩形坐标,并且顺序相同,因此我不明白为什么某些注释最终会移位。hashMapannotfreeTextAnnot

这是我的代码,用于使用现有的打字机注释数据创建新的文本框。请注意,您需要设置inputPathoutputPath以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;
                            }
                        }
                    }
                }
mkl

原因

您已经找到了更改注释的位置和尺寸的原因:

看来部分问题可能在于对的调用pdfStamper.AddAnnotation(annot,1),因为在此调用之后annot/Rect的值会更改。

... PdfStamper.AddAnnotation()链接到源代码)行1463-1493中的代码负责

确实,如果旋转页面,该代码将更改注释矩形。

这样做的基本原理是,对于旋转的页面,iText尝试减轻将旋转和平移添加到绘制直立文本所需的页面内容的负担,并使坐标系原点位于用户肩膀页面的左下角,以便用户根本不需要处理页面旋转。因此,它对于注释也是如此。

对于页面内容,有一个默认PdfStamper属性,如果一个人明确不希望这种旋转和平移,则可以将其关闭。不幸的是,注释没有类似的属性,它们的位置和大小总是得到“校正”,即旋转和平移。RotateContentstrue

解决方法

由于页面旋转是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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何更改文本区域大小的位置?

如何根据屏幕大小更改文本的位置?

如何防止Webview在方向更改时更改文本大小?

如何更改导航视图菜单项和文本的大小?如何更改菜单之间的空间?

如何使用替换文本更改字体大小

更改列表视图的字体大小和文本大小

如何更改文本的大小

如何在Android中更改列表视图行中单击位置的图像和文本颜色

如何使用 facet_grid 和文本位置更改直方图的颜色?

如何在 R 中更改饼图上的字体系列和文本位置

如何在图像和文本的对齐方式随HTML中的浏览器窗口大小变化的位置旁边放置图像和文本?

如何更改按钮背景和文本颜色?

更改按钮和文本相对于表格的位置

如何更改字幕文本的大小?

如何防止JButton更改大小?

更改散景标签注释的文本大小

如何更改html文本的位置?

div更改其位置如何防止

如何使用QTextDocumentFragment在QTextEdit中设置图像和文本的大小

如何更改微调器的文字大小和文字颜色?

如何为按钮内的图标和文本设置不同的位置?

Swift 在 webview 中加载 html 文件,更改图像大小、字体和文本大小

如何防止Excel自动更改文本颜色

在散景图中使用滑块动态更改注释的坐标和文本

悬停时如何同时更改svg和文本的颜色?

SweetAlert2 - 如何更改标题和文本颜色?

如何在Yakuake中更改背景和文本颜色?

如何在悬停时更改图标和文本的颜色?

悬停时如何使图标和文本同时更改颜色?