画布的.MoveUp方法中应使用什么值?

6
以下代码将从一个PDF文件复制所有页面到一个新文件,并在第一页插入一个带红色边框的矩形,上面有一段简短的文本。
如果我不移动它,在顶部会留下一个间隙(这里放大了很多,字体大小只有8):

enter image description here

然而,如果我将矩形向上移动一个经验值 4

    iText.Kernel.Geom.Rectangle pageSize = firstPage.GetCropBox().MoveUp(4);

顶部将有一个完美的匹配:

enter image description here

数值4与字体大小无关。

我不喜欢代码中的“魔法数字”,所以我的问题是:为什么是4?哪个表达式能揭示这个值为4?

这行代码在第一个方法中。第二个方法是使用它的地方,第三个方法是从第一个方法调用的;它只提供了一种样式:

private static void RegisterDocument(PdfDocument pdfDocument, string registration)
{
    // Magic value to close gap between top of page and top of rectangle with the registration.
    const float moveUp = 4F;

    Document document = new Document(pdfDocument, new PageSize(PageSize.A4));
    PdfPage firstPage = document.GetPdfDocument().GetFirstPage();

    Paragraph paragraph = new Paragraph(registration).AddStyle(RegistrationStyle());

    iText.Kernel.Geom.Rectangle pageSize = firstPage.GetCropBox().MoveUp(moveUp);
    LayoutContext layoutContext = new LayoutContext(new LayoutArea(1, pageSize));
    IRenderer renderer = paragraph.CreateRendererSubTree();
    renderer.SetParent(document.GetRenderer()).Layout(layoutContext);

    Canvas canvas = new Canvas(new PdfCanvas(firstPage, true), pageSize);
    canvas.Add(paragraph);          

    document.Close();   
}

public static void RegisterPdf(string sourceFilename, string targetFilename, string registration)
{
    if (registration.Length > 0)
    {
        // Open source and target PDF files.
        PdfDocument sourcePdf = new PdfDocument(new PdfReader(sourceFilename));
        PdfDocument targetPdf = new PdfDocument(new PdfWriter(targetFilename));

        // Copy all pages from source PDF to target PDF.
        sourcePdf.CopyPagesTo(1, sourcePdf.GetNumberOfPages(), targetPdf);

        // Add registration to page 1 of target and save the document.
        RegisterDocument(targetPdf, registration);

        // Close the files.
        sourcePdf.Close();
        targetPdf.Close();
    }
}

private static Style RegistrationStyle()
{
    // Fixed design values for font and rectangle.
    PdfFont font = PdfFontFactory.CreateFont(StandardFonts.HELVETICA);
    const float fontSize = 8F;
    const float rightPadding = 3F;
    TextAlignment textAlignment = TextAlignment.RIGHT;
    iText.Kernel.Colors.Color borderColor = ColorConstants.RED;
    iText.Kernel.Colors.Color fillColor = ColorConstants.WHITE;
    const float borderWidth = 0.7F;

    Style style = new Style()
        .SetFont(font)
        .SetFontSize(fontSize)
        .SetPaddingRight(rightPadding)
        .SetTextAlignment(textAlignment)
        .SetBackgroundColor(fillColor)
        .SetBorder(new SolidBorder(borderColor, borderWidth));

    return style;
}
2个回答

2
你在翻译以下文本:

You wonder

I dislike magic numbers in code so, my question is: Why 4? What expression would reveal this value of 4?

iText 在计算某些实体的布局时,从多个来源检索属性,特别是实体本身和其渲染器。它不仅要求它们提供明确设置的属性,还要求它们提供默认值。

在这种情况下,您可以看到 Paragraph 类的默认 上边距 值起作用:

public override T1 GetDefaultProperty<T1>(int property) {
    switch (property) {
        case Property.LEADING: {
            return (T1)(Object)new Leading(Leading.MULTIPLIED, childElements.Count == 1 && childElements[0] is Image ? 
                1 : 1.35f);
        }

        case Property.FIRST_LINE_INDENT: {
            return (T1)(Object)0f;
        }

        case Property.MARGIN_TOP:
        case Property.MARGIN_BOTTOM: {
            return (T1)(Object)UnitValue.CreatePointValue(4f);
        }

        case Property.TAB_DEFAULT: {
            return (T1)(Object)50f;
        }

        default: {
            return base.GetDefaultProperty<T1>(property);
        }
    }
}
(iText Layout Paragraph 方法)

如果您将段落的上边距设置为0,您可以极大简化您的代码:

public static void RegisterPdfImproved(string sourceFilename, string targetFilename, string registration)
{
    using (PdfDocument pdf = new PdfDocument(new PdfReader(sourceFilename), new PdfWriter(targetFilename)))
    using (Document document = new Document(pdf))
    {
        document.SetMargins(0, 0, 0, 0);
        Paragraph paragraph = new Paragraph(registration)
            .AddStyle(RegistrationStyle())
            .SetMarginTop(0);
        document.Add(paragraph);
    }
}

"现在您可以获得没有任何魔法值的结果"

screen shot


非常尊敬您。这正是我在寻找的答案,而且还有详细的解释和一个大大改进的解决方案 - 我再也不能期望更多了。您作为ITEXT的顾问所做的工作必定受到赞赏。 - Gustav
1
谢谢。其实我对iText中的布局并不是很熟悉,所以我不得不在调试器中逐步查找_4_的来源... ;) - mkl

1

如果不查看您代码的所有细节,就无法确定。它可能取决于任意数量的情况和它们的组合。例如:

  • 您正在使用的PDF库中的默认值
  • 文档中定义的边距

感谢您的关注。这是完整的代码,我已经使用“各种各样”的PDF文档进行了测试(即来自许多不同来源的样本),并且行为是一致的。该库是当前和干净的iText7。 - Gustav
你找对了方向。那是默认的边距设置(请参见上面的答案)。我没想到那个。 - Gustav

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接