Runbook: JasperReports PDF Font Embedding
Overview
Section titled “Overview”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.
Problem Description
Section titled “Problem Description”Symptoms
Section titled “Symptoms”- 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
Root Cause Analysis
Section titled “Root Cause Analysis”| Issue | Root Cause |
|---|---|
| Characters rendered as spaces in PDF | JasperReports Engine lacks the custom font and the font is not embedded in the PDF output |
| Web UI works but REST API fails | The 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 silently | Permission mismatch — .jar files owned by root when Tomcat runs as a different OS user |
Solution Architecture
Section titled “Solution Architecture”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-by-Step Resolution
Section titled “Step-by-Step Resolution”Step 1: Prepare Font Extension in Jaspersoft Studio
Section titled “Step 1: Prepare Font Extension in Jaspersoft Studio”1.1 Add the Custom Font
Section titled “1.1 Add the Custom Font”- Open Jaspersoft Studio
- Navigate to: Preferences → Fonts
- Click Add and select your font file (e.g.,
CustomFont.ttf) - Set Family Name to match how you will reference it in reports
1.2 Configure PDF Embedding (Critical)
Section titled “1.2 Configure PDF Embedding (Critical)”Navigate to the PDF Details tab for the font:
| Setting | Value | Description |
|---|---|---|
| PDF Encoding | Identity-H | Unicode horizontal encoding — required for non-Latin scripts |
| Embed this font in PDF document | ✅ Checked | Critical: Font data must be physically embedded in the PDF |
1.3 Export Font Extension
Section titled “1.3 Export Font Extension”- Click Export
- Save as:
CustomFont.jar - The JAR contains:
- Font files (
.ttf) - Font descriptor XML (
fontsfamily.xml) - Extension properties (
jasperreports_extension.properties)
- Font files (
Step 2: Install Font Extension on the Server
Section titled “Step 2: Install Font Extension on the Server”2.1 Upload Font JAR
Section titled “2.1 Upload Font JAR”Transfer the .jar file to the server:
# Option 1: SCPscp CustomFont.jar user@your-server:/tmp/
# Option 2: SFTPsftp user@your-serverput CustomFont.jar /tmp/Move to the JasperReports lib directory:
sudo mv /tmp/CustomFont.jar /opt/tomcat/webapps/jasperserver/WEB-INF/lib/2.2 Set Correct File Permissions
Section titled “2.2 Set Correct File Permissions”Critical: The JAR must be owned by the OS user that runs Tomcat (commonly tomcat), not root.
# Set ownershipsudo chown tomcat:tomcat /opt/tomcat/webapps/jasperserver/WEB-INF/lib/CustomFont.jar
# Set read permissionssudo chmod 644 /opt/tomcat/webapps/jasperserver/WEB-INF/lib/CustomFont.jarVerify:
ls -l /opt/tomcat/webapps/jasperserver/WEB-INF/lib/CustomFont.jar# Expected: -rw-r--r-- 1 tomcat tomcat <size> <date> CustomFont.jarStep 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.
3.1 Open the Global Configuration File
Section titled “3.1 Open the Global Configuration File”sudo nano /opt/tomcat/webapps/jasperserver/WEB-INF/classes/jasperreports.properties3.2 Add Font Extension Configuration
Section titled “3.2 Add Font Extension Configuration”Append the following to the end of the file:
# Enable font extension registrynet.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 supportnet.sf.jasperreports.default.pdf.encoding=Identity-H
# Force font embedding in all PDF exportsnet.sf.jasperreports.default.pdf.embedded=trueConfiguration Reference
Section titled “Configuration Reference”| Property | Value | Purpose |
|---|---|---|
extension.registry.factory.fonts | DefaultExtensionsRegistryFactory | Enables the .jar-based font extension system |
default.font.name | CustomFont | Default font for all reports (must match JAR Family Name) |
default.pdf.encoding | Identity-H | Unicode horizontal encoding for non-Latin scripts |
default.pdf.embedded | true | Forces 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
.jrxmlfiles - 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
Step 4: Clean Server Restart
Section titled “Step 4: Clean Server Restart”4.1 Check for Zombie Processes
Section titled “4.1 Check for Zombie Processes”ps -ef | grep tomcat4.2 Kill All Tomcat Processes
Section titled “4.2 Kill All Tomcat Processes”sudo pkill -9 -f tomcat
# Verify no processes remainps -ef | grep tomcat4.3 Clear Tomcat Cache
Section titled “4.3 Clear Tomcat Cache”sudo rm -rf /opt/tomcat/work/Catalina/localhost/jasperserver
# Verify deletionls /opt/tomcat/work/Catalina/localhost/4.4 Start Tomcat
Section titled “4.4 Start Tomcat”sudo /opt/tomcat/bin/startup.sh
# Monitor startup logstail -f /opt/tomcat/logs/catalina.outWait for the startup completion message:
INFO: Server startup in [XXXX] millisecondsVerification
Section titled “Verification”Test 1: Check Font Availability in Logs
Section titled “Test 1: Check Font Availability in Logs”tail -f /opt/tomcat/logs/catalina.out | grep -i fontExpected: 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 bytomcat) - File location (
WEB-INF/lib/directory) - Configuration syntax in
jasperreports.properties
Test 2: Test REST API PDF Generation
Section titled “Test 2: Test REST API PDF Generation”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.pdfOpen test-report.pdf and verify:
- Custom-font characters render correctly (not blank)
- PDF properties show the font listed under Embedded Fonts
Test 3: File Size Check
Section titled “Test 3: File Size Check”PDF files with embedded fonts are noticeably larger:
Without embedded font: ~50 KBWith 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.
Troubleshooting
Section titled “Troubleshooting”Issue 1: “Font is not available” persists after restart
Section titled “Issue 1: “Font is not available” persists after restart”Steps:
# Verify JAR contains font filesjar -tf /opt/tomcat/webapps/jasperserver/WEB-INF/lib/CustomFont.jar | grep ttf
# Check extension properties inside JARunzip -p /opt/tomcat/webapps/jasperserver/WEB-INF/lib/CustomFont.jar \ jasperreports_extension.properties
# Verify family name in JAR matches properties fileunzip -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)”# Find the process holding the portsudo lsof -i :8080
# Kill itsudo kill -9 <PID>
# Or via systemctlsudo systemctl stop tomcatsudo systemctl start tomcatIssue 3: Permission Denied Errors
Section titled “Issue 3: Permission Denied Errors”# Fix ownership recursivelysudo chown -R tomcat:tomcat /opt/tomcat/webapps/jasperserver/
# Fix permissionssudo chmod -R 755 /opt/tomcat/webapps/jasperserver/Issue 4: Web UI Works, REST API Does Not
Section titled “Issue 4: Web UI Works, REST API Does Not”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).
Issue 5: Complete Debug Checklist
Section titled “Issue 5: Complete Debug Checklist”- Font JAR is in
WEB-INF/lib/ - Permissions are
644, owned bytomcat -
jasperreports.propertieshas all 4 configuration lines - Server restarted cleanly (no zombie processes)
- No font errors in
catalina.out
If all above pass, enable debug logging:
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 jasperreportsMonitoring: Health Check Script
Section titled “Monitoring: Health Check Script”#!/bin/bashFONT_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 existsif [ -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 permissionsOWNER=$(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 configurationif 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 processif pgrep -f tomcat > /dev/null; then echo "OK Tomcat is running"else echo "FAIL Tomcat is not running"fi
echo "=== Check Complete ==="sudo chmod +x /opt/scripts/check-jasper-fonts.shsudo /opt/scripts/check-jasper-fonts.sh