Linux服务器和Windows环境下生成的目录页码不一致

你好,我在Windows环境下将生成的原wordwin-原.docx (1.1 MB)添加目录得到得wordwin-得.docx (1.1 MB)
我在Linux环境下将生成的原wordlinux-原.docx (1.1 MB)添加目录得到linux-得.docx (1.1 MB)
发现在Linux服务器上页码对应不上对比图.png (46.2 KB)
我生成目录的方法如下

public static void creat(String resourceWordPath, String targetWordPath, String pageHeader) throws Exception
{
	Document doc = new Document(resourceWordPath);
	DocumentBuilder builder = new DocumentBuilder(doc);
	doc.getFirstSection().getBody().prependChild(new Paragraph(doc));
	//将光标移到文档开始的位置
	builder.moveToDocumentStart();
	// 设置目录的格式
	// “目录”两个字居中显示、加粗、宋体
	builder.getCurrentParagraph().getParagraphFormat().setAlignment(ParagraphAlignment.CENTER);
	builder.setBold(true);
	builder.getFont().setName("宋体");
	builder.getFont().setSize(16);
	builder.writeln("目  录");
	// 清清除所有样式设置
	builder.getParagraphFormat().clearFormatting();
	// 目录居左
	builder.getParagraphFormat().setAlignment(ParagraphAlignment.LEFT);
	// 插入目录,这是固定的
	builder.insertTableOfContents("\\o \"1-4\" \\h \\z \\u");
	builder.insertBreak(BreakType.SECTION_BREAK_NEW_PAGE);
	// 添加目录和正文的页眉页脚
	addHeaderFooter(builder, pageHeader);
	// 更新域
	doc.updateFields();
	 // 1、给目录设置相应的样式
		for (Field field : doc.getRange().getFields())
		{
			if (field.getType() == (FieldType.FIELD_PAGE_REF))
			{
				FieldPageRef pageRef = (FieldPageRef) field;
				if (!Objects.equals(pageRef.getBookmarkName(), "") || pageRef.getBookmarkName().startsWith("_Toc"))
				{
					Paragraph tocItem = (Paragraph) field.getStart().getAncestor(NodeType.PARAGRAPH);
					tocItem.getParagraphFormat().setLineSpacing(15);
					for (Run run : tocItem.getRuns())
					{
						run.getFont().setName("宋体");
						run.getFont().setSize(12);
						run.getFont().setBold(false);
					}
				}
			}
		}
		// 2、锁定目录,避免手动更新目录后,格式失效
		for (Field field : doc.getRange().getFields())
		{
			if (field.getType() == (FieldType.FIELD_TOC))
			{
				field.isLocked(true);
			}
		}
	doc.save(targetWordPath);
}

其中添加页码页脚方法:

public static void addHeaderFooter(DocumentBuilder builder, String pageHeader)
{
	try
	{
		SectionCollection sections = builder.getDocument().getSections();
		for (int i = 2; i < sections.getCount(); i++)
		{
			Section section1 = sections.get(i);
			// 页码格式: https://reference.aspose.com/words/java/com.aspose.words/NumberStyle
			section1.getPageSetup().setPageNumberStyle(NumberStyle.ARABIC);
			section1.getPageSetup().setRestartPageNumbering(false);
		}
		// 正文设置页眉页脚
		Section section = builder.getCurrentSection();
		// https://forum.aspose.com/t/wod/204805/2
		// 在该部分的开头重新开始页码,则PageSetup.RestartPageNumbering返回true
		// 如果其值设置为false,则RestartPageNumbering属性将覆盖PageStartingNumber属性,以便可以从上一节继续进行页码编号
		section.getPageSetup().setRestartPageNumbering(true);
		section.getPageSetup().setPageNumberStyle(NumberStyle.ARABIC);
		section.getHeadersFooters().linkToPrevious(false);
		// 页码
		builder.moveToHeaderFooter(HeaderFooterType.FOOTER_PRIMARY);
		builder.getCurrentParagraph().getParagraphFormat().setAlignment(ParagraphAlignment.CENTER);
		// 设置页脚与页面底部之间的距离(以磅为单位)
		builder.getPageSetup().setFooterDistance(50);
		// FieldType.FIELD_PAGE
		builder.insertField("Page");
		// 页眉
		builder.moveToHeaderFooter(HeaderFooterType.HEADER_PRIMARY);
		builder.getCurrentParagraph().getParagraphFormat().setAlignment(ParagraphAlignment.LEFT);
		builder.getFont().setSize(9);
		// 设置页眉和页面顶部之间的距离(以磅为单位)
		builder.getPageSetup().setHeaderDistance(40);
		builder.write(pageHeader);
		// 目录页眉
		builder.moveToSection(0);
		builder.moveToHeaderFooter(HeaderFooterType.HEADER_PRIMARY);
		builder.getCurrentParagraph().getParagraphFormat().setAlignment(ParagraphAlignment.LEFT);
		builder.getFont().setSize(9);
		builder.getPageSetup().setHeaderDistance(40);
		builder.write(pageHeader);
	}
	catch (Exception e)
	{
		e.printStackTrace();
	}
}

生成目录

public static void main(String[] args) throws Exception
{
   creat("D:/word/原.docx", "D:/word/得.docx");
}

@kongbai, 您能否将最终文档在 Linux 和 Windows 上转换为 PDF 并附加到此线程以进行分析?

creat("D:/word/原.docx", "D:/word/得.pdf");

在Windows环境下生成的pdfwin-得.pdf (1.6 MB)
在Linux环境下生成的pdflinux-得.pdf (1.7 MB)

通过我上传的pdf,请问有找到原因吗?

@kongbai, 原因是 Windows 和 Linux 上的字体不同。 如果字体相同,Aspose.Words 会生成相同的输出文档。 在您的情况下,Linux 有更多字体。 请看字体的区别:

Windows Linux
<no font> PMingLiu Regular 7.00
<no font> MS Mincho Regular 5.05
SimSun Regular 5.16 SimSun Regular 5.16
Times New Roman Bold 7.00 Times New Roman Bold 7.00
Times New Roman Regular 3.00 Times New Roman Regular 7.00
MS UI Gothic Regular 5.32 MS UI Gothic Regular 5.32

确保您在 Linux 和 Windows 上具有相同的字体,然后再次尝试创建文档。

感谢你的答复,我将Linux环境的/usr/share/fonts下字体文件全部删除替换为Windows环境下的所有字体,确实目录页码保存一致了。我还想问一下,这个字体不一致的对比表你是怎么找到的?
我前面也遇到过字体缺少的问题有什么好的解决方案,就是将Linux环境和Windows环境的字体保持一致就可以吗?

@kongbai, 要制作字体比较表,您可以执行以下步骤:
1.将Word文档转换为PDF。 PDF 文件包含用于显示字符的嵌入字体。
2. 从 PDF 中提取嵌入的字体。您可以使用 Aspose.PDF[mutool](https://mupdf.com/docs/manual-mutool-extract.html) 程序。
3. 收集提取的嵌入字体的字体名称和版本。 您可以为此使用 Aspose.Font 或使用 fonttools Python 包:

from fontTools.ttLib.ttFont import TTFont
from pathlib import Path

currentDir = Path(R".")
fonts = currentDir.glob("*.ttf")
ttfonts = [(TTFont(f), f) for f in fonts]
fontInfo = [(str(f[1]), f[0]['name'].getBestFamilyName(), f[0]['name'].getBestSubFamilyName(), f[0]['name'].getName(5, 1, 0).toStr()) for f in ttfonts]
for f in fontInfo:
    print("\t".join(f))

关于保持Linux和Windows环境字体一致的解决方案,我不知道有什么现成的解决方案。 您可能可以创建自己的程序 Aspose.PDFAspose.Font,它们将收集 Linux 和 Windows 上的字体名称和版本,并显示差异并同步它们。

我明白了,感谢你的答复。