Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

Results 1 to 7 of 7

Thread: Is it wrong to create BufferedImage for using FontMetrics only?

  1. #1
    Junior Member
    Join Date
    Nov 2012
    Posts
    11
    Thanks
    3
    Thanked 1 Time in 1 Post

    Default Is it wrong to create BufferedImage for using FontMetrics only?

    Hi All,

    I am hoping this is the right subforum as I could not find a 'Graphics' subforum.

    I have a question regarding initiating a BufferedImage just for the use of a FontMetrics. To be short: how dirty is the code below? But let me explain the problem, first.

    I want to do a couple of things, one of them is to draw a rectangle as a background behind a couple of strings. As the string can differ in length, so need the rectangle. Also I do some other calculations based on the strings width. For instance, the position where every string needs to be drawn.

    I use FontMetrics to get the width of the string(s). To use FontMetrics you need a Graphics variable, if I understood correctly. Therefore, I assume the most logical place to use FontMetrics, would be the method is which you paint. However, in my code a lot (100+) of calculations needs to be done based on this string widths. As all calculations needs to be done once, I would like to do the calculations only once (using the constructor) instead of calculating it every ‘repaint’. I assume this would (drastically) boost the performance of my game loop.

    This led me to another problem. I call the constructor (/ create the object) in different methods, none being a paintable method. So, when I call the constructor I do not have a Graphics variable. Can anyone tell me how wrong and dirty it is to temporarily create a (new) bufferedImage with a Graphics variable, please? If this implementation is (horribly) wrong, can you tell me what the better solution is, please?

    Below I have an image of my architecture, just to clarify if needed.

    I created a (simplified) workable demo to show how I ‘dirty’ implemented a new BufferedImage.

    import java.awt.Font;
    import java.awt.FontMetrics;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.image.BufferedImage;
     
    public class MetricsDemo {
     
    	MetricsDemo() {
    		Font contentFont = new Font("Arial", Font.PLAIN, 16);
     
    		String messageText = "A text just for demonstration purposes.";
     
    		BufferedImage image = new BufferedImage(1, 1,
    				BufferedImage.TYPE_INT_RGB);
    		Graphics gTemp = image.getGraphics();
    		FontMetrics metrics = gTemp.getFontMetrics(contentFont);
    		int stringLength = metrics.stringWidth(messageText);
    		int stringHeight = metrics.getHeight();
     
    		System.out.printf("Text: %s \nLenght: %s, height: %s \n", messageText,
    				stringLength, stringHeight);
    	}
     
    	public void render(Graphics2D g) {
    		// In my real code this method is later called to draw the MetricsDemo.
    	}
     
    	public static void main(String[] args) {
    		new MetricsDemo();
    	}
     
    }

    Below the shortened architecture of my program. The Launcher class will create a GamePanel, which gets to the LevelState class via the GameStateManager. The LevelState uses multiple GameModes to draw specific objects, entities, menus, etc.. At some point in the PlanMode class I initiate the dPane which then does its calculations in its constructor.
    After PlanMode initiated the dPane it will call the render method of the dPane. The dPane is temporarily, it will be ‘de-initiated’ when the user has given his input.

    Attached Images Attached Images


  2. #2
    Crazy Cat Lady KevinWorkman's Avatar
    Join Date
    Oct 2010
    Location
    Washington, DC
    Posts
    5,424
    My Mood
    Hungover
    Thanks
    144
    Thanked 636 Times in 540 Posts

    Default Re: Is it wrong to create BufferedImage for using FontMetrics only?

    Can't you just cache the values the first time you paint, and then not recalculate them after that?

    This assumes that the font of the component, or the way it's being drawn, won't change.
    Useful links: How to Ask Questions the Smart Way | Use Code Tags | Java Tutorials
    Static Void Games - Play indie games, learn from game tutorials and source code, upload your own games!

  3. #3
    Junior Member
    Join Date
    Nov 2012
    Posts
    11
    Thanks
    3
    Thanked 1 Time in 1 Post

    Default Re: Is it wrong to create BufferedImage for using FontMetrics only?

    All the calculations needs to be done once and then they will not change. So, I think your solution will work. Thank you for this answer!
    Never thought of that (as I am a self taught java 'developper').

    I looked on Google on how to implement this. Is there a cache class in Java or should I built it from the start? If so, could anyone give my a little guidance on the direction I need to take, please?

  4. #4
    Crazy Cat Lady KevinWorkman's Avatar
    Join Date
    Oct 2010
    Location
    Washington, DC
    Posts
    5,424
    My Mood
    Hungover
    Thanks
    144
    Thanked 636 Times in 540 Posts

    Default Re: Is it wrong to create BufferedImage for using FontMetrics only?

    You're thinking too hard. When I said "cache", all I meant was "save the value to a variable".
    Useful links: How to Ask Questions the Smart Way | Use Code Tags | Java Tutorials
    Static Void Games - Play indie games, learn from game tutorials and source code, upload your own games!

  5. #5
    Junior Member
    Join Date
    Nov 2012
    Posts
    11
    Thanks
    3
    Thanked 1 Time in 1 Post

    Default Re: Is it wrong to create BufferedImage for using FontMetrics only?

    Quote Originally Posted by KevinWorkman View Post
    You're thinking too hard. When I said "cache", all I meant was "save the value to a variable".
    And there goes everybody's respect of me as good Java 'developper'. Sorry, enthusiastic but noobish of me to 'forget' this. But, then I do not know if I understand you, correctly. You are saying to calculate in the render method and to store the values then? If so, would that not cause a lot of drag?

    To store calculations in a variable, you need to do the calculations. As in, you can only store the value 3 once you calculated 1 + 2. Well, my '1 + 2' calculation depends on the strings width. So, I can only calculate '3' by using a FontMetrics. I can use a BufferedImage in the constructor (see first post). Advantage: constructor is called once, so calculations are done once. Disadvantage: I need to create a BufferedImage doing nothing, just to have the possibility to create a FontMetrics variable.

    I can also use a FontMetrics in the render method, but this method gets called in my game loop and, therefore, the fontmetrics (calculations) will be done over and over again while the outcome is always the same. Advantage: no extra BufferedImage needed. Disadvantage: the game loop needs to run 100+ calculations every time it passes this render loop, slowing down the whole game.

    I assume you do not meant the last option. But, for my understanding could you clarify when you want to do and to store the calculations, please?

  6. #6
    Crazy Cat Lady KevinWorkman's Avatar
    Join Date
    Oct 2010
    Location
    Washington, DC
    Posts
    5,424
    My Mood
    Hungover
    Thanks
    144
    Thanked 636 Times in 540 Posts

    Default Re: Is it wrong to create BufferedImage for using FontMetrics only?

    I mean, only store it the *first* time you do the drawing. Something like this:

    import java.awt.FontMetrics;
    import java.awt.Graphics;
    import java.awt.geom.Rectangle2D;
     
    import javax.swing.JFrame;
    import javax.swing.JPanel;
     
    public class Test extends JPanel{
     
    	boolean needToCalculate = true;
    	int stringWidth;
    	int stringHeight;
     
    	public void paintComponent(Graphics g){
    		super.paintComponent(g);
     
    		String label = "measure me";
     
    		if(needToCalculate){
    			System.out.println("CALCULATING");
    			FontMetrics fm = g.getFontMetrics();
    			Rectangle2D stringRect = fm.getStringBounds(label, g);
    			stringWidth = (int) stringRect.getWidth();
    			stringHeight = (int) stringRect.getHeight();
    			needToCalculate = false;
    		}
     
    		g.drawString(label, 100, 100);
    		g.drawRect(100, 100-stringHeight, stringWidth, stringHeight);
     
     
    	}
     
    	public static void main(String... args){
     
    		JFrame frame = new JFrame("FontMetrics Test");
    		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
    		frame.add(new Test());
     
    		frame.setSize(500, 500);
    		frame.setVisible(true);	
    	}
    }

    Actually, now that I'm playing with this, it turns out you can just call getFontMetrics() on the component itself, then pass in null to the getStringBounds() function instead of a Graphics instance:

    import java.awt.FontMetrics;
    import java.awt.Graphics;
    import java.awt.geom.Rectangle2D;
     
    import javax.swing.JFrame;
    import javax.swing.JPanel;
     
    public class Test extends JPanel{
     
    	String label = "measure me";
    	int stringWidth;
    	int stringHeight;
     
    	public Test(){
    		FontMetrics fm = getFontMetrics(getFont());
    		Rectangle2D stringRect = fm.getStringBounds(label, null);
    		stringWidth = (int) stringRect.getWidth();
    		stringHeight = (int) stringRect.getHeight();
    	}
     
    	public void paintComponent(Graphics g){
    		super.paintComponent(g);
     
    		g.drawString(label, 100, 100);
    		g.drawRect(100, 100-stringHeight, stringWidth, stringHeight);
    	}
     
    	public static void main(String... args){
     
    		JFrame frame = new JFrame("FontMetrics Test");
    		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
    		frame.add(new Test());
     
    		frame.setSize(500, 500);
    		frame.setVisible(true);	
    	}
    }
    Useful links: How to Ask Questions the Smart Way | Use Code Tags | Java Tutorials
    Static Void Games - Play indie games, learn from game tutorials and source code, upload your own games!

  7. The Following User Says Thank You to KevinWorkman For This Useful Post:

    Vinvar (August 21st, 2014)

  8. #7
    Junior Member
    Join Date
    Nov 2012
    Posts
    11
    Thanks
    3
    Thanked 1 Time in 1 Post

    Default Re: Is it wrong to create BufferedImage for using FontMetrics only?

    Great, thanks!

Similar Threads

  1. Replies: 7
    Last Post: February 10th, 2014, 09:45 AM
  2. Using BufferedImage with JFrame
    By Zyrion in forum AWT / Java Swing
    Replies: 6
    Last Post: September 13th, 2013, 10:00 AM
  3. Transparency to bufferedImage
    By Serthy in forum AWT / Java Swing
    Replies: 21
    Last Post: August 29th, 2013, 05:11 AM
  4. BufferedImage create flicker in simple code
    By arnbook in forum What's Wrong With My Code?
    Replies: 0
    Last Post: March 12th, 2011, 12:22 AM
  5. Creating a bufferedimage!
    By Vexst in forum Java ME (Mobile Edition)
    Replies: 0
    Last Post: June 16th, 2010, 08:05 AM

Tags for this Thread