The term font
is vague and different people use it in
different ways.
For now assume a font an array of tiny
graphics, created by an artist so they
share a particular look, and which map
to letters, digits,
and other characters.
(For the real story search the Internet and visit
Unicode.org and see the
javadoc API comments for java.awt.Font
.)
These graphics are called glyphs
.
Glyphs are to characters what numerals are to numbers:
a visual representation of an abstract concept (e.g. the
letter A
).
Many different glyphs can represent the same character;
they just look different.
Type designers knew some things about how humans read text, and
devised serif
fonts which are letter shapes
composed of lines (or strokes
) of varying
thickness and small extra bits on the ends of the strokes.
Text of such fonts is much easier to read and pretty much all books
and magazines use serif fonts for body text.
(As should you!)
Text without the extra bits, and often drawn with lines of constant
thickness, are called sans-serif
(sans
is
French for without
) and are used for attention-grabbing such
as for headings and captions.
In the early computer era usually a single screen font was built into
terminals.
Printers were based on daisy-wheel or line-printer
technology, again that supported a single font.
These early computer screens and printers were limited to drawing
each character in the same sized rectangular block.
Such fonts are called mono-spaced
since all
characters take up the same amount of horizontal space.
This leads to an un-even appearance as fat letters such as
'm' take the same space as skinny letters such as 'i'.
As the technology grew more sophisticated computers and printers
became capable of displaying traditional fonts called
proportional
.
In these fonts the space between the characters is the same, giving
the text an even appearance.
(Are you reading this in a mono-spaced or proportional font?
Look at this to decide: MMMMllll
.)
So a font can be either proportional or mono-spaced.
It can have serifs or be sans-serif.
That's four possibilities, but fonts can have other attributes
such as heaviness of the strokes (e.g., bold
) or if the
letters are straight (roman
) or slanted (italics
).
Early Unix systems used X Window
fonts that were named for
each of 14 possible font attributes.
You could find a bold, 12 point (one point
is
roughly 1/72 of an inch) font by doing a directory listing for:
-*-*-bold-*-*-*-12-*-*-*-*-*-*-*
which might find the font file:
-adobe-utopia-bold-r-normal--12-120-75-75-p-70-iso8859-1
Nowadays fonts have names such as Helvetica
or
Bookman DemiBold
which is much less helpful.
When Java programmers set a font to use, they typically don't know
what fonts are available on the user's system.
So if you guess to use a font Arial
it may or may not
be available.
However all home computers ship with a set of fonts standard for
that platform.
So for every platform Sun supports, they picked 3 available fonts
(these are the actual fonts installed and are called
physical
) and gave them names you can use in your
program.
The names are called logical
font names since the
names reflect the type of the font:
Monospaced
(usually sans-serif too, but not necessarily), SansSerif
(a proportional font), and Serif
(also proportional).
So in your program you can chose the system-specific mono-spaced
font for code listings, sans-serif for headings and captions, and
serif for body text.
And you don't need to know the real or physical
name for that font.
Most home computer systems also have a distinct look and feel to
the pop-up dialog boxes and other system elements (e.g., window
titles).
You can use these as well as Sun has kindly defined
the system standard fonts for dialog boxes as
and
Dialog
logical font names,
so you can make your dialogs appear native.
DialogInput
Modern AWT does include classes and methods to list all available fonts installed so you can look for specific (physical) fonts. However in AWT you are limited to only using the fonts chosen for the logical font names! With swing you can use any font available. Consider the following code:
import javax.swing.*; public class Fonts2 extends JFrame { public static void main ( String [] args ) { JFrame f = new Fonts(); f.setSize(200,300); f.setVisible(true); JLabel lbl = new JLabel("hello world"); lbl.setFont( new Font("Broadway", Font.PLAIN, 24) ); f.add( lbl ); } }
import java.awt.*; public class Fonts1 extends Frame { public static void main ( String [] args ) { Frame f = new Fonts(); f.setSize(200,300); f.setVisible(true); Label lbl = new Label("hello world"); lbl.setFont( new Font("Broadway", Font.PLAIN, 24) ); f.add( lbl ); } }
Only the swing version will display the label in the selected
font.
(If you don't have Broadway
font available on your system,
choose a different font, but make sure it is weird enough so
you will see the difference between swing and AWT.)
Here's some code to list all installed fonts, and also a list of all the fonts available for use by Java:
import java.awt.*; public class ShowFonts { public static void main ( String [] args ) { Font[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment() .getAllFonts(); for ( int i = 0; i < fonts.length; ++i ) { System.out.print( fonts[i].getFontName() + " : " ); System.out.print( fonts[i].getFamily() + " : " ); System.out.println( fonts[i].getName() ); } System.out.println( "\n\n\tAvailable Fonts:\n" ); String[] names = GraphicsEnvironment.getLocalGraphicsEnvironment() .getAvailableFontFamilyNames(); for ( int i = 0; i < names.length; ++i ) System.out.println( names[i] ); } // end of main }
Still it may be a problem to not know the actual font used by some
logical font name, as different proportional fonts can do line breaks
in different places and mess up the carefully planned appearance of
your application or applet.
For this reason the JRE ships with a set of related
fonts called Lucida
.
These physical fonts are available in all Sun JREs
and include mono-spaced, Sans-Serif, and Serif versions.
(Look in .../jre/lib/fonts
on your system.)
In short, Sun as identified three of the fonts on each platform and given them logical names. You can use one of these three or the platform-specific dialog fonts (making five logical font names in all), or pick some actual font name (a physical font) and hope it is available. It will be if you pick Lucida and you have a Sun JRE.
Remember each font is a collection
(an array or vector
) of graphics known as glyphs
.
(It's more than that really.)
Each glyph is identified by a number.
For example a capital A
glyph in any font that has such
a glyph is identified by the number 65.
Of course anyone can make their own collection of glyphs as a font,
and identify any glyph with any number.
For Java and most software today the mapping of numbers to glyphs
is the one defined by the Unicode standard.
The numbers are called code points
.
Unicode had defined numbers for many thousands of glyphs and it is unlikely you have a single font file that has every glyph defined by Unicode. This can be a problem since you don't always know if the font you're using has a glyph for all the symbols, arrows, smiley faces, Greek letters, math and engineering symbols, etc., that you might want to use. If that is a problem you can find a font that can display the characters you need with code such as this:
for (Iterator<Font> i = fontList.iterator(); i.hasNext(); ) { Font f = i.next(); if ( ! f.canDisplay( '\u25B6' ) ) i.remove(); }
(See UnicodeSymbols.java for a sample applet with source that does this.) Fonts will claim they can display a character if it falls in the covered range of that font, even if there is no glyph for it!
There are a couple of other issues you should know about.
One is that Java defines the size of fonts in
points
, which should be 1/72 of an inch.
This unit worked well with early font technology since dot-matrix
printers and computer monitors had 72 pixels to the inch.
(Horizontally anyway; monitors often use rectangular pixels that
are taller than they are wide.)
A shortcut
was taken for fonts where the font designers
assumed 1 point = 1 pixel.
Todays monitors can use much smaller pixels and they are spaced
closer together.
This is called the monitor's DPI
(dots per inch).
This is why when you increase a monitor's resolution, most fonts
come out looking tiny.
Some software is smart enough to correct for that;
AWT toolkit provides a method to find the
DPI value.
When using logical font names,
Java may not be able to pick a single physical font that
contains all the Unicode characters, or even a significant number
of them.
This is because many physical fonts only define 256 glyphs.
In this case the logical font name may actually refer to several
physical fonts that are stitched together
to define lots
more glyphs than any one standard font available on your system.
On my Java6 JRE on Windows XP, the
file defines the logical font serif to use the physical font
fontconfig.properties
Times New Roman
for the standard 256 alphabetic glyphs, and
the font MS Mincho
for any Japanese glyphs.
By using the logical font name Serif
you can use
specify any Latin, Chinese, Hebrew, Japanese, or Korean
glyph and it will display correctly, even though there isn't
a single physical font that contains all those glyphs in
the Windows XP standard set of fonts.
If you used the physical font Times New Roman
and your
text contained the Unicode number for some Japanese glyph,
it won't display correctly.
(Usually the system displays a square in these cases.)
Another issue is that different font files store the glyph
data in different formats.
Your software must be able to read the format or it can't use
the font.
Currently Java 1.6 for Windows platform can read
TrueType
and OpenType
font formats, but probably not other formats such as
PostScript Type 1
fonts.
On the other hand with older Unix/Linux systems, Java 6 seems
to only recognize PostScript
fonts and not TrueType
or OpenType
.
(There are other standards for font files such as FreeType;
Web pages will get support in HTML 5 for a
new
font system called WOFF (Web Open Font Format).)
In addition not all font files use Unicode to translate characters
to glyphs; Java uses Unicode code points
to identify the
glyphs.
For these reasons you may have installed some font and find
that Java can't use it, even if other software on your system can.
The final issue is one of encoding text.
Text is composed of a series of numbers (the code points
)
that identify characters.
This text doesn't change if you change the font you use to render
(i.e., draw) the glyphs for those characters.
The problem is the numbers can take up 4 or more
bytes in Unicode.
So how should the text string
be stored?
It might be 4 bytes per number, or two, or
even one, with special rules to handle large numbers.
This is called the text ABC
encoding
.
(For more information about Unicode and encoding, see
the resource
Encoding and Character Sets.)
Internally Java uses two byte numbers, with a special
convention to represent characters defined in Unicode with numbers
larger than 65,536 (the biggest value you can store in two
bytes).
This is why the Java data type
is a two
byte value.
However most operating systems historically used one byte numbers.
This is because before Unicode, most Western fonts contained fewer
than 256 glyphs, more than enough for the Latin alphabet commonly used
in the US and the UK.
When reading or writing text a program must pick the
proper encoding.
char
Unfortunately there is no easy way to tell what encoding to use, or what encoding is used. If you use a web browser the web page (which is just text) contains a header stating what encoding is used. Try changing that and see the results, especially for curly quotes and bullets.
There is a whole lot more to the story including ligatures, kerning, leading, and other fascinating (to me anyway) facts and history. (Did you know that originally printers (human ones) traveled with cases containing little wooden (or soft metal) font blocks? The capital letters were used much less often than the others and were stored in the top or upper part of the case while the rest were kept in the more convenient lower part of the case, and that's how we got the terms lowercase and uppercase letters. Is that interesting or what?)
Actually using fonts in Java is easy:
Font titleFont = new Font( name, style, size );
where name
is a logical font name or the name of a
physical (real) font installed on your system,
stye
is one of:
Font.PLAIN
Font.BOLD
Font.ITALIC
Font.BOLD+Font.ITALIC
(or equivalently, Font.BOLD|Font.ITALIC
)
and size
is the size specified in points, which is
probably really pixels on most monitors.
Note the size is the average height of the alphabetic glyphs.
The styles are limiting, you can't specify a "demi" weight or "slanted" instead of italic. However most physical font files are named for the actual style: Regular, DemiBold, or Bold. So you can pick a physical font name incuding the whole style part of the name. (Keep in mind that you can't use physical fonts with AWT.)