将多行多页格式化文本渲染为BufferedImage(不在Android中)

时间:2013-12-20 11:03:45

标签: java text bufferedimage

我只需要实现PNG图像的创建,渲染出文本文件的内容。在线搜索我发现了一些使用Android的实现,但没有使用标准Java的多行文本的完整示例,因此我认为值得在此处发布我的解决方案。

要求是:

获取可能任意大小的字符串,并使用格式正确的段落将其渲染为适合PNG图像,将字符串和段落正确分割。如果渲染的文档不适合一个页面,则生成多个BufferedImage,每个页面一个。

1 个答案:

答案 0 :(得分:0)

我在Java文档中找到了一些示例代码,用于呈现一个段落,在此基础上我做了以下内容:

private static final Font FONT = new Font("Serif", Font.PLAIN, 14);
private static final float PARAGRAPH_BREAK = 10;
private static final float MARGIN = 20;

private Graphics2D setupGraphics(BufferedImage img) {
    Graphics2D g2d = img.createGraphics();
    g2d.setFont(FONT);
    g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
    g2d.setColor(Color.BLACK);
    return g2d;
}

private List<BufferedImage> renderText(String str, int width, int height) {
    String[] paragraphs = str.split("\n");

    List<BufferedImage> images = new ArrayList<>();

    BufferedImage img = new BufferedImage(width, 
            height, 
            BufferedImage.TYPE_3BYTE_BGR);
    images.add(img);
    Graphics2D g2d = setupGraphics(img);

    float drawPosY = 0;

    for (int paragraph=0;paragraph<paragraphs.length;paragraph++) {

        drawPosY += PARAGRAPH_BREAK;

        AttributedString attStr = new AttributedString(paragraphs[paragraph]);
        AttributedCharacterIterator it = attStr.getIterator();
        LineBreakMeasurer measurer = new LineBreakMeasurer(it, g2d.getFontRenderContext());
        measurer.setPosition(it.getBeginIndex());

        while (measurer.getPosition() < it.getEndIndex()) {
            TextLayout layout = measurer.nextLayout(img.getWidth()-MARGIN*2);

            if (drawPosY > img.getHeight() - layout.getAscent() - layout.getDescent() - layout.getLeading()) {
                drawPosY = 0;
                img = new BufferedImage((int)(
                        width, 
                        height, 
                        BufferedImage.TYPE_3BYTE_BGR);
                images.add(img);
                g2d.dispose();
                g2d = setupGraphics(img);
            }

            drawPosY += layout.getAscent();

            layout.draw(g2d, MARGIN, drawPosY);

            drawPosY += layout.getDescent()+layout.getLeading();
        }
    }
    g2d.dispose();

    return images;
}

在我的情况下,我需要在内存中生成PNG,所以我按如下方式创建了它:

    try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
        ImageIO.write(output, "png", baos);
        ret.setImageData(baos.toByteArray());
    } catch (IOException ex) {
        Logger.getLogger(ImageGenerationService.class.getName()).log(Level.SEVERE, null, ex);
        return null;
    }

本节中几乎完全相同的代码会导致ImageIO写出不同格式的文件(例如“jpg”而不是“png”)或将图像写入文件(使用FileOutputStream代替{{1 }})。

我希望这可以帮助其他人解决同样的问题。