Java Forum / First Aid / January 2006
How do you reliably extract a font from a JAR file?
Oliver - 07 Jan 2006 07:03 GMT I've discovered that the method I use to extract a font from a jar file is flawed, and causing problems in my program. Providing code will not help, what I need is a code example of how to do this reliably. The code I have works on every platform except Windows XP. So I need 100% portable java code. thanks.
Oliver
Andrew Thompson - 07 Jan 2006 08:53 GMT > I've discovered that the method I use to extract a font from a jar file Is it on the application's class path? If so, you can..
URL theFontURL = this.getClass().getResource("theFontFile");
..then..
InputStream stream = theFontURL.openStream();
HTH
 Signature Andrew Thompson physci, javasaver, 1point1c, lensescapes - athompson.info/andrew
Oliver - 09 Jan 2006 04:26 GMT Hi Andrew Thompson, thanks for replying.
My method uses InputStream in = getClass().getResourceAsStream(fileName); which is similar but different than what you describe. I'll change it around a bit and see if that works. Thanks again sir :)
Oliver Richman
Roedy Green - 07 Jan 2006 19:49 GMT >I've discovered that the method I use to extract a font from a jar file >is flawed, and causing problems in my program. Providing code will not >help, what I need is a code example of how to do this reliably. The >code I have works on every platform except Windows XP. So I need 100% >portable java code. thanks. here is my SCCE. It baffles me. It seems to find and construct the Font from the jar just fine, but when I use it, I just see Dialog. I tried in with three different TTF files, same result.
package com.mindprod.example; import java.awt.Color; import java.awt.Font; import java.awt.FontFormatException; import java.awt.Frame; import java.awt.Label; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; import java.io.InputStream; /** * How to include a custom font with your application.<br> * Demonstrate use of java.awt.Font.createFont<br> * Accessing an uninstalled Font bundled in a jar or on the classpath.<br> * Note this technique is illegal if you don't have licensing permission from * the font designer. * * @author Roedy Green */ public class TestCreateFont {
/** * Debugging harness for a Frame * * @param args * command line arguments are ignored. * @throws FontFormatException * if font is not a valid TrueType font * @throws IOException * if there is some problem reading the font file. */ public static void main ( String args[] ) throws FontFormatException, IOException { final Frame frame = new Frame(); // Uninstalled font is a resource on classpath or in jar named // "com/mindprod/example/verdana.ttf"
InputStream fontStream = TestCreateFont.class .getResourceAsStream( "verdana.ttf" ); Font onePoint = Font.createFont( Font.TRUETYPE_FONT, fontStream ); fontStream.close(); Font snowFont = onePoint.deriveFont( Font.PLAIN, 18 ); System.out.println ( snowFont); Label Label = new Label( "Snow Alert" ); Label.setBackground( Color.BLACK ); Label.setForeground( Color.WHITE ); Label.setFont( snowFont ); frame.add( Label ); frame.setSize( 100, 100 ); frame.addWindowListener( new WindowAdapter() {
/** * Handle request to shutdown. * * @param e * event giving details of closing. */ public void windowClosing ( WindowEvent e ) { System.exit( 0 ); } // end WindowClosing } // end anonymous class ); // end addWindowListener line frame.validate(); frame.setVisible( true ); } // end main }
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Oliver - 09 Jan 2006 03:40 GMT Hi Roedy Green. Thanks for replying to my question. Your answer probably helped me :)
After looking at your code I thought to myself, "Interesting, that is basically the way I was doing it." That is, //////////////////////////////////////////// // roedy green's way //////////////////////////////////////////// InputStream fontStream = TestCreateFont.class .getResourceAsStream( "verdana.ttf" ); Font onePoint = Font.createFont( Font.TRUETYPE_FONT, fontStream ); ////////////////////////////////////////////
However, I had heard there "might be" some "compatability" problems with "netscape", all very vague, so I did it this way:
//////////////////////////////////////////// // Oliver's way that he read about somewhere (I deny all responsibility) //////////////////////////////////////////// byte[] buffer; InputStream in = getClass().getResourceAsStream(fileName);
int length = in.available(); buffer = new byte[length]; in.read( buffer );
InputStream is = new ByteArrayInputStream(buffer); the_font = Font.createFont(Font.TRUETYPE_FONT, is); ////////////////////////////////////////////
By moving the data through a 'buffer' you are supposed to get around a problem in netscape. I read this method on http://www.javaworld.com/javaworld/jw-07-1998/jw-07-jar-p2.html and adapted it for use with fonts. As it turns out this may not be the best way to do things after all. I am only concerned that my code will not work somewhere. I think it's odd and stupid that Java code will work on many platforms but not one platform, it must be a bug in the windows implementation of Java because "oliver's way" works on other systems. Oh well.
Thanks guys. I hope this works :>
Oliver Richman
Roedy Green - 09 Jan 2006 04:18 GMT >// Oliver's way that he read about somewhere (I deny all >responsibility) [quoted text clipped - 9 lines] > the_font = Font.createFont(Font.TRUETYPE_FONT, is); >//////////////////////////////////////////// What you may be thinking of is the old Netscape bug that getResource did not work.
What your code looks like it is trying to do is bypass a bug in createFont if it did a zero read and gave up, rather than reading again. This would only happen if you were reading the font as a resource over the net. It would not likely happen if you read the resource from a jar or from the local file system.
However, your code does not do that. See http://mindprod.com/jgloss/readeverything.html
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Roedy Green - 09 Jan 2006 04:20 GMT >http://www.javaworld.com/javaworld/jw-07-1998/jw-07-jar-p2.html and this code is nonsense:
try{ int length = in.available(); thanksToNetscape = new byte[length]; in.read( thanksToNetscape ); image = toolkit.createImage( thanksToNetscape ); }
I don't think the author understands the meaning of in.available. It is not the same thing at the total size of the image.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Roedy Green - 08 Jan 2006 13:12 GMT >I've discovered that the method I use to extract a font from a jar file >is flawed, and causing problems in my program. Providing code will not >help, what I need is a code example of how to do this reliably. The >code I have works on every platform except Windows XP. So I need 100% >portable java code. thanks. This works. The trick is this does not work in AWT, only Swing. see http://mindprod.com/jgloss/font.html#BUNDLING and http://mindprod.com/jgloss/font.html#GOTCHAS
package com.mindprod.example; import java.awt.Color; import java.awt.Font; import java.awt.FontFormatException; import java.io.IOException; import java.io.InputStream;
import javax.swing.JFrame; import javax.swing.JLabel; /** * How to include a custom font with your application.<br> * Demonstrate use of java.awt.Font.createFont<br> * Accessing an uninstalled Font bundled in a jar or on the classpath.<br> * Note this technique is illegal if you don't have licensing permission from * the font designer. * This only works in Swing! * * @author Roedy Green */ public class TestCreateFont {
/** * Debugging harness for a Frame * * @param args * command line arguments are ignored. * @throws FontFormatException * if font is not a valid TrueType font * @throws IOException * if there is some problem reading the font file. */ public static void main ( String args[] ) throws FontFormatException, IOException { final JFrame frame = new JFrame();
// Uninstalled font is a resource on classpath or in jar named // "com/mindprod/example/IGLOOLAS.TTF" // This example font is a decorative font with snowcaps // on the capital letters.
InputStream fontStream = TestCreateFont.class .getResourceAsStream( "IGLOOLAS.TTF" ); Font onePoint = Font.createFont( Font.TRUETYPE_FONT, fontStream ); fontStream.close(); Font snowFont = onePoint.deriveFont( Font.PLAIN, 18 ); System.out.println( snowFont );
JLabel label = new JLabel( "SNOW ALERT" ); label.setBackground( Color.WHITE ); label.setForeground( Color.BLACK ); label.setFont( snowFont );
frame.add( label ); frame.setSize( 300, 100 ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.validate(); frame.setVisible( true ); } // end main } // end class
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Oliver - 08 Jan 2006 15:51 GMT Thanks Roedy, you're a lifesaver. It appears to work.
Here is the core difference:
My old method (works on everything but Win XP)
InputStream in = getClass().getResourceAsStream(fileName); the_font = Font.createFont(Font.TRUETYPE_FONT, in); the_font = the_font.deriveFont((float)pointsize);
Your "new" and working method (works everywhere):
InputStream in = Screen.class.getResourceAsStream(fileName); the_font = Font.createFont(Font.TRUETYPE_FONT, in); in.close(); the_font = the_font.deriveFont(Font.PLAIN, pointsize);
As you can see, there are a couple of subtle differences. Regardless of the details it works, and it's a great relief to me. THANKS.. ^^
Oliver
Roedy Green - 09 Jan 2006 09:31 GMT >My old method (works on everything but Win XP) > [quoted text clipped - 11 lines] >As you can see, there are a couple of subtle differences. Regardless of >the details it works, and it's a great relief to me. THANKS.. ^^ I can't see why your code would fail. Leaving the stream open just wastes RAM. It should have no effect on the result. Your float cast is not needed, but it should not hurt. What is this? perhaps you are getting a different resource with a different package.
public Font deriveFont(int style, float size){ Hashtable newAttributes = (Hashtable)getRequestedAttributes().clone(); applyStyle(style, newAttributes); applySize(size, newAttributes); return new Font(newAttributes, createdFont, font2DHandle); }
is almost identical to:
public Font deriveFont(float size){ Hashtable newAttributes = (Hashtable)getRequestedAttributes().clone(); applySize(size, newAttributes); return new Font(newAttributes, createdFont, font2DHandle); }
If I were redesigning this createFont would give you a default font size somewhere in the range 10 to 12 so that if you used it plain,it would still be readable.
The other key is you must use Swing not AWT. AWT peers don't understand anything but the basic logical fonts.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|