mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-09-08 17:51:20 +02:00
refactor
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
This commit is contained in:
parent
a849b9166c
commit
df31630aed
@ -1,5 +1,6 @@
|
|||||||
package stirling.software.SPDF.utils.text;
|
package stirling.software.SPDF.utils.text;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.Normalizer;
|
import java.text.Normalizer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -96,7 +97,6 @@ public class WidthCalculator {
|
|||||||
for (int codePoint : codePoints) {
|
for (int codePoint : codePoints) {
|
||||||
String character = new String(Character.toChars(codePoint));
|
String character = new String(Character.toChars(codePoint));
|
||||||
Float charWidth = calculateSingleCharacterWidth(font, character, fontSize);
|
Float charWidth = calculateSingleCharacterWidth(font, character, fontSize);
|
||||||
if (charWidth == null) return null;
|
|
||||||
|
|
||||||
totalWidth += charWidth;
|
totalWidth += charWidth;
|
||||||
if (previousCodePoint != -1) {
|
if (previousCodePoint != -1) {
|
||||||
@ -133,7 +133,7 @@ public class WidthCalculator {
|
|||||||
|
|
||||||
if (encoded == null && font instanceof PDType0Font) {
|
if (encoded == null && font instanceof PDType0Font) {
|
||||||
try {
|
try {
|
||||||
encoded = character.getBytes("UTF-8");
|
encoded = character.getBytes(StandardCharsets.UTF_8);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.debug("UTF-8 encoding failed for '{}': {}", character, e.getMessage());
|
log.debug("UTF-8 encoding failed for '{}': {}", character, e.getMessage());
|
||||||
}
|
}
|
||||||
@ -271,7 +271,6 @@ public class WidthCalculator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try multi-byte interpretation for Unicode fonts
|
|
||||||
if (encoded.length >= 2 && font instanceof PDType0Font) {
|
if (encoded.length >= 2 && font instanceof PDType0Font) {
|
||||||
try {
|
try {
|
||||||
int glyphCode = ((encoded[0] & 0xFF) << 8) | (encoded[1] & 0xFF);
|
int glyphCode = ((encoded[0] & 0xFF) << 8) | (encoded[1] & 0xFF);
|
||||||
@ -348,7 +347,6 @@ public class WidthCalculator {
|
|||||||
return enhancedAverage;
|
return enhancedAverage;
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Ultimate fallback
|
|
||||||
float conservativeWidth = text.length() * CONSERVATIVE_CHAR_WIDTH_RATIO * fontSize;
|
float conservativeWidth = text.length() * CONSERVATIVE_CHAR_WIDTH_RATIO * fontSize;
|
||||||
log.debug("Conservative fallback width: {}", conservativeWidth);
|
log.debug("Conservative fallback width: {}", conservativeWidth);
|
||||||
return conservativeWidth;
|
return conservativeWidth;
|
||||||
@ -394,7 +392,6 @@ public class WidthCalculator {
|
|||||||
i += Character.charCount(codePoint);
|
i += Character.charCount(codePoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log composition analysis for debugging
|
|
||||||
log.debug(
|
log.debug(
|
||||||
"Text composition analysis - Spaces: {}, Upper: {}, Lower: {}, Digits: {}, Punct: {}",
|
"Text composition analysis - Spaces: {}, Upper: {}, Lower: {}, Digits: {}, Punct: {}",
|
||||||
spaceCount,
|
spaceCount,
|
||||||
@ -410,7 +407,6 @@ public class WidthCalculator {
|
|||||||
try {
|
try {
|
||||||
float baseAverage = font.getAverageFontWidth();
|
float baseAverage = font.getAverageFontWidth();
|
||||||
|
|
||||||
// Try to get more specific metrics
|
|
||||||
float capHeight = 0;
|
float capHeight = 0;
|
||||||
float xHeight = 0;
|
float xHeight = 0;
|
||||||
|
|
||||||
@ -419,7 +415,6 @@ public class WidthCalculator {
|
|||||||
xHeight = font.getFontDescriptor().getXHeight();
|
xHeight = font.getFontDescriptor().getXHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use metrics to adjust the average width estimation
|
|
||||||
float adjustmentFactor = 1.0f;
|
float adjustmentFactor = 1.0f;
|
||||||
if (capHeight > 0 && xHeight > 0) {
|
if (capHeight > 0 && xHeight > 0) {
|
||||||
adjustmentFactor = Math.max(0.8f, Math.min(1.2f, xHeight / capHeight));
|
adjustmentFactor = Math.max(0.8f, Math.min(1.2f, xHeight / capHeight));
|
||||||
@ -439,7 +434,6 @@ public class WidthCalculator {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check cache first
|
|
||||||
String cacheKey = createReliabilityCacheKey(font);
|
String cacheKey = createReliabilityCacheKey(font);
|
||||||
Boolean cachedResult = reliabilityCache.get(cacheKey);
|
Boolean cachedResult = reliabilityCache.get(cacheKey);
|
||||||
if (cachedResult != null) {
|
if (cachedResult != null) {
|
||||||
@ -452,26 +446,22 @@ public class WidthCalculator {
|
|||||||
|
|
||||||
boolean result = performReliabilityCheck(font);
|
boolean result = performReliabilityCheck(font);
|
||||||
|
|
||||||
// Cache the result
|
|
||||||
reliabilityCache.put(cacheKey, result);
|
reliabilityCache.put(cacheKey, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean performReliabilityCheck(PDFont font) {
|
private boolean performReliabilityCheck(PDFont font) {
|
||||||
try {
|
try {
|
||||||
// Check if font is damaged
|
|
||||||
if (font.isDamaged()) {
|
if (font.isDamaged()) {
|
||||||
log.debug("Font {} is damaged", font.getName());
|
log.debug("Font {} is damaged", font.getName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check basic width calculation capability
|
|
||||||
if (!TextEncodingHelper.canCalculateBasicWidths(font)) {
|
if (!TextEncodingHelper.canCalculateBasicWidths(font)) {
|
||||||
log.debug("Font {} cannot perform basic width calculations", font.getName());
|
log.debug("Font {} cannot perform basic width calculations", font.getName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test with a simple character
|
|
||||||
try {
|
try {
|
||||||
font.getStringWidth("A");
|
font.getStringWidth("A");
|
||||||
return true;
|
return true;
|
||||||
@ -495,95 +485,4 @@ public class WidthCalculator {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public float calculateCharacterWidth(PDFont font, String character, float fontSize) {
|
|
||||||
if (font == null || character == null || character.isEmpty() || fontSize <= 0) return 0;
|
|
||||||
|
|
||||||
String cacheKey = createCacheKey(font, character, fontSize);
|
|
||||||
Float cachedWidth = widthCache.get(cacheKey);
|
|
||||||
if (cachedWidth != null) return cachedWidth;
|
|
||||||
|
|
||||||
Float width = calculateSingleCharacterWidth(font, character, fontSize);
|
|
||||||
if (width == null) width = calculateAverageCharacterWidth(font, fontSize);
|
|
||||||
|
|
||||||
widthCache.put(cacheKey, width);
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String createWidthMatchingPlaceholder(
|
|
||||||
String originalText,
|
|
||||||
float targetWidth,
|
|
||||||
PDFont font,
|
|
||||||
float fontSize,
|
|
||||||
String placeholderChar) {
|
|
||||||
if (originalText == null || originalText.isEmpty() || targetWidth <= 0) return "";
|
|
||||||
|
|
||||||
if (placeholderChar == null || placeholderChar.isEmpty()) placeholderChar = " ";
|
|
||||||
|
|
||||||
try {
|
|
||||||
float placeholderCharWidth = calculateCharacterWidth(font, placeholderChar, fontSize);
|
|
||||||
if (placeholderCharWidth <= 0) {
|
|
||||||
return " ".repeat(Math.max(1, originalText.length()));
|
|
||||||
}
|
|
||||||
|
|
||||||
int placeholderCount = Math.max(1, Math.round(targetWidth / placeholderCharWidth));
|
|
||||||
int originalLength = originalText.length();
|
|
||||||
int maxReasonableLength = Math.max(originalLength * 3, Math.max(placeholderCount, 10));
|
|
||||||
placeholderCount = Math.min(placeholderCount, maxReasonableLength);
|
|
||||||
placeholderCount = Math.max(1, placeholderCount);
|
|
||||||
|
|
||||||
return placeholderChar.repeat(placeholderCount);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
return " ".repeat(Math.max(1, originalText.length()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean canCalculateTextWidth(PDFont font, String text) {
|
|
||||||
if (font == null || text == null || text.isEmpty()) return false;
|
|
||||||
if (!isWidthCalculationReliable(font)) return false;
|
|
||||||
|
|
||||||
List<Integer> codePoints = getCodePoints(text);
|
|
||||||
int testSampleSize = Math.min(5, codePoints.size());
|
|
||||||
|
|
||||||
for (int i = 0; i < testSampleSize; i++) {
|
|
||||||
int codePoint = codePoints.get(i);
|
|
||||||
String character = new String(Character.toChars(codePoint));
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!TextEncodingHelper.canEncodeCharacters(font, character)) {
|
|
||||||
log.debug(
|
|
||||||
"Cannot encode character U+{} in text '{}'",
|
|
||||||
Integer.toHexString(codePoint),
|
|
||||||
text);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
float width = calculateCharacterWidth(font, character, 12.0f);
|
|
||||||
if (width <= 0) {
|
|
||||||
log.debug(
|
|
||||||
"Character U+{} has invalid width: {}",
|
|
||||||
Integer.toHexString(codePoint),
|
|
||||||
width);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.debug(
|
|
||||||
"Error testing character U+{}: {}",
|
|
||||||
Integer.toHexString(codePoint),
|
|
||||||
e.getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearWidthCache() {
|
|
||||||
widthCache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearReliabilityCache() {
|
|
||||||
reliabilityCache.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user