java 将自定义字体嵌入到从HTML创建的PDF中

tzxcd3kk  于 2024-01-05  发布在  Java
关注(0)|答案(3)|浏览(182)

我用jsoup和OpenHTMLToPDF从HTML创建了一个PDF。我必须在PDF中使用不同的字体来覆盖非拉丁字形(见此处)。如何正确嵌入字体?

再现问题的简化程序:

源代码/main/资源/测试.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8" />
  5. <title>Font Test</title>
  6. <style>
  7. @font-face {
  8. font-family: 'source-sans';
  9. font-style: normal;
  10. font-weight: 400;
  11. src: url(fonts/SourceSansPro-Regular.ttf);
  12. }
  13. </style>
  14. </head>
  15. <body>
  16. <p style="font-family: 'source-sans',serif">Latin Script</p>
  17. <p style="font-family: 'source-sans',serif">Είμαι ελληνικό κείμενο.</p>
  18. </body>
  19. </html>

字符串
此文件需要转换为PDF。
在浏览器中,它看起来正确,并使用Source Sans字体。

源代码/主代码/java/main.java:

  1. import com.openhtmltopdf.extend.FSSupplier;
  2. import com.openhtmltopdf.pdfboxout.PdfRendererBuilder;
  3. import org.jsoup.Jsoup;
  4. import org.jsoup.helper.W3CDom;
  5. import org.w3c.dom.Document;
  6. import java.io.*;
  7. import java.nio.charset.StandardCharsets;
  8. import java.util.Objects;
  9. public class main {
  10. public static void main(String[] args) {
  11. System.out.println("Starting");
  12. try {
  13. final W3CDom w3cDom = new W3CDom();
  14. final Document w3cDoc = w3cDom.fromJsoup(Jsoup.parse(readFile()));
  15. final OutputStream outStream = new FileOutputStream("test.pdf");
  16. final PdfRendererBuilder pdfBuilder = new PdfRendererBuilder();
  17. pdfBuilder.useFastMode();
  18. pdfBuilder.withW3cDocument(w3cDoc, "/");
  19. pdfBuilder.useFont(new File(main.class.getClassLoader().getResource("fonts/SourceSansPro-Regular.ttf").getFile()), "source-sans");
  20. pdfBuilder.toStream(outStream);
  21. pdfBuilder.run();
  22. outStream.close();
  23. } catch (Exception e) {
  24. System.out.println("PDF could not be created: " + e.getMessage());
  25. }
  26. System.out.println("Finish.");
  27. }
  28. private static String readFile() throws IOException {
  29. final ClassLoader classLoader = main.class.getClassLoader();
  30. final InputStream inputStream = classLoader.getResourceAsStream("test.html");
  31. final StringBuilder sb = new StringBuilder();
  32. final Reader r = new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8);
  33. char[] buf = new char[1024];
  34. int amt = r.read(buf);
  35. while(amt > 0) {
  36. sb.append(buf, 0, amt);
  37. amt = r.read(buf);
  38. }
  39. return sb.toString();
  40. }
  41. }


不要为第二个函数而烦恼,它只是读取HTML文件,并且只包括在这里,以拥有一个完整的程序。

src/main/资源/字体/SourceSansPro-常规.ttf

从此处下载:https://www.fontsquirrel.com/fonts/source-sans-pro

pom.xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>paf</groupId>
  7. <artifactId>test</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <build>
  10. <plugins>
  11. <plugin>
  12. <groupId>org.apache.maven.plugins</groupId>
  13. <artifactId>maven-compiler-plugin</artifactId>
  14. <configuration>
  15. <source>7</source>
  16. <target>7</target>
  17. </configuration>
  18. </plugin>
  19. </plugins>
  20. </build>
  21. <dependencies>
  22. <dependency>
  23. <groupId>com.openhtmltopdf</groupId>
  24. <artifactId>openhtmltopdf-pdfbox</artifactId>
  25. <version>0.0.1-RC18</version>
  26. </dependency>
  27. <dependency>
  28. <groupId>org.jsoup</groupId>
  29. <artifactId>jsoup</artifactId>
  30. <version>1.11.2</version>
  31. </dependency>
  32. </dependencies>
  33. </project>

程序输出:

  1. Starting
  2. com.openhtmltopdf.load INFO:: TIME: parse stylesheets 148ms
  3. com.openhtmltopdf.match INFO:: media = print
  4. com.openhtmltopdf.match INFO:: Matcher created with 147 selectors
  5. com.openhtmltopdf.load INFO:: Loading font(source-sans) from InputStream supplier now.
  6. com.openhtmltopdf.exception WARNING:: bad URL given: /fonts/SourceSansPro-Regular.ttf
  7. com.openhtmltopdf.exception WARNING:: Could not load @font-face font: /fonts/SourceSansPro-Regular.ttf
  8. com.openhtmltopdf.exception WARNING:: Font metrics not available. Probably a bug.
  9. com.openhtmltopdf.exception WARNING:: Font metrics not available. Probably a bug.
  10. com.openhtmltopdf.render WARNING:: Font is null.
  11. com.openhtmltopdf.render WARNING:: Font is null.
  12. com.openhtmltopdf.render WARNING:: Font is null.
  13. com.openhtmltopdf.render WARNING:: Font is null.
  14. com.openhtmltopdf.render WARNING:: Font is null.
  15. com.openhtmltopdf.render WARNING:: Font is null.
  16. com.openhtmltopdf.render WARNING:: Font is null.
  17. Finish.

生成的PDF

  1. Latin Script
  2. ##### ######## #######.


以衬线字体。

qxsslcnc

qxsslcnc1#

好的,感谢@Tilman Hausherr的评论,我在openhtmltopdf and got some help的GitHub问题跟踪器中询问。
这些变化使它工作,如果有人登陆这里感兴趣:

src/main/java/main.java(仅更改部分,见上文其余部分):

  1. public static void main(String[] args) {
  2. System.out.println("Starting");
  3. try {
  4. final W3CDom w3cDom = new W3CDom();
  5. final Document w3cDoc = w3cDom.fromJsoup(Jsoup.parse(readFile()));
  6. final OutputStream outStream = new FileOutputStream("test.pdf");
  7. final PdfRendererBuilder pdfBuilder = new PdfRendererBuilder();
  8. pdfBuilder.useFastMode();
  9. pdfBuilder.withW3cDocument(w3cDoc, "/");
  10. pdfBuilder.useFont(new File(main.class.getClassLoader().getResource("fonts/SourceSansPro-Regular.ttf").getFile()), "source-sans");
  11. pdfBuilder.toStream(outStream);
  12. pdfBuilder.run();
  13. outStream.close();
  14. } catch (Exception e) {
  15. System.out.println("PDF could not be created: " + e.getMessage());
  16. }
  17. System.out.println("Finish.");
  18. }

字符串

src/main/资源/字体/SourceSansPro-常规.ttf

已下载最新版本:https://github.com/adobe-fonts/source-sans-pro/releases

来自src/main/resources/test.html(仅更改部分,参见上文其余部分)

  1. @font-face {
  2. font-family: 'source-sans';
  3. font-style: normal;
  4. font-weight: 400;
  5. src: url(fonts/SourceSansPro-Regular.ttf);
  6. -fs-font-subset: complete-font;
  7. }

展开查看全部
ujv3wf0j

ujv3wf0j2#

尝试了所有上述解决方案,但它没有从我工作.
然而,使用标签代替@font-face对我来说很有效。
下面是HTML的例子:

  1. <html
  2. xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
  5. <link rel="preconnect" href="https://fonts.googleapis.com">
  6. <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  7. <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+Ethiopic&display=swap" rel="stylesheet">
  8. </head>
  9. <body class="c9" style="font-family: 'Noto Serif Ethiopic', serif;">
  10. <p> {my content here} </p>

字符串
因此,使用链接和使用谷歌字体特定的语言,我需要解决的问题对我来说。
我希望这能帮助其他人。

展开查看全部
trnvg8h3

trnvg8h33#

我解决了加载字体作为流代替File的。
范例:

  1. ...
  2. pdfBuilder.useFont(getResourceAsStream("/fonts/SourceSansPro-Regular.ttf"), "source-sans");
  3. ....
  4. public FSSupplier<InputStream> getResourceAsStream(String resource) {
  5. return new FSSupplier<InputStream>(){
  6. @Override
  7. public InputStream supply() {
  8. return PdfUtils.class.getClassLoader().getResourceAsStream(resource);
  9. }
  10. };
  11. }

字符串

展开查看全部

相关问题