2

Is it possible to create a custom font with a .ttf file that is inside a .jar file? I've created a jar file with the following structure

Game.jar
├──Snake  
│  ├── lib  
│  |   └── game_over.ttf  
|  ├── src  
│  |   ├── GameFrame.class  
│  |   ├── GamePanel.class  
│  |   └── SnakeGame.class

I've tried to get the custom font by doing

Font GAMEOVER_FONT;
InputStream is = this.getClass().getClassLoader().getResourceAsStream("Snake/lib/game_over.ttf");

GAMEOVER_FONT = Font.createFont(Font.TRUETYPE_FONT, is).deriveFont(200f);   
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, is));
g.setFont(GAMEOVER_FONT);

What am I doing wrong? Is it even possible to achieve what I'm trying?

André Clérigo
  • 846
  • 1
  • 10
  • 30
  • André, maybe it is just a problem when you created the question, but the name of the font in your jar is `game_over.tff `. Please, note the typo, should be 'ttf'. Then use the code from @cello - basically, include `/` before `Snake` in you path, and get rid of the second `Font.createFont` method invocation, use `ge.registerFont(GAMEOVER_FONT)`, it should work properly, – jccampanero Mar 05 '21 at 23:10
  • ye it's a typo on the question the extension is right – André Clérigo Mar 05 '21 at 23:19
  • Thank you for the clarification. And, the code of cello, does not work? It should be, indeed. Please, what problem has you got if you run it? The `null` `InputStream`? – jccampanero Mar 05 '21 at 23:22
  • I checked if (is == null) and it is when i run the jar I get ```java.io.IOException: Problem reading font data.``` – André Clérigo Mar 05 '21 at 23:23
  • 1
    Please, in your use case should be the same, but, can you try `this.getClass().getResourceAsStream()` instead of `this.getClass().getClassLoader().getResourceAsStream()`? Note the difference in `getClassLoader().`. In addition, please, place the font in your classes, your Java output directory, and try to read it from there, in order to check if there is an actual problem with the font or not. – jccampanero Mar 05 '21 at 23:31
  • Thats It! Write an answer so I can accept it as correct – André Clérigo Mar 05 '21 at 23:35
  • That is great André, I am happy to see that it worked!! – jccampanero Mar 05 '21 at 23:37

2 Answers2

2

Please, although I think in your use case the result should be the same, try:

this.getClass().getResourceAsStream()

Instead of:

this.getClass().getClassLoader().getResourceAsStream()

Note the difference in getClassLoader().

Perhaps there is some difference in the class loader hierarchy and it can provide you different outputs.

In addition, you can try placing the font in your classes, your Java output directory, and read it from there, in order to check if there is an actual problem with the font or not.

jccampanero
  • 50,989
  • 3
  • 20
  • 49
  • Does the InputStream interfere with Serialization? After that my Serialization stopped working – André Clérigo Mar 05 '21 at 23:54
  • It should not André. Please, can you explain your new problem? – jccampanero Mar 05 '21 at 23:55
  • I think its too long to post on comments should I open another issue? but anyway the error i'm getting is ```java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream``` – André Clérigo Mar 05 '21 at 23:58
  • As you wish André. If you think that the new problem is closely related with this one, modify the question, although I think it is preferable to create a new one, it is better to only post a _question_ per question in order to help people identify the actual problem that it is being resolved in the issue. – jccampanero Mar 06 '21 at 00:01
  • I have to go now, but will gladly review the new question early in the morning as well. – jccampanero Mar 06 '21 at 00:03
  • I openned an issue here https://stackoverflow.com/questions/66501097/java-io-writeabortedexception-writing-aborted-issue/66501132#66501132 but i already solved it, the InputStream was declared as a variable class so I moved it inside the constructor – André Clérigo Mar 06 '21 at 00:13
  • That is fine André, I am happy to see that you were able to solve the second issue as well. – jccampanero Mar 06 '21 at 11:06
0

1: Use an absolute path to access the font-resource, like this:

InputStream is = this.getClass().getClassLoader().getResourceAsStream("/Snake/lib/game_over.ttf");

Note the / before Snake.

If you don't use an absolute name, I think Java will search in the package of the class, and not at the root level of the Jar.

2: You are using the InputStream twice, as you actually call Font.createFont(...) twice. At least the second time, the input stream will either be closed or at the end, where nothing else can be read, so the second invocation will fail. Just use the loaded font for registering it:

GAMEOVER_FONT = Font.createFont(Font.TRUETYPE_FONT, is).deriveFont(200f);   
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(GAMEOVER_FONT); // <-- do not load 2nd time
g.setFont(GAMEOVER_FONT);
cello
  • 5,356
  • 3
  • 23
  • 28