mirror of
https://gitee.com/mafgwo/stackedit
synced 2024-11-15 19:22:27 +08:00
优化pdf导出
This commit is contained in:
parent
9419865d76
commit
bda261a767
10
docs/大文档导出PDF方式.md
Normal file
10
docs/大文档导出PDF方式.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# 大文档导出PDF方式说明
|
||||
> 由于大文档导出PDF,需要消费非常多的服务器资源,而且很容易导致导出超时,故导出PDF的MD文档过大时,可以使用 **[wkhtmltopdf](https://wkhtmltopdf.org/downloads.html)** 工具导出。
|
||||
|
||||
# 操作步骤
|
||||
- 先在 **[StackEdit中文版](https://stackedit.cn/app)** 中使用 `导出为HTML` 功能导出MD文档,导出后可以得到一个HTML文档。
|
||||
- 到 **[wkhtmltopdf](https://wkhtmltopdf.org/downloads.html)** 官网下载安装程序。
|
||||
- 使用 wkhtmltopdf 的导出PDF的命令 `wkhtmltopdf [GLOBAL OPTION]... [OBJECT]... <output file>` 把HTML导出为PDF,如简单的导出命令:`wkhtmltopdf test.html test.pdf`,具体的 `GLOBAL OPTION` 参数说明可以通过 `wkhtmltopdf -H` 查看帮助文档。
|
||||
|
||||
|
||||
|
88
package-lock.json
generated
88
package-lock.json
generated
|
@ -1278,38 +1278,6 @@
|
|||
"postcss-value-parser": "^3.2.3"
|
||||
}
|
||||
},
|
||||
"aws-sdk": {
|
||||
"version": "2.317.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.317.0.tgz",
|
||||
"integrity": "sha512-X2Cd1Gb9Cf9WVgGOiBSW4TK6q5Mb6AYiGmEA9XikCgur4H8E4TgmgWbBWJnTzxssugclVLVoWQfw3RshNKJksg==",
|
||||
"requires": {
|
||||
"buffer": "4.9.1",
|
||||
"events": "1.1.1",
|
||||
"ieee754": "1.1.8",
|
||||
"jmespath": "0.15.0",
|
||||
"querystring": "0.2.0",
|
||||
"sax": "1.2.1",
|
||||
"url": "0.10.3",
|
||||
"uuid": "3.1.0",
|
||||
"xml2js": "0.4.19"
|
||||
},
|
||||
"dependencies": {
|
||||
"xml2js": {
|
||||
"version": "0.4.19",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
|
||||
"integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
|
||||
"requires": {
|
||||
"sax": ">=0.6.0",
|
||||
"xmlbuilder": "~9.0.1"
|
||||
}
|
||||
},
|
||||
"xmlbuilder": {
|
||||
"version": "9.0.7",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
|
||||
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
|
||||
}
|
||||
}
|
||||
},
|
||||
"aws-sign2": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||
|
@ -2351,7 +2319,8 @@
|
|||
"base64-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
|
||||
"integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw=="
|
||||
"integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==",
|
||||
"dev": true
|
||||
},
|
||||
"bcrypt-pbkdf": {
|
||||
"version": "1.0.2",
|
||||
|
@ -2599,6 +2568,7 @@
|
|||
"version": "4.9.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
|
||||
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"base64-js": "^1.0.2",
|
||||
"ieee754": "^1.1.4",
|
||||
|
@ -5392,7 +5362,8 @@
|
|||
"events": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
|
||||
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
|
||||
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
|
||||
"dev": true
|
||||
},
|
||||
"eventsource-polyfill": {
|
||||
"version": "0.9.6",
|
||||
|
@ -8665,16 +8636,6 @@
|
|||
"delegate": "^3.1.2"
|
||||
}
|
||||
},
|
||||
"google-id-token-verifier": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/google-id-token-verifier/-/google-id-token-verifier-0.2.3.tgz",
|
||||
"integrity": "sha1-nmt41FieLQUNqBYT+4kK26MKTqg=",
|
||||
"requires": {
|
||||
"request": "^2.65.0",
|
||||
"rsa-pem-from-mod-exp": "^0.8.4",
|
||||
"underscore": "^1.8.3"
|
||||
}
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
|
||||
|
@ -9663,7 +9624,8 @@
|
|||
"ieee754": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz",
|
||||
"integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q="
|
||||
"integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=",
|
||||
"dev": true
|
||||
},
|
||||
"iferr": {
|
||||
"version": "0.1.5",
|
||||
|
@ -11262,11 +11224,6 @@
|
|||
"url-regex": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"jmespath": {
|
||||
"version": "0.15.0",
|
||||
"resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
|
||||
"integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc="
|
||||
},
|
||||
"jpeg-js": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.2.0.tgz",
|
||||
|
@ -15312,7 +15269,8 @@
|
|||
"punycode": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
|
||||
"integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
|
||||
"integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
|
||||
"dev": true
|
||||
},
|
||||
"q": {
|
||||
"version": "1.5.1",
|
||||
|
@ -15338,7 +15296,8 @@
|
|||
"querystring": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
|
||||
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
|
||||
"dev": true
|
||||
},
|
||||
"querystring-es3": {
|
||||
"version": "0.2.1",
|
||||
|
@ -16458,11 +16417,6 @@
|
|||
"inherits": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"rsa-pem-from-mod-exp": {
|
||||
"version": "0.8.4",
|
||||
"resolved": "https://registry.npmjs.org/rsa-pem-from-mod-exp/-/rsa-pem-from-mod-exp-0.8.4.tgz",
|
||||
"integrity": "sha1-NipCxtMEBW1JOz8SvOq7LGV2ptQ="
|
||||
},
|
||||
"rsvp": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz",
|
||||
|
@ -17753,7 +17707,8 @@
|
|||
"sax": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
|
||||
"integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o="
|
||||
"integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=",
|
||||
"dev": true
|
||||
},
|
||||
"schema-utils": {
|
||||
"version": "0.3.0",
|
||||
|
@ -20610,7 +20565,8 @@
|
|||
"underscore": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
|
||||
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
|
||||
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=",
|
||||
"dev": true
|
||||
},
|
||||
"undertaker": {
|
||||
"version": "1.3.0",
|
||||
|
@ -20885,15 +20841,6 @@
|
|||
"integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
|
||||
"dev": true
|
||||
},
|
||||
"url": {
|
||||
"version": "0.10.3",
|
||||
"resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz",
|
||||
"integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=",
|
||||
"requires": {
|
||||
"punycode": "1.3.2",
|
||||
"querystring": "0.2.0"
|
||||
}
|
||||
},
|
||||
"url-loader": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.1.tgz",
|
||||
|
@ -21018,11 +20965,6 @@
|
|||
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
|
||||
"dev": true
|
||||
},
|
||||
"uuid": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
|
||||
"integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g=="
|
||||
},
|
||||
"v8flags": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz",
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
"dependencies": {
|
||||
"@vue/test-utils": "^1.0.0-beta.16",
|
||||
"abcjs": "^5.2.0",
|
||||
"aws-sdk": "^2.317.0",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"bezier-easing": "^1.1.0",
|
||||
"body-parser": "^1.18.2",
|
||||
|
@ -35,7 +34,6 @@
|
|||
"compression": "^1.7.0",
|
||||
"diff-match-patch": "^1.0.0",
|
||||
"file-saver": "^1.3.8",
|
||||
"google-id-token-verifier": "^0.2.3",
|
||||
"handlebars": "^4.0.10",
|
||||
"indexeddbshim": "^3.6.2",
|
||||
"js-yaml": "^3.11.0",
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
const pandocPath = process.env.PANDOC_PATH || 'pandoc';
|
||||
const wkhtmltopdfPath = process.env.WKHTMLTOPDF_PATH || 'wkhtmltopdf';
|
||||
const userBucketName = process.env.USER_BUCKET_NAME || 'stackedit-users';
|
||||
const paypalUri = process.env.PAYPAL_URI || 'https://www.paypal.com/cgi-bin/webscr';
|
||||
const paypalReceiverEmail = process.env.PAYPAL_RECEIVER_EMAIL;
|
||||
|
||||
const dropboxAppKey = process.env.DROPBOX_APP_KEY;
|
||||
|
@ -20,8 +18,6 @@ const giteaUrl = process.env.GITEA_URL;
|
|||
exports.values = {
|
||||
pandocPath,
|
||||
wkhtmltopdfPath,
|
||||
userBucketName,
|
||||
paypalUri,
|
||||
paypalReceiverEmail,
|
||||
dropboxAppKey,
|
||||
dropboxAppKeyFull,
|
||||
|
|
|
@ -2,7 +2,6 @@ const compression = require('compression');
|
|||
const serveStatic = require('serve-static');
|
||||
const bodyParser = require('body-parser');
|
||||
const path = require('path');
|
||||
const user = require('./user');
|
||||
const github = require('./github');
|
||||
const gitee = require('./gitee');
|
||||
const gitea = require('./gitea');
|
||||
|
@ -30,12 +29,8 @@ module.exports = (app) => {
|
|||
app.get('/oauth2/giteeToken', gitee.giteeToken);
|
||||
app.get('/oauth2/giteaToken', gitea.giteaToken);
|
||||
app.get('/conf', (req, res) => res.send(conf.publicValues));
|
||||
app.get('/userInfo', user.userInfo);
|
||||
app.post('/pdfExport', pdf.generate);
|
||||
app.post('/pandocExport', pandoc.generate);
|
||||
app.post('/paypalIpn', bodyParser.urlencoded({
|
||||
extended: false,
|
||||
}), user.paypalIpn);
|
||||
app.get('/giteeClientId', (req, res) => {
|
||||
const giteeClientIds = conf.values.giteeClientId.split(',');
|
||||
// 仅一个 则直接返回
|
||||
|
|
|
@ -59,7 +59,7 @@ exports.generate = (req, res) => {
|
|||
const metadata = readJson(req.query.metadata);
|
||||
const params = [];
|
||||
|
||||
params.push('--pdf-engine=xelatex');
|
||||
params.push('--latex-engine=xelatex');
|
||||
params.push('--webtex=http://chart.apis.google.com/chart?cht=tx&chf=bg,s,FFFFFF00&chco=000000&chl=');
|
||||
if (options.toc) {
|
||||
params.push('--toc');
|
||||
|
|
116
server/user.js
116
server/user.js
|
@ -1,116 +0,0 @@
|
|||
const request = require('request');
|
||||
const AWS = require('aws-sdk');
|
||||
const verifier = require('google-id-token-verifier');
|
||||
const conf = require('./conf');
|
||||
|
||||
const s3Client = new AWS.S3();
|
||||
|
||||
const cb = (resolve, reject) => (err, res) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(res);
|
||||
}
|
||||
};
|
||||
|
||||
exports.getUser = id => new Promise((resolve, reject) => {
|
||||
s3Client.getObject({
|
||||
Bucket: conf.values.userBucketName,
|
||||
Key: id,
|
||||
}, cb(resolve, reject));
|
||||
})
|
||||
.then(
|
||||
res => JSON.parse(`${res.Body}`),
|
||||
(err) => {
|
||||
if (err.code !== 'NoSuchKey') {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
exports.putUser = (id, user) => new Promise((resolve, reject) => {
|
||||
s3Client.putObject({
|
||||
Bucket: conf.values.userBucketName,
|
||||
Key: id,
|
||||
Body: JSON.stringify(user),
|
||||
}, cb(resolve, reject));
|
||||
});
|
||||
|
||||
exports.removeUser = id => new Promise((resolve, reject) => {
|
||||
s3Client.deleteObject({
|
||||
Bucket: conf.values.userBucketName,
|
||||
Key: id,
|
||||
}, cb(resolve, reject));
|
||||
});
|
||||
|
||||
exports.getUserFromToken = idToken => new Promise((resolve, reject) => verifier
|
||||
.verify(idToken, conf.values.googleClientId, cb(resolve, reject)))
|
||||
.then(tokenInfo => exports.getUser(tokenInfo.sub));
|
||||
|
||||
exports.userInfo = (req, res) => exports.getUserFromToken(req.query.idToken)
|
||||
.then(
|
||||
user => res.send(Object.assign({
|
||||
sponsorUntil: 0,
|
||||
}, user)),
|
||||
err => res
|
||||
.status(400)
|
||||
.send(err ? err.message || err.toString() : 'invalid_token'),
|
||||
);
|
||||
|
||||
exports.paypalIpn = (req, res, next) => Promise.resolve()
|
||||
.then(() => {
|
||||
const userId = req.body.custom;
|
||||
const paypalEmail = req.body.payer_email;
|
||||
const gross = parseFloat(req.body.mc_gross);
|
||||
let sponsorUntil;
|
||||
if (gross === 5) {
|
||||
sponsorUntil = Date.now() + (3 * 31 * 24 * 60 * 60 * 1000); // 3 months
|
||||
} else if (gross === 15) {
|
||||
sponsorUntil = Date.now() + (366 * 24 * 60 * 60 * 1000); // 1 year
|
||||
} else if (gross === 25) {
|
||||
sponsorUntil = Date.now() + (2 * 366 * 24 * 60 * 60 * 1000); // 2 years
|
||||
} else if (gross === 50) {
|
||||
sponsorUntil = Date.now() + (5 * 366 * 24 * 60 * 60 * 1000); // 5 years
|
||||
}
|
||||
if (
|
||||
req.body.receiver_email !== conf.values.paypalReceiverEmail ||
|
||||
req.body.payment_status !== 'Completed' ||
|
||||
req.body.mc_currency !== 'USD' ||
|
||||
(req.body.txn_type !== 'web_accept' && req.body.txn_type !== 'subscr_payment') ||
|
||||
!userId || !sponsorUntil
|
||||
) {
|
||||
// Ignoring PayPal IPN
|
||||
return res.end();
|
||||
}
|
||||
// Processing PayPal IPN
|
||||
req.body.cmd = '_notify-validate';
|
||||
return new Promise((resolve, reject) => request.post({
|
||||
uri: conf.values.paypalUri,
|
||||
form: req.body,
|
||||
}, (err, response, body) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else if (body !== 'VERIFIED') {
|
||||
reject(new Error('PayPal IPN unverified'));
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}))
|
||||
.then(() => exports.putUser(userId, {
|
||||
paypalEmail,
|
||||
sponsorUntil,
|
||||
}))
|
||||
.then(() => res.end());
|
||||
})
|
||||
.catch(next);
|
||||
|
||||
exports.checkSponsor = (idToken) => {
|
||||
if (!conf.publicValues.allowSponsorship) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
if (!idToken) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
return exports.getUserFromToken(idToken)
|
||||
.then(userInfo => userInfo && userInfo.sponsorUntil > Date.now(), () => false);
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<modal-inner aria-label="导出到PDF">
|
||||
<div class="modal__content">
|
||||
<p>请为您的<b> pdf导出</b>选择模板。(该导出很消耗服务器资源,文档太大或图片太多可能会导出超时失败,限时开放使用!)</p>
|
||||
<p>请为您的<b> pdf导出</b>选择模板。(该导出很消耗服务器资源,文档太大或图片太多可能会导出超时失败!可参考 <a href="https://gitee.com/mafgwo/stackedit/blob/master/docs/大文档导出PDF方式.md">大文档导出PDF方式</a> 自行导出大文档!)</p>
|
||||
<form-entry label="模板">
|
||||
<select class="textfield" slot="field" v-model="selectedTemplate" @keydown.enter="resolve()">
|
||||
<option v-for="(template, id) in allTemplatesById" :key="id" :value="id">
|
||||
|
|
|
@ -99,7 +99,7 @@ samp {
|
|||
blockquote {
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
padding: 0.5em 1em;
|
||||
border-left: 8px solid rgba(0, 0, 0, 0.1);
|
||||
border-left: 8px solid #cfd1d6;
|
||||
background: #e2e4e9;
|
||||
word-break: break-word !important;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user