Thursday, May 20, 2010

Adventures with Fonts

One of the biggest problems facing report developers is how to efficiently support multiple languages using multiple output formats (HTML, PDF, Excel...) BIRT provides support for multiple languages but the support is both OS and output format dependent. Having gone through this process a couple of times, I have been asked to share my experiences, hopefully it will simplify the task if you run into similar issues.

What I knew going in was that fonts are handled differently depending on the type of output. HTML fonts are rendered in the users browser, PDF fonts are rendered on the server by BIRT, and chart fonts are rendered on the server by Java AWT. On top of all that, fonts in the development environment are rendered by SWT. There are different ways to configure fonts for each of these situations.

For HTML reports, the user must have the appropriate fonts installed on their machine.

For PDF reports, BIRT renders the fonts on the server using information in the various fontsConfigXXX.xml files located in plugins/org.eclipse.birt.report.engine.fonts_XXX. The base file is fontsConfig.xml and there are additional files to handle specific operating systems. There are some useful comments in fontsConfig.xml that explain how this works. I know these files are used for PDF generation and I think they are also used for rendering fonts in the development environment.

From a previous font adventure, I knew that BIRT uses AWT to render charts, so font configuration is done in the lib folder of the JRE by manipulating various properties files. Documentation on this seems to be a bit sketchy, but this site has some information.

My customer's problem, had to do with PDF output. Thai characters were displaying as question marks in their 2.2.1.1 BIRT reports. This was happening on all the OS's they ran, including Windows, Solaris and Linux. The characters looked fine in HTML output, but the PDF rendered characters incorrectly. Their system administrator stated that they had full language packs installed on all of the machines.

I started my investigations on their Windows box, running Windows Server 2003. The first thing I looked at was the fontsConfig.xml file in plugins/org.eclipse.birt.report.engine.fonts_2.2.1.v20070823. I noticed there was a block element for Thai in the commented out section:

<block name="Thai" start="e00" end="e7f" index="27" font-family="Font-Family"/>

I realized this has the rather nice effect of dynamically switching fonts in mid-string whenever characters within this range are encountered. There's no need to use a special font in the report design and that's particularly important in multi-lingual environments.

The only problem was the font family. The sample element didn't tell me what it should be and I couldn't tell by looking looking at the font files in C:\windows\fonts. I tried downloading several font viewers but none of them told me what I needed to know.

Then I had the good luck to check on my laptop, which runs Windows 7. In Windows 7, the font listing in windows explorer shows lots more information about the fonts, including a column called "Designed For". I found there were several fonts that were "designed for" Thai and Angsana New was one that also existed on their server. I used Angsana New for the font family in the block element and restarted their web application and it fixed it!

Next I had to preform this feat on their Solaris box.

Of course I tried Angsana New right off the bat, but it wasn't going to be that easy.

I started exploring the installed packages on my on Ubuntu box by searching for "font" in the synaptic package manager. I found all kinds of programs and spent a good amount of time looking at the man pages for them and trying them out, but the only one I found that told me which fonts support which character ranges was gucharmap, the Gnome version of the character map program.

The left side has a list of "Scripts" and one of them was Thai. Clicking on that showed the Thai character set (which is relatively small). I found that holding the right mouse button down over a character would display its font name. On my Ubuntu box the font was Waree, which worked for my machine but did not solve the client's issue.

Using gucharmap on the clients machine showed that their server was using AngsanaUPC. A quick modification to the fontsConfigXXX.xml to use AngsanaUPC and the problem was resolved. The main lesson I learned from this was how to find font families that support specific blocks of unicode characters.

For windows, Windows 7 explorer works nicely. I am unsure how to handle this if you are using XP. For Linux gucharmap worked, but it was dependent on the particular distro of Linux. The only downside to this approach was the need to have XWindows access. I will continue looking for a good command line utility that can be used to research installed fonts on servers. If anyone has found a utility like this, I would love to hear about it.

Thursday, May 06, 2010

More on Chart Interactivity

In an earlier post we examined chart interactivity with a focus on the Invoke Script Action, which allowed client side scripts to be called. This post is available here.

At the end of the post we mentioned predefined variables that are passed to the script that is invoked. These variables are:


evt – The Event Object.
categoryData – The Chart Category Value.
valueData – The Chart Orthogonal Value.
valueSeriesName – The specific Series Name.
legendItemText – The specific legend entry Text.
legendItemValue – The value of the specific legend entry.
axisLabel – The value of the specific axis label selected.


What these predefined variables contain depends on the chart type, how the chart is configured and what event is being fired. For example if you define a Bar chart with legend interactivity and do not show the legend value, all the variables will be null with the exception of the evt Object and the legendItemText variable. Generally these values will be populated like (evt object is always populated):

Series Interactivity Invoke Script – categoryData, valueData, valueSeriesName populated, the rest are null.
Legend Interactivity Invoke Script – legendItemText and legendItemValue populated, the rest are null.
Axis Interactivity Invoke Script – axisLabel populated, the rest are null.
All other Interactivity Invoke Script – All are null.

To see the values you can call an invoke script function to alert them. For example, select a specific series on a chart within the third tab of the chart wizard and select interactivity. For the event enter Mouse Click. For the Action choose invoke script and enter the following script.





ShowEventData(evt, categoryData, valueData, valueSeriesName, legendItemText, legendItemValue, axisLabel);





Next add a text element to the report that has the following value.

<script language="JavaScript">

function ShowEventData(evt, categoryData, valueData, valueSeriesName, legendItemText, legendItemValue, axisLabel) {

alert( "categoryData=" + categoryData + 
"\nvalueData=" + valueData + 
"\nvalueSeriesName=" + valueSeriesName + 
"\nlegendItemText=" + legendItemText + 
"\nlegendItemValue=" + legendItemValue + 
"\naxisLabel=" + axisLabel);
 
}
</script>

Make sure you set the type to HTML for the text element. The output when clicking on the series should look similar to:



An example report that contains this event on all interactivity elements is available at Birt-Exchange.

An example that uses the predefined variables with client side script to toggle the visibly of a chart series is also available at Birt-Exchange.