如何获取指定字体下单词的实际尺寸?(Kotlin+Apache POI XSLF)
解决PPTX文本替换后的尺寸匹配问题(Kotlin + Apache POI XSLF)
一、提取嵌入字体供AWT计算精准宽度
如果PPTX中嵌入了目标字体,可通过Apache POI提取字体文件并加载到AWT中,利用FontMetrics计算文本实际宽度:
import org.apache.poi.xslf.usermodel.XMLSlideShow import java.awt.Font import java.awt.FontMetrics import java.awt.Graphics2D import java.awt.image.BufferedImage import java.io.ByteArrayInputStream import java.io.FileInputStream // 提取PPTX中嵌入的字体并返回字体名称到Font的映射 fun loadEmbeddedFonts(slideShow: XMLSlideShow): Map<String, Font> { val fontMap = mutableMapOf<String, Font>() slideShow.packagePart.package.run { getPartsByName(Regex("/ppt/fonts/.*\\.(ttf|otf)")).forEach { part -> val fontFileName = part.partName.name.split("/").last() val fontName = fontFileName.substringBeforeLast('.') val fontBytes = part.inputStream.readBytes() val rawFont = Font.createFont(Font.TRUETYPE_FONT, ByteArrayInputStream(fontBytes)) fontMap[fontName] = rawFont } } return fontMap } // 计算指定字体下文本的实际宽度(单位:像素) fun getTextWidth(text: String, font: Font): Float { val dummyImage = BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB) val g2d = dummyImage.graphics as Graphics2D val metrics = g2d.getFontMetrics(font) val width = metrics.stringWidth(text).toFloat() g2d.dispose() return width }
若PPTX未嵌入字体,需匹配系统已安装的字体(注意处理字体名称的兼容问题,比如PPT中的"Calibri"对应系统同名字体)。
二、无AWT依赖的近似估算方案
如果无法加载字体,可基于字体大小和字符平均宽度做近似估算,适合对精度要求不高的场景:
import org.apache.poi.xslf.usermodel.XSLFTextRun // 估算指定文本运行下的文本宽度(单位:点) fun estimateTextWidth(textRun: XSLFTextRun, text: String): Double { val fontSize = textRun.fontSize ?: 12.0 // 根据字体类型调整系数:等宽字体用0.5,无衬线用0.6,衬线用0.65 val charWidthCoefficient = when (textRun.fontFamily) { "Courier New", "Consolas" -> 0.5 "Arial", "Calibri" -> 0.6 "Times New Roman" -> 0.65 else -> 0.6 } return text.length * fontSize * charWidthCoefficient }
三、替换时的尺寸匹配逻辑
拿到原单词宽度后,从拉丁语单词列表中选择宽度最接近的目标单词:
fun pickBestMatchingLatinWord(originalWidth: Float, latinCandidates: List<String>, font: Font): String { return latinCandidates.minByOrNull { candidate -> val candidateWidth = getTextWidth(candidate, font) kotlin.math.abs(candidateWidth - originalWidth) } ?: latinCandidates.first() }
注意事项
- 嵌入字体是保证宽度计算精准的前提,未嵌入字体的PPT会因系统字体差异导致估算偏差
- 带连字、字距调整的复杂字体,AWT的
FontMetrics计算结果更准确 - 处理多行文本时,需额外考虑换行和行间距对整体尺寸的影响
内容的提问来源于stack exchange,提问作者Poui
相关产品推荐
相关产品推荐

