Commit 66e49698 authored by Rob Hulswit's avatar Rob Hulswit

Merge branch 'feature/pdf-header-footer' into 'master'

Add setting page margins and headers and footers to GeneratePDF

See merge request !243
parents df013cdd 4367049e
......@@ -204,7 +204,7 @@ PUBLIC STATIC OBJECTTYPE ChromePDFAPI EXTEND ComposerBase
RETURN filelist;
}
ASYNC FUNCTION GeneratePDFInternal(BLOB data)
ASYNC FUNCTION GeneratePDFInternal(BLOB data, RECORD options DEFAULTSTO DEFAULT RECORD)
{
RECORD ARRAY filelist := this->GetFileList(data);
IF(Length(filelist) = 0)
......@@ -213,15 +213,15 @@ PUBLIC STATIC OBJECTTYPE ChromePDFAPI EXTEND ComposerBase
OBJECT server := NEW AdHocServer(/*[ logdebug := TRUE ]*/);
server->PrecacheFiles(filelist);
BLOB pdf := AWAIT this->GeneratePDFFromURL(server->baseurl || "/.contents");
BLOB pdf := AWAIT this->GeneratePDFFromURL(server->baseurl || "/.contents", options);
server->Close();
RETURN pdf;
}
PUBLIC ASYNC FUNCTION GeneratePDF()
PUBLIC ASYNC FUNCTION GeneratePDF(RECORD options DEFAULTSTO DEFAULT RECORD)
{
this->PrepareHTMLVersion();
RETURN AWAIT this->GeneratePDFInternal(DEFAULT BLOB);
RETURN AWAIT this->GeneratePDFInternal(DEFAULT BLOB, options);
}
PUBLIC BLOB FUNCTION GenerateSource()
......@@ -241,10 +241,10 @@ PUBLIC STATIC OBJECTTYPE ChromePDFAPI EXTEND ComposerBase
RETURN result;
}
PUBLIC ASYNC FUNCTION GeneratePDFFromBlob(BLOB data, RECORD ARRAY embedded_files DEFAULTSTO DEFAULT RECORD ARRAY)
PUBLIC ASYNC FUNCTION GeneratePDFFromBlob(BLOB data, RECORD ARRAY embedded_files DEFAULTSTO DEFAULT RECORD ARRAY, RECORD options DEFAULTSTO DEFAULT RECORD)
{
this->embedded_files := embedded_files;
RETURN AWAIT this->GeneratePDFInternal(data);
RETURN AWAIT this->GeneratePDFInternal(data, options);
}
ASYNC FUNCTION GotoThePage(STRING url, RECORD options)
......
......@@ -12,5 +12,6 @@
## Things that are nice to know
- WRD types now have a `haspersonaldata` flag, which can be set to TRUE for types that may contain sensitive user data. All types that refer to a type that has set `haspersonaldata` to TRUE are also considered to contain user data. The `WRD_PERSON` type has this flag set by default. When exporting or syncing WRD schemas you can choose to only export/sync non-personal data, all data or select which types to export/sync. Exporting and syncing WRD schemas now also logs audit events.
- Tollium now has support for custom implementations and component parsers. See [Custom implementations and component parsers](topic:tollium-components/parsing) for more information and examples.
- `GeneratePDF` now supports setting the page margins and headers and footers
## Things you should do
......@@ -190,6 +190,8 @@ PUBLIC STATIC OBJECTTYPE Page EXTEND EventEmitter
CELL[ ...sharedpageprepoptions
, scale := 1m
, displayheaderfooter := FALSE
, headertemplate := ""
, footertemplate := ""
, landscape := FALSE
, pageranges := ""
, format := ""
......@@ -225,6 +227,8 @@ PUBLIC STATIC OBJECTTYPE Page EXTEND EventEmitter
RECORD parameters :=
CELL[ options.landscape
, options.displayheaderfooter
, options.headertemplate
, options.footertemplate
, options.printbackground
, options.scale
, paperwidth
......
......@@ -141,6 +141,8 @@ PUBLIC RECORD FUNCTION GenerateBrowserScreenshot(STRING url, RECORD options DEFA
}
/** @short Generate a PDF from a witty record
@long Header and footer templates can use `<span class="pageNumber"></span>` and `<span class="totalPages"></span>` to show the page number and total number of pages respectively, but due to a Chrome limitation
these are only shown if you also set the page margins to not intersect with these elements
@param data Witty data
@cell options.pdfengine PDF Engine to use. 'chrome' (default)
@cell options.printbackground Print backgrounds too? (defaults to true)
......@@ -150,6 +152,10 @@ PUBLIC RECORD FUNCTION GenerateBrowserScreenshot(STRING url, RECORD options DEFA
@cell(string) options.media Media to use - 'screen' (default) or 'print'
@cell(boolean) options.debug Enable debug mode
@cell(integer) options.delay How much milliseconds to wait after setting the url before taking a screenshot
@cell(record) options.margin Page marginn (eg `[ top := "0.5cm", bottom := "0.5cm", left := "1cm", right := "1cm" ]`). Defaults to no margins
@cell(boolean) options.displayheaderfooter Display header and footer. Defaults to FALSE
@cell(string) options.headertemplate Header template HTML code
@cell(string) options.footertemplate Header template HTML code
@return Wrapped file containing the PDF (or ZIP, if getsource is used)
*/
PUBLIC RECORD FUNCTION GeneratePDF(RECORD data, RECORD options DEFAULTSTO CELL[])
......@@ -163,6 +169,10 @@ PUBLIC RECORD FUNCTION GeneratePDF(RECORD data, RECORD options DEFAULTSTO CELL[]
, getsource := FALSE
, delay := 0
, lookupresource := DEFAULT FUNCTION PTR
, displayheaderfooter := FALSE
, headertemplate := ""
, footertemplate := ""
, margin := DEFAULT RECORD
], options, [ enums := [ pdfengine := ["chrome"]
, media := ["print","screen"]
]
......@@ -191,8 +201,20 @@ PUBLIC RECORD FUNCTION GeneratePDF(RECORD data, RECORD options DEFAULTSTO CELL[]
pdfgenerator->mergerecord := data;
pdfgenerator->lookupresource := options.lookupresource;
BLOB pdfdata := options.getsource ? pdfgenerator->GenerateSource() : WaitForPromise(pdfgenerator->GeneratePDF());
RETURN WrapBlob(pdfdata, options.filename);
BLOB filedata;
IF(options.getsource)
{
filedata := pdfgenerator->GenerateSource();
}
ELSE
{
filedata := WaitForPromise(pdfgenerator->GeneratePDF(CELL[ options.displayheaderfooter
, options.headertemplate
, options.footertemplate
, options.margin
]));
}
RETURN WrapBlob(filedata, options.filename);
}
THROW NEW Exception("GeneratePDF failed");
......
<?wh
LOADLIB "wh::files.whlib";
LOADLIB "wh::internet/urls.whlib";
LOADLIB "mod::system/lib/configure.whlib";
......@@ -15,7 +16,7 @@ STRING doc := `<!DOCTYPE html>
<head>
<style>
html,body { background-color: transparent; }
html { font: 45px Arial; color: #00000; }
html { font: 45px Arial; color: #000000; }
</style>
</head>
<body>
......@@ -23,6 +24,21 @@ STRING doc := `<!DOCTYPE html>
</body>
</html>`;
STRING multipagedoc := `<!DOCTYPE html>
<html>
<head>
<style>
html,body { background-color: transparent; }
html { font: 45px Arial; color: #000000; }
</style>
</head>
<body>
<p>Page 1</p>
<p style="page-break-before: always">Page 2</p>
<p style="page-break-before: always">Page 3</p>
</body>
</html>`;
STRING bgdoc := `<!DOCTYPE html>
<html>
<head>
......@@ -46,7 +62,7 @@ MACRO TestPDFs()
TestEq(1,Length(images));
Testeq("page-1.jpg", images[0].filename);
testfw->CompareWithImage(images[0].data, Resolve("testdata/fullscreenshot.png"), [ maxmse := 500 ]); //ADDME lower maxmse but we'll probably need a webfont
testfw->CompareWithImage(images[0].data, Resolve("testdata/fullscreenshot.png"), [ maxmse := 500 ]); //TODO lower maxmse but we'll probably need a webfont
RECORD result2 := GeneratePDF( [ body := PTR Print(bgdoc)
, wittypath := "inline::[body]"
......@@ -57,7 +73,7 @@ MACRO TestPDFs()
BLOB final := ApplyOverlayToPDF(result.data, result2.data);
images := __ExtractPDFImages(final);
testfw->CompareWithImage(images[0].data, Resolve("testdata/merged.png"), [ maxmse := 500 ]); //ADDME lower maxmse but we'll probably need a webfont
testfw->CompareWithImage(images[0].data, Resolve("testdata/merged.png"), [ maxmse := 500 ]); //TODO lower maxmse but we'll probably need a webfont
//test empty concat
TestThrows (PTR ConcatenatePDFs(BLOB[]));
......@@ -75,6 +91,19 @@ MACRO TestPDFs()
testfw->CompareWithImage(images[x].data, Resolve("testdata/fullscreenshot.png"), [ maxmse := 500 ]);
testfw->CompareWithImage(images[x+1].data, Resolve("testdata/background.png"), [ maxmse := 25 ]);
}
result := GeneratePDF( [ body := PTR Print(multipagedoc)
, wittypath := "inline::[body]"
], [ printbackground := FALSE
, displayheaderfooter := TRUE
, margin := [ top := "0.5cm", left := "0.5cm", right := "0.5cm", bottom := "0.5cm" ]
, headertemplate := `<div style="width:100%; text-align:right; font-size:12px;">HEADER: <span class='pageNumber'></span>/<span class='totalPages'></span></div>`
, footertemplate := `<div style="width:100%; text-align:right; font-size:12px;">FOOTER: <span class='pageNumber'></span>/<span class='totalPages'></span></div>`
]);
images := __ExtractPDFImages(result.data);
TestEq(3,Length(images));
Testeq("page-2.jpg", images[1].filename);
testfw->CompareWithImage(images[1].data, Resolve("testdata/pagenumberedpage.png"), [ maxmse := 500 ]); //TODO lower maxmse but we'll probably need a webfont
}
ASYNC MACRO TestWittyDialog()
......@@ -96,7 +125,7 @@ MACRO TestPDFFromURL()
TestEq(1,Length(images));
Testeq("page-1.jpg", images[0].filename);
testfw->CompareWithImage(images[0].data, Resolve("testdata/webpage.png"), [ maxmse := 500 ]); //ADDME lower maxmse but we'll probably need a webfont
testfw->CompareWithImage(images[0].data, Resolve("testdata/webpage.png"), [ maxmse := 500 ]); //TODO lower maxmse but we'll probably need a webfont
}
MACRO TestScreenshots()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment