Tuesday, October 8, 2019

My errors much more than my trials: showtext and Cairo


Looking for some alternatives to the extrafont package to import custom fonts into R to use with graphics, I found showtext package and was immediately impressed. The intro to the showtext package “showtext: Using Fonts More Easily in R Graphs”“ says that it is able to support more font formats and more graphics devices, and avoids using external software such as Ghostscript. Also, showtext makes it even easier to use various types of fonts (TrueType, OpenType, Type 1, web fonts, etc.) in R graphs.
To create a graph using showtext, I’ll have to do the following:
  • (*) Load the font
  • Open the graphics device
  • (*) Claim that I want to use showtext to render the text
  • Plot
  • Close the device,
where only the steps marked with (*) are newly added, I was told.
One thing I need to take care. I am using Rstudio to create my posts and RstudioGD (graphic device) doesn’t work well with showtext. For that matter I’ll have to manually open one: either windows(), or bmp(), or jpeg(), or png(), or tiff(), or pdf(), or postscript().
Here, I tried out the showtext package by adapting the code for Cairo-1.png plot of the package intro. This package allows the loading of web fonts as well as fonts on the PC.
library(ggplot2)
library(showtext)
font_add_google(name = "Padauk", family = "pa-dauk")
font_add("pyi", regular = "Pyidaungsu-1.8.3_Regular.ttf")
font_add("mya-3", regular = "Myanmar3_0.ttf")
# check font loading
font.families()
[1] "sans"         "serif"        "mono"         "wqy-microhei" "pa-dauk"      "pyi"         
[7] "mya-3"       
bg <- ggplot(NULL, aes(x = 1, y = 1)) + ylim(0.8, 1.2) +
  theme(axis.title = element_blank(), axis.ticks = element_blank(),
  axis.text = element_blank())
png("png-1.png")
showtext_begin()
txt1 <- annotate("text", 1, 1.2, label = "-- With showtext package --", size = 7)
txt2 <- annotate("text", 1, 1.1, label = "Pyidaungsu font", size = 7)
txt3 <- annotate("text", 1, 1.05, label = "အ အာ အိ အီ အု အူ", family = "pyi", size = 10)
txt4 <- annotate("text", 1, 1.0, label = "Google font", size = 7, colour = "red")
txt5 <- annotate("text", 1, 0.95, label = "အ အာ အိ အီ အု အူ", family = "pa-dauk", size = 10, colour = "red")
txt6 <- annotate("text", 1, 0.9, label = "Myanmar3 font", size = 7, colour = "blue")
txt7 <- annotate("text", 1, 0.85, label = "အ အာ အိ အီ အု အူ", family = "mya-3", size = 10, colour = "blue")
print(bg + txt1 + txt2 + txt3 + txt4 + txt5 + txt6 + txt7)
showtext_end()
dev.off()
null device 
          1 
We can see that the individual code points for all the three fonts were rendered right. But combining them into syllables has not been done at all for the Pyidaungsu font!
Now I try the Cairo package to see if it could solve the problem of using custom fonts in R graphics.
First you have to install the Cairo package. Then you can directly use fonts on your Windows system by giving the actual font family name in your code for plotting. This is convenient, but the results are still NOT OK!
library(Cairo)
library(ggplot2)
bg <- ggplot(NULL, aes(x = 1, y = 1)) + ylim(0.8, 1.2) +
  theme(axis.title = element_blank(), axis.ticks = element_blank(),
  axis.text = element_blank())
CairoPNG("Cairo-1.png")
txt1 <- annotate("text", 1, 1.2, label = "-- With Cairo package --", size = 7)
txt2 <- annotate("text", 1, 1.1, label = "Pyidaungsu font", size = 7)
txt3 <- annotate("text", 1, 1.05, label = "အေ အဲ အော့ အော် အံ အား", family = "Pyidaungsu Bold", size = 9)
txt4 <- annotate("text", 1, 0.95, label = "Myanmar3 font", size = 7, colour = "blue")
txt5 <- annotate("text", 1, 0.9, label = "အေ အဲ အော့ အော် အံ အား",  family = "Myanmar3", size = 9, colour = "blue")
print(bg + txt1 + txt2 + txt3 + txt4 + txt5)
dev.off()
null device 
          1 
I’m not knowledgeable enough to be able to look into software packages to find out the source of such problems. However, in the case of showtext as described in showtext: Using System Fonts in R Graphics by Yixuan Qiu, showtext overrides the default graphics function and take over the text rendering procedure.
The basic idea behind showtext is quite simple: it converts text into raster images (for bitmap and on-screen devices) or polygons (for vector graphics), and then put them in the graphics. This design comes from the fact that handling text is a very complicated task for graphics devices, but polygons and raster images are lower-level operations that are easier to deal with. Therefore, as long as a device understands how to draw polygons or overlay bitmap on its canvas, it will also be able to show text with the help of this package.
More specifically, the showtext package develops a general framework to render text in R graphics. First, it overrides the functions contained in the graphics device that are responsible for drawing text, so that showtext will take over the text rendering procedure. Then, it uses the FreeType library to read the font file and analyze the character string that is going to be displayed in the graph. Finally, the text is transformed into basic graphical components (raster images or polygons) that can be easily rendered by the device. As a result, the created graph does not rely on the original font file, thus being platform-independent.
And I guess that was where text rendering for Myanmar Unicode didn’t work quite right for showtext. As described by Wikipedia, Cairo creates a mask consisting of vector primitive, in our case, for True Type Fonts as the first step of its drawing process. May be it got wrong at this step for rendering Myanmar Unicode fonts. May be Myanmar language users, as yet, were strangers to these systems and lack of interaction with their developers may be the reason that such problems remain undetected or remain unfixed.

No comments:

Post a Comment