mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-11-16 01:21:16 +01:00
move fonts and auto bold
This commit is contained in:
parent
f645eaff18
commit
e2ba4cf693
BIN
app/core/src/main/resources/static/fonts/DejaVuSans-Bold.ttf
Normal file
BIN
app/core/src/main/resources/static/fonts/DejaVuSans-Bold.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
app/core/src/main/resources/static/fonts/DejaVuSans-Oblique.ttf
Normal file
BIN
app/core/src/main/resources/static/fonts/DejaVuSans-Oblique.ttf
Normal file
Binary file not shown.
BIN
app/core/src/main/resources/static/fonts/DejaVuSans.ttf
Normal file
BIN
app/core/src/main/resources/static/fonts/DejaVuSans.ttf
Normal file
Binary file not shown.
BIN
app/core/src/main/resources/static/fonts/DejaVuSansMono-Bold.ttf
Normal file
BIN
app/core/src/main/resources/static/fonts/DejaVuSansMono-Bold.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
app/core/src/main/resources/static/fonts/DejaVuSansMono.ttf
Normal file
BIN
app/core/src/main/resources/static/fonts/DejaVuSansMono.ttf
Normal file
Binary file not shown.
BIN
app/core/src/main/resources/static/fonts/DejaVuSerif-Bold.ttf
Normal file
BIN
app/core/src/main/resources/static/fonts/DejaVuSerif-Bold.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
app/core/src/main/resources/static/fonts/DejaVuSerif-Italic.ttf
Normal file
BIN
app/core/src/main/resources/static/fonts/DejaVuSerif-Italic.ttf
Normal file
Binary file not shown.
BIN
app/core/src/main/resources/static/fonts/DejaVuSerif.ttf
Normal file
BIN
app/core/src/main/resources/static/fonts/DejaVuSerif.ttf
Normal file
Binary file not shown.
BIN
app/core/src/main/resources/static/fonts/LiberationMono-Bold.ttf
Normal file
BIN
app/core/src/main/resources/static/fonts/LiberationMono-Bold.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
app/core/src/main/resources/static/fonts/NotoSans-Bold.ttf
Normal file
BIN
app/core/src/main/resources/static/fonts/NotoSans-Bold.ttf
Normal file
Binary file not shown.
BIN
app/core/src/main/resources/static/fonts/NotoSans-BoldItalic.ttf
Normal file
BIN
app/core/src/main/resources/static/fonts/NotoSans-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
app/core/src/main/resources/static/fonts/NotoSans-Italic.ttf
Normal file
BIN
app/core/src/main/resources/static/fonts/NotoSans-Italic.ttf
Normal file
Binary file not shown.
@ -49,7 +49,16 @@ public class PdfJsonFallbackFontService {
|
||||
Map.entry("tinos", "fallback-liberation-serif"),
|
||||
Map.entry("courier", "fallback-liberation-mono"),
|
||||
Map.entry("couriernew", "fallback-liberation-mono"),
|
||||
Map.entry("cousine", "fallback-liberation-mono"));
|
||||
Map.entry("cousine", "fallback-liberation-mono"),
|
||||
// DejaVu fonts - widely used open source fonts
|
||||
Map.entry("dejavu", "fallback-dejavu-sans"),
|
||||
Map.entry("dejavusans", "fallback-dejavu-sans"),
|
||||
Map.entry("dejavuserif", "fallback-dejavu-serif"),
|
||||
Map.entry("dejavumono", "fallback-dejavu-mono"),
|
||||
Map.entry("dejavusansmono", "fallback-dejavu-mono"),
|
||||
// Noto Sans - Google's universal font (use as last resort generic fallback)
|
||||
Map.entry("noto", "fallback-noto-sans"),
|
||||
Map.entry("notosans", "fallback-noto-sans"));
|
||||
|
||||
private static final Map<String, FallbackFontSpec> BUILT_IN_FALLBACK_FONTS =
|
||||
Map.ofEntries(
|
||||
@ -85,40 +94,172 @@ public class PdfJsonFallbackFontService {
|
||||
Map.entry(
|
||||
"fallback-liberation-sans",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/pdfjs-legacy/standard_fonts/LiberationSans-Regular.ttf",
|
||||
"classpath:/static/fonts/LiberationSans-Regular.ttf",
|
||||
"LiberationSans-Regular",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-liberation-sans-bold",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/pdfjs-legacy/standard_fonts/LiberationSans-Bold.ttf",
|
||||
"classpath:/static/fonts/LiberationSans-Bold.ttf",
|
||||
"LiberationSans-Bold",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-liberation-sans-italic",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/pdfjs-legacy/standard_fonts/LiberationSans-Italic.ttf",
|
||||
"classpath:/static/fonts/LiberationSans-Italic.ttf",
|
||||
"LiberationSans-Italic",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-liberation-sans-bolditalic",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/pdfjs-legacy/standard_fonts/LiberationSans-BoldItalic.ttf",
|
||||
"classpath:/static/fonts/LiberationSans-BoldItalic.ttf",
|
||||
"LiberationSans-BoldItalic",
|
||||
"ttf")),
|
||||
// Liberation Serif family
|
||||
Map.entry(
|
||||
"fallback-liberation-serif",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/pdfjs-legacy/standard_fonts/LiberationSerif-Regular.ttf",
|
||||
"classpath:/static/fonts/LiberationSerif-Regular.ttf",
|
||||
"LiberationSerif-Regular",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-liberation-serif-bold",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/LiberationSerif-Bold.ttf",
|
||||
"LiberationSerif-Bold",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-liberation-serif-italic",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/LiberationSerif-Italic.ttf",
|
||||
"LiberationSerif-Italic",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-liberation-serif-bolditalic",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/LiberationSerif-BoldItalic.ttf",
|
||||
"LiberationSerif-BoldItalic",
|
||||
"ttf")),
|
||||
// Liberation Mono family
|
||||
Map.entry(
|
||||
"fallback-liberation-mono",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/pdfjs-legacy/standard_fonts/LiberationMono-Regular.ttf",
|
||||
"classpath:/static/fonts/LiberationMono-Regular.ttf",
|
||||
"LiberationMono-Regular",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-liberation-mono-bold",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/LiberationMono-Bold.ttf",
|
||||
"LiberationMono-Bold",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-liberation-mono-italic",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/LiberationMono-Italic.ttf",
|
||||
"LiberationMono-Italic",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-liberation-mono-bolditalic",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/LiberationMono-BoldItalic.ttf",
|
||||
"LiberationMono-BoldItalic",
|
||||
"ttf")),
|
||||
// Noto Sans family (enhanced with weight variants)
|
||||
Map.entry(
|
||||
FALLBACK_FONT_ID,
|
||||
new FallbackFontSpec(
|
||||
DEFAULT_FALLBACK_FONT_LOCATION, "NotoSans-Regular", "ttf")),
|
||||
Map.entry(
|
||||
"fallback-noto-sans-bold",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/NotoSans-Bold.ttf",
|
||||
"NotoSans-Bold",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-noto-sans-italic",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/NotoSans-Italic.ttf",
|
||||
"NotoSans-Italic",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-noto-sans-bolditalic",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/NotoSans-BoldItalic.ttf",
|
||||
"NotoSans-BoldItalic",
|
||||
"ttf")),
|
||||
// DejaVu Sans family
|
||||
Map.entry(
|
||||
"fallback-dejavu-sans",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/DejaVuSans.ttf", "DejaVuSans", "ttf")),
|
||||
Map.entry(
|
||||
"fallback-dejavu-sans-bold",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/DejaVuSans-Bold.ttf",
|
||||
"DejaVuSans-Bold",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-dejavu-sans-oblique",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/DejaVuSans-Oblique.ttf",
|
||||
"DejaVuSans-Oblique",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-dejavu-sans-boldoblique",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/DejaVuSans-BoldOblique.ttf",
|
||||
"DejaVuSans-BoldOblique",
|
||||
"ttf")),
|
||||
// DejaVu Serif family
|
||||
Map.entry(
|
||||
"fallback-dejavu-serif",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/DejaVuSerif.ttf",
|
||||
"DejaVuSerif",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-dejavu-serif-bold",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/DejaVuSerif-Bold.ttf",
|
||||
"DejaVuSerif-Bold",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-dejavu-serif-italic",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/DejaVuSerif-Italic.ttf",
|
||||
"DejaVuSerif-Italic",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-dejavu-serif-bolditalic",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/DejaVuSerif-BoldItalic.ttf",
|
||||
"DejaVuSerif-BoldItalic",
|
||||
"ttf")),
|
||||
// DejaVu Mono family
|
||||
Map.entry(
|
||||
"fallback-dejavu-mono",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/DejaVuSansMono.ttf",
|
||||
"DejaVuSansMono",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-dejavu-mono-bold",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/DejaVuSansMono-Bold.ttf",
|
||||
"DejaVuSansMono-Bold",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-dejavu-mono-oblique",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/DejaVuSansMono-Oblique.ttf",
|
||||
"DejaVuSansMono-Oblique",
|
||||
"ttf")),
|
||||
Map.entry(
|
||||
"fallback-dejavu-mono-boldoblique",
|
||||
new FallbackFontSpec(
|
||||
"classpath:/static/fonts/DejaVuSansMono-BoldOblique.ttf",
|
||||
"DejaVuSansMono-BoldOblique",
|
||||
"ttf")));
|
||||
|
||||
private final ResourceLoader resourceLoader;
|
||||
@ -198,7 +339,7 @@ public class PdfJsonFallbackFontService {
|
||||
|
||||
/**
|
||||
* Resolve fallback font ID based on the original font name and code point. Attempts to match
|
||||
* font family for visual consistency.
|
||||
* font family and weight/style for visual consistency.
|
||||
*
|
||||
* @param originalFontName the name of the original font (may be null)
|
||||
* @param codePoint the Unicode code point that needs to be rendered
|
||||
@ -223,13 +364,22 @@ public class PdfJsonFallbackFontService {
|
||||
|
||||
String aliasedFontId = FONT_NAME_ALIASES.get(baseName);
|
||||
if (aliasedFontId != null) {
|
||||
// Detect weight and style from the normalized font name
|
||||
boolean isBold = detectBold(normalized);
|
||||
boolean isItalic = detectItalic(normalized);
|
||||
|
||||
// Apply weight/style suffix to fallback font ID
|
||||
String styledFontId = applyWeightStyle(aliasedFontId, isBold, isItalic);
|
||||
|
||||
log.debug(
|
||||
"Matched font '{}' (normalized: '{}', base: '{}') to fallback '{}'",
|
||||
"Matched font '{}' (normalized: '{}', base: '{}', bold: {}, italic: {}) to fallback '{}'",
|
||||
originalFontName,
|
||||
normalized,
|
||||
baseName,
|
||||
aliasedFontId);
|
||||
return aliasedFontId;
|
||||
isBold,
|
||||
isItalic,
|
||||
styledFontId);
|
||||
return styledFontId;
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,6 +387,89 @@ public class PdfJsonFallbackFontService {
|
||||
return resolveFallbackFontId(codePoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if font name indicates bold weight.
|
||||
*
|
||||
* @param normalizedFontName lowercase font name without subset prefix or spaces
|
||||
* @return true if bold weight is detected
|
||||
*/
|
||||
private boolean detectBold(String normalizedFontName) {
|
||||
// Check for explicit bold indicators
|
||||
if (normalizedFontName.contains("bold")
|
||||
|| normalizedFontName.contains("heavy")
|
||||
|| normalizedFontName.contains("black")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for numeric weight indicators (600-900 = bold)
|
||||
// Handles: "Arimo_700wght", "Arial-700", "Font-w700"
|
||||
if (normalizedFontName.matches(".*[_-]?[6-9]00(wght)?.*")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if font name indicates italic/oblique style.
|
||||
*
|
||||
* @param normalizedFontName lowercase font name without subset prefix or spaces
|
||||
* @return true if italic style is detected
|
||||
*/
|
||||
private boolean detectItalic(String normalizedFontName) {
|
||||
return normalizedFontName.contains("italic") || normalizedFontName.contains("oblique");
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply weight/style suffix to fallback font ID.
|
||||
*
|
||||
* <p>Weight/style variants are only applied to font families where we have the actual font
|
||||
* files available. Currently supported: - Liberation Sans: Regular, Bold, Italic, BoldItalic
|
||||
* (full support) - Liberation Serif: Regular, Bold, Italic, BoldItalic (full support) -
|
||||
* Liberation Mono: Regular, Bold, Italic, BoldItalic (full support) - Noto Sans: Regular, Bold,
|
||||
* Italic, BoldItalic (full support) - DejaVu Sans: Regular, Bold, Oblique, BoldOblique (full
|
||||
* support) - DejaVu Serif: Regular, Bold, Italic, BoldItalic (full support) - DejaVu Mono:
|
||||
* Regular, Bold, Oblique, BoldOblique (full support)
|
||||
*
|
||||
* <p>To add weight/style support for additional font families: 1. Download the font files
|
||||
* (Bold, Italic, BoldItalic) to: app/core/src/main/resources/static/fonts/ 2. Register the
|
||||
* variants in BUILT_IN_FALLBACK_FONTS map (see lines 63-267) 3. Update the check below to
|
||||
* include the font family prefix
|
||||
*
|
||||
* @param baseFontId base fallback font ID (e.g., "fallback-liberation-sans")
|
||||
* @param isBold true if bold weight needed
|
||||
* @param isItalic true if italic style needed
|
||||
* @return styled font ID (e.g., "fallback-liberation-sans-bold"), or base ID if variants not
|
||||
* available
|
||||
*/
|
||||
private String applyWeightStyle(String baseFontId, boolean isBold, boolean isItalic) {
|
||||
// Only apply weight/style to font families where we have the font files available
|
||||
// Supported: Liberation (Sans/Serif/Mono), Noto Sans, DejaVu (Sans/Serif/Mono)
|
||||
boolean isSupported =
|
||||
baseFontId.startsWith("fallback-liberation-")
|
||||
|| baseFontId.equals("fallback-noto-sans")
|
||||
|| baseFontId.startsWith("fallback-dejavu-");
|
||||
|
||||
if (!isSupported) {
|
||||
return baseFontId;
|
||||
}
|
||||
|
||||
// DejaVu Sans and Mono use "oblique" instead of "italic"
|
||||
boolean useOblique =
|
||||
baseFontId.equals("fallback-dejavu-sans")
|
||||
|| baseFontId.equals("fallback-dejavu-mono");
|
||||
|
||||
if (isBold && isItalic) {
|
||||
return baseFontId + (useOblique ? "-boldoblique" : "-bolditalic");
|
||||
} else if (isBold) {
|
||||
return baseFontId + "-bold";
|
||||
} else if (isItalic) {
|
||||
return baseFontId + (useOblique ? "-oblique" : "-italic");
|
||||
}
|
||||
|
||||
return baseFontId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve fallback font ID based on Unicode code point properties.
|
||||
*
|
||||
|
||||
@ -23,15 +23,19 @@
|
||||
- Update `buildFontMap` to resolve aliases when recreating PDFBox fonts, and adjust the front end to load programs via the canonical UID.
|
||||
- Optional: expose a lazy endpoint for the original COS dictionary if the canonical record strips it, so export still reconstructs untouched fonts.
|
||||
|
||||
- **Font Weight Matching for Fallback Fonts**
|
||||
- Font family matching is now implemented (Arial→LiberationSans, Times→LiberationSerif, Courier→LiberationMono).
|
||||
- However, fallback fonts still use Regular weight for all missing glyphs, regardless of the original font weight (e.g., bold text falls back to regular weight).
|
||||
- TODO: Parse weight from font names (e.g., `Arimo_700wght`, `Arial-Bold`, `TimesNewRoman,SemiBold`) and map to corresponding Liberation font variants:
|
||||
- Regular/Normal → LiberationSans-Regular, LiberationSerif-Regular, LiberationMono-Regular
|
||||
- Bold/700 → LiberationSans-Bold, LiberationSerif-Bold, LiberationMono-Bold
|
||||
- Italic/Oblique → LiberationSans-Italic, LiberationSerif-Italic, LiberationMono-Italic
|
||||
- BoldItalic → LiberationSans-BoldItalic, LiberationSerif-BoldItalic, LiberationMono-BoldItalic
|
||||
- Add all Liberation font variants to `BUILT_IN_FALLBACK_FONTS` map with appropriate IDs (e.g., `fallback-liberation-sans-bold`).
|
||||
- Update `resolveFallbackFontId(String originalFontName, int codePoint)` in `PdfJsonFallbackFontService.java` to detect weight/style and return the matching variant ID.
|
||||
- Benefits: Better visual consistency when editing text in bold/italic fonts, as missing characters will match the original weight.
|
||||
- Implementation reference: `app/proprietary/src/main/java/stirling/software/SPDF/service/PdfJsonFallbackFontService.java:186-213`
|
||||
- **Font Weight Matching for Fallback Fonts** ✓ COMPLETED (January 2025)
|
||||
- Font family matching is now implemented:
|
||||
- Liberation fonts (metric-compatible with Microsoft core): Arial/Helvetica→LiberationSans, Times→LiberationSerif, Courier→LiberationMono
|
||||
- DejaVu fonts (widely used open source): DejaVu→DejaVuSans, DejaVuSerif, DejaVuMono
|
||||
- Noto fonts (Google universal font): Noto→NotoSans
|
||||
- Font weight/style matching is now implemented for multiple font families:
|
||||
- Liberation Sans/Serif/Mono: Regular, Bold, Italic, BoldItalic (full support)
|
||||
- Noto Sans: Regular, Bold, Italic, BoldItalic (full support)
|
||||
- DejaVu Sans/Serif/Mono: Regular, Bold, Italic/Oblique, BoldItalic/BoldOblique (full support)
|
||||
- All font variants registered in `BUILT_IN_FALLBACK_FONTS` map (`PdfJsonFallbackFontService.java:63-267`)
|
||||
- Weight/style detection implemented in `resolveFallbackFontId()`:
|
||||
- `detectBold()`: Detects "bold", "heavy", "black", or numeric weights 600-900 (e.g., "700wght")
|
||||
- `detectItalic()`: Detects "italic" or "oblique"
|
||||
- `applyWeightStyle()`: Applies appropriate suffix (handles both "italic" and "oblique" naming)
|
||||
- All fonts consolidated from Type3 library into main fonts directory for unified fallback support
|
||||
- Benefits: Comprehensive visual consistency when editing text in bold/italic fonts across many font families
|
||||
|
||||
Loading…
Reference in New Issue
Block a user