-
Bug
-
Resolution: Fixed
-
P4
-
1.2.0
-
1.2beta4
-
generic, sparc
-
generic, solaris_2.6
-
Not verified
Name: rm29839 Date: 02/04/98
/*****
Environment:
JDK 1.2beta2 Solaris 2.6 Sparc
Bug 1:
FontMetrics are consistently wrong.
The class below measures the real ascent and descent
of a font, which does not match the FontMetrics provided
by the AWT.
Bug 2:
Given optional command line Font tuples, this class usually
core dumps printing unicode values above 190 decimal.
Sample (default) output:
...
251
252
253
254
255
java.awt.Font[family=Courier,name=Courier,style=bold,size=19]
sun.awt.image.BufferedImageGraphics2D[font=java.awt.Font[family=Courier,name=Courier,style=bold,size=19],color=java.awt.
Color[r=255,g=0,b=0]]
Component's FontMetrics:
sun.awt.motif.X11FontMetrics[font=java.awt.Font[family=Courier,name=Courier,style=bold,size=19]ascent=18, descent=5, h
eight=24]
ascent: 18 descent: 5
Graphics' FontMetrics:
sun.awt.font.FontDesignMetrics[font=java.awt.Font[family=Courier,name=Courier,style=bold,size=19]ascent=19, descent=4,
height=24]
ascent: 19 descent: 4
Measured:
ascent: 15 descent: 5
*****/
import java.awt.*;
import java.awt.image.ColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.PixelGrabber;
import java.util.Hashtable;
import java.lang.reflect.Array;
/** Measures the real ascent & descent. */
public class FontStats
{
private static Hashtable ht = new Hashtable();
// only changed by main(), the unit test routine
private static boolean ascii = true;
private static boolean log = false;
// only accessed by main(), the unit test routine
private static Image im;
// results
public int realAscent, realDescent;
private FontStats() { }
/** Measure the ascent & descent of the font in the components
* resolution.
*/
public static FontStats measure(Component c, Font f)
{
FontStats s = (FontStats) ht.get(f);
if (s != null)
return s;
s = buildStats(c, f);
if (s != null)
ht.put(f, s);
return s;
}
private static FontStats buildStats(Component c, Font f)
{
FontMetrics fm = c.getFontMetrics(f);
int h = fm.getHeight();
int w = fm.charWidth('W');
// create an oversized image buffer
im = c.createImage(2*w, 2*h);
if (im == null)
{
System.err.println("Can't create image yet.");
return null;
}
Graphics g = im.getGraphics();
char[] ca = new char[1];
int start, stop;
if (ascii)
{
start = ' '; // printable ascii subset
stop = '~';
}
else
{
start = Character.MIN_VALUE; // all unicode chars!
stop = Character.MAX_VALUE;
}
// draw all chars on top of each other
for (int i = start ; i <= stop ; i++)
{
ca[0] = (char)i;
if (f.canDisplay(ca[0]))
{
if (log)
{
System.err.println(i);
System.err.flush();
}
g.drawChars(ca, 0 , 1, 0, h);
}
}
// draw a baseline
g.setColor(Color.red);
g.drawLine(0, h, 2*w, h);
// grab the pixels
PixelGrabber pg = new PixelGrabber(im, 0, 0, 2*w, 2*h, false);
try
{
if (!pg.grabPixels())
{
System.err.println(
"FontMeasurer: Error grabbing pixels.");
return null;
}
}
catch(InterruptedException e)
{
System.err.println(
"FontMeasurer: Interrupted grabbing pixels.");
return null;
}
if ((pg.getStatus() & ImageObserver.ABORT) != 0)
{
System.err.println(
"FontMeasurer: Image fetch aborted.");
return null;
}
Object pixObj = pg.getPixels();
ColorModel cm = pg.getColorModel();
int bg = c.getBackground().getRGBA();
FontStats fs = measureArray(pixObj, 2*w, 2*h, cm, bg);
if (log)
{
System.err.println("\n" + f);
System.err.println(g);
System.err.println("\nComponent's FontMetrics: ");
System.err.println(" " + fm);
System.err.println(" ascent: " + fm.getAscent()
+ " descent: " + fm.getDescent());
FontMetrics fm2 = g.getFontMetrics();
System.err.println("\nGraphics' FontMetrics: ");
System.err.println(" " + fm2);
System.err.println(" ascent: " + fm2.getAscent()
+ " descent: " + fm2.getDescent());
System.err.println("\nMeasured: ");
System.err.println(" ascent: " + fs.realAscent
+ " descent: " + fs.realDescent);
}
return fs;
}
// pix is either a byte[] or an int[]
private static FontStats measureArray(Object pix, int w, int h,
ColorModel cm, int rgb_bg)
{
FontStats fs = new FontStats();
int index, len, baseline = h/2;
// this would be faster if I could find a way to convert
// rgb_bg into the cm ColorModel.
//
// looking for the top
index = 0;
len = Array.getLength(pix);
for (index = 0 ; index < len ; index++ )
if (cm.getRGB(Array.getInt(pix, index)) != rgb_bg)
break;
fs.realAscent = baseline - (index/w);
// looking for the bottom
index = len - 1;
for (index = len ; --index >= 0 ;)
if (cm.getRGB(Array.getInt(pix, index)) != rgb_bg)
break;
// I am assuming that "below the baseline" means
// below the infinitely thin baseline, not below
// the pixel row where a baseline line would be
// drawn
fs.realDescent = (index/w) - baseline + 1;
return fs;
}
/** Unit test routine. Also shows the image so that the
* ascent and descent can be visually confirmed.
*/
public static void main(String args[])
{
String usage = "java FontStats [ -ascii ] [ FaceName Style Size ]";
boolean ascii = false;
int len = args.length;
Font font = null;
if (len == 2 || len > 4)
{
System.err.println(usage);
System.exit(-1);
}
if (len == 1 || len == 4)
{
if (!args[0].equals("-ascii"))
{
System.err.println(usage);
System.exit(-1);
}
ascii = true;
}
if (len == 4 || len == 3)
{
int size = Integer.parseInt(args[len-1]);
String style = args[len-2];
String face = args[len-3];
int styleI = Font.PLAIN;
if (style.equals("PLAIN"))
styleI = Font.PLAIN;
else if (style.equals("BOLD"))
styleI = Font.BOLD;
else if (style.equals("ITALIC"))
styleI = Font.ITALIC;
else
{
System.err.println(usage);
System.exit(-1);
}
font = new Font(face, styleI, size);
System.err.println(font);
}
else
{
font = new Font("Courier", Font.BOLD, 19);
}
FontStats.ascii = ascii;
FontStats.log = true;
Frame f = new Frame();
ImageCanvas c = new ImageCanvas();
c.setSize(100, 100);
f.add(c);
f.pack();
f.show();
c.setFont(font);
FontStats fs = FontStats.measure(c, font);
c.setImage(fs.im);
}
}
class ImageCanvas extends Canvas
{
Image im;
public void setImage(Image im) { this.im = im; repaint(); }
public void paint(Graphics g)
{ if (im != null) g.drawImage(im, 0, 0, this); }
}
(Review ID: 24494)
======================================================================
- relates to
-
JDK-4130434 The Measurement of Text
-
- Closed
-