Skip to content

Runbook: JasperReports PDF Font Embedding

This runbook resolves custom font rendering failures in JasperReports Server when generating PDF reports via the REST API. Without explicit font embedding configuration, characters from non-Latin or custom font families may appear as blank spaces or render incorrectly — even when the web UI displays them correctly.

  • Characters appear as blank spaces in generated PDF reports
  • Diacritics render without base characters (floating marks)
  • Reports display correctly in the JasperReports web UI but fail when called via REST API
  • Font-related errors in server logs: Font is not available to the JVM
IssueRoot Cause
Characters rendered as spaces in PDFJasperReports Engine lacks the custom font and the font is not embedded in the PDF output
Web UI works but REST API failsThe REST API pipeline loads fonts separately and ignores extension fonts unless globally configured
Server restart fails (BindException)Zombie Tomcat / Java processes are still holding the port from a previous failed shutdown
Report deployment fails silentlyPermission mismatch — .jar files owned by root when Tomcat runs as a different OS user

graph TB
    subgraph "Font Preparation (Jaspersoft Studio)"
        A[Add Custom Font<br/>e.g. CustomFont.ttf] --> B[Configure PDF Settings<br/>Identity-H encoding, Embed enabled]
        B --> C[Export as .jar<br/>CustomFont.jar]
    end

    subgraph "Server Installation (Ubuntu)"
        C --> D[Upload to Server<br/>/opt/tomcat/webapps/jasperserver/WEB-INF/lib/]
        D --> E[Set Permissions<br/>chown tomcat:tomcat]
    end

    subgraph "Global Configuration"
        E --> F[Edit jasperreports.properties<br/>Enable font extension]
        F --> G[Set default font name]
        G --> H[Enable PDF embedding<br/>Identity-H encoding]
    end

    subgraph "Service Restart"
        H --> I[Kill zombie processes]
        I --> J[Clear Tomcat cache]
        J --> K[Restart Tomcat]
    end

    style A fill:#e1f5ff
    style D fill:#fff4e1
    style F fill:#ffe0e0
    style I fill:#ffebee

Step 1: Prepare Font Extension in Jaspersoft Studio

Section titled “Step 1: Prepare Font Extension in Jaspersoft Studio”
  1. Open Jaspersoft Studio
  2. Navigate to: PreferencesFonts
  3. Click Add and select your font file (e.g., CustomFont.ttf)
  4. Set Family Name to match how you will reference it in reports

Navigate to the PDF Details tab for the font:

SettingValueDescription
PDF EncodingIdentity-HUnicode horizontal encoding — required for non-Latin scripts
Embed this font in PDF document✅ CheckedCritical: Font data must be physically embedded in the PDF
  1. Click Export
  2. Save as: CustomFont.jar
  3. The JAR contains:
    • Font files (.ttf)
    • Font descriptor XML (fontsfamily.xml)
    • Extension properties (jasperreports_extension.properties)

Step 2: Install Font Extension on the Server

Section titled “Step 2: Install Font Extension on the Server”

Transfer the .jar file to the server:

Terminal window
# Option 1: SCP
scp CustomFont.jar user@your-server:/tmp/
# Option 2: SFTP
sftp user@your-server
put CustomFont.jar /tmp/

Move to the JasperReports lib directory:

Terminal window
sudo mv /tmp/CustomFont.jar /opt/tomcat/webapps/jasperserver/WEB-INF/lib/

Critical: The JAR must be owned by the OS user that runs Tomcat (commonly tomcat), not root.

Terminal window
# Set ownership
sudo chown tomcat:tomcat /opt/tomcat/webapps/jasperserver/WEB-INF/lib/CustomFont.jar
# Set read permissions
sudo chmod 644 /opt/tomcat/webapps/jasperserver/WEB-INF/lib/CustomFont.jar

Verify:

Terminal window
ls -l /opt/tomcat/webapps/jasperserver/WEB-INF/lib/CustomFont.jar
# Expected: -rw-r--r-- 1 tomcat tomcat <size> <date> CustomFont.jar

Step 3: Configure Global JasperReports Settings

Section titled “Step 3: Configure Global JasperReports Settings”

This step forces JasperReports to embed fonts in all reports — including those generated via REST API — without modifying individual .jrxml files.

Terminal window
sudo nano /opt/tomcat/webapps/jasperserver/WEB-INF/classes/jasperreports.properties

Append the following to the end of the file:

# Enable font extension registry
net.sf.jasperreports.extension.registry.factory.fonts=net.sf.jasperreports.extensions.DefaultExtensionsRegistryFactory
# Set the default font (must match Family Name in Studio)
net.sf.jasperreports.default.font.name=CustomFont
# Unicode horizontal encoding for non-Latin character support
net.sf.jasperreports.default.pdf.encoding=Identity-H
# Force font embedding in all PDF exports
net.sf.jasperreports.default.pdf.embedded=true
PropertyValuePurpose
extension.registry.factory.fontsDefaultExtensionsRegistryFactoryEnables the .jar-based font extension system
default.font.nameCustomFontDefault font for all reports (must match JAR Family Name)
default.pdf.encodingIdentity-HUnicode horizontal encoding for non-Latin scripts
default.pdf.embeddedtrueForces font data to be physically embedded in every PDF

Why global configuration works where per-report configuration fails:

  • Applies system-wide — no need to modify individual .jrxml files
  • REST API PDF generation picks up this configuration; per-extension loading does not apply to the API pipeline
  • Existing reports automatically inherit the configured font

Terminal window
ps -ef | grep tomcat
Terminal window
sudo pkill -9 -f tomcat
# Verify no processes remain
ps -ef | grep tomcat
Terminal window
sudo rm -rf /opt/tomcat/work/Catalina/localhost/jasperserver
# Verify deletion
ls /opt/tomcat/work/Catalina/localhost/
Terminal window
sudo /opt/tomcat/bin/startup.sh
# Monitor startup logs
tail -f /opt/tomcat/logs/catalina.out

Wait for the startup completion message:

INFO: Server startup in [XXXX] milliseconds

Terminal window
tail -f /opt/tomcat/logs/catalina.out | grep -i font

Expected: No Font is not available to the JVM errors.

If errors appear: The JAR is not loading correctly. Check:

  • File permissions (-rw-r--r--, owned by tomcat)
  • File location (WEB-INF/lib/ directory)
  • Configuration syntax in jasperreports.properties
Terminal window
curl -X POST "http://your-server:8080/jasperserver/rest_v2/reports/reports/sample_report.pdf" \
-H "Authorization: Basic $(echo -n 'username:password' | base64)" \
-H "Content-Type: application/json" \
-d '{}' \
--output test-report.pdf

Open test-report.pdf and verify:

  1. Custom-font characters render correctly (not blank)
  2. PDF properties show the font listed under Embedded Fonts

PDF files with embedded fonts are noticeably larger:

Without embedded font: ~50 KB
With embedded font: ~150 KB (varies by font file size)

If file size is unchanged after the fix, the font is still not being embedded — recheck Step 3.


Issue 1: “Font is not available” persists after restart

Section titled “Issue 1: “Font is not available” persists after restart”

Steps:

Terminal window
# Verify JAR contains font files
jar -tf /opt/tomcat/webapps/jasperserver/WEB-INF/lib/CustomFont.jar | grep ttf
# Check extension properties inside JAR
unzip -p /opt/tomcat/webapps/jasperserver/WEB-INF/lib/CustomFont.jar \
jasperreports_extension.properties
# Verify family name in JAR matches properties file
unzip -p /opt/tomcat/webapps/jasperserver/WEB-INF/lib/CustomFont.jar \
fontsfamily*.xml | grep "<family>"

Issue 2: Port Already in Use (BindException)

Section titled “Issue 2: Port Already in Use (BindException)”
Terminal window
# Find the process holding the port
sudo lsof -i :8080
# Kill it
sudo kill -9 <PID>
# Or via systemctl
sudo systemctl stop tomcat
sudo systemctl start tomcat
Terminal window
# Fix ownership recursively
sudo chown -R tomcat:tomcat /opt/tomcat/webapps/jasperserver/
# Fix permissions
sudo chmod -R 755 /opt/tomcat/webapps/jasperserver/

Root Cause: The REST API generates PDFs in a separate pipeline that does not load fonts from web extensions unless jasperreports.properties forces them globally.

Solution: Ensure Step 3 is complete and Tomcat was fully restarted (no zombie processes).

  • Font JAR is in WEB-INF/lib/
  • Permissions are 644, owned by tomcat
  • jasperreports.properties has all 4 configuration lines
  • Server restarted cleanly (no zombie processes)
  • No font errors in catalina.out

If all above pass, enable debug logging:

Terminal window
sudo nano /opt/tomcat/webapps/jasperserver/WEB-INF/classes/log4j.properties
# Add:
log4j.logger.net.sf.jasperreports=DEBUG
# Restart and inspect:
tail -f /opt/tomcat/logs/catalina.out | grep jasperreports

/opt/scripts/check-jasper-fonts.sh
#!/bin/bash
FONT_JAR="/opt/tomcat/webapps/jasperserver/WEB-INF/lib/CustomFont.jar"
PROPERTIES="/opt/tomcat/webapps/jasperserver/WEB-INF/classes/jasperreports.properties"
FONT_NAME="CustomFont"
echo "=== JasperReports Font Health Check ==="
# Check JAR exists
if [ -f "$FONT_JAR" ]; then
echo "OK Font JAR exists: $FONT_JAR"
ls -lh "$FONT_JAR"
else
echo "FAIL Font JAR missing: $FONT_JAR"
fi
# Check permissions
OWNER=$(stat -c '%U:%G' "$FONT_JAR" 2>/dev/null)
if [ "$OWNER" == "tomcat:tomcat" ]; then
echo "OK Correct ownership: $OWNER"
else
echo "FAIL Wrong ownership: $OWNER (expected tomcat:tomcat)"
fi
# Check configuration
if grep -q "net.sf.jasperreports.default.font.name=${FONT_NAME}" "$PROPERTIES"; then
echo "OK Font configuration found in jasperreports.properties"
else
echo "FAIL Font configuration missing from jasperreports.properties"
fi
# Check Tomcat process
if pgrep -f tomcat > /dev/null; then
echo "OK Tomcat is running"
else
echo "FAIL Tomcat is not running"
fi
echo "=== Check Complete ==="
Terminal window
sudo chmod +x /opt/scripts/check-jasper-fonts.sh
sudo /opt/scripts/check-jasper-fonts.sh