I\'m developing a web application which use JFreeChart to render chart. However, when server dose not have any Chinese font installed, JFreeChart dose not display Chinese ch
When you create a Font directly from the TTF, Java obviously knows where to get a copy of the font file itself from within that single Font object. So why does the font also need to be registered in order to use it? The answer is that it does not always have to be registered, or at least not so long as the entire chain of control uses the original Font object directly.
The nuance is in how JFreeChart asks to render the text. Rendering of text is performed in the TextUtilities#drawRotatedString method from jcommon. On JDK7, this method will, by default:
AttributedString based on the "attributes" of the font that you have passed in,Graphics2D#drawString on the attributed string, which thenTextLayout object.TextLayout is the class that selects the actual Font object to be provided to Graphics2D. TextLayout is designed to support the rendering of multilingual text using various fonts (even if the same single source String needs to be rendered in multiple fonts) by using automatic font selection to find an appropriate font for each piece of the string.
The "attributes" mentioned above are simple facts about the font (like font family name, size, etc) that are derived from the Font that you provide. In the event that the font you've provided is unable to render all of the characters in the input string, the attributes are used to select similar fonts to use for those runs of text that need to use a different font.
When JFreeChart invokes TextLayout, it always functions like this:
Font object you supplied,Font#getFont to get a font that matches the supplied attributes (see TextLayout#singleFont), andIf you have not statically registered your font somewhere (like with GraphicsEnvironment#registerFont), then all that the static Font#getFont method will have to go on is the attribute string containing the font family name. It won't know where to access the Font object that contains the reference to the TTF, let alone any of the data needed to actually render the font.
If you don't want to register the font, then the trick is in making sure that your text is rendered only with the Font object that you provide. It so happens that there is another constructor for TextLayout that accepts a Font object directly, rather than a set of attributes that are used to look up a font.
Helpfully, JFreeChart even provides a way to force it to use this constructor instead. In TextUtilities#drawRotatedString, a special configuration parameter can be used to force JFreeChart to construct the TextLayout object itself using the exact Font object you provide.
To do this, you can either set up a jcommon.properties file like this:
jcommon.properties (which should end up in the root level of your classpath/JAR), andorg.jfree.text.UseDrawRotatedStringWorkaround=true
or else simply make a call to the static function:
TextUtilities.setUseDrawRotatedStringWorkaround(true)
This will ask JFreeChart to render the text using your font directly, and...voila! It works even without having registered the font. This was tested in the context of the question above, which is that of using JFreeChart to render the text directly to a raster image. Your mileage might vary if you are trying to render to a display device (which I did not try).
I can't say for sure. One of my applications runs inside an OSGi container and I was wary of creating PermGen classloader leaks by statically registering a Font that can never be unregistered. Using the Font object directly avoids that problem, which is why I wanted to go this route. I suppose it's always possible that a specific Java platform might have trouble if you did this, but this works fine in my tests on at least Windows, Linux, and OS X hosts with Oracle JDK 7.