web-dev-qa-db-fra.com

Convertir du contenu texte en image

Existe-t-il une bibliothèque Java permettant de convertir le contenu texte en fichiers image? Je ne connais que ImageMagick (JMagick dans ce cas) mais je ne voudrais pas installer tous les binaires externes (mon application sera déployée en tant que fichier .war sur un serveur Tomcat, donc je ne veux pas d'autres dépendances que Java).

Par exemple, à partir de la chaîne "Bonjour", je voudrais générer cette image simple:

Basic image from string "hello"

25
jarandaf

L'API Graphics 2D devrait être capable de réaliser ce dont vous avez besoin. Il possède également des capacités de gestion de texte complexes.

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

    }

}

Consultez également Écriture/Enregistrement et Image

AVERTISSEMENT J'ai utilisé cela pour générer des images PNG 90k uniquement pour découvrir qu'elles peuvent être affichées dans IE mais pas dans Chrome Version 70.0.3538.77

Le code ci-dessus fonctionne très bien pour moi (j'ai changé la couleur du texte en WHITE pour que je puisse le voir en chrome)

Running in Chrome

J'utilisais Chrome 70.0.3538.77 sur Mac OS Mojave 10.14 en utilisant Java 10.0.2. L'image résultante était de 4778x2411 pixels ...

Mis à jour...

Sur IE qui est noir sur blanc mais sur Chrome qui est noir sur noir. Pourtant, je mets l'arrière-plan sur blanc).

Donc, ce que vous me dites, un PNG transparent est affiché différemment sur différents navigateurs, car les navigateurs utilisent des arrière-plans par défaut différents ... pourquoi êtes-vous surpris par cela?

La solution originale a délibérément utilisé une image transparente. Cela est évident par l'utilisation de BufferedImage.TYPE_INT_ARGB lors de la création de l'image, qui applique un modèle de couleur basé sur Alpha (A) RGB.

Ceci est inattendu car il existe g2d.setBackground (Color.white).

Non, en fait, c'est tout à fait prévu, si seulement vous comprenez ce que setBackground fait réellement et comment il doit être utilisé

Depuis JavaDocs

Définit la couleur d'arrière-plan du contexte Graphics2D. La couleur d'arrière-plan est utilisée pour effacer une région . Lorsqu'un Graphics2D est construit pour un composant, la couleur d'arrière-plan est héritée du composant. La définition de la couleur d'arrière-plan dans le contexte Graphics2D n'affecte que les appels clearRect suivants et non la couleur d'arrière-plan du composant. Pour modifier l'arrière-plan du composant, utilisez les méthodes appropriées du composant.

A partir des "sons" des choses, vous voulez une image non transparente, avec une couleur de fond pleine. Donc, encore une fois, c'est parti pour JavaDocs et un peu de lecture vous aurait conduit à BufferedImage.TYPE_INT_RGB, ce qui supprime le canal Alpha, mais vous devrez toujours remplir l'arrière-plan de l'image.

Pour cela, j'utiliserais Graphics2D#setColor et Graphics2D#fillRect, uniquement parce que cela fonctionne.

Donc, vous vous retrouveriez avec une version modifiée de ce qui précède qui pourrait ressembler à quelque chose comme ...

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

Si je passe à "jpg", je reçois du texte orange/rose sur fond noir sur les deux IE et Chrome

Eh bien, cela est lié à un problème/bogue bien connu et malheureusement commun à ImageIO, qui tente d'appliquer le canal alpha des modèles de couleur transparents au JPG, qui ne prend pas en charge les canaux alpha.

Voir Problème avec le fichier jpg ImageIO.write: fond rose pour plus de détails.

Mais la solution de base consiste à utiliser PNG, qui prend en charge les canaux alpha, ou à utiliser une image non transparente.

Donc, le long et le court de tout cela est. Le problème N'EST PAS avec la réponse d'origine, ni avec ImageIO, BufferedImage, Graphics, la bibliothèque AWT, Chrome ou IE , mais avec votre manque de compréhension du fonctionnement de ces API (et de l'exemple).

62
MadProgrammer

Sans aucune bibliothèque externe, procédez comme suit:

  1. Mesurez la taille du texte en pixels (voir Mesure du texte )
  2. Créez une image Java.awt.image.BufferedImage à la bonne taille pour le texte
  3. Acquérir l'objet graphique pour BufferedImage à l'aide de la méthode createGraphics ()
  4. Dessinez le texte
  5. Enregistrez l'image à l'aide de la classe javax ImageIO

Modifier - corrigé le lien

6
Barak Itkin

Considérez l'extrait de code suivant:

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

Utilise uniquement l'API graphique Java Graphics) pour créer une image basée sur une police rendue sur une image tamponnée.

2
initramfs

Voici un programme simple pour écrire du contenu graphique au format 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

Au cas où quelqu'un voudrait TextImages avec plusieurs lignes. J'en ai fait et je les ai affichées avec

new ImageIcon(*here the image*)

dans JOptionPane (sans ajouter de texte). Cela remplit bien tout le JOptionPane. Voici le code:

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