Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PROJECT: Templates for openhtmltopdf. Initial commit. #544

Merged
merged 4 commits into from
Sep 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/build-templates-website.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Build Templates Website

on:
workflow_dispatch:
inputs:
message:
description: 'Commit message for this website deploy'
required: true
default: 'Update templates website'

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Compile with Maven
run: mvn -B install -DskipTests
- name: Build website
run: cd openhtmltopdf-templates && mvn -B exec:java -Dexec.mainClass="com.openhtmltopdf.templates.Application" && cd ..
- name: Deploy website
uses: peaceiris/actions-gh-pages@v3
with:
external_repository: danfickle/pdf-templates
personal_token: ${{ secrets.PERSONAL_TOKEN }}
publish_dir: ./openhtmltopdf-templates/target/website/pdfs
commit_message: ${{ github.event.inputs.message }}
15 changes: 15 additions & 0 deletions openhtmltopdf-templates/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Openhtmltopdf Templates Module

## Website
Coming soon.

## Purpose
This module aims to provide pre-built templates for Openhtmltopdf in both
Thymeleaf and raw HTML formats.

## License
Unlike the rest of the project this module is licensed under MIT license. This
should enable copying and pasting of templates.

## Contributing
Contributions of templates welcome. Details coming soon.
100 changes: 100 additions & 0 deletions openhtmltopdf-templates/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-parent</artifactId>
<version>1.0.5-SNAPSHOT</version>
</parent>

<artifactId>openhtmltopdf-templates</artifactId>

<packaging>jar</packaging>

<name>Openhtmltopdf Templates</name>
<description>PDF templates and website generation for Openhtmltopdf. It is not deployed with a release.</description>

<licenses>
<license>
<name>MIT</name>
<url>https://opensource.org/licenses/MIT</url>
</license>
</licenses>

<dependencies>
<dependency>
<groupId>com.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-pdfbox</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-svg-support</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>

<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>

<dependency>
<groupId>org.imgscalr</groupId>
<artifactId>imgscalr-lib</artifactId>
<version>4.2</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
</dependency>

<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.26</version>
</dependency>

<dependency>
<groupId>org.codelibs</groupId>
<artifactId>jhighlight</artifactId>
<version>1.0.3</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<use>false</use>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package com.openhtmltopdf.templates;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.imageio.ImageIO;

import org.apache.commons.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.imgscalr.Scalr;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;

import com.openhtmltopdf.templates.DataGenerator.DataProvider;
import com.openhtmltopdf.util.XRLog;
import com.uwyn.jhighlight.renderer.XmlXhtmlRenderer;

public class Application {
private final PdfCreator _pdfCreator = new PdfCreator();
private final ThymeleafProcessor _thymeleaf = new ThymeleafProcessor();
private final VisualTester _tester = new VisualTester(new File("./target/test/"));
private final File _websiteBase = new File("./target/website/pdfs/");
private final XmlXhtmlRenderer _highlighter = new XmlXhtmlRenderer();
private final String _codeStyles = createStyles(XmlXhtmlRenderer.DEFAULT_CSS);
private final List<String> _templates = new ArrayList<>();

@SuppressWarnings({ "rawtypes", "unchecked" })
private static String createStyles(Map styles) {
StringBuilder sb = new StringBuilder();
Iterator iter = styles.entrySet().iterator();

while (iter.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry<String, String>) iter.next();
if (entry.getKey().equals("h1")) {
continue;
}
sb.append(entry.getKey())
.append(" { \n")
.append(entry.getValue())
.append("}\n");
}

return sb.toString();
}

public static class Attribution {
public String author;
public String link;
}

public static class TemplateSettings {
public String description;
public String license;
public List<Attribution> attributions;
}

private TemplateSettings getYaml(String props) {
Constructor cons = new Constructor(TemplateSettings.class);
Yaml yaml = new Yaml(cons);
return yaml.load(props);
}

private boolean runTemplate(String template, DataProvider provider) throws Exception {
boolean fail = false;

System.out.println("Running: " + template);
_templates.add(template);

Map<String, Object> args = provider.provide();
String html = _thymeleaf.process(template, args);
byte[] actual = _pdfCreator.runRenderer("/templates/", html);

if (Application.class.getResource("/expected/" + template + ".pdf") != null) {
try (InputStream is = Application.class.getResourceAsStream("/expected/" + template + ".pdf")) {
byte[] expected = IOUtils.toByteArray(is);
fail |= !_tester.testPdfEquality(expected, actual, template);
}
} else {
System.err.println("Test proof not found for: " + template);
fail = true;
}

File webTemplateBase = new File(_websiteBase, template);
webTemplateBase.mkdirs();

Files.write(new File(webTemplateBase, template + ".pdf").toPath(), actual);

try (PDDocument docActual = PDDocument.load(actual)) {
PDFRenderer rendActual = new PDFRenderer(docActual);
BufferedImage bi = rendActual.renderImageWithDPI(0, 192f, ImageType.RGB);

String filename = template + "-large.png";
ImageIO.write(bi, "png", new File(webTemplateBase, filename));

BufferedImage small = Scalr.resize(bi, 900);
String smallname = template + "-small.png";
ImageIO.write(small, "png", new File(webTemplateBase, smallname));
}

String thymeleaf;
try (InputStream in = Application.class.getResourceAsStream("/templates/" + template + ".html")) {
thymeleaf = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)).lines().collect(Collectors.joining("\n"));
}

String highlightHtml = _highlighter.highlight(template + ".html", html, "UTF-8", true);
String highlightThymeleaf = _highlighter.highlight(template, thymeleaf, "UTF-8", true);

String[] parts = thymeleaf.split(Pattern.quote("====="));
TemplateSettings meta = getYaml(parts[1]);

Map<String, Object> webArgs = new HashMap<>();
webArgs.put("thymeleaf", highlightThymeleaf);
webArgs.put("raw", highlightHtml);
webArgs.put("name", template);
webArgs.put("code_style", _codeStyles);
webArgs.put("meta", meta);

String webpage = _thymeleaf.process("webpage-details", webArgs);
Files.write(new File(webTemplateBase, "details.html").toPath(), webpage.getBytes(StandardCharsets.UTF_8));

return fail;
}

public int run() {
boolean fail = false;
try {
_websiteBase.mkdirs();

fail |= runTemplate("arboshiki-invoice", DataGenerator.INVOICE);

Map<String, Object> args = Collections.singletonMap("templates", _templates);
String indexHtml = _thymeleaf.process("webpage-index", args);

Files.write(new File(_websiteBase, "index.html").toPath(), indexHtml.getBytes(StandardCharsets.UTF_8));

} catch (Exception e) {
System.out.println("Exception while generating templates...");
e.printStackTrace();
return -1;
}
return fail ? -1 : 0;
}

public static void main(String[] args) {
XRLog.listRegisteredLoggers().forEach(logger -> XRLog.setLevel(logger, Level.WARNING));
System.exit(new Application().run());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.openhtmltopdf.templates;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;

import com.openhtmltopdf.templates.dto.Address;
import com.openhtmltopdf.templates.dto.Company;
import com.openhtmltopdf.templates.dto.Invoice;

public class DataGenerator {
public interface DataProvider {
Map<String, Object> provide();
}

public static Address defaultAddress() {
return new Address("Unit 1", "123 Main St", "Springfield", "Ohio", "USA", "54325");
}

public static Address address2() {
return new Address("125 Second Ave", null, "Waterside", "California", "America", null);
}

public static Company defaultCompany() {
return new Company("ACME Corp", "images/flyingsaucer.png", defaultAddress(), "[email protected]", "http://example.com", "555-5432");
}

public static Company company2() {
return new Company("ABC", null, address2(), "[email protected]", "http://abc.example.com", "555-1234");
}

public static final DataProvider INVOICE = () ->
Collections.singletonMap("invoice", new Invoice(
"1-2-3",
defaultCompany(),
company2(),
"John Citizen",
LocalDate.of(2025, 03, 25),
LocalDate.of(2025, 05, 25),
Arrays.asList(
new Invoice.InvoiceItem("Create simple website", 1, BigDecimal.valueOf(150000, 2), BigDecimal.valueOf(150000, 2)),
new Invoice.InvoiceItem("Social media posts", 10, BigDecimal.valueOf(10000, 2), BigDecimal.valueOf(100000, 2)),
new Invoice.InvoiceItem("Email templates", 2, BigDecimal.valueOf(15073, 2), BigDecimal.valueOf(30146, 2))
),
BigDecimal.valueOf(280146, 2),
BigDecimal.valueOf(2500, 2),
BigDecimal.valueOf(70037, 2),
BigDecimal.valueOf(350183, 2),
"A finance charge of 1.5% will be made on unpaid balances after 30 days."
));
}
Loading