web-dev-qa-db-ja.com

テキストコンテンツを画像に変換する

Javaテキストコンテンツを画像ファイルに変換できるライブラリがありますか? ImageMagick (この場合はJMagick)しか知りませんが、インストールしたくない外部バイナリ(私のアプリはTomcatサーバーに.warファイルとしてデプロイされるため、Java以外の依存関係は必要ありません)。

たとえば、文字列「Hello」から、次の簡単な画像を生成したいと思います。

Basic image from string "hello"

25
jarandaf

Graphics 2D APIは、必要なものを達成できるはずです。いくつかの複雑なテキスト処理機能も備えています。

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();
        }

    }

}

また、チェックアウト 書き込み/保存と画像

警告IEではなくChromeバージョン70.0.3538.77で表示できることを確認するためにのみ、これを使用して90k PNG画像を生成しました。

上記のコードは私のためにうまく機能します(テキストの色をWHITEに変更したので、クロムで見ることができました)

Running in Chrome

Chrome 70.0.3538.77 on Mac OS Mojave 10.14でJava 10.0.2を使用していました。結果の画像は4778x2411ピクセルでした...

更新しました...

On IEそれは白に黒ですが、on Chromeそれは黒に黒です。それでも背景を白に設定します。

ブラウザが異なるデフォルトの背景を使用しているため、あなたは私に言っているのは、透明なPNGが異なるブラウザで異なるように表示されることです...なぜあなたはこれに驚いていますか?

元のソリューションでは、意図的に透明ベースの画像を使用していました。これは、アルファ(A)ベースのRGBカラーモデルを適用している画像を作成するときにBufferedImage.TYPE_INT_ARGBを使用することで明らかです。

G2d.setBackground(Color.white)があるため、これは予想外です。

いいえ、実際には、setBackgroundが実際に行うことと、その使用方法を理解している場合にのみ、完全に予期されます。

JavaDocs から

Graphics2Dコンテキストの背景色を設定します。背景色は、領域のクリアに使用されます。コンポーネント用にGraphics2Dが構築されると、背景色はコンポーネントから継承されます。 Graphics2Dコンテキストで背景色を設定しても、コンポーネントの背景色ではなく、後続のclearRect呼び出しのみに影響します。コンポーネントの背景を変更するには、コンポーネントの適切なメソッドを使用します。

物の「音」から、背景色が塗りつぶされた不透明な画像が必要です。したがって、もう一度、 JavaDocs に進み、少し読むとBufferedImage.TYPE_INT_RGBに導かれ、アルファチャネルが削除されますが、それでも背景を埋める必要があります。画像の。

このため、Graphics2D#setColorGraphics2D#fillRectを使用しますが、それが機能するからです。

だから、あなたは上のように見えるかもしれない上記の修正版で終わるでしょう...

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();
}

「jpg」に変更すると、IEとChromeの両方で黒い背景にオレンジ/ピンクのテキストが表示されます

さて、これはImageIOのよく知られた、悲しいことによくある問題/バグに関連しています。これは、アルファチャネルをサポートしないJPGに透明なカラーモデルのアルファチャネルを適用しようとします。

ImageIO.write jpgファイルを使用した問題:ピンクの背景 を参照してください。

ただし、基本的な解決策は、アルファチャネルをサポートするPNGを使用するか、不透明な画像を使用することです。

だから、このすべての長短はそうです。問題は元の答えではなく、ImageIOBufferedImageGraphics、AWTライブラリ、ChromeまたはIE 、ただし、これらのAPI(および例)がどのように機能するかについて理解していない場合。

62
MadProgrammer

外部ライブラリなしで、以下を実行します:

  1. テキストサイズをピクセル単位で測定します( テキストの測定 を参照)
  2. テキストに適したサイズでJava.awt.image.BufferedImageを作成します
  3. CreateGraphics()メソッドを使用して、BufferedImageのグラフィックスオブジェクトを取得します。
  4. テキストを描く
  5. Javax ImageIOクラスを使用して画像を保存する

編集-リンクを修正

6
Barak Itkin

次のスニペットを検討してください。

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;
}

Java Graphics APIのみを使用して、bufferedimageにレンダリングされたフォントに基づいて画像を作成します。

2
initramfs

以下は、グラフィックコンテンツを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);

    }

}
1
S. M. AMRAN

誰かが複数行のTextImageを必要とする場合に備えて。私はいくつかを作り、それらを表示しました

new ImageIcon(*here the image*)

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;
   }
}
0
gute Fee