Skip to content

Commit 443aa8e

Browse files
authoredAug 9, 2021
Merge pull request #17 from pdsuwwz/feature/combine-pdf
feat: combine pdf
2 parents 05438ae + 7e7394e commit 443aa8e

12 files changed

+206
-9
lines changed
 

‎__test__/axios-browser.html

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>Document</title>
8+
</head>
9+
<body>
10+
11+
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
12+
<script>
13+
const service = axios.create({
14+
baseURL: 'http://localhost:5000',
15+
timeout: 60000
16+
});
17+
const pdfList = [
18+
{
19+
url: 'https://github.com/pdsuwwz',
20+
},
21+
{
22+
url: 'https://vuejs.org/v2/api/',
23+
}
24+
]
25+
service({
26+
method: 'post',
27+
url: '/combine-pdf',
28+
responseType: 'blob',
29+
data: {
30+
pdfList
31+
}
32+
}).then((res) => {
33+
const url = window.URL.createObjectURL(res.data)
34+
35+
const link = document.createElement('a')
36+
link.style.display = 'none'
37+
link.href = url
38+
link.download = 'combine-test.pdf'
39+
40+
document.body.appendChild(link)
41+
link.click()
42+
document.body.removeChild(link)
43+
})
44+
</script>
45+
</body>
46+
</html>
47+

‎__test__/axios-node.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const axios = require('axios').default
2+
const fs = require('fs')
3+
const service = axios.create({
4+
baseURL: 'http://localhost:5000'
5+
})
6+
7+
service({
8+
method: 'post',
9+
url: '/combine-pdf',
10+
responseType: 'arraybuffer',
11+
data: {
12+
pdfList: [
13+
{
14+
url: 'https://github.com/pdsuwwz',
15+
},
16+
{
17+
url: 'https://vuejs.org/v2/api/',
18+
hasMargin: false,
19+
cookies: [
20+
{
21+
name: 'token',
22+
value: 'fc83532c-f833-11eb-8526-0242ac130002',
23+
domain: 'localhost'
24+
}
25+
]
26+
}
27+
]
28+
}
29+
}).then((res) => {
30+
fs.writeFileSync('combime-test1.pdf', res.data)
31+
})

‎package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
"clean:dist": "rm -rf ./dist",
1818
"build": "yarn clean:dist && rollup -c",
1919
"tsbuild": "yarn clean:dist && tsc && tsc-alias",
20-
"prestart": "yarn build",
2120
"start": "pm2 start ecosystem.config.js --env production",
2221
"restart": "pm2 restart ecosystem.config.js --env production",
2322
"stop": "pm2 stop ecosystem.config.js",
@@ -33,6 +32,7 @@
3332
"koa": "^2.13.1",
3433
"koa-bodyparser": "4.3.0",
3534
"koa-router": "^10.0.0",
35+
"pdf-lib": "^1.16.0",
3636
"puppeteer": "^10.1.0"
3737
},
3838
"devDependencies": {
@@ -51,6 +51,7 @@
5151
"@types/node": "^15.12.5",
5252
"@typescript-eslint/eslint-plugin": "^4.28.1",
5353
"@typescript-eslint/parser": "^4.28.1",
54+
"axios": "^0.21.1",
5455
"babel-plugin-module-resolver": "^4.1.0",
5556
"conventional-changelog-cli": "^2.1.1",
5657
"eslint": "^7.29.0",
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import Koa from 'koa'
2+
3+
import GeneratePdfService from '@/services/generate-pdf'
4+
import GenerateCombinePdfService from '@/services/generate-combine-pdf'
5+
import { RequestBody } from '@/controllers/generate-pdf'
6+
7+
class GenerateCombinePdfController {
8+
private pdfService: GeneratePdfService = new GeneratePdfService()
9+
private service: GenerateCombinePdfService = new GenerateCombinePdfService()
10+
11+
generate = async (ctx: Koa.Context) => {
12+
let {
13+
pdfList
14+
}: {
15+
pdfList: RequestBody[]
16+
} = ctx.request.body
17+
18+
pdfList = pdfList.filter((pdfItem) => {
19+
return pdfItem.url
20+
})
21+
22+
if (!pdfList.length) {
23+
ctx.status = 404
24+
ctx.body = {
25+
status: 'NOT-FOUND'
26+
}
27+
return
28+
}
29+
30+
31+
const pdfPromises = pdfList.map((pdfItem) => {
32+
return this.pdfService.generate(pdfItem)
33+
})
34+
35+
const totalPdf = await this.service.generate(
36+
...pdfPromises
37+
)
38+
39+
if (Object.prototype.toString.call(totalPdf) === '[object Uint8Array]') {
40+
ctx.type = 'application/pdf'
41+
}
42+
ctx.body = totalPdf
43+
};
44+
}
45+
46+
export default new GenerateCombinePdfController()

‎src/controllers/generate-pdf.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export interface RequestBody {
1111
/** description... */
1212
url?: string
1313
cookies?: Array<Cookies>
14-
hasMargin?: boolean | true
14+
hasMargin?: boolean
1515
}
1616

1717
class GeneratePdfController {

‎src/main.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@ app.listen(PORT)
2727

2828

2929
const address = getLocalAddress()
30+
const localhost = address[Object.keys(address)[0]]?.[0]
31+
3032
const blank1 = ''.padStart(1)
3133
const blank2 = ''.padStart(2)
3234

3335
console.log('\n', blank1, '🚀 Puppeteer Server\n')
3436
console.log(blank2, `> Local: http://localhost:${PORT}`)
35-
console.log(blank2, `> Network: http://${address.en0[0]}:${PORT}\n`)
37+
console.log(blank2, `> Network: http://${localhost}:${PORT}\n`)

‎src/routes.ts

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import homeController from '@/controllers/home'
22
import GenerateImageController from '@/controllers/generate-image'
33
import GeneratePdfController from '@/controllers/generate-pdf'
44
import GenerateSimplePdfController from '@/controllers/generate-simple-pdf'
5+
import GenerateCombinePdfController from '@/controllers/generate-combine-pdf'
56

67
interface routeConfig {
78
path: string
@@ -29,6 +30,11 @@ const routes: Array<routeConfig> = [
2930
path: '/simple-pdf',
3031
method: 'get',
3132
action: GenerateSimplePdfController.generate
33+
},
34+
{
35+
path: '/combine-pdf',
36+
method: 'post',
37+
action: GenerateCombinePdfController.generate
3238
}
3339
]
3440
export default routes

‎src/services/generate-combine-pdf.ts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import {
2+
PDFDocument,
3+
PDFPage
4+
} from 'pdf-lib'
5+
6+
/**
7+
* @example
8+
9+
curl --location --request GET \
10+
'http://localhost:5000/simple-pdf?url=https://www.google.com/' \
11+
--output test-simple-pdf.pdf
12+
13+
*/
14+
15+
export default class GenerateCombinePdfService {
16+
generate = async (...combineList: Promise<Uint8Array>[]): Promise<Buffer> => {
17+
const mergedPdf = await PDFDocument.create()
18+
19+
const pdfsToMerge: Uint8Array[] = await Promise.all(combineList)
20+
21+
for await (const pdfBytes of pdfsToMerge) {
22+
const pdf = await PDFDocument.load(pdfBytes)
23+
const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices())
24+
25+
copiedPages.forEach((page: PDFPage) => {
26+
mergedPdf.addPage(page)
27+
})
28+
}
29+
30+
const buffer = await mergedPdf.save()
31+
32+
return Buffer.from(buffer)
33+
}
34+
}

‎src/services/generate-pdf.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ curl --location --request POST 'http://localhost:5000/pdf' \
3737
*/
3838

3939
export default class GeneratePdfService {
40-
generate = async (params: RequestBody): Promise<unknown> => {
40+
generate = async (params: RequestBody): Promise<Buffer> => {
4141
const {
4242
url,
43-
cookies,
44-
hasMargin
43+
cookies = [],
44+
hasMargin = true
4545
} = params
4646

4747
const browser = await puppeteer.launch({

‎src/services/generate-simple-pdf.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ curl --location --request GET \
1111
*/
1212

1313
export default class GenerateSimplePdfService {
14-
generate = async (params: RouterQuery): Promise<unknown> => {
14+
generate = async (params: RouterQuery): Promise<Buffer> => {
1515

1616
const { url } = params
1717

‎src/utils/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { networkInterfaces } from 'os'
22

33

4+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
45
export function getLocalAddress (): any {
56
const nets = networkInterfaces()
67
const results = Object.create(null) // Or just '{}', an empty object

‎yarn.lock

+31-2
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,20 @@
10171017
"@opencensus/core" "^0.0.8"
10181018
uuid "^3.2.1"
10191019

1020+
"@pdf-lib/standard-fonts@^1.0.0":
1021+
version "1.0.0"
1022+
resolved "https://registry.yarnpkg.com/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz#8ba691c4421f71662ed07c9a0294b44528af2d7f"
1023+
integrity sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==
1024+
dependencies:
1025+
pako "^1.0.6"
1026+
1027+
"@pdf-lib/upng@^1.0.1":
1028+
version "1.0.1"
1029+
resolved "https://registry.yarnpkg.com/@pdf-lib/upng/-/upng-1.0.1.tgz#7dc9c636271aca007a9df4deaf2dd7e7960280cb"
1030+
integrity sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==
1031+
dependencies:
1032+
pako "^1.0.10"
1033+
10201034
"@pm2/agent@~2.0.0":
10211035
version "2.0.0"
10221036
resolved "https://registry.yarnpkg.com/@pm2/agent/-/agent-2.0.0.tgz#b3ab77cd12d85187dd155c59a9771b04e7e345a3"
@@ -1606,7 +1620,7 @@ async@^3.2.0, async@~3.2.0:
16061620
resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
16071621
integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==
16081622

1609-
axios@^0.21.0:
1623+
axios@^0.21.0, axios@^0.21.1:
16101624
version "0.21.1"
16111625
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
16121626
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
@@ -4300,6 +4314,11 @@ pako@^0.2.5:
43004314
resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
43014315
integrity sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=
43024316

4317+
pako@^1.0.10, pako@^1.0.11, pako@^1.0.6:
4318+
version "1.0.11"
4319+
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
4320+
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
4321+
43034322
parent-module@^1.0.0:
43044323
version "1.0.1"
43054324
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
@@ -4377,6 +4396,16 @@ path-type@^4.0.0:
43774396
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
43784397
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
43794398

4399+
pdf-lib@^1.16.0:
4400+
version "1.16.0"
4401+
resolved "https://registry.yarnpkg.com/pdf-lib/-/pdf-lib-1.16.0.tgz#63cacec0d6139bf7a670dea8bad747ebf4c1fb42"
4402+
integrity sha512-P/1SSmElOBKrPlbc+Sn7UxikRQbzVA64+4Dh6/uczPscvq/NatP9eryoOguyBTpTnzICNiG8EnMH4Ziqp2TnFA==
4403+
dependencies:
4404+
"@pdf-lib/standard-fonts" "^1.0.0"
4405+
"@pdf-lib/upng" "^1.0.1"
4406+
pako "^1.0.11"
4407+
tslib "^1.11.1"
4408+
43804409
pend@~1.2.0:
43814410
version "1.2.0"
43824411
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
@@ -5397,7 +5426,7 @@ tslib@2.1.0:
53975426
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
53985427
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
53995428

5400-
tslib@^1.8.1:
5429+
tslib@^1.11.1, tslib@^1.8.1:
54015430
version "1.14.1"
54025431
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
54035432
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==

0 commit comments

Comments
 (0)
Please sign in to comment.