[prog] Java/Swing and antialiased fonts

Almut Behrens almut-behrens at gmx.net
Fri Apr 2 03:02:03 EST 2004


On Thu, Apr 01, 2004 at 12:02:36AM +0200, Riccarda Cassini wrote:
> 
> Can I make my IDE (netbeans) directly insert the correct widget
> instantiations (i.e. AA.JLabel instead of the default javax.swing.JLabel)
> into the code sections it automatically generates?  (If I simply edit
> them outside of the IDE, they'll of course be overwritten next time I
> make a change via the IDE...)  Any other IDEs I should look into?

I'm afraid I can't help you here. Actually, I was hoping someone else
would answer the question ;)   Sorry, I don't know. Haven't taken the
time to find out, yet. (Did I already mention I'm not a java guru? :)
Anyone else?

Whenever I had to get around this problem, I just wrote a little perl
script to automatically do the necessary editing (every time) before
the build phase.  I'm using 'ant' (Java's version of 'make') for
building, so this is rather easy to do.

In its most simple form (when you simply need to replace all
occurrences), the script would look something like:

#!/usr/bin/perl -p

s/new javax\.swing\.JLabel/new AA.JLabel/g;
s/new javax\.swing\.JCheckBox/new AA.JCheckBox/g;
# ...more widgets here...


(things would get somewhat more complex, if you wanted to replace only
specific occurrences)


> 
> Yes, I'd definitely be interested in your truetype class. I think
> that'll make him happy :-)

Okay, I've attached it.  (I figured it might perhaps also be of
interest to someone else, sometime - so I'm sending it to the list.
My apologies to anyone not interested.)


> 
> Almut, I guess you saved my butt.

glad I could help :)

Cheers,
Almut


-------- TT/Font.java ---------

A couple of notes:

The purpose of the class if to make handling of your own truetype fonts
easier (not to add truetype functionality in general - java has this
functionality already built in).

Background:
Java font configuration is done in a file "font.properties" located in
the installation directory of the runtime environment. Some JREs ship
with with their own fonts. For example, most linux versions come with
the (truetype) font family Lucida.  font.properties maps fontnames to
real fontfiles (among other things). JREs which do not come with their
own complete set of fonts, normally use some fonts available somewhere
else on the system. Due to this, it's unfortunately _not_ guaranteed,
that you always get the same glyphs when a certain font (like
java.awt.Font("DialogInput",0,12)) is rendered. This is suboptimal,
if you want to write applications that look the same across several
platforms (rather large deviations exist between Linux and HP-UX with
typical JREs, for example). A layout carefully done on one platform,
can look totally cluttered on another. Also, from a sysadmin point of
view, it's usually not desirable to add application-specific fonts to
the default JRE installation/configuration.

The approach of this class is quite simple: you have your own font
directory that you would distribute with the application. In there,
you put all the *.ttf files you need. The directory is specified upon
startup of the JVM by setting a SystemProperty via -D

java -Dfontpath=/path/to/my/fonts ...

(a colon-seperated list of directories is allowed, if needed)

Fontnames you specify in your application directly correspond to the
filenames of the .ttf files. If you have a file called Verdana-Bold.ttf
you would write TT.Font("Verdana-Bold", size) in the code.

The class does simple caching to avoid unnecessary reloading and
scaling of fonts. Caching is only effective, if you have just _one_
instance of the class/object for the whole application. Thus it's
implemented static.
This means you simply write "java.awt.Font myfont = TT.Font(...)"
instead of "= new TT.Font()".

(Probably forgot something - so, feel free to ask...)

-------------------------------

package TT;

import java.awt.Font.*;

public class Font {
    
    static private String fontPath = System.getProperty("fontpath")
                                     +":"+System.getProperty("java.home")+"/lib/fonts";
    
    static private java.util.HashMap fontCache = new java.util.HashMap();
    
    static private java.awt.Font defaultFont = new java.awt.Font("Default",0,12);

    
    // this is the (class-)method you'd normally use:
    
    static public java.awt.Font getFont( String fontName, double size) {
        return getFont(fontName, size, true);
    }
    
    static public java.awt.Font getFont( String fontName, double size, boolean failSilently) {
        String id = fontName+size;
        if (fontCache.containsKey(id)) {
            return (java.awt.Font) fontCache.get(id);
        } else {
            java.awt.Font font = createFont(fontName, size, failSilently, true);
            fontCache.put(id, font);
            return font;
        }
    }

    static public java.awt.Font createFont( String fontName, double size) {
        return createFont(fontName, size, true);
    }
    
    static public java.awt.Font createFont( String fontName, double size, boolean failSilently) {
        return createFont(fontName, size, failSilently, false);
    }
    

    static protected java.awt.Font createFont( String fontName, double size, boolean failSilently, boolean doCache) {
        java.awt.Font font = null;
        // when caching requested, check whether font file has already been read (i.e. unscaled font is in cache)
        if (doCache && fontCache.containsKey(fontName)) {
            font = (java.awt.Font) fontCache.get(fontName);
        }
        if (font == null) {
            font = createFont(fontName, failSilently);
            if (doCache && font != null) {
                fontCache.put(fontName, font);
            }
        }
        if (font != null) {
            font = font.deriveFont((float) size);
        }
        return font;
    }
    
    static protected java.awt.Font createFont( String fontName, boolean failSilently) {
        java.awt.Font font = defaultFont;
        String path = fontPath;
        String err = "";
        while (!path.equals("")) {
            err = "";
            int sepIdx = path.indexOf(':');
            String tryPath;
            if (sepIdx == -1) {
                tryPath = path;
                path = "";
            } else {
                tryPath = path.substring(0,sepIdx);
                path = path.substring(sepIdx+1);
            }
            try {
                java.io.FileInputStream ttFontStream = new java.io.FileInputStream(
                    new java.io.File(tryPath+"/"+fontName+".ttf")
                );
                font = java.awt.Font.createFont(java.awt.Font.TRUETYPE_FONT, ttFontStream);
                ttFontStream.close();
                break;
            }
            catch (Exception e) {
                err = e.toString();
            }
        }
        if (!err.equals("")) {
            System.err.println("Error loading font '"+fontName+"': "+err);
            if (!failSilently) {
                return null;
            }
        }
        return font;
    }
}


-------- example mini application -------

public class AADemo extends javax.swing.JFrame {

    private java.awt.Font verdanaBI = TT.Font.getFont("Verdana-BoldItalic", 13.5);
    private java.awt.Font dialogInpI = new java.awt.Font("DialogInput", java.awt.Font.ITALIC, 14);
    
    public AADemo() {
        setTitle("Antialiasing Demo");
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                System.exit(0);
            }
        });

        javax.swing.JLabel text_TT_AA = new AA.JLabel(" Verdana-BoldItalic (truetype), antialiased ");
        text_TT_AA.setFont(verdanaBI);

        javax.swing.JLabel text_TT = new javax.swing.JLabel(" Verdana-BoldItalic (truetype), normal ");
        text_TT.setFont(verdanaBI);
        
        javax.swing.JLabel text_AA = new AA.JLabel(" DialogInput Italic (system), antialised ");
        text_AA.setFont(dialogInpI);

        javax.swing.JLabel text = new javax.swing.JLabel(" DialogInput Italic (system), normal ");
        text.setFont(dialogInpI);

        java.awt.Container content = getContentPane();
        content.setLayout(new java.awt.GridLayout(4,1));
        content.add(text_TT_AA);
        content.add(text_TT);
        content.add(text_AA);
        content.add(text);
        pack();
    }
    
    public static void main(String args[]) {
        new AADemo().show();
    }
}



More information about the Programming mailing list