• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1324
  • Last Modified:

java Grapics drawString Text Positioning

Hello,

I'm using the below code to insert text into an existing image, but the text length can vary.  In order to accomodate longer text I may need to shrink the font if its length is greater than a certain number...etc.  Is there a built in way to auto position the text within the set width/height of the existing image?  



public class DrawImage {
    public static void main(String [] args) throws Exception
    {
        URL url = new URL("http://nscraps.com/images/logo.png");
        Image image = ImageIO.read(url);
        BufferedImage cpimg=bufferImage(image);
        Graphics g = cpimg.createGraphics();
        Font fnt=new Font("Arial",1,11);//setting Font size and style
        Color fntC = new Color(0,0,0);//setting font color
        g.setColor(fntC);
        g.setFont(fnt);
        g.drawString("Text cont",10,20);//Text will be priented
        File f1 = new File("c://temp//test.png");
        ImageIO.write(cpimg, "png", f1);
    }
    public static BufferedImage bufferImage(Image image) {
        return bufferImage(image,BufferedImage.TYPE_INT_RGB);
    }
    public static BufferedImage bufferImage(Image image, int type) {
        BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
        Graphics2D g = bufferedImage.createGraphics();
        g.drawImage(image, null, null);
        return bufferedImage;
    }
}

Open in new window

0
cgray1223
Asked:
cgray1223
  • 19
  • 10
  • 9
  • +1
4 Solutions
 
for_yanCommented:
There is a useful FontMetrics class which would allow you to determin the
legnth and heiight of any String
0
 
for_yanCommented:
You can use getFontMetricson your selected font
FontMetrics fm = g.getFontMetrics(Font f);

and FontMetrics has lots of methods which would allow you to determine String width height
so then you can compare and try with another font.


You can od all the and then make decision which font to use.
You can make a method which will selcet the best font for your string.
Don't know if there is anything automatic

0
 
CEHJCommented:
>>Is there a built in way to auto position the text within the set width/height of the existing image?

No. I would suggest you use Font.deriveFont in a loop until it's metrics fit
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
CEHJCommented:
Come to think of it - a loop isn't necessary ;)
0
 
cgray1223Author Commented:
Thanks for the responses.  I have a set font I have to use.  The issue I have is how to derive the x and y coordinates for the drawString  method based on the length of characters I'm writing on top of the Image.  I didn't see a way FontMetrics could help there unless I overlooked something in that api...ideas?


 g.drawString("Text cont",10,20);
0
 
for_yanCommented:
But if you know the coordionates of your picture with which you don't want to overlap,
then with the help of FontMetrics you can calculate the length of the string and uyou can calculete if it is going to ovrelap
0
 
cgray1223Author Commented:
well I know the height and width of the image I want to overlap, but depending on the text size I write to the image, I'll want to maybe break it to a second line and center it vertically and horizontally.  I can just look at the length of the text and make a best guess.  
0
 
for_yanCommented:
Yes, that's what i'm talking about and FontMetrics allows you
to translate your String into its height and width
0
 
cgray1223Author Commented:
Ok, I'll give it a shot and see if it meets my exact needs, thanks
0
 
for_yanCommented:
Sure, give it a try, and let me know if you have any questions about FontMetrics
I used to use it some time ago, and rememeber, it served my purpose
0
 
CEHJCommented:
Here's an example of using deriveFont. If you compile and then run it with


appletviewer Moire.java

you'll see the text filling the window, whatever you resize it to
/*
 <applet code="Moire" width="300" height="200"></applet>
 */
import java.applet.Applet;

import java.awt.*;


public class Moire extends Applet {

    public void paint(Graphics g) {
	Font f = g.getFont();
        String s = "The quick brown fox jumps over the lazy dog";
        FontMetrics fm = g.getFontMetrics();
        int width = fm.stringWidth(s);
	//Insets i = getInsets();
	//System.out.println(i);
	//System.out.printf("The width of the string is %d\n", width);
	Font centred = f.deriveFont(f.getSize() * (float)getWidth()/width);
	g.setFont(centred);
        g.drawString(s, 0, 50);
    }
}

Open in new window

0
 
cgray1223Author Commented:
CEHJ, what is in your getWidth method?  Thanks for the example.
0
 
CEHJCommented:
That's the getWidth method of the Component (the applet)
0
 
cgray1223Author Commented:
I'm assuming getWidth is just the width of where you want to write the text on the image?
0
 
CEHJCommented:
>>I'm assuming getWidth is just the width of where you want to write the text on the image?

Yes, effectively
0
 
CEHJCommented:
You can probably just use the image width
0
 
objectsCommented:
> I'm assuming getWidth is just the width of where you want to write the text on the image?

Its actually the width of the entire Applet

the example I posted has a method that you can pass a Rectangle giving the size to fit the font within
0
 
for_yanCommented:
You really don't need to worry about that applet and its width.
You even don't need to go to deriveFont  (ther are many ways to change fonts by the way),
but once you stated that you need to use the font which
you have, you probably don't need them either.  You just be within your application. Use FontMetrics to drteremine
the length of your string. As you know location of picture and waht limits you in your
case you determine where to start writing this string, and if you are really limited on that side,
determine if you need to break it into two lines. - it is all within your drawing - it should not be difficult
and FontMetrics has all methods necessary to do it.
0
 
cgray1223Author Commented:
Objects, I tried to implement the Font resizer you suggested.  The problem is I get a 0.0 from fontSize = (rect.width / width ) * fontSize.  

int width = g.getFontMetrics(font).stringWidth(text) yields an int of 175

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;


public class ImageCreator {
    public static void main(String [] args) throws Exception
    {
        String text = "Testinggggggggggggggggg";
        File f = new File("c://temp//dc_text_image.png");
        Image image = ImageIO.read(f);
        BufferedImage img=bufferImage(image);
        Graphics g = img.createGraphics();
        Font fnt=new Font("Garamound",1,14);
        Color fntC = new Color(4, 4, 109);
        g.setColor(fntC);
        Rectangle rect = new Rectangle(150, 75);
        Graphics g1 = img.createGraphics();
        Font finalFnt = scaleFont(text, rect, g, fnt);
        g.setFont(finalFnt);
        g.drawString(text,10,20);
        File f1 = new File("c://temp//test.png");
        ImageIO.write(img, "png", f1);          
    }
    public static Font scaleFont(String text, Rectangle rect, Graphics g, Font pFont) {       
        float fontSize = 14.0f;
        Font font = pFont;
        font = g.getFont().deriveFont(fontSize);
        int width = g.getFontMetrics(font).stringWidth(text);
        fontSize = (rect.width / width ) * fontSize;
        return g.getFont().deriveFont(fontSize);
}
    public static BufferedImage bufferImage(Image image) {
        return bufferImage(image,BufferedImage.TYPE_INT_RGB);
    }
    public static BufferedImage bufferImage(Image image, int type) {
        BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
        Graphics2D g = bufferedImage.createGraphics();
        g.drawImage(image, null, null);
        return bufferedImage;
    }
}

Open in new window

0
 
cgray1223Author Commented:
@for_yan:

Using FontMetrics how would you write the text withing a certain box constraint, say 175 width and 75 height and it automatically break to the next line if the text is greater than the 175 width?
0
 
for_yanCommented:
because when you divide tow intgeters that's where you get zero
rect.width / width
0
 
CEHJCommented:
fontSize = ((double)rect.width / width ) * fontSize;

btw - that code is no different from what i've already posted
0
 
for_yanCommented:
First thing ddi you state above that you cannot change font?
0
 
for_yanCommented:
You just first take default font and compare the length of your string (using FontMetrics you dfind it )
with the width of your box
0
 
for_yanCommented:
If it is bigger, then break you text into tow lines and measure each of the
two llines wdths
0
 
CEHJCommented:
For deriveFont, try

fontSize = (float)(1.0f * rect.width / width ) * fontSize);
0
 
for_yanCommented:
Of course find appropiriate word where you want to break.
Then determine heigt and chek if two llines will fir into the height
0
 
for_yanCommented:
If you see that with your original font you'll not fit then try to change the font.
i your string always constant or it will be different as a result of your calculation?
0
 
for_yanCommented:
If it is constant, then best of all to do it with trial and error method
just setting the font size and printing the widh with
System.out.println(fontmetrics.getWidth(String)

If it is not constant, then you need to devise some strategy, how you will be breaking
line, depending on the string, etc  That may be more difficult but you probably know some
options about waht may be in the string, so usually it is also doable.
0
 
cgray1223Author Commented:
The string will be a max of 30 characters and will vary.  My current with is 175 for it to fit and if the text is greater than 175 width, I need to break it to the next line.  I guess I can do that by looking for a space between words and then center both
0
 
for_yanCommented:
Yes, you determine where you want to break dependeuingon some variablitiy of the cntents
0
 
for_yanCommented:
FontMetrics allows you not to think in terms of charactes and spaces between the words.
If there are the same anchor words present maybe you want to  break afterone of them.
If these 30 chars absolutely arbitrary then you  may really want to coune characters.
It all depends what can be in your string. If you could explain what is in te string we could thing togehet
0
 
objectsCommented:
> Objects, I tried to implement the Font resizer you suggested.  The problem is I get a 0.0 from fontSize = (rect.width / width ) * fontSize.  

The code was only pseudo code, you need to cast the ints to floats so you do floating point division

If you want word wrap then use a JTextArea (of the required width) to handle the rendering for you
0
 
for_yanCommented:
Yes, if you want these two lines to be centerd there is exactly where
fontmetrics.stringWidth(String) method willb every helpful - as
once you know both of your lines you can calcvulte their length
and determine wher to start second line to make them centerd
0
 
objectsCommented:
0
 
for_yanCommented:
Before you start changing code, check if you cannpt fit your string into two lines.
0
 
CEHJCommented:
It would probably be easier just to set a background image in a text component with the component set to wrap text over it
0
 
for_yanCommented:
Before you start changing font, check if you cannpt fit your string into two lines (that's waht I meant above)
0
 
cgray1223Author Commented:
yeah I'm able to break it into two lines.  I'll have to dynamically look at the strings length and split it into an array since 15 characters max will fit on each line.   I'm using the below to center and write the text.



import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;


public class ImageCreator {   
      public static void main(String [] args) throws Exception
    {     
        File f = new File("c://temp//dc_text_image.png");
        Image image = ImageIO.read(f);
        BufferedImage img=bufferImage(image);
        Graphics g = img.createGraphics();
        Font fnt=new Font("Dante",1,18);
        Color fntC = new Color(4, 4, 109);       
        g.setColor(fntC);
        g.setFont(fnt);
        Dimension d = new Dimension(200, 85);
        drawCenteredString("\"This issssssss", d.width-15, d.height, g);
        drawCenteredString("centereddddddd\"", d.width, d.height+40, g);      
        File f1 = new File("c://temp//test.png");
        ImageIO.write(img, "png", f1);
    }
    public static BufferedImage bufferImage(Image image) {
        return bufferImage(image,BufferedImage.TYPE_INT_RGB);
    }
    public static BufferedImage bufferImage(Image image, int type) {
        BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
        Graphics2D g = bufferedImage.createGraphics();
        g.drawImage(image, null, null);
        return bufferedImage;
    }

    public static void drawCenteredString(String s, int w, int h, Graphics g) {
        FontMetrics fm = g.getFontMetrics();
        int x = (w - fm.stringWidth(s)) / 2;
        int y = (fm.getAscent() + (h - (fm.getAscent() + fm.getDescent())) / 2);
        g.drawString(s, x, y);
  }
}

Open in new window

0
 
CEHJCommented:
... but you're not changing the size of the font..? It will look a lot neater centred in one line
0
 
objectsCommented:
> I'll have to dynamically look at the strings length and split it into an array since 15 characters max will fit on each line.  

there are existing approaches that will do that for you. See my previous 2 comments
0
 
for_yanCommented:
I am glad it worked for you.



0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

  • 19
  • 10
  • 9
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now