White border around my background when generating a PDF certificate from an HTML template with FlyingSaucer

huangapple go评论67阅读模式
英文:

White border around my background when generating a PDF certificate from an HTML template with FlyingSaucer

问题

我需要在完成课程后生成PDF证书。这些PDF是使用Thymeleaf的HTML模板生成的。一切都通过转换进行,但结果中出现了背景图像周围的白色边框。背景图像的分辨率是1920x1440。

这是我的Spring Boot 3.1.0上的代码:

public String parseThymeleafTemplate(String verificationCode, Long certificateId) {
    ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
    templateResolver.setSuffix(".html");
    templateResolver.setTemplateMode(TemplateMode.HTML);

    TemplateEngine templateEngine = new SpringTemplateEngine();
    templateEngine.setTemplateResolver(templateResolver);

    User student = User.builder()
            .surname("Test_surname").name("Test_name").build();
    User mentor = User.builder()
            .surname("Test_mentor").name("Test_mentor").position("Java dev").build();
    Course course = Course.builder()
            .mentor(mentor)
            .name("Java Developer for 3 weeks").build();
    }

    Certificate certificate = Certificate.builder()
            .id(54L)
            .course(course)
            .student(student)
            .verificationCode(verificationCode)
            .issuedDate(LocalDate.now())
            .build();
    Context context = new Context();
    context.setVariable("company_name", "test_company");
    context.setVariable("student_name", certificate.getStudent().getSurname() + " " + certificate.getStudent().getName());
    context.setVariable("course_name", certificate.getCourse().getName());
    context.setVariable("mentor_name", certificate.getCourse().getMentor().getSurname() + " " + certificate.getCourse().getMentor().getName());
    context.setVariable("issued_date", certificate.getIssuedDate());
    context.setVariable("verification_code", certificate.getVerificationCode());
    String generatedFileName = this.generatePdfFromHtml(templateEngine.process("pdf_cert_temp", context),
            "Java", certificate);
    certificate.setFileName(generatedFileName);
    return generatedFileName;
}

public String generatePdfFromHtml(String html, String courseTag, Certificate certificate) {
    String fileName = courseTag + "_" +
            transliterateUtil.transliterateTextFromRussianToLatin(certificate.getStudent().getName()) + "_" +
            certificate.getIssuedDate().toString() + "_" + certificate.getId() +
            CertStrings.CERT_EXTENSION;
    String outputFolder = CertStrings.PATH_TO_PDF_CERTS + File.separator + fileName;
    try (OutputStream outputStream = new FileOutputStream(outputFolder)) {
        ITextRenderer renderer = new ITextRenderer();
        renderer.setDocumentFromString(html);
        renderer.layout();
        renderer.createPDF(outputStream);
    } catch (IOException e) {
        throw new RuntimeException(CertStrings.ERROR_WHILE_OUTPUT_STREAM + e);
    } catch (DocumentException e) {
        throw a RuntimeException(CertStrings.ERROR_CREATING_PDF + e);
    }
    return fileName;
}

这是用于创建PDF的Thymeleaf模板:

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <style th:inline="text">
        @page {
            size: 1920px 1440px;
        }

        body {
            font-family: Arial, sans-serif;
            background-image: url(http://some_url/files/cert_templates/java_template_bg.jpg);
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
            width: 100%;
            height: 100%;
            margin: 0px;
            padding: 0px;
            box-sizing: border-box;
        }

        /* 其他样式规则 */
    </style>
</head>
<body>
<div>
    <!-- 内容 -->
</div>
</body>
</html>

这是我的pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>PdfGeneratorTest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>PdfGeneratorTest</name>
    <description>PdfGeneratorTest</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <!-- 依赖列表 -->
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

这是生成的PDF示例:

生成的PDF示例

尝试修改HTML模板,但未奏效。调整图像大小或输出页面大小也未奏效。

英文:

I need to generate PDF certificates after completing courses. These pdf's generating by HTML template with Thymeleaf. Everything is OK through converting, but in result appear white border around the background image. Resolution of Background image is 1920x1440.
There is my code on Spring Boot 3.1.0:

public String parseThymeleafTemplate(String verificationCode, Long certificateId) {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setSuffix(&quot;.html&quot;);
templateResolver.setTemplateMode(TemplateMode.HTML);
TemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
User student = User.builder()
.surname(&quot;Test_surname&quot;).name(&quot;Test_name&quot;).build();
User mentor = User.builder()
.surname(&quot;Test_mentor&quot;).name(&quot;Test_mentor&quot;).position(&quot;Java dev&quot;).build();
Course course = Course.builder()
.mentor(mentor)
.name(&quot;Java Developer for 3 weeks&quot;).build();
}
Certificate certificate = Certificate.builder()
.id(54L)
.course(course)
.student(student)
.verificationCode(verificationCode)
.issuedDate(LocalDate.now())
.build();
Context context = new Context();
context.setVariable(&quot;company_name&quot;, &quot;test_company&quot;);
context.setVariable(&quot;student_name&quot;, certificate.getStudent().getSurname() + &quot; &quot; + certificate.getStudent().getName());
context.setVariable(&quot;course_name&quot;, certificate.getCourse().getName());
context.setVariable(&quot;mentor_name&quot;, certificate.getCourse().getMentor().getSurname() + &quot; &quot; + certificate.getCourse().getMentor().getName());
context.setVariable(&quot;issued_date&quot;, certificate.getIssuedDate());
context.setVariable(&quot;verification_code&quot;, certificate.getVerificationCode());
String generatedFileName = this.generatePdfFromHtml(templateEngine.process(&quot;pdf_cert_temp&quot;, context),
&quot;Java&quot;, certificate);
certificate.setFileName(generatedFileName);
return generatedFileName;
}
public String generatePdfFromHtml(String html, String courseTag, Certificate certificate) {
String fileName = courseTag + &quot;_&quot; +
transliterateUtil.transliterateTextFromRussianToLatin(certificate.getStudent().getName()) + &quot;_&quot; +
certificate.getIssuedDate().toString() + &quot;_&quot; + certificate.getId() +
CertStrings.CERT_EXTENSION;
String outputFolder = CertStrings.PATH_TO_PDF_CERTS + File.separator + fileName;
try (OutputStream outputStream = new FileOutputStream(outputFolder)) {
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(html);
renderer.layout();
renderer.createPDF(outputStream);
} catch (IOException e) {
throw new RuntimeException(CertStrings.ERROR_WHILE_OUTPUT_STREAM + e);
} catch (DocumentException e) {
throw new RuntimeException(CertStrings.ERROR_CREATING_PDF + e);
}
return fileName;
}

There is my Thymeleaf template for creating PDF

&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&gt;
&lt;head&gt;
&lt;style th:inline=&quot;text&quot;&gt;
@page {
size: 1920px 1440px;
}
body {
font-family: Arial, sans-serif;
background-image: url(http://some_url/files/cert_templates/java_template_bg.jpg);
background-size: cover;
background-position: center;
background-repeat: no-repeat;
width: 100%;
height: 100%;
margin: 0px;
padding: 0px;
box-sizing: border-box;
}
.company-name {
text-align: center;
color: #D9AF58;
font-style: italic;
font-size: 70px;
font-weight: 100;
position: absolute;
margin-top: 5%;
left: 44%;
}
.student-name {
text-align: center;
color: #D9AF58;
font-family: &quot;Times New Roman&quot;, Times, serif;
font-size: 70px;
font-weight: 100;
position: absolute;
margin-top: 31%;
left: 38.5%;
}
.course-completing {
text-align: center;
color: #D9AF58;
font-family: &quot;Times New Roman&quot;, Times, serif;
font-weight: 100;
font-size: 51px;
position: absolute;
margin-top: 36%;
left: 30%;
}
.course-description {
text-align: center;
color: #D9AF58;
font-family: &quot;Times New Roman&quot;, Times, serif;
font-size: 50px;
font-weight: 100;
position: absolute;
margin-top: 40%;
left: 35%;
}
.mentor-name {
text-align: center;
color: #D9AF58;
font-family: &quot;Times New Roman&quot;, Times, serif;
font-size: 30px;
font-weight: 100;
position: absolute;
margin-top: 44%;
left: 39%;
}
.verification-code {
text-align: center;
color: #D9AF58;
font-size: 25px;
font-weight: 100;
position: absolute;
margin-top: 46%;
left: 34.5%;
}
.issued-date {
text-align: left;
color: #D9AF58;
font-size: 50px;
font-weight: 100;
position: absolute;
margin-top: 55%;
left: 21.1%;
}
.signature {
text-align: left;
color: #D9AF58;
font-size: 50px;
font-weight: 100;
position: absolute;
margin-top: 55%;
right: 21.5%;
}
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div&gt;
&lt;div class=&quot;company-name&quot;&gt;
&lt;span th:text=&quot;${company_name}&quot;&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;div class=&quot;student-name&quot;&gt;
&lt;span th:text=&quot;${student_name}&quot;&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;div class=&quot;course-completing&quot;&gt;
&lt;span&gt;has successfully completing course&lt;/span&gt;
&lt;/div&gt;
&lt;div class=&quot;course-description&quot;&gt;
&lt;u th:text=&quot;${course_name}&quot;&gt;&lt;/u&gt;
&lt;/div&gt;
&lt;div class=&quot;mentor-name&quot;&gt;
Taught by &lt;span th:text=&quot;${mentor_name}&quot;&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;div class=&quot;verification-code&quot;&gt;
Verification code: &lt;span th:text=&quot;${verification_code}&quot;&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div class=&quot;issued-date&quot;&gt;
&lt;span th:text=&quot;${issued_date}&quot;&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;div class=&quot;signature&quot;&gt;
&lt;span th:text=&quot;&#39;Test S.&#39;&quot;&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;

This is my pom.xml:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
&lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
&lt;parent&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
&lt;version&gt;3.1.0&lt;/version&gt;
&lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;
&lt;/parent&gt;
&lt;groupId&gt;com.example&lt;/groupId&gt;
&lt;artifactId&gt;PdfGeneratorTest&lt;/artifactId&gt;
&lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
&lt;name&gt;PdfGeneratorTest&lt;/name&gt;
&lt;description&gt;PdfGeneratorTest&lt;/description&gt;
&lt;properties&gt;
&lt;java.version&gt;17&lt;/java.version&gt;
&lt;/properties&gt;
&lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;com.ibm.icu&lt;/groupId&gt;
&lt;artifactId&gt;icu4j&lt;/artifactId&gt;
&lt;version&gt;69.1&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-thymeleaf&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.xhtmlrenderer&lt;/groupId&gt;
&lt;artifactId&gt;flying-saucer-pdf&lt;/artifactId&gt;
&lt;version&gt;9.1.22&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;ognl&lt;/groupId&gt;
&lt;artifactId&gt;ognl&lt;/artifactId&gt;
&lt;version&gt;3.2.10&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.apache.commons&lt;/groupId&gt;
&lt;artifactId&gt;commons-lang3&lt;/artifactId&gt;
&lt;version&gt;3.12.0&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
&lt;artifactId&gt;lombok&lt;/artifactId&gt;
&lt;optional&gt;true&lt;/optional&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;
&lt;build&gt;
&lt;plugins&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
&lt;configuration&gt;
&lt;excludes&gt;
&lt;exclude&gt;
&lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
&lt;artifactId&gt;lombok&lt;/artifactId&gt;
&lt;/exclude&gt;
&lt;/excludes&gt;
&lt;/configuration&gt;
&lt;/plugin&gt;
&lt;/plugins&gt;
&lt;/build&gt;
&lt;/project&gt;

This is example, what is look like:
Example of generated PDF

Tried to modify HTML tempalte, but it didn't work. Resize of image or output page also didn't work.

答案1

得分: 3

这是正常的打印行为,它只是添加了正常打印机的 "夹持边距"(以防墨水弄脏滚筒)。您需要添加CSS以减小打印机的媒体边距到 "无边框"。

一种方法是将@Media打印设置为body为零。

这可能不会精确删除所有白色区域(可能会有一两个像素的微小变化),因为通常会对比例进行一些单位舍入,这可能会因浏览器而异,并且通常依赖于当前页面的缩放。

所以这是我用于减小打印机边框的粗略值:

<head>
    <style th:inline="text">
        @media print {
        @page {
        size: 1920px 1440px;
        border: 0px;
        margin: 0px;
        padding: 0px;
        }
        }
英文:

This is Normal Printing Behaviour, it is simply adding normal printer "gripper margins" (so the ink does not foul the rollers). You will need to add CSS to reduce printer Media Margins to "Borderless"

White border around my background when generating a PDF certificate from an HTML template with FlyingSaucer

One way is to set the @Media print for the body to Zer0

White border around my background when generating a PDF certificate from an HTML template with FlyingSaucer

This may not remove precisely all white areas (without a minor pixel or two change) since there is often some unit rounding off for scale ratios, which can vary from browser to browser, and often depend on current page scaling.

So here are the crude values I used for reducing the printer border

&lt;head&gt;
&lt;style th:inline=&quot;text&quot;&gt;
@media print {
@page {
size: 1920px 1440px;
border: 0px;
margin: 0px;
padding: 0px;
}
}

huangapple
  • 本文由 发表于 2023年6月19日 21:06:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76506944.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定