Skip to content

merge with upstream - conflicts resolved #6

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
33 changes: 20 additions & 13 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
FROM node:12.13.0-alpine as builder
# syntax=docker/dockerfile:1.3.0-labs

FROM node:17.2.0-alpine as builder

ENV NODE_ENV production
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
Expand All @@ -12,26 +14,31 @@ COPY decktape.js ./

RUN npm install

FROM alpine:3.11.2
FROM alpine:3.15.0

LABEL org.opencontainers.image.source="https://github.com/astefanutti/decktape"

ENV TERM xterm-color

RUN <<EOF cat > /etc/apk/repositories
http://dl-cdn.alpinelinux.org/alpine/edge/main
http://dl-cdn.alpinelinux.org/alpine/edge/community
http://dl-cdn.alpinelinux.org/alpine/edge/testing
EOF

# Chromium, CA certificates, fonts
# https://git.alpinelinux.org/cgit/aports/log/community/chromium
RUN apk update && apk upgrade && \
echo @edge http://nl.alpinelinux.org/alpine/edge/community >> /etc/apk/repositories && \
echo @edge http://nl.alpinelinux.org/alpine/edge/main >> /etc/apk/repositories && \
echo @edge http://nl.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories && \
apk add --no-cache \
ca-certificates \
libstdc++@edge \
chromium@edge=86.0.4240.111-r0 \
font-noto-emoji@edge \
freetype@edge \
harfbuzz@edge \
nss@edge \
ttf-freefont@edge \
wqy-zenhei@edge && \
libstdc++ \
chromium=99.0.4844.51-r0 \
font-noto-emoji \
freetype \
harfbuzz \
nss \
ttf-freefont \
wqy-zenhei && \
# /etc/fonts/conf.d/44-wqy-zenhei.conf overrides 'monospace' matching FreeMono.ttf in /etc/fonts/conf.d/69-unifont.conf
mv /etc/fonts/conf.d/44-wqy-zenhei.conf /etc/fonts/conf.d/74-wqy-zenhei.conf && \
rm -rf /var/cache/apk/*
Expand Down
8 changes: 6 additions & 2 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@ The following slide deck examples have been exported using DeckTape:
|===
|HTML5 Presentation |Framework |Exported PDF

|https://revealjs.com/demo/[Reveal.js Demo]
|reveal.js
|https://astefanutti.github.io/decktape/examples/reveal-js-demo.pdf[reveal-js-demo.pdf] (2.0MB)

|https://tdd.github.io/devoxx-es6-maintenant/[ES6+ maintenant !]
|reveal.js
|https://astefanutti.github.io/decktape/examples/devoxx-es6-maintenant.pdf[devoxx-es6-maintenant.pdf] (2.3MB)
Expand Down Expand Up @@ -247,7 +251,7 @@ The following slide deck examples have been exported using DeckTape:

|https://formidable.com/open-source/spectacle/[Spectacle: A ReactJS Presentation Library]
|Spectacle
|https://astefanutti.github.io/decktape/examples/spectacle-reactjs-presentation.pdf[spectacle-reactjs-presentation.pdf] (8.9MB)
|https://astefanutti.github.io/decktape/examples/spectacle-reactjs-presentation.pdf[spectacle-reactjs-presentation.pdf] (1.2MB)
|===

== Docker
Expand All @@ -260,7 +264,7 @@ For example:

* To convert an online HTML presentation and have it exported into the working directory under the `slides.pdf` filename:
[source,shell,subs=attributes+]
$ docker run --rm -t -v `pwd`:/slides astefanutti/decktape https://revealjs.com/demos/3.9.2 slides.pdf
$ docker run --rm -t -v `pwd`:/slides astefanutti/decktape https://revealjs.com/demo/ slides.pdf

* Or, to convert an HTML presentation that's stored on the local file system in the `home` directory:
[source,shell]
Expand Down
45 changes: 39 additions & 6 deletions decktape.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,25 @@ parser.script('decktape').options({
list : true,
help : 'Additional argument to pass to the Chrome instance, can be repeated',
},
// PDF meta data
metaAuthor : {
full : 'pdf-author',
metavar : '<arg>',
type : 'string',
help : 'String to set as the author of the resulting pdf document',
},
metaTitle : {
full : 'pdf-title',
metavar : '<arg>',
type : 'string',
help : 'String to set as the title of the resulting pdf document',
},
metaSubject : {
full : 'pdf-subject',
metavar : '<arg>',
type : 'string',
help : 'String to set as the subject of the resulting pdf document',
},
});

function parseSize(size) {
Expand Down Expand Up @@ -201,6 +220,12 @@ process.on('unhandledRejection', error => {
await page.emulateMediaType('screen');
const pdf = await PDFDocument.create();
pdf.setCreator('Decktape');
if (options.metaAuthor)
pdf.setAuthor(options.metaAuthor);
if (options.metaSubject)
pdf.setSubject(options.metaSubject);
if (options.metaTitle)
pdf.setTitle(options.metaTitle);

page
.on('console', async msg => {
Expand All @@ -217,7 +242,7 @@ process.on('unhandledRejection', error => {
.on('pageerror', error => console.log(chalk`\n{red Page error: ${error.message}}`));

console.log('Loading page', options.url, '...');
const load = page.waitForNavigation({ waitUntil: 'load', timeout: 60000 });
const load = page.waitForNavigation({ waitUntil: 'load', timeout: 20000 });
page.goto(options.url, { waitUntil: 'networkidle0', timeout: 60000 })
// wait until the load event is dispatched
.then(response => load
Expand Down Expand Up @@ -351,7 +376,7 @@ async function exportSlide(plugin, page, pdf, context) {
pageRanges : '1',
displayHeaderFooter : false,
});
printSlide(pdf, await PDFDocument.load(buffer, { parseSpeed: ParseSpeeds.Fastest }), context);
await printSlide(pdf, await PDFDocument.load(buffer, { parseSpeed: ParseSpeeds.Fastest }), context);
context.exportedSlides++;

if (options.screenshots) {
Expand All @@ -373,12 +398,16 @@ async function exportSlide(plugin, page, pdf, context) {
}

async function printSlide(pdf, slide, context) {
const duplicatedEntries = [];
const [page] = await pdf.copyPages(slide, [0]);
pdf.addPage(page);
// Traverse the page to consolidate duplicates
parseResources(page.node);
// And delete all the collected duplicates
duplicatedEntries.forEach(ref => pdf.context.delete(ref));

function parseResources(dictionary) {
const resources = dictionary.get(PDFName.of('Resources'));
const resources = dictionary.get(PDFName.Resources);
if (resources.has(PDFName.XObject)) {
const xObject = resources.get(PDFName.XObject);
xObject.entries().forEach(entry => parseXObject(entry, xObject));
Expand Down Expand Up @@ -423,8 +452,12 @@ async function printSlide(pdf, slide, context) {
}
const bytes = decodePDFRawStream(file).decode();
const font = Font.create(Buffer.from(bytes), { type: 'ttf', hinting: true });
// PDF font name does not contain sub family on Windows 10 so a more robust key
// is computed from the font metadata
// Some fonts happen to have no metadata, which is required by fonteditor
if (!font.data.name) {
font.data.name = {};
}
// PDF font name does not contain sub family on Windows 10,
// so a more robust key is computed from the font metadata
const id = descriptor.get(PDFName.of('FontName')).value() + ' - ' + fontMetadataKey(font.data.name);
if (context.pdfFonts[id]) {
const f = context.pdfFonts[id].font;
Expand All @@ -440,7 +473,7 @@ async function printSlide(pdf, slide, context) {
}
});
descriptor.set(PDFName.of('FontFile2'), context.pdfFonts[id].ref);
pdf.context.delete(ref);
duplicatedEntries.push(ref);
} else {
context.pdfFonts[id] = { ref: ref, font: font };
}
Expand Down
Binary file added docs/examples/reveal-js-demo.pdf
Binary file not shown.
Binary file modified docs/examples/spectacle-reactjs-presentation.pdf
Binary file not shown.
Loading