Skip to content
ComPDF
DemoSampleAPI ReferenceFAQ
New Release

Open-Source PDF SDK & AI Document Processing

Get the full self-hosted SDK and AI document processing on GitHub. One-click deploy to quickly build your document workflows.

Guides

Font Management

ComPDF SDK can read font families and styles installed on the device and generate a font PsName that can be used in annotations, forms, watermarks, headers & footers, Bates numbers, and other scenarios. This chapter focuses on three things: understanding font families and styles, getting available fonts, and importing custom fonts.

Understanding font families, styles, and PsName

Font Family

Font family is the series name of a font and represents a collection of fonts with a consistent design style.

For example, Helvetica is a font family that may include multiple styles:

  • Helvetica Regular
  • Helvetica Bold
  • Helvetica Italic

These fonts share the same overall style but differ in weight or italicization.

Font Style

Font style distinguishes specific variants within the same font family, such as Regular, Bold, and Italic.

PsName

PsName is the final font name used by the SDK when setting a font. In most cases, you first get the font family and style, then generate the corresponding PsName with CPDFTextAttribute.FontNameHelper.obtainFontName().

Getting Fonts

If you want to set fonts for annotations or forms, the usual flow is:

  1. Retrieve all available font families (Font Family) on the system.
  2. Select a target font family from the list and obtain the corresponding CPDFFontName object.
  3. From CPDFFontName, retrieve the list of supported styles (Font Style) for that family.
  4. Generate the corresponding font PsName based on the font family name and style name.
  5. Use the generated PsName to set fonts for annotations, forms, and other features.

The example below shows how to obtain a usable PsName. In a real project, you can also display the font list and style list in the UI and let the user choose the font.

java
public String getFontPsName() {
    List<CPDFFontName> fontList = CPDFFont.getFontName();
    if (fontList.isEmpty()) {
        return null;
    }

    CPDFFontName fontName = fontList.get(0);
    List<String> fontStyles = fontName.getStyleName();
    if (fontStyles.isEmpty()) {
        return null;
    }

    return CPDFTextAttribute.FontNameHelper.obtainFontName(
            fontName.getFamilyName(),
            fontStyles.get(0)
    );
}
kotlin
fun getFontPsName(): String? {
    val fontName = CPDFFont.getFontName().firstOrNull() ?: return null
    val styleName = fontName.styleName.firstOrNull() ?: return null

    return CPDFTextAttribute.FontNameHelper.obtainFontName(
        fontName.familyName,
        styleName
    )
}

After you get a PsName, you can apply it to the corresponding feature object:

  • For FreeText annotations, call CPDFFreetextAnnotation.setFreetextDa(new CPDFTextAttribute(psName, fontSize, fontColor)).
  • For ListBox forms, call CPDFListboxWidget.setFontName(psName).
  • Other scenarios, such as watermarks, headers & footers, and Bates numbers, can reuse the same PsName.

Importing Custom Fonts

By default, the SDK uses fonts installed on the device system. Since system font sets may vary across regions and devices, you can extend the available fonts by importing custom fonts.

Before you start, make sure that:

  1. You have prepared the font files you want to import, such as .ttf or .otf.
  2. The font files are copied to a local directory that the app can access.
  3. CPDFSdk.setImportFontDir() is called before CPDFSdk.init().
  4. If your project enables SDK auto-initialization, switch to manual CPDFSdk.init() so the font directory is configured first.

The example below uses the demo helper CFileUtils.copyAssetsDirToPhone() to copy assets/extraFonts into the app's private directory. If your project does not include this helper, use your own file copy logic to complete the same step.

java
// Copy fonts from assets to the app storage directory
String fontDir = new File(getFilesDir(), "extraFonts/").getAbsolutePath();
CFileUtils.copyAssetsDirToPhone(
        this,
        "extraFonts",
        getFilesDir().getAbsolutePath()
);

// Whether to also load system fonts
boolean addSysFont = true;

// Set font import directory
CPDFSdk.setImportFontDir(fontDir, addSysFont);

// Initialize SDK
CPDFSdk.init(this, "your license key", true);
kotlin
// Copy fonts from assets to the app storage directory
val fontDir = File(filesDir, "extraFonts/").absolutePath
CFileUtils.copyAssetsDirToPhone(
    this,
    "extraFonts",
    filesDir.absolutePath
)

// Whether to also load system fonts
val addSysFont = true

// Set font import directory
CPDFSdk.setImportFontDir(fontDir, addSysFont)

// Initialize SDK
CPDFSdk.init(this, "your license key", true)

Note The font import directory must be set before SDK initialization, otherwise the fonts in that directory will not be loaded during the current initialization flow.

Updating the Imported Font Directory

After the SDK has been initialized, you can still dynamically update the current font directory via CPDFDocument.setImportFontDir().

Steps:

  1. Prepare a new font directory and copy the font files into it.
  2. Call CPDFDocument.setImportFontDir(fontDir, addSysFont) to update the current font source.
  3. Call CPDFFont.getFontName() again to get the latest available font list.
java
String fontDir = new File(getFilesDir(), "extraFonts2/").getAbsolutePath();
CFileUtils.copyAssetsDirToPhone(
        this,
        "extraFonts2",
        getFilesDir().getAbsolutePath()
);

boolean addSysFont = true;

// Update font directory
CPDFDocument.setImportFontDir(fontDir, addSysFont);
kotlin
val fontDir = File(filesDir, "extraFonts2/").absolutePath
CFileUtils.copyAssetsDirToPhone(
    this,
    "extraFonts2",
    filesDir.absolutePath
)

val addSysFont = true

// Update font directory
CPDFDocument.setImportFontDir(fontDir, addSysFont)

Note After re-specifying the font directory, any previously set font directories will be cleared, and only the fonts in the currently specified directory will be retained.

After the update, you can follow the previous section again to regenerate PsName and apply it to the corresponding feature object.