You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否用iText7 .NET仅嵌入问题字符以优化PDF文件大小?

解决方案:用iText7 .NET实现字体子集化,仅嵌入问题字符

完全可以通过iText7的字体子集化功能实现你的需求——只嵌入PDF中实际用到的特定字符(包括č、ć这类缺失字符),既解决手机端字符显示问题,又能最大程度控制PDF体积。

核心思路

RDLC生成的未嵌入字体PDF体积小,但缺失的字符依赖系统字体;而全字体嵌入会大幅增加体积。子集化的本质是:提取文档中实际使用的字符集,仅嵌入这些字符对应的字体glyphs,而非整个字体文件。

具体实现步骤(C#)

  1. 准备依赖:安装iText7的NuGet包:itext7 和 itext7.fonts
  2. 加载源PDF并收集需嵌入的字符:遍历PDF内容,收集所有出现的字符(至少包含č、ć)
  3. 创建子集字体:加载对应字体文件,生成仅包含目标字符的子集
  4. 替换原PDF字体并嵌入子集:将原PDF中未嵌入的字体替换为子集字体,确保字符能正确渲染

示例代码

using iText.Kernel.Font;
using iText.Kernel.Pdf;
using iText.Layout.Font;
using System.Text;

// 源PDF路径和输出PDF路径
string sourcePdfPath = "input.pdf";
string outputPdfPath = "output.pdf";

// 收集文档中所有用到的字符(主动添加问题字符,再补充页面所有字符)
HashSet<char> requiredChars = new HashSet<char> { 'č', 'ć' };

// 加载源PDF,遍历页面收集所有字符
using (PdfReader reader = new PdfReader(sourcePdfPath))
using (PdfDocument pdfDoc = new PdfDocument(reader))
{
    for (int pageNum = 1; pageNum <= pdfDoc.GetNumberOfPages(); pageNum++)
    {
        PdfPage page = pdfDoc.GetPage(pageNum);
        string pageText = PdfTextExtractor.GetTextFromPage(page);
        foreach (char c in pageText)
        {
            requiredChars.Add(c);
        }
    }
}

// 加载RDLC使用的字体文件(替换为实际字体路径,比如Arial.ttf)
string fontPath = @"C:\Windows\Fonts\arial.ttf";
FontProgram fontProgram = FontProgramFactory.CreateFont(fontPath);

// 生成仅包含目标字符的子集字体
fontProgram.Subset(requiredChars.Select(c => (int)c).ToArray());
PdfFont subsetFont = PdfFontFactory.CreateFont(fontProgram, PdfEncodings.IDENTITY_H, true);

// 替换原PDF中的未嵌入字体并嵌入子集
using (PdfReader reader = new PdfReader(sourcePdfPath))
using (PdfWriter writer = new PdfWriter(outputPdfPath))
using (PdfDocument pdfDoc = new PdfDocument(reader, writer))
{
    PdfDictionary resources = pdfDoc.GetCatalog().GetPdfObject().GetAsDictionary(PdfName.Resources);
    if (resources == null) return;
    
    PdfDictionary fontDict = resources.GetAsDictionary(PdfName.Font);
    foreach (PdfName fontName in fontDict.KeySet())
    {
        PdfDictionary font = fontDict.GetAsDictionary(fontName);
        // 匹配未嵌入的目标字体(根据实际字体名称调整判断逻辑)
        if (font.GetAsString(PdfName.BaseFont)?.ToString().Contains("Arial") == true 
            && !font.GetAsBoolean(PdfName.Embedded))
        {
            // 替换为子集字体并标记为已嵌入
            font.Put(PdfName.BaseFont, subsetFont.GetPdfObject().GetAsString(PdfName.BaseFont));
            font.Put(PdfName.FontDescriptor, subsetFont.GetFontDescriptor().GetPdfObject());
            font.Put(PdfName.Embedded, PdfBoolean.TRUE);
        }
    }
}

关键注意事项

  • 字体匹配:确保加载的字体文件和RDLC生成PDF时使用的字体完全一致,否则可能出现字符渲染偏差
  • 字符收集:主动添加č、ć后再遍历页面文本收集所有字符,避免遗漏其他潜在问题字符
  • 编码设置:使用IDENTITY_H编码支持Unicode字符,确保特殊字符能正确嵌入

这种方法相比“RDLC全嵌入再压缩”的优势在于:仅嵌入必要字符,体积增加微乎其微,同时从根源解决了手机端因缺少字体导致的字符缺失问题。

内容的提问来源于stack exchange,提问作者Milan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 13:44:57