Java 将文本内容转换为图像

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18800717/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 11:11:31  来源:igfitidea点击:

Convert text content to Image

javaimagetextfontsawt

提问by jarandaf

Is there out any Java library that allows converting text content to image files? I only know of ImageMagick(JMagick in this case) but I wouldn't like to install any external binaries (my app will be deployed as a .war file in a Tomcat server so I don't want any other dependencies more than Java).

是否有任何允许将文本内容转换为图像文件的 Java 库?我只知道ImageMagick(在这种情况下是 JMagick),但我不想安装任何外部二进制文件(我的应用程序将作为 .war 文件部署在 Tomcat 服务器中,所以我不想要任何其他依赖项而不是 Java) .

For example, from the string "Hello", I would like to generate this simple image:

例如,从字符串“Hello”,我想生成这个简单的图像:

Basic image from string "hello"

来自字符串“hello”的基本图像

采纳答案by MadProgrammer

The Graphics 2DAPI should be capable of achieving what you need. It has some complex text handling capabilities as well.

图形2DAPI应该能够实现你需要什么。它还具有一些复杂的文本处理功能。

enter image description here

在此处输入图片说明

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class TextToGraphics {

    public static void main(String[] args) {
        String text = "Hello";

        /*
           Because font metrics is based on a graphics context, we need to create
           a small, temporary image so we can ascertain the width and height
           of the final image
         */
        BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = img.createGraphics();
        Font font = new Font("Arial", Font.PLAIN, 48);
        g2d.setFont(font);
        FontMetrics fm = g2d.getFontMetrics();
        int width = fm.stringWidth(text);
        int height = fm.getHeight();
        g2d.dispose();

        img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        g2d = img.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
        g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
        g2d.setFont(font);
        fm = g2d.getFontMetrics();
        g2d.setColor(Color.BLACK);
        g2d.drawString(text, 0, fm.getAscent());
        g2d.dispose();
        try {
            ImageIO.write(img, "png", new File("Text.png"));
        } catch (IOException ex) {
            ex.printStackTrace();
        }

    }

}

Also check out Writing/Saving and Image

另请查看写作/保存和图像

WARNING I used this to generate 90k PNG images only to find that they can be viewed in IE but not in Chrome Version 70.0.3538.77

警告我用它来生成 90k PNG 图像只是发现它们可以在 IE 中查看,但不能在 Chrome 版本 70.0.3538.77 中查看

The above code works just fine for me (I changed the text color to WHITEso I could see it in chrome)

上面的代码对我来说很好用(我将文本颜色更改为WHITE这样我可以在 chrome 中看到它)

Running in Chrome

在 Chrome 中运行

I was using Chrome 70.0.3538.77 on Mac OS Mojave 10.14 using Java 10.0.2. The resulting image was 4778x2411 pixels ...

我在使用 Java 10.0.2 的 Mac OS Mojave 10.14 上使用 Chrome 70.0.3538.77。生成的图像为 4778x2411 像素...

Updated...

更新...

On IE that is black on white but on Chrome that is black on black. Yet I set background to white.

在 IE 上是白底黑字,但在 Chrome 上是黑底黑字。但是我将背景设置为白色。

So what you're telling me is, a transparent PNG is been displayed differently on different browsers, because the browsers use different default backgrounds ... why are you surprised by this?

所以你告诉我的是,透明的 PNG 在不同的浏览器上显示不同,因为浏览器使用不同的默认背景......为什么你对此感到惊讶?

The original solution, deliberately, used a transparent based image. This is evident by the use of BufferedImage.TYPE_INT_ARGBwhen creating the image, which is applying a Alpha (A) based RGBcolor model.

最初的解决方案有意使用了基于透明的图像。这BufferedImage.TYPE_INT_ARGB在创建图像时使用 是显而易见的,它应用了A基于Alpha ( ) 的RGB颜色模型。

This is unexpected as there is g2d.setBackground(Color.white).

这是出乎意料的,因为有 g2d.setBackground(Color.white)。

No, actually, it is entirely expected, if only you understood what setBackgroundactually does and how it should be used

不,实际上,这是完全可以预期的,只要您了解setBackground实际的作用以及应该如何使用它

From the JavaDocs

来自JavaDocs

Sets the background color for the Graphics2D context. The background color is used for clearing a region. When a Graphics2D is constructed for a Component, the background color is inherited from the Component. Setting the background color in the Graphics2D context only affects the subsequent clearRect callsand not the background color of the Component. To change the background of the Component, use appropriate methods of the Component.

设置 Graphics2D 上下文的背景颜色。背景色用于清除区域。当为组件构造 Graphics2D 时,背景颜色从组件继承。在 Graphics2D 上下文中设置背景颜色只会影响后续的 clearRect 调用,而不会影响组件的背景颜色。要更改组件的背景,请使用组件的适当方法。

From the "sounds" of things, you want a non-transparent image, with a filled background color. So, once again, it's off to the JavaDocsand a little bit of reading would have lead you to BufferedImage.TYPE_INT_RGB, which removes the Alpha channel, but you'd still have to fill the background of the image.

从事物的“声音”来看,您需要一个带有填充背景颜色的非透明图像。所以,再一次,它是关于JavaDocs 的,稍微阅读一下就会把你带到BufferedImage.TYPE_INT_RGB,它删除了 Alpha 通道,但你仍然需要填充图像的背景。

For this, I'd use Graphics2D#setColorand Graphics2D#fillRect, only because it works.

为此,我会使用Graphics2D#setColorand Graphics2D#fillRect,只是因为它有效。

So, you'd end up with a modified version of the above which might look something like...

所以,你最终会得到上面的修改版本,它可能看起来像......

img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
g2d = img.createGraphics();
//...
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
g2d.setColor(Color.BLACK);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
try {
    ImageIO.write(img, "png", new File("Text.png"));
} catch (IOException ex) {
    ex.printStackTrace();
}

If I change to "jpg" then I get orange/pink text on black background on both IE and Chrome

如果我更改为“jpg”,那么我在 IE 和 Chrome 上都会在黑色背景上看到橙色/粉红色文本

Well, this is related to a well known, and sadly, common issue/bug in ImageIO, which attempts to apply the alpha channel of transparent color models to the JPG, which doesn't support alpha channels.

嗯,这与 中一个众所周知的,可悲的是,常见的问题/错误有关ImageIO,它试图将透明颜色模型的 alpha 通道应用于不支持 alpha 通道的 JPG。

See Issue using ImageIO.write jpg file: pink backgroundfor more details.

有关更多详细信息,请参阅使用 ImageIO.write jpg 文件的问题:粉红色背景

But the basic solution is to either use PNG, which supports alpha channels, or to use a non-transparent image.

但基本的解决方案是要么使用支持 alpha 通道的 PNG,要么使用不透明的图像。

So, the long and short of all this is. The problem is NOT with the original answer, nor is it with ImageIO, BufferedImage, Graphics, the AWT library, Chrome or IE, but with your lack of understanding of how these APIs (and the example) works.

所以,这一切的长短是。这个问题是不是与原来的答案,也不是有ImageIOBufferedImageGraphics,在AWT库,Chrome或IE浏览器,但你缺乏这些API(和示例)是如何工作的理解。

回答by Barak Itkin

Without any external libraries, do the following:

在没有任何外部库的情况下,执行以下操作:

  1. Measure the text size in pixels (see Measuring Text)
  2. Create a java.awt.image.BufferedImage in the right size for the text
  3. Acquire the graphics object for the BufferedImage using the createGraphics() method
  4. Draw the text
  5. Save the image using the javax ImageIO class
  1. 以像素为单位测量文本大小(请参阅测量文本
  2. 为文本创建一个合适大小的 java.awt.image.BufferedImage
  3. 使用 createGraphics() 方法获取 BufferedImage 的图形对象
  4. 绘制文本
  5. 使用 javax ImageIO 类保存图像

Edit - fixed the link

编辑 - 修复了链接

回答by initramfs

Consider the following snippet:

考虑以下片段:

public static final HashMap<RenderingHints.Key, Object> RenderingProperties = new HashMap<>();

static{
    RenderingProperties.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    RenderingProperties.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
    RenderingProperties.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
}

public static BufferedImage textToImage(String Text, Font f, float Size){
    //Derives font to new specified size, can be removed if not necessary.
    f = f.deriveFont(Size);

    FontRenderContext frc = new FontRenderContext(null, true, true);

    //Calculate size of buffered image.
    LineMetrics lm = f.getLineMetrics(Text, frc);

    Rectangle2D r2d = f.getStringBounds(Text, frc);

    BufferedImage img = new BufferedImage((int)Math.ceil(r2d.getWidth()), (int)Math.ceil(r2d.getHeight()), BufferedImage.TYPE_INT_ARGB);

    Graphics2D g2d = img.createGraphics();

    g2d.setRenderingHints(RenderingProperties);

    g2d.setBackground(Color.WHITE);
    g2d.setColor(Color.BLACK);

    g2d.clearRect(0, 0, img.getWidth(), img.getHeight());

    g2d.setFont(f);

    g2d.drawString(Text, 0, lm.getAscent());

    g2d.dispose();

    return img;
}

Uses only the java Graphics API to create a image based on a font rendered onto a bufferedimage.

仅使用 java Graphics API 根据渲染到缓冲图像上的字体创建图像。

回答by S. M. AMRAN

Here is a simple Program to write Graphics contents to pngformat.

这是一个将图形内容写入png格式的简单程序。

import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.io.File;
import javax.imageio.ImageIO;

class ImageWriteEx extends JPanel{

    public void paint(Graphics g){

        Image img = createImageWithText();
        g.drawImage(img, 20, 20, this);

    }

    private static BufferedImage createImageWithText(){ 

        BufferedImage bufferedImage = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB);
        Graphics g = bufferedImage.getGraphics();

        g.drawString("www.stackoverflow.com", 20, 20);
        g.drawString("www.google.com", 20, 40);
        g.drawString("www.facebook.com", 20, 60);
        g.drawString("www.youtube.com", 20, 80);
        g.drawString("www.oracle.com", 20, 1000);

        return bufferedImage;

    }

    public static void main(String[] args){

        try{
            BufferedImage bi = createImageWithText();
            File outputfile = new File("save.png");
            ImageIO.write(bi, "png", outputfile);
        } catch(Exception e){
            e.printStackTrace();
        }

        JFrame frame = new JFrame();
        frame.getContentPane().add(new ImageWriteEx());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300,300);
        frame.setVisible(true);

    }

}

回答by gute Fee

In case someone wants TextImages with several lines. I made some and displayed them with

如果有人想要多行的 TextImages。我做了一些并展示了它们

new ImageIcon(*here the image*)

in JOptionPane (without adding text). That fills the whole JOptionPane nicely. Here the code:

在 JOptionPane 中(不添加文本)。这很好地填充了整个 JOptionPane。这里的代码:

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;

public class TextImage
{
   public static BufferedImage make(String...textrows)
   {
      BufferedImage helperImg = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
      Graphics2D g2d = helperImg.createGraphics();
      Font font = *here some font*;
      g2d.setFont(font);
      FontMetrics fm = g2d.getFontMetrics();
      String longestText = "";
      for(String row: textrows)
      {
         if(row.length()>longestText.length())
         {
            longestText = row;
         }
      }
      int width = fm.stringWidth(longestText);
      int height = fm.getHeight()*textrows.length;
      g2d.dispose();


      BufferedImage finalImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
      g2d = finalImg.createGraphics();
      g2d.setColor(*here some Color*);
      g2d.fillRect(0, 0, width, height);
      g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
      g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
      g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
  g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
      g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
      g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
      g2d.setFont(font);
      fm = g2d.getFontMetrics();
      g2d.setColor(Color.BLACK);
      int y = fm.getAscent();
      for(String row: textrows)
      {
         g2d.drawString(row, 0, y);
         y += fm.getHeight();
      }
      g2d.dispose();
      return finalImg;
   }
}