mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Add ConvertHtmlToPdfAction
This commit is contained in:
@ -97,6 +97,23 @@
|
||||
<artifactId>java-dotenv</artifactId>
|
||||
<version>5.2.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
<artifactId>velocity-engine-core</artifactId>
|
||||
<version>2.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- the next 2 deps are for html to pdf - per https://www.baeldung.com/java-html-to-pdf -->
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<version>1.15.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xhtmlrenderer</groupId>
|
||||
<artifactId>flying-saucer-pdf-openpdf</artifactId>
|
||||
<version>9.1.22</version>
|
||||
</dependency>
|
||||
|
||||
<!-- the next 3 deps are being added for google drive support -->
|
||||
<dependency>
|
||||
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.actions.templates;
|
||||
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.actions.AbstractQActionFunction;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.templates.ConvertHtmlToPdfInput;
|
||||
import com.kingsrook.qqq.backend.core.model.templates.ConvertHtmlToPdfOutput;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.xhtmlrenderer.layout.SharedContext;
|
||||
import org.xhtmlrenderer.pdf.ITextRenderer;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Action to convert a string of HTML to a PDF!
|
||||
**
|
||||
** Much credit to https://www.baeldung.com/java-html-to-pdf
|
||||
*******************************************************************************/
|
||||
public class ConvertHtmlToPdfAction extends AbstractQActionFunction<ConvertHtmlToPdfInput, ConvertHtmlToPdfOutput>
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public ConvertHtmlToPdfOutput execute(ConvertHtmlToPdfInput input) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
ConvertHtmlToPdfOutput output = new ConvertHtmlToPdfOutput();
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// convert the input HTML to XHTML, as needed for ITextRenderer //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
Document document = Jsoup.parse(input.getHtml());
|
||||
document.outputSettings().syntax(Document.OutputSettings.Syntax.xml);
|
||||
|
||||
//////////////////////////////
|
||||
// convert the XHTML to PDF //
|
||||
//////////////////////////////
|
||||
ITextRenderer renderer = new ITextRenderer();
|
||||
SharedContext sharedContext = renderer.getSharedContext();
|
||||
sharedContext.setPrint(true);
|
||||
sharedContext.setInteractive(false);
|
||||
|
||||
if(input.getBasePath() != null)
|
||||
{
|
||||
String baseUrl = input.getBasePath().toUri().toURL().toString();
|
||||
renderer.setDocumentFromString(document.html(), baseUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.setDocumentFromString(document.html());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// register any custom fonts the input supplied //
|
||||
//////////////////////////////////////////////////
|
||||
for(Map.Entry<String, Path> entry : CollectionUtils.nonNullMap(input.getCustomFonts()).entrySet())
|
||||
{
|
||||
renderer.getFontResolver().addFont(entry.getValue().toAbsolutePath().toString(), entry.getKey(), "UTF-8", true, null);
|
||||
}
|
||||
|
||||
renderer.layout();
|
||||
renderer.createPDF(input.getOutputStream());
|
||||
|
||||
return (output);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QException("Error converting html to pdf", e));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.templates;
|
||||
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ConvertHtmlToPdfInput extends AbstractActionInput
|
||||
{
|
||||
private String html;
|
||||
private OutputStream outputStream;
|
||||
|
||||
private Path basePath;
|
||||
private Map<String, Path> customFonts = new HashMap<>();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ConvertHtmlToPdfInput(QInstance instance)
|
||||
{
|
||||
super(instance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for html
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getHtml()
|
||||
{
|
||||
return html;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for html
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setHtml(String html)
|
||||
{
|
||||
this.html = html;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for html
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ConvertHtmlToPdfInput withHtml(String html)
|
||||
{
|
||||
this.html = html;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for outputStream
|
||||
**
|
||||
*******************************************************************************/
|
||||
public OutputStream getOutputStream()
|
||||
{
|
||||
return outputStream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for outputStream
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setOutputStream(OutputStream outputStream)
|
||||
{
|
||||
this.outputStream = outputStream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for outputStream
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ConvertHtmlToPdfInput withOutputStream(OutputStream outputStream)
|
||||
{
|
||||
this.outputStream = outputStream;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for basePath
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Path getBasePath()
|
||||
{
|
||||
return basePath;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for basePath
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setBasePath(Path basePath)
|
||||
{
|
||||
this.basePath = basePath;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for basePath
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ConvertHtmlToPdfInput withBasePath(Path basePath)
|
||||
{
|
||||
this.basePath = basePath;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for customFonts
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, Path> getCustomFonts()
|
||||
{
|
||||
return customFonts;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for customFonts
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setCustomFonts(Map<String, Path> customFonts)
|
||||
{
|
||||
this.customFonts = customFonts;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for customFonts
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ConvertHtmlToPdfInput withCustomFonts(Map<String, Path> customFonts)
|
||||
{
|
||||
this.customFonts = customFonts;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for customFonts
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ConvertHtmlToPdfInput withCustomFont(String name, Path path)
|
||||
{
|
||||
if(this.customFonts == null)
|
||||
{
|
||||
this.customFonts = new HashMap<>();
|
||||
}
|
||||
this.customFonts.put(name, path);
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.templates;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ConvertHtmlToPdfOutput extends AbstractActionOutput
|
||||
{
|
||||
private String result;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for result
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getResult()
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for result
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setResult(String result)
|
||||
{
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for result
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ConvertHtmlToPdfOutput withResult(String result)
|
||||
{
|
||||
this.result = result;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -436,13 +436,29 @@ public class CollectionUtils
|
||||
**
|
||||
** Meant to help avoid null checks on foreach loops.
|
||||
*******************************************************************************/
|
||||
public static <T> Collection<T> nonNullCollection(Collection<T> list)
|
||||
public static <T> Collection<T> nonNullCollection(Collection<T> c)
|
||||
{
|
||||
if(list == null)
|
||||
if(c == null)
|
||||
{
|
||||
return (new ArrayList<>());
|
||||
}
|
||||
return (list);
|
||||
return (c);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Returns the input map, unless it was null - in which case a new HashMap is returned.
|
||||
**
|
||||
** Meant to help avoid null checks on foreach loops.
|
||||
*******************************************************************************/
|
||||
public static <K, V> Map<K, V> nonNullMap(Map<K, V> map)
|
||||
{
|
||||
if(map == null)
|
||||
{
|
||||
return (new HashMap<>());
|
||||
}
|
||||
return (map);
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.actions.templates;
|
||||
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Path;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||
import com.kingsrook.qqq.backend.core.model.templates.ConvertHtmlToPdfInput;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for ConvertHtmlToPdfAction
|
||||
*******************************************************************************/
|
||||
class ConvertHtmlToPdfActionTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test() throws QException, IOException
|
||||
{
|
||||
QInstance instance = TestUtils.defineInstance();
|
||||
ConvertHtmlToPdfInput input = new ConvertHtmlToPdfInput(instance);
|
||||
input.setSession(new QSession());
|
||||
|
||||
input.setHtml("""
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.center_div {
|
||||
border: 1px solid gray;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 90%;
|
||||
background-color: #d0f0f6;
|
||||
text-align: left;
|
||||
padding: 8px;
|
||||
font-family: Helvetica;
|
||||
}
|
||||
</style>
|
||||
<link href="styles/styles.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div class="center_div">
|
||||
<h1>
|
||||
<img src="images/qqq-logo-2.png" width=50>
|
||||
Hello QQQ!
|
||||
</h1>
|
||||
<div class="myclass">
|
||||
<p>This is a test of converting HTML to PDF!!</p>
|
||||
<p style="font-family: SF-Pro; font-size: 24px;">(btw, is this in SF-Pro???)</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
""");
|
||||
|
||||
OutputStream outputStream = new FileOutputStream("/tmp/file.pdf");
|
||||
input.setOutputStream(outputStream);
|
||||
|
||||
String resourceDir = "src/test/resources/actions/templates";
|
||||
input.withCustomFont("SF-Pro", Path.of(resourceDir + "/fonts/SF-Pro-Rounded-Regular.otf"));
|
||||
input.withCustomFont("Helvetica", Path.of(resourceDir + "/fonts/Helvetica.ttc"));
|
||||
input.withBasePath(Path.of(resourceDir));
|
||||
|
||||
new ConvertHtmlToPdfAction().execute(input);
|
||||
System.out.println("Wrote /tmp/file.pdf");
|
||||
|
||||
outputStream.close();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// for local dev on a mac, turn this on to auto-open the generated PDF //
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Runtime.getRuntime().exec(new String[] { "/usr/bin/open", "/tmp/file.pdf" });
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
h1
|
||||
{
|
||||
text-align: center;
|
||||
border-bottom: 1px solid red;
|
||||
}
|
Reference in New Issue
Block a user