在Itext7中使用自定义字体定位文本有些奇怪 [英] Something strange with positioning text with custom font in Itext7

查看:164
本文介绍了在Itext7中使用自定义字体定位文本有些奇怪的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个程序,该程序创建多个pdf文档并将不同的文本放在它们的相同位置. 文本应放在特定区域,如果宽度不合适,则应将其换行.它还具有自定义字体,并且在该区域可能会以不同的方式对齐.它应该与顶部垂直对齐,因为当该区域布置为三行并且我只有一条时,它应该出现在顶部.最后,我需要保持字体大小的领先地位.

I'm working on a program that creates several pdf docs and puts different text in the same location in them. Text should be placed in a particular area and if it doesn't fit it in width it should wrap. It also has a custom font and may be differently aligned in that area. It should be Vertically aligned to Top because when the area is laid out for three lines and I has only one, it should appear on the top. Finally, I need to preserve leading on the level of font-size.

精确定位文本非常重要(例如,我需要"Hello world"中的"H"的左上角肯定显示为0、100).

It is important to be precise in text positioning (e.g. I need an upper left corner of "H" from "Hello world" to appear definitely at 0, 100).

现在,我正在使用

canvas.showTextAligned(paragraph, 0, 300,
                    TextAlignment.valueOf(alignment),
                    VerticalAlignment.TOP);

但是,当我尝试用不同的字体实现它时,它与所需的y = 300有不同的偏移量.此外,偏移量因字体而异.对于Helvetica(每处使用50 fontSize),偏移量约为13 px,对于Oswald而言,偏移量约为17 px,对于SedgwickAveDisplay而言,偏移量为90 px. 我在段落中添加了边框以进行调试,结果变得更加奇怪.

However, when I try to implement it with different fonts it has a various offset from desired y = 300. Moreover, offset differ from font to font. For Helvetica (everywhere 50 fontSize is used) offset is about 13 px, for Oswald about 17 px and for SedgwickAveDisplay it is massive 90 px. I added borders to paragraph for debugging purpose and things become more strange.

Helvetica: SedgwickAveDisplay:

Helvetica: SedgwickAveDisplay:

我创建pdf的代码的完整摘要如下:

The full snippet of my code to create pdf is below:

public byte[] createBadgeInMemory(int i) throws IOException {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    PdfDocument newPdf = new PdfDocument(new PdfWriter(out));
    srcPdf.copyPagesTo(1,1,newPdf);
    PdfPage page = newPdf.getFirstPage();
    PdfCanvas pdfCanvas = new PdfCanvas(page);
    Canvas canvas = new Canvas(pdfCanvas, newPdf, pageSize);

    File defaultFont = new File("src/main/resources/fonts/Helvetica.otf");
    PdfFont font  = PdfFontFactory
            .createFont(fontPath == null ? defaultFont.getAbsolutePath() : fontPath,
                    PdfEncodings.IDENTITY_H, true);

    String value = "Example word";
    Paragraph paragraph = new Paragraph(value);
    float textWidth = font.getWidth("Example", 50);
    paragraph.setWidth(textWidth);
    switch (alignment) {
        case("CENTER"):
            textWidth /= 2;
            break;
        case("RIGHT"):
            break;
        default:
            textWidth = 0;
            break;
    }

    paragraph.setFont(font)
            .setFontSize(fontSize)
            .setFixedLeading(fontSize)
            .setFontColor(new DeviceRgb(red, green, blue))
            .setMargin(0)
            .setPadding(0);
    paragraph.setBorderTop(new DashedBorder(Color.BLACK, 0.5f))
            .setBorderBottom(new DashedBorder(Color.BLACK, 0.5f))
            .setBorderRight(new DashedBorder(Color.BLACK, 0.5f));
    paragraph.setHyphenation(new HyphenationConfig(0,
            "Example".length()));

    canvas.showTextAligned(paragraph,
            0 + textWidth,
            300,
            TextAlignment.valueOf(alignment),
            VerticalAlignment.TOP);

    newPdf.close();

    return out.toByteArray();
}

我还尝试了

I also tried variant from here, but for some reason text inside rectangle cuts out at some point (for instance, if I have area width 100px and text snippet I put in that I know occupies exactly 100 px (with the help of font.getWidth(value)), I have my text cut at nearly 80 px). I also haven't found a way to align text inside a rectangle. This is the result with Rectangle. A solid border is Rectangle border. As you can see it cuts letter "t" in "Redundant". It also should contain "word" on the second line, but it doesn't. I copied code from an example.

我需要你的帮助.我在做什么错或者可能存在另一种使用对齐方式和字体在特定区域中布局文本的方法? 先感谢您.

I need your help. What am I doing wrong or may be there is another way to layout text in particular area with alignment and font? Thank you in advance.

更新21.09.17 还尝试过使用SedgwickAveDisplay 此问题的变体:

Update 21.09.17 Also tried variant from this question with SedgwickAveDisplay:

paragraph.setHorizontalAlignment(HorizontalAlignment.LEFT);
            paragraph.setVerticalAlignment(VerticalAlignment.TOP);
            paragraph.setFixedPosition( 0, 300 - textHeight, "Example".length());
            doc.add(paragraph);

结果与第二个屏幕截图相同.

The result is the same as on the second screenshot.

推荐答案

最后,我创建了一个适用于我的变体.

Finally, I created a variant that worked for me.

pdfCanvas.beginText()
                .setFontAndSize(font, fontSize)
                .setLeading(fontSize)
                .moveText(0, 300);

        numberOfLines = 0;
        sumOfShifts = 0;
        float maxWidth = computeStringWidth("Exaxple");
        String[] words = value.split("\\s");
        StringBuilder line = new StringBuilder();
        line.append(words[0]);
        float spaceWidth = computeStringWidth(" ") ;
        float lineWidth;
        for (int index = 1; index < words.length; index++) {
            String word = words[index];
            float wordWidth = computeStringWidth(word) ;
            lineWidth = computeStringWidth(line.toString()) ;
            if (lineWidth + spaceWidth + wordWidth <= maxWidth) {
                line.append(" ").append(word);
            } else {
                showTextAligned(alignment, pdfCanvas, line.toString(), lineWidth, maxWidth);
                line.delete(0, line.length());
                line.append(word);
            }
        }
        if(line.length() != 0) {
            lineWidth = computeStringWidth(line.toString()) ;
            showTextAligned(alignment, pdfCanvas, line.toString(), lineWidth, maxWidth);
        }

        pdfCanvas.endText();

我使用的是computeStringWidth(String str)

Toolkit.getToolkit().getFontLoader().computeStringWidth(String str, Font font);

来自import com.sun.javafx.tk.Toolkit

和来自javafx.scene.text.Font的字体.我之所以选择它,是因为我在应用程序的其他部分中使用了它.

from import com.sun.javafx.tk.Toolkit with Font from javafx.scene.text.Font. I've chosen it because I use it in other parts of my app.

showTextAligned(...)是我自己的方法,看起来像这样:

showTextAligned(...) is my own method that looks this way:

private void showTextAligned(String alignment,
                                  PdfCanvas pdfCanvas,
                                  String line,
                                  float lineWidth,
                                  float maxWidth) {
        switch (alignment) {
            case "CENTER": {
                float shift = (maxWidth - lineWidth) / 2 - sumOfShifts;
                pdfCanvas.moveText(shift, 0);
                if(numberOfLines == 0) pdfCanvas.showText(line);
                else pdfCanvas.newlineShowText(line);
                numberOfLines++;
                sumOfShifts += shift;
                break;
            }
            case "RIGHT": {
                float shift = maxWidth - lineWidth - sumOfShifts;
                pdfCanvas.moveText(shift, 0);
                if(numberOfLines == 0) pdfCanvas.showText(line);
                else pdfCanvas.newlineShowText(line);
                numberOfLines++;
                sumOfShifts += shift;
                break;
            }
            default:
                pdfCanvas.moveText(0, 0);
                if(numberOfLines == 0) pdfCanvas.showText(line);
                else pdfCanvas.newlineShowText(line);
                numberOfLines++;
                break;
        }
    }

在我的项目中,我使用了变体,因为它使我有机会更深入地处理连字(例如,将来我可以添加功能以避免将介词放在最后一行).

In my project, I used my variant, because it gives me an opportunity to work with hyphenation deeper (for instance, I can in future add functionality to avoid putting prepositions as a last word in the line).

这篇关于在Itext7中使用自定义字体定位文本有些奇怪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆