Signin/Signup with: 
Welcome, Guest
Username: Password: Remember me
Questions about Android development and PDF
  • Page:
  • 1
  • 2

TOPIC:

Support for Type 1 fonts 9 years 3 months ago #8322

  • ashughes
  • ashughes's Avatar Topic Author
  • Offline
  • Junior Member
  • Junior Member
  • Posts: 37
  • Thank you received: 1
This post reflects what I have done so far to support Type 1 fonts in my implementation of the PDF Viewer SDK for Android. There are still things I don't understand and a few questions I have, so I hope others can help answer them.

According to Wikipedia :

Standard Type 1 Fonts (Standard 14 Fonts)
Fourteen typefaces, known as the standard 14 fonts, have a special significance in PDF documents:

Times (v3) (in regular, italic, bold, and bold italic)
Courier (in regular, oblique, bold and bold oblique)
Helvetica (v3) (in regular, oblique, bold and bold oblique)
Symbol
Zapf Dingbats

These fonts are sometimes called the base fourteen fonts. These fonts, or suitable substitute fonts with the same metrics, must always be available in all PDF readers and so need not be embedded in a PDF. PDF viewers must know about the metrics of these fonts. Other fonts may be substituted if they are not embedded in a PDF.


Basically, many programs that generate PDFs expect that PDF readers should be able to render PDFs that do not include the Type 1 fonts embedded in them. So instead they reference the font without embedding it.

The above quote from Wikipedia makes it sound like the PDF Viewer SDK should automatically support the Type 1 fonts without any extra work on my part:

These fonts, or suitable substitute fonts with the same metrics, must always be available in all PDF readers and so need not be embedded in a PDF.

Unfortunately it does not (yet?).

In my app that uses the PDF Viewer SDK to render PDFs, this unfortunately means if a user opens a PDF that does not have one of the Type 1 fonts embedded in it, that text is displayed incorrectly and the user is frustrated.

So, my main question is, how can I support these Type 1 fonts? Here's what I've done so far:

First, Times New Roman and Courier are fonts that must be licensed to be distributed. However there are free alternatives to these fonts that are "metrically compatible", for example Tinos and Cousine , which I am currently using.

Helvetica must also be licensed, however Roboto , which is the default font on Android, is similar to Helvetica, and seems to be a good fallback when Helvetica is not included. Apparently Arial is also similar to Helvetica, and there is a free font metrically compatible with Arial called Arimo .

I'm not really sure about Symbol and Zapf Dingbats.

Now, how do we add these fonts to the PDF Viewer SDK?

1. Add the font ttf files to the assets directory in the PDF Viewer SDK project. I created a subfolder called "fonts", so my ttf files are in "assets/fonts/" (e.g. "assets/fonts/Tinos-Regular.ttf").

2. Create a method in Global.java that copies the font file out of the assets to another location (e.g. your app data folder). For example:
private static String copyFontFromAssets(Context context, String fontName) {
    // Make sure font directory exists
    File fontDir = new File(context.getFilesDir(), "fonts");
    fontDir.mkdirs();
    // Only copy font if it doesn't already exist
    File fontFile = new File(fontDir, fontName);
    if (!fontFile.exists()) {
        try {
            InputStream src;
            FileOutputStream dst = new FileOutputStream(fontFile);
            src = context.getAssets().open("fonts/" + fontName);
            int read;
            byte buf[] = new byte[4096];
            while ((read = src.read(buf)) > 0) {
                dst.write(buf, 0, read);
            }
            src.close();
            dst.close();
        } catch (Exception e) {
        }
    }
    return fontFile.getAbsolutePath();
}

3. In between fontfileListStart() and fontfileListEnd(), call copyFontFromAssets() and add the path to the font file list. For example:
fontfileListStart();
// ...system fonts here...
fontfileListAdd(copyFontFromAssets(app, "Tinos-Regular.ttf"));
fontfileListAdd(copyFontFromAssets(app, "Tinos-Bold.ttf"));
fontfileListAdd(copyFontFromAssets(app, "Tinos-Italic.ttf"));
fontfileListAdd(copyFontFromAssets(app, "Tinos-BoldItalic.ttf"));
fontfileListAdd(copyFontFromAssets(app, "Cousine-Regular.ttf"));
fontfileListAdd(copyFontFromAssets(app, "Cousine-Bold.ttf"));
fontfileListAdd(copyFontFromAssets(app, "Cousine-Italic.ttf"));
fontfileListAdd(copyFontFromAssets(app, "Cousine-BoldItalic.ttf"));
fontfileListEnd();

4. After fontfileListEnd() and before setDefaultFont(), call fontfileMapping() to map font names to the fonts you added. For example:
// Add font mapping for Times New Roman. "Times" automatically matches to "Times-Roman", "TimesNewRoman", but not "Times New Roman".
if (!fontfileMapping("Times", "Tinos")) {
    Log.d("PDF", "Failed to map Times");
}
if (!fontfileMapping("Times New Roman", "Tinos")) {
    Log.d("PDF", "Failed to map Times New Roman");
}

// Add font mapping for Times New Roman Bold
if (!fontfileMapping("Times-Bold", "Tinos-Bold")) {
    Log.d("PDF", "Failed to map Times-Bold");
}
if (!fontfileMapping("Times New Roman,Bold", "Tinos-Bold")) {
    Log.d("PDF", "Failed to map Times New Roman,Bold");
}

// Add font mapping for Times New Roman Italic
if (!fontfileMapping("Times-Italic", "Tinos-Italic")) {
    Log.d("PDF", "Failed to map Times-Italic");
}
if (!fontfileMapping("Times New Roman,Italic", "Tinos-Italic")) {
    Log.d("PDF", "Failed to map Times New Roman,Italic");
}

// Add font mapping for Times New Roman BoldItalic
if (!fontfileMapping("Times-BoldItalic", "Tinos-BoldItalic")) {
    Log.d("PDF", "Failed to map Times-BoldItalic");
}
if (!fontfileMapping("Times New Roman,BoldItalic", "Tinos-BoldItalic")) {
    Log.d("PDF", "Failed to map Times New Roman,BoldItalic");
}

// Add font mapping for Courier
if (!fontfileMapping("Courier", "Cousine")) {
    Log.d("PDF", "Failed to map Courier");
}
if (!fontfileMapping("Courier New", "Cousine")) {
    Log.d("PDF", "Failed to map Courier New");
}

// Add font mapping for Courier Bold
if (!fontfileMapping("Courier-Bold", "Cousine-Bold")) {
    Log.d("PDF", "Failed to map Courier-Bold");
}
if (!fontfileMapping("Courier New,Bold", "Cousine-Bold")) {
    Log.d("PDF", "Failed to map Courier New,Bold");
}

// Add font mapping for Courier Italic
if (!fontfileMapping("Courier-Italic", "Cousine-Italic")) {
    Log.d("PDF", "Failed to map Courier-Italic");
}
if (!fontfileMapping("Courier New,Italic", "Cousine-Italic")) {
    Log.d("PDF", "Failed to map Courier New,Italic");
}

// Add font mapping for Courier BoldItalic
if (!fontfileMapping("Courier-BoldItalic", "Cousine-BoldItalic")) {
    Log.d("PDF", "Failed to map Courier-BoldItalic");
}
if (!fontfileMapping("Courier New,BoldItalic", "Cousine-BoldItalic")) {
    Log.d("PDF", "Failed to map Courier New,BoldItalic");
}

5. That's it. If you want to print out the list of face names, you can do the following:
int faceCount = getFaceCount();
for (int i = 0; i < faceCount; i++) {
    Log.d("PDF", "Face Name: " + getFaceName(i));
}

I found that I get a "null" face name for every call to fontfileMapping().

Questions I still have:

1. Why doesn't PDF Viewer SDK support the Type 1 fonts out of the box? Is it a font licensing limitation, or something else?

2. What is supported in PDF Viewer SDK out of the box? I see that the following files are included in the PDF Viewer SDK: rdf008, rdf013, cmaps1, cmaps2, umaps1, umaps2. These files are set in Global.java via load_std_font() and setCMapsPath(). What are these? Do these have anything to do with the Type 1 fonts, or some other font support?

3. Is there already support in PDF Viewer SDK for Symbol and Zapf Dingbats fonts? If not, is there a recommendation for how to add support?

4. Is my example above the "correct" way to add support for Times and Courier?

5. Am I missing any font mappings for Times and Courier? I had to use trial and error to determine the font mappings I included in the example above. Is there a list of font names somewhere for referencing fonts in a PDF?

6. What kind of matching does fontfileMapping() do on the first parameter (map_name)? For example, passing in "Times" appears to match both "Times-Roman" and "TimesNewRoman", but not "Times New Roman".

7. Should getFaceName() include a "null" for every call to fontfileMapping()?

Thanks,
Andrew

Please Log in or Create an account to join the conversation.

Support for Type 1 fonts 9 years 3 months ago #8323

  • ashughes
  • ashughes's Avatar Topic Author
  • Offline
  • Junior Member
  • Junior Member
  • Posts: 37
  • Thank you received: 1
Attached is a PDF I use to test some of the Type 1 fonts. The PDF contains a sentence in Arial, Times New Roman, Courier, and Roboto in each of the 4 styles (regular, bold, italic, and bold italic). The PDF doesn't have any embedded fonts.

I tried attaching a version of the PDF with the fonts embedded as well, but it won't attach to the post...it's only 340kB...
Attachments:

Please Log in or Create an account to join the conversation.

Last edit: by kokywrite.

Support for Type 1 fonts 9 years 2 months ago #8392

  • erik_mct
  • erik_mct's Avatar
  • Offline
  • New Member
  • New Member
  • Posts: 9
  • Thank you received: 0
This is an excellent set of questions and I would really like to get an official comment from the developers regarding how this should be done. I am doing something very similar in my Global class where I move the font files, add them by calling fontfileListAdd(), and then run the font file mapping. I have done some trial and error as well with various files to try to figure out how the font names come through in various cases. I have also tried to use the PDF specification to determine the names of the Type 1 fonts that I might encounter. I'm currently using the following code for my mapping, but it looks like you have some additional/different ones.
Global.fontfileMapping("Times-Roman", "Tinos");
Global.fontfileMapping("Times-Bold", "Tinos Bold");
Global.fontfileMapping("Times-Italic", "Tinos Italic");
Global.fontfileMapping("Times-BoldItalic", "Tinos Bold Italic");
Global.fontfileMapping("Courier", "Cousine");
Global.fontfileMapping("Courier-Bold", "Cousine Bold");
Global.fontfileMapping("Courier-Oblique", "Cousine Italic");
Global.fontfileMapping("Courier-BoldOblique", "Cousine Bold Italic");
Global.fontfileMapping("Helvetica", "Arimo");
Global.fontfileMapping("Helvetica-Bold", "Arimo Bold");
Global.fontfileMapping("Helvetica-Oblique", "Arimo Italic");
Global.fontfileMapping("Helvetica-BoldOblique", "Arimo Bold Italic");
Global.fontfileMapping("Times New Roman", "Tinos");
Global.fontfileMapping("Arial", "Arimo");

Please Log in or Create an account to join the conversation.

Last edit: by erik_mct.

Support for Type 1 fonts 9 years 2 months ago #8403

  • support
  • support's Avatar
  • Offline
  • Administrator
  • Administrator
  • Posts: 692
  • Thank you received: 59
Dear ashughes and erik_mct,
some aspect you should consider:
  • To make Android completely free and open source, Google decided not to include any font apart of Roboto fonts set, the operating system is lacking of font families.
  • To take library price as lower as possible we decided not to license fonts from producer. You should know that fonts are freely reproducible within documents (both printed and digital one as PDF file are) but not integrable within any software.
  • ISO ratified PDF within some declination (i.e.: PDF/A-1, PDF/X, PDF/E, etc.), aim of these ratification is to define how to share Pdf document outside our own company and how to make external companies be able to read them. ISO defined all that file should embed fonts and NEVER have dependencies from external resources.
  • Our tool is a rendering engine and not a full PDF reader. You should look our official reader ( play.google.com/store/apps/details?id=radaee.pdf ) and will see it's embedding fonts
  • We are aware about a lot of free fonts families but all of them are GPL2/3 licensed and we can't provide them to our customers.
  • We are aware a lot of developers are sharing fonts, tools and libraries infringing licenses (a lot of commercial applications are using MuPDF library, MuPDF fonts, Liberation Fonts, etc.)

For your knowledge, some interesting links and examples about fonts files:
en.wikipedia.org/wiki/Liberation_fonts
www.fonts.com/font/itc/itc-zapf-dingbats (look at Mobile Apps license, you could see each font family will cost about $300 per single apps)

Even if my reply isn't giving a direct solution about your question, I hope it could be a good explanation about our position and decision about fonts.

Please Log in or Create an account to join the conversation.

Last edit: by support.

Support for Type 1 fonts 9 years 2 months ago #8405

  • ashughes
  • ashughes's Avatar Topic Author
  • Offline
  • Junior Member
  • Junior Member
  • Posts: 37
  • Thank you received: 1
This is really great information! Thank you for clarifying your position and explaining why the Radaee PDF SDK does not have support for the Type 1 fonts.

I would really appreciate it if you could provide more insight into what the Radaee PDF SDK does provide (e.g. what are the rdf008, rdf013, cmaps1, cmaps2, umaps1, umaps2 files that are provided with the SDK?) and how we can make sure our apps do have support for the Type 1 fonts.

Basically, I would love to get answers to my questions 2-7 from my original post:

2. What is supported in PDF Viewer SDK out of the box? I see that the following files are included in the PDF Viewer SDK: rdf008, rdf013, cmaps1, cmaps2, umaps1, umaps2. These files are set in Global.java via load_std_font() and setCMapsPath(). What are these? Do these have anything to do with the Type 1 fonts, or some other font support?

3. Is there already support in PDF Viewer SDK for Symbol and Zapf Dingbats fonts? If not, is there a recommendation for how to add support?

4. Is my example above the "correct" way to add support for Times and Courier?

5. Am I missing any font mappings for Times and Courier? I had to use trial and error to determine the font mappings I included in the example above. Is there a list of font names somewhere for referencing fonts in a PDF?

6. What kind of matching does fontfileMapping() do on the first parameter (map_name)? For example, passing in "Times" appears to match both "Times-Roman" and "TimesNewRoman", but not "Times New Roman".

7. Should getFaceName() include a "null" for every call to fontfileMapping()?


You kind of already answered question 3 by referencing where to purchase a license for Zapf Dingbats, but what about Symbol? Is Symbol part of what's included with the SDK, or is that something we need to license (or find a free alternative) elsewhere? I'm not even sure what "Symbol" is, but it's listed in the Wikipedia article for the Type 1 fonts.

Also, I just wanted to note that the links I provided to the free alternatives to Times, Courier, and Arial (Tinos, Cousine, and Arimo respectively) are all Apache 2.0 licensed.

Thanks,
Andrew

Please Log in or Create an account to join the conversation.

Support for Type 1 fonts 9 years 2 months ago #8411

  • support
  • support's Avatar
  • Offline
  • Administrator
  • Administrator
  • Posts: 692
  • Thank you received: 59
Andrew, I quick reply to your last question: all the standard 14 fonts are available from the same fonts' e-commerce.

About more technical requests: I'm forwarding them to developers and will be back to you as soon as possible.
We will create a new knowledge base article about that.

Please Log in or Create an account to join the conversation.

  • Page:
  • 1
  • 2
Powered by Kunena Forum