Milan Herda 04/2023
Samostatná REST služba naprogramovaná v JS s využitím knižnice pdfmake
Výhody:
Nevýhody:
Bez serveru
Každá aplikácia si PDF generuje po svojom. PDF generátor je poskytovaný ako balíček. Šablóny môžu byť v balíčku tiež.
Server bez šablón
Server neobsahuje žiadne šablóny a klient mu posiela dáta a aj definíciu šablóny.
Server so šablónami
Klient pošle na PDF server názov šablóny a dáta, ktoré chce do nej vložiť.
Ako generovať PDF a mať to štandardizované alebo aspoň čiastočne centralizované?
Výhody:
Nevýhody:
Výhody:
Nevýhody:
Výhody:
Nevýhody:
Naozaj?
Bez serveru
Každá aplikácia si PDF generuje po svojom. PDF generátor je poskytovaný ako balíček. Šablóny môžu byť v balíčku tiež.
Server bez šablón
Server neobsahuje žiadne šablóny a klient mu posiela dáta a aj definíciu šablóny.
Server so šablónami
Klient pošle na PDF server názov šablóny a dáta, ktoré chce do nej vložiť.
Ako generovať PDF a mať to štandardizované alebo aspoň čiastočne centralizované?
Generovanie PDF na základe XML
Generovanie PDF na základe šablóny zapísanej pomocou XML
<?xml version='1.0' standalone='yes'?>
<document>
<images>
<image-url
name="logo"
src="https://www.monkeyuser.com/assets/images/2017/62-design-patterns-bureaucracy.png"
/>
<image-url
name="cover"
src="https://www.monkeyuser.com/assets/images/2020/177-devs-journey.png"
/>
</images>
<content>
<text fontSize="18" color="grey">Hello World!</text>
<image name="cover" width="250" />
<text pageBreak="before" fontSize="16" color="blue">Table Example</text>
<table>
<tr>
<td>Bunka 1</td>
<td>Bunka 2</td>
</tr>
<tr>
<td>Bunka 3</td>
<td><image name="logo" fit="[500, 500]"/></td>
</tr>
</table>
</content>
</document>
yarn ts-node generate-from-file.ts --xml=test.xml --pdf=/tmp/a.pdf
function readXmlFile(xmlFile: string) {
const buffer = fs.readFileSync(xmlFile);
return buffer.toString();
}
async function main() {
const { xmlFile, pdfFile } = parseCommandLineArguments();
const xml = readXmlFile(xmlFile);
const pdfCommands = await createPdfFromXmlString(xml);
printPdf(pdfCommands, pdfFile);
}
main();
yarn server
XML="
<?xml version='1.0' standalone='yes'?>
<document>
<content>
<text fontSize='18' color='blue'>Hello World</text>
<qr>Have a nice day!</qr>
</content>
</document>
"
XML=`echo $XML | jq -Rsa`
curl -X POST http://127.0.0.1:8080/pdf/create/moj-zivotopis.pdf \
-H 'Content-Type: application/json' \
-d "{\"xml\": $XML}"
import { pipePdfToResponse } from './js/server';
app.post('/pdf/create/:filename', async (req, res) => {
res.status(200);
try {
const fonts = {
Roboto: {
normal: './node_modules/@fontsource/roboto/files/roboto-all-700-normal.woff',
bold: './node_modules/@fontsource/roboto/files/roboto-all-900-normal.woff',
italics: './node_modules/@fontsource/roboto/files/roboto-all-700-italic.woff',
bolditalics: './node_modules/@fontsource/roboto/files/roboto-all-900-italic.woff',
},
};
pipePdfToResponse(
req.body.xml,
fonts,
res,
req.params.filename
);
} catch (e: any) {
// ...
}
});
yarn dev
import showWithPdfjs from './js/browser';
const xml = `...`;
const fonts = {
Roboto: {
normal: `${document.location.protocol}//${document.location.host}/node_modules/@fontsource/roboto/files/roboto-all-700-normal.woff`,
bold: `${document.location.protocol}//${document.location.host}/node_modules/@fontsource/roboto/files/roboto-all-900-normal.woff`,
italics: `${document.location.protocol}//${document.location.host}/node_modules/@fontsource/roboto/files/roboto-all-700-italic.woff`,
bolditalics: `${document.location.protocol}//${document.location.host}/node_modules/@fontsource/roboto/files/roboto-all-900-italic.woff`,
},
};
async function main() {
await showWithPdfjs(
xml,
<HTMLCanvasElement>document.getElementById('canvas'),
fonts,
'./node_modules/pdfjs-dist/build/pdf.worker.js',
1
);
}
main();
Nájdeme v dokumentácii
<?xml version='1.0' standalone='yes'?>
<document>
<content>
Hello World
<text bold='true' fontSize='18' color='blue'>Farebný Hello World</text>
<text
decoration='underline'
decorationStyle='wavy'
decorationColor='green'
>
Zelená vlnovka
</text>
</content>
</document>
# PRESENTING CODE
<?xml version='1.0' standalone='yes'?>
<document>
<content>
<columns>
<stack>
<text>Prvý riadok</text>
<text>Druhý riadok</text>
<text>Tretí riadok</text>
</stack>
<text
width='100'
bold='true'
fontSize='18'
color='blue'
>Farebný Hello World</text>
<text
width='50'
decoration='underline'
decorationStyle='wavy'
decorationColor='green'
>Zelená vlnovka</text>
</columns>
</content>
</document>
# PRESENTING CODE
<?xml version='1.0' standalone='yes'?>
<document>
<images>
<image-url name='logo' src='https://www.monkeyuser.com/assets/images/2017/62-design-patterns-bureaucracy.png' />
<image-url name='cover' src='https://www.monkeyuser.com/assets/images/2020/177-devs-journey.png' />
</images>
<content>
<image name='logo' width='250' />
<image name='cover' fit='[200, 200]' />
</content>
</document>
# PRESENTING CODE
<?xml version='1.0' standalone='yes'?>
<document>
<content>
<svg-wrapper width='15'>
<svg
xmlns='http://www.w3.org/2000/svg'
width='30'
height='30'
viewBox='0 0 30 30'
>
<g transform='translate(-517 -1486)'><g transform='translate(517 1486)'><circle cx='15' cy='15' r='15' fill='#f7af26'/></g><g transform='translate(524 1493)'><path d='M14,1H2A2,2,0,0,0,0,3v.4L8,7.9l8-4.4V3A2,2,0,0,0,14,1Z' fill='#fff'/><path d='M7.5,9.9,0,5.7V13a2,2,0,0,0,2,2H14a2,2,0,0,0,2-2V5.7L8.5,9.9A1.243,1.243,0,0,1,7.5,9.9Z' fill='#fff'/></g></g>
</svg>
</svg-wrapper>
</content>
</document>
# PRESENTING CODE
<?xml version='1.0' standalone='yes'?>
<document>
<content>
<ul type='disc'>
<text>Prvá položka</text>
<text>Druhá položka</text>
<ul type='circle'>
<text>Podpoložka 1</text>
<text>Podpoložka 2</text>
</ul>
</ul>
<ol type='lower-alpha' start='5'>
<text>Prvá položka</text>
<text>Druhá položka</text>
<text>Tretia položka</text>
</ol>
</content>
</document>
# PRESENTING CODE
<?xml version='1.0' standalone='yes'?>
<document>
<content>
<table widths='["30%", "*"]'>
<tr>
<td borderColor='["red", "green", "blue", "violet"]'>Bunka 1</td>
<td fillColor='gold'>Bunka 2</td>
</tr>
<tr>
<td colspan='2'>Bunka 3</td>
<td></td>
</tr>
<tr>
<td rolspan='2'>Bunka 5</td>
<td>Bunka 6</td>
</tr>
<tr>
<td></td>
<td>Bunka 8</td>
</tr>
</table>
</content>
</document>
# PRESENTING CODE
<?xml version='1.0' standalone='yes'?>
<document>
<content>
<qr>Hello World!</qr>
<qr foreground='red' background='gold'>Hello World!</qr>
<qr fit='50'>Hello World!</qr>
</content>
</document>
# PRESENTING CODE
<?xml version='1.0' standalone='yes'?>
<document>
<content>
<toc id='main'>Obsah</toc>
<text marginTop='50' tocItem='main' bold='true'>Nadpis 1</text>
<text>Lorem Ipsum...</text>
<text tocItem='main' bold='true'>Nadpis 2</text>
<text>Lorem Ipsum...</text>
<text tocItem='main' tocMargin='[20, 0, 0, 0]' bold='true'>Podnadpis 2.2</text>
<text>Lorem Ipsum...</text>
</content>
</document>
# PRESENTING CODE