2016-11-02 5 views
0

У меня проблемы с масштабированием шрифта, чтобы он соответствовал ширине фона. У меня есть высота ширины 1000 и 350, и я пытаюсь масштабировать шрифт, когда он больше фона. Я провел несколько тестов с разными шрифтами, и результаты совпадают, некоторые пропущенные буквы или пробелы в конце текста.Масштаб шрифта Java Graphics2D для заполнения фона

Это код:

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

}

это текст в масштабе "Lorem Ipsum боль сидеть Амет asdkf SDM" и это текст масштабируется с аффинным преобразованием.

output image with font scaled and 'm' letter missed

Я надеюсь, что вы можете мне помочь, спасибо

+0

Причина, по которой она ведет себя, поскольку она обусловлена ​​тем, что выбирает самый близкий размер шрифта pt к ширине. В этом случае 14pt вместо 13pt, но 13pt не будет «заполнять» всю ширину. Возможно, вам придется попробовать создать изображение с текстом, а затем масштабировать изображение. –

ответ

0

вы можете измерить длину строки и проверьте, подходит ли он в содержании.

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

Следующее из моего комментария ранее, вот решение, в котором используется самый близкий размер шрифта к ширине изображения. Текст нарисован на отдельном изображении, изменен, а затем нарисован на конечное изображение. Все это делается в методе createTextImage(). Обратите внимание, что я создал фоновое изображение вместо использования файла.

Результат может быть не таким четким, как хотелось бы, но вы можете поэкспериментировать с различными алгоритмами для изменения размера. Надеюсь, это даст вам отправную точку.

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

Спасибо, это отлично работает для меня, но у меня есть другой вопрос. Если мне нужно сделать то же самое с каким-то изображением в качестве фона, мне придется делать операцию с первым масштабом с прозрачным фоном, не так ли? или есть другой способ? – SheenStvz

+0

@SheenStvz Проверьте этот вопрос http://stackoverflow.com/questions/17271812/save-buffered-image-with-transparent-background –

0

Что мне делать, чтобы соответствовать игровой экран до определенного разрешения, чтобы заранее рассчитать соотношение, после тестирования его максимальная связаны. Что-то вроде этого (я изменил мой фактический код для Вашего случая):

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

В моей игре, я бы сохранить масштаб, как поплавок, а не двойной, чтобы избежать сложных вычислений на ходу, но для вас это всего лишь простой масштабирование, не так ли?

Все, что вам нужно сделать, это изучить код и реализовать его на свой.

Надеюсь, я помог.

Имейте славный день. :)

Смежные вопросы