HTML to PDF or PNG

This commit is contained in:
Abdussamed 2024-09-23 17:23:24 +03:00
commit 3a5d699c9c
7 changed files with 2116 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
.vscode

20
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,20 @@
{
// Olası öznitelikler hakkında bilgi edinmek için IntelliSense kullanın.
// Mevcut özniteliklerin açıklamalarını görüntülemek için üzerine gelin.
// Daha fazla bilgi için şu adresi ziyaret edin: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Debug Main Process",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"args" : ["."],
"outputCapture": "std"
}
]
}

240
main.js Normal file
View File

@ -0,0 +1,240 @@
const { app, BrowserWindow } = require('electron');
const {randomUUID} = require("node:crypto");
const { Command } = require('commander');
const express = require('express');
const multer = require('multer');
const path = require("path");
const fs = require("fs");
function writeFile(ext,data)
{
let file = randomUUID() + "." + ext;
fs.writeFileSync(
path
.resolve(
__dirname,
"./output/",
file
),
data
);
return file;
}
/**
* @param {{type,website,range,background,size}} options
* @returns {Promise<[Buffer,string]>}
*/
async function generatePDF(options) {
const win = new BrowserWindow({
webPreferences:{
contextIsolation: true,
nodeIntegration: false,
disableDialogs: false,
webSecurity: true
},
show: false,
width: options.width,
height: options.height
});
await new Promise(ok => {
win.webContents.addListener("did-finish-load",()=>{
ok()
});
win.webContents.addListener("did-fail-load",()=>{
console.error("Hata oluştu")
});
if(options.htmlcontent)
{
win.loadURL(`data:text/html;base64,${Buffer.from(options.htmlcontent).toString("base64")}`);
}else{
win.loadURL(options.endpoint);
}
})
let result = await new Promise(result => {
switch(options.type)
{
case "mhtml":{
win.webContents.savePage(path.resolve(__dirname, randomUUID() + ".mhtml"),"HTMLOnly");
break;
}
case "image":{
win.webContents.setZoomFactor(Math.max(0, Math.min(3.0, options.zoom)))
win.webContents.capturePage().then(e => {
let binary = e.toPNG();
result([binary, "png"]);
});
break;
}
case "pdf":{
win.webContents.printToPDF({
printBackground: true,
displayHeaderFooter: false,
scale: options.scale,
landscape: options.landscape,
pageSize: options.pageSize,
pageRanges: options.pageRanges
}).then(data => {
result([data, "pdf"]);
});
break;
}
}
});
win.destroy();
return result;
};
app.disableDomainBlockingFor3DAPIs();
app.disableHardwareAcceleration();
app.addListener("window-all-closed",function(){
});
async function main()
{
await new Promise(ok => {
app.whenReady().then(() => {
ok()
});
});
let port = express();
port.use(express.static(path.resolve(__dirname,"./output/"),{
acceptRanges: true,
cacheControl: true,
etag: true,
lastModified: true
}))
port.use(express.static(path.resolve(__dirname,"./public/"),{
acceptRanges: true,
cacheControl: true,
etag: true,
lastModified: true
}))
port.use(function(request, response, next){
response.header("Access-Control-Allow-Origin","*");
response.header("Access-Control-Allow-Headers","*");
response.header("Access-Control-Allow-Methods","GET, POST, OPTION");
next();
});
let memory = multer({storage: multer.memoryStorage()}).none();
port.post("/pdf", memory,async (request, response) => {
let {
width,
height,
scale,
content: htmlcontent,
endpoint,
isLandscape,
pageSize,
pageRanges,
output
} = request.body;
output = output || "content";
let [content, extension] = await generatePDF({
htmlcontent,
endpoint,
type: "pdf",
landscape: isLandscape || false,
scale: scale || 1.0,
width: width || 1920,
height: height || 1080,
pageSize: pageSize || "A4",
range: pageRanges || ""
});
switch(output)
{
case "json":{
let image = writeFile(extension,content);
response.json({
status: "success",
data: image,
type: "pdf"
});
break;
}
case "json+base64":{
response.json({
status: "success",
data: `data:application/pdf;base64,${content.toString("base64")}`,
type: "pdf"
});
break;
}
case "content":{
response.contentType(extension);
response.end(content);
break;
}
}
});
port.post("/image", memory,async (request, response) => {
let {
width,
height,
zoom,
content: htmlcontent,
endpoint,
output
} = request.body;
output = output || "content";
let [content, extension] = await generatePDF({
htmlcontent,
endpoint,
type: "image",
zoom: zoom || 1.0,
width: width || 1920,
height: height || 1080
});
switch(output)
{
case "json":{
let image = writeFile(extension,content);
response.json({
status: "success",
data: image,
type: "image"
});
break;
}
case "json+base64":{
response.json({
status: "success",
data: `data:image/png;base64,${content.toString("base64")}`,
type: "image"
});
break;
}
case "content":{
response.contentType(extension);
response.end(content);
break;
}
}
});
port.listen(8473);
}
process.nextTick(main);

1714
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

17
package.json Normal file
View File

@ -0,0 +1,17 @@
{
"name": "pdfgenerator",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "electron . --inspect"
},
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"commander": "^12.1.0",
"electron": "^32.1.2",
"express": "^4.21.0",
"multer": "^1.4.5-lts.1"
}
}

11
public/index.html Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./script.js"></script>
</body>
</html>

112
public/script.js Normal file
View File

@ -0,0 +1,112 @@
/*
imagé({
input: "htmlcontent",
content: "<meta charset=\"UTF-8\"><h1 style='background-color:red;color:White'>This is a PDF</h1>",
generate: "pdf",
output: "json",
success: (data)=> {
console.log(data)
}
});
*/
async function imagé(options)
{
if(typeof options != "object")
{
throw new Error();
}
const {
input,
content,
endpoint,
generate,
output,
success,
...otheroptions
} = options;
let form = new FormData();
if(input == "htmlcontent")
{
if(typeof content != "string" || !content){
throw new Error();
};
form.append("content", content)
}
if(input == "endpoint")
{
if(typeof endpoint != "string" || !endpoint){
throw new Error();
};
form.append("endpoint", content)
}
if(generate != "pdf" && generate == "image")
{
throw new Error();
}
switch(output)
{
case "json":
case "json+base64":
case "content":{
form.append("output", output);
break;
};
default:{
throw new Error();
}
}
for (const name in otheroptions) {
const value = otheroptions[name];
form.append(name, value);
}
let t = await fetch("http://localhost:8473/" + generate,{
method:"post",
body: form
});
if(!t.ok)
{
throw new Error();
}
if(
t.headers.get("content-type").indexOf("application/pdf") != -1 ||
t.headers.get("content-type").indexOf("image/png") != -1
)
{
let blob = await t.blob(), file;
if(generate == "pdf")
{
file = new File([blob],"File.pdf",{
lastModified: new Date(),
type:"application/pdf"
});
}else if(generate == "image"){
file = new File([blob],"File.png",{
lastModified: new Date(),
type:"image/png"
});
}
return (
typeof options.success == "function" &&
options.success(file),
file
);
}else{
let data = await t.json();
return (
typeof options.success == "function" &&
options.success(data),
data
);
}
}