2016-11-02 4 views
0

Ich habe Probleme mit der Skalierung der Schriftart, um in die Hintergrundbreite zu passen. Ich habe einen Hintergrund mit einer Höhe von 1000 und einer Breite von 350, und ich versuche, die Schrift zu skalieren, wenn sie größer als der Hintergrund ist. Ich habe mehrere Tests mit verschiedenen Schriften gemacht und die Ergebnisse sind gleich, einige Buchstaben fehlen oder Leerzeichen am Ende des Textes.Java Graphics2D Schriftart zum Ausfüllen des Hintergrunds

Dies ist der Code:

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

public class PruebaStackoverflow { 

public static void main(String[] args) { 

    String titleText = null; 
    Graphics2D g2D = null; 
    Font testFont = null; 

    File imageGrayBackgroundFile = new File(
      "resources/pruebaAltaResolucionGris.png"); 
    File destinationImageGray = new File("resources/outputTextGray.png"); 

    BufferedImage background = readImage(imageGrayBackgroundFile); 

    titleText = "Lorem ipsum dolor sit amet asdkf sdm"; 
    testFont = new Font("Lucida Console", Font.PLAIN, 50); 

    g2D = background.createGraphics(); 
    g2D.setColor(Color.BLACK); 
    g2D.setFont(testFont); 

    g2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, 
      RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 

    g2D = scaleFontFromFontMetrics(g2D, background, titleText); 

    g2D.drawString(titleText, 0, 150); 
    g2D.dispose(); 

    writeImage(destinationImageGray, background); 

} 

private static Graphics2D scaleFontFromFontMetrics(Graphics2D g2D, 
     BufferedImage backgroundImage, String text) { 
    double xScale; 
    double yScale; 
    double scale; 
    Integer backgroundWidth = null; 
    Integer backgroundHeight = null; 
    Integer textWidth = null; 
    Integer textHeigth = null; 

    backgroundWidth = backgroundImage.getWidth(); 
    backgroundHeight = backgroundImage.getHeight(); 

    Font f = g2D.getFont(); 
    FontMetrics fm = g2D.getFontMetrics(f); 

    textWidth = fm.stringWidth(text); 
    textHeigth = fm.getHeight(); 

    xScale = backgroundWidth/(double) textWidth; 
    yScale = backgroundHeight/(double) textHeigth; 

    if (xScale > yScale) { 
     scale = yScale; 
    } else { 
     scale = xScale; 
    } 

    g2D.setFont(f.deriveFont(AffineTransform.getScaleInstance(scale, scale))); 

    return g2D; 
} 

private static BufferedImage readImage(File sourceImage) { 
    BufferedImage bufferedImage = null; 
    try { 
     bufferedImage = ImageIO.read(sourceImage); 
    } catch (IOException e1) { 
     e1.printStackTrace(); 
    } 
    return bufferedImage; 
} 

private static void writeImage(File destinationImage, 
     BufferedImage bufferedImage) { 
    try { 
     ImageIO.write(bufferedImage, "png", destinationImage); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    System.out.println("Image Saved"); 
} 

}

dies ist der Text "Lorem ipsum dolor sit amet asdkf sdm" und dies wird Text skaliert mit affiner Transformation zu skalieren.

output image with font scaled and 'm' letter missed

Ich hoffe, dass Sie mir helfen können, dank

+0

Der Grund dafür, dass es so verhält, wie es ist, liegt daran, dass es die engste Schriftgröße zur Breite auswählt. In diesem Fall wird 14pt statt 13pt, aber 13pt nicht die gesamte Breite "füllen". Möglicherweise müssen Sie versuchen, ein Bild mit dem Text zu erstellen und dann das Bild zu skalieren. –

Antwort

0

Sie die Länge eines Strings messen und überprüfen, ob es in Ihrem Inhalt passt.

int lengthInPixel = graphics.getFontMetrics().stringWidth("Lorem ipsum dolor sit amet asdkf sdm") 
0

Folgend auf meinen Kommentar früher, hier ist eine Lösung, wo die engste Schriftgröße zur Bildbreite verwendet wird. Der Text wird in ein separates Bild gezeichnet, in der Größe angepasst und dann zum endgültigen Bild gezogen. Dies alles geschieht in der createTextImage() Methode. Hinweis: Ich habe ein Hintergrundbild erstellt, anstatt eine Datei zu verwenden.

Das Ergebnis ist möglicherweise nicht so klar wie gewünscht, aber Sie könnten mit verschiedenen Algorithmen zur Größenänderung experimentieren. Hoffentlich gibt es dir einen Startpunkt.

import java.awt.Color; 
import java.awt.Font; 
import java.awt.Graphics2D; 
import java.awt.Image; 
import java.awt.geom.AffineTransform; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 
import javax.imageio.ImageIO; 

public class Main { 

    public static void main(String[] args) { 
     String titleText = "Lorem ipsum dolor sit amet asdkf sdm"; 
     Font initialFont = new Font("Lucida Console", Font.PLAIN, 50); 
     BufferedImage textImg = createTextImage(titleText, 350, 1000, 150, 
       initialFont, Color.BLACK, Color.GRAY); 
     writeImage(new File("outputTextGray.png"), textImg); 
    } 

    private static BufferedImage createTextImage(String text, int targetWidth, 
      int targetHeight, int textYOffset, Font font, Color textColor, Color bgColor) { 

     // The final image 
     BufferedImage finalImg = createBackgroundImg(targetWidth, targetHeight, bgColor); 
     Graphics2D finalImgG = finalImg.createGraphics();   
     Font closestFont = scaleFont(finalImg, font, text); 
     finalImgG.setFont(closestFont); 

     // Create new image to fit text 
     int textWidth = finalImgG.getFontMetrics().stringWidth(text); 
     int textHeight = finalImgG.getFontMetrics().getHeight(); 
     BufferedImage textImg = createBackgroundImg(textWidth, textHeight * 2, bgColor); 

     // Draw text 
     Graphics2D textImgG = textImg.createGraphics(); 
     textImgG.setFont(closestFont); 
     textImgG.setColor(textColor); 
     textImgG.drawString(text, 0, textHeight); 

     // Scale text image 
     double scale = getScale(textImg.getWidth(), textImg.getHeight(), 
       targetWidth, targetHeight); 
     Image resized = textImg.getScaledInstance((int) (textImg.getWidth() * scale), 
       (int) (textImg.getHeight() * scale), Image.SCALE_SMOOTH); 

     // Draw text image onto final image 
     finalImgG.drawImage(resized, 0, textYOffset, null); 
     return finalImg; 
    } 

    private static Font scaleFont(BufferedImage img, Font font, String text) { 
     Graphics2D g2D = img.createGraphics(); 
     g2D.setFont(font); 
     double scale = getScale(g2D.getFontMetrics().stringWidth(text), 
       g2D.getFontMetrics().getHeight(), img.getWidth(), 
       img.getHeight()); 
     return g2D.getFont().deriveFont(AffineTransform.getScaleInstance(scale, scale)); 
    } 

    private static double getScale(int width, int height, int targetWidth, int targetHeight) { 
     assert width > 0 && height > 0 : "width and height must be > 0"; 
     double scaleX = (double) targetWidth/width; 
     double scaleY = (double) targetHeight/height; 
     return scaleX > scaleY ? scaleY : scaleX; 
    } 

    private static BufferedImage createBackgroundImg(int width, int height, Color color) { 
     BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 
     for (int x = 0; x < bufferedImage.getWidth(); x++) { 
      for (int y = 0; y < bufferedImage.getHeight(); y++) { 
       bufferedImage.setRGB(x, y, color.getRGB()); 
      } 
     } 
     return bufferedImage; 
    } 

    private static void writeImage(File destinationImage, 
      BufferedImage bufferedImage) { 
     try { 
      ImageIO.write(bufferedImage, "png", destinationImage); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     System.out.println("Image Saved"); 
    } 
} 
+0

Danke, es funktioniert gut für mich, aber ich habe eine andere Frage. Wenn ich dasselbe mit einem Bild als Hintergrund machen müsste, müsste ich die erste Skalierung mit transparentem Hintergrund machen, oder? oder gibt es einen anderen Weg? – SheenStvz

+0

@SheenStvz Überprüfen Sie diese Frage http://stackoverflow.com/questions/17271812/save-buffered-image-with-transparent-background –

0

Etwas, was ich tun, ein Spiel-Bildschirm auf eine bestimmte Auflösung zu passen, ist das Verhältnis im Voraus zu berechnen, nachdem ihr Maximum gebunden zu testen. So etwas wie dies (ich änderte meinen eigentlichen Code, um Ihren Fall):

double calculateScaling(BufferedImage image, String text, Font font){ 

    //These are final to avoid accidental mending, since they are 
    //the base for our calculations. 
    //Belive me, it took me a while to debug the 
    //scale calculation when I made this for my games :P 

    /** 
    * imageWidth and imageHeight are the bounds 
    */ 
    final int imageWidth = image.getWidth(); 
    final int imageHeight = image.getHeight(); 

    Graphics2D g2 = image.createGraphics(); 
    FontMetrics fm = g2.getFontMetrics(font); 


    /** 
    * requestedStringWidthSize e requestedStringHeightSize are the measures needed 
    * to draw the text WITHOUT resizing. 
    */ 
    final int requestedStringWidthSize = fm.stringWidth(text); 
    final int requestedStringHeightSize = fm.getHeight(); 


    double stringHeightSizeToUse = imageHeight; 
    double stringWidthSizeToUse; 

    double scale = stringHeightSizeToUse/requestedStringHeightSize; 
    stringWidthSizeToUse = scale*requestedStringWidthSize; 

    /** 
    * Checking if fill in height makes the text go out of bound in width, 
    * if it does, it rescalates it to size it to maximum width. 
    */ 
    if(imageWidth < ((int)(Math.rint(stringWidthSizeToUse)))) { 
     stringWidthSizeToUse = imageWidth; 

     scale = stringWidthSizeToUse/requestedStringWidthSize; 
     //stringHeightSizeToUse = scale*requestedStringHeightSize; 
    } 

    g2.dispose(); //we created this to use fontmetrics, now we don't need it. 

    return scale; 
} 

In meinem Spiel, ich würde die Waage als Schwimmer speichern, anstatt der doppelten schwere Berechnungen auf der Flucht zu vermeiden, aber für Sie, es ist nur ein einfaches Skalierung, oder?

Alles, was Sie jetzt tun müssen, ist, den Code zu studieren und ihn in Ihren zu implementieren.

Ich hoffe, ich habe geholfen.

Einen schönen Tag noch. :)

Verwandte Themen