我只需要实现PNG图像的创建,渲染出文本文件的内容。在线搜索我发现了一些使用Android的实现,但没有使用标准Java的多行文本的完整示例,因此我认为值得在此处发布我的解决方案。
要求是:
获取可能任意大小的字符串,并使用格式正确的段落将其渲染为适合PNG图像,将字符串和段落正确分割。如果渲染的文档不适合一个页面,则生成多个BufferedImage
,每个页面一个。
答案 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 }})。
我希望这可以帮助其他人解决同样的问题。