Compare commits

...

160 Commits

Author SHA1 Message Date
f535eacd97 3.2.2 2025-02-25 18:22:06 +00:00
9908897aa2 fix(SmartPdf): Fix buffer handling for PDF conversion and text extraction 2025-02-25 18:22:06 +00:00
29d3cbb0b6 3.2.1 2025-02-25 18:06:45 +00:00
babc20649a fix(SmartPdf): Fix type for extractTextFromPdfBuffer function 2025-02-25 18:06:45 +00:00
1188643c4b 3.2.0 2025-02-25 18:03:27 +00:00
6b74301588 feat(smartpdf): Improve dependency versions and optimize PDF to PNG conversion. 2025-02-25 18:03:27 +00:00
168527573c 3.1.8 2024-11-30 20:43:05 +01:00
3d7bb37849 fix(core): Fix candidate handling in PDF generation 2024-11-30 20:43:05 +01:00
12a581ced9 3.1.7 2024-09-27 23:21:31 +02:00
857e1717a5 fix(dependencies): Update dependencies to latest versions 2024-09-27 23:21:30 +02:00
186bfb9d12 update description 2024-05-29 14:15:22 +02:00
c5bc354f65 3.1.6 2024-04-30 17:48:12 +02:00
c48bb0428f fix(core): update 2024-04-30 17:48:11 +02:00
46fbb615a0 3.1.5 2024-04-27 12:07:16 +02:00
3df4e103f9 fix(core): update 2024-04-27 12:07:16 +02:00
addff418c6 3.1.4 2024-04-26 13:39:58 +02:00
14d653e701 fix(core): update 2024-04-26 13:39:57 +02:00
040bac5256 3.1.3 2024-04-26 13:29:32 +02:00
bf44901a0a fix(core): update 2024-04-26 13:29:32 +02:00
b4d0f4e949 3.1.2 2024-04-26 13:28:07 +02:00
b2b47b1f6a fix(core): update 2024-04-26 13:28:07 +02:00
1b1398653b 3.1.1 2024-04-26 13:27:28 +02:00
1f61dcb115 fix(core): update 2024-04-26 13:27:27 +02:00
1476fc9174 3.1.0 2024-04-25 18:48:08 +02:00
d157a3acd9 feat(now supports pdf -> jpg): update 2024-04-25 18:48:08 +02:00
fe6be928a9 update tsconfig 2024-04-14 18:07:39 +02:00
8e537be454 update npmextra.json: githost 2024-04-01 21:37:16 +02:00
6947529e02 update npmextra.json: githost 2024-04-01 19:59:15 +02:00
b6d78929b9 update npmextra.json: githost 2024-03-30 21:48:15 +01:00
e997189a64 3.0.17 2024-03-19 17:52:28 +01:00
31940deb7a fix(core): update 2024-03-19 17:52:27 +01:00
922c6da234 3.0.16 2023-07-26 14:17:12 +02:00
aa8fb165eb fix(core): update 2023-07-26 14:17:11 +02:00
4cd4431565 switch to new org scheme 2023-07-11 01:24:04 +02:00
826183be8c switch to new org scheme 2023-07-10 10:17:20 +02:00
6d9b7ee0e4 3.0.15 2022-11-07 23:11:30 +01:00
3c66acb653 fix(core): update 2022-11-07 23:11:29 +01:00
aa0ad1dce5 3.0.14 2022-10-26 23:04:59 +02:00
65756457aa fix(core): update 2022-10-26 23:04:59 +02:00
67f21d2500 3.0.13 2022-10-26 22:58:26 +02:00
1cf095a5cc fix(core): update 2022-10-26 22:58:26 +02:00
ffeaec7fe9 3.0.12 2022-09-16 08:27:25 +02:00
a31e196e5b fix(core): update 2022-09-16 08:27:25 +02:00
57851d90a5 3.0.11 2022-09-15 20:52:22 +02:00
1e4b16b734 fix(core): update 2022-09-15 20:52:22 +02:00
876466b18d 3.0.10 2022-09-13 18:39:38 +02:00
82b1c187ee fix(core): update 2022-09-13 18:39:38 +02:00
4f93d258b8 3.0.9 2022-09-13 18:26:15 +02:00
60993fc005 fix(core): update 2022-09-13 18:26:14 +02:00
db4965c8f5 3.0.8 2022-09-05 01:02:05 +02:00
36a964d931 fix(core): update 2022-09-05 01:02:05 +02:00
6d90f4c9b4 3.0.7 2022-06-29 00:24:44 +02:00
839eafd73f fix(core): update 2022-06-29 00:24:43 +02:00
f4141bf201 3.0.6 2022-06-15 22:16:44 +02:00
5a46028053 fix(core): update 2022-06-15 22:16:44 +02:00
18d26647e1 3.0.5 2022-06-15 22:14:55 +02:00
0b5ec86780 fix(core): update 2022-06-15 22:14:55 +02:00
5e15729045 3.0.4 2022-06-12 19:26:49 +02:00
c98a5f1ac3 fix(core): update 2022-06-12 19:26:49 +02:00
7f02146a0e 3.0.3 2022-06-12 19:26:34 +02:00
5dab8c7351 fix(core): update 2022-06-12 19:26:34 +02:00
505e0e9a30 3.0.2 2022-03-25 01:14:12 +01:00
9e3510955a fix(core): update 2022-03-25 01:14:12 +01:00
c006d4fbc7 3.0.1 2022-03-24 23:32:28 +01:00
5e02c44647 fix(core): update 2022-03-24 23:32:27 +01:00
47f7cb18b5 3.0.0 2022-03-24 14:34:46 +01:00
3faf065c66 2.0.19 2022-03-24 14:32:50 +01:00
dfffd03790 fix(core): update 2022-03-24 14:32:49 +01:00
796aa905d2 2.0.18 2022-01-06 13:23:05 +01:00
253fb95143 fix(core): update 2022-01-06 13:23:04 +01:00
f3ea075b72 2.0.17 2022-01-06 13:10:12 +01:00
af725a7f78 fix(core): update 2022-01-06 13:10:12 +01:00
016e0db797 2.0.16 2022-01-05 23:55:38 +01:00
4cf8b2e1f8 fix(core): update 2022-01-05 23:55:37 +01:00
67b0aa9d47 2.0.15 2022-01-05 17:20:28 +01:00
567c6eafea fix(core): update 2022-01-05 17:20:28 +01:00
ff890fb2af 2.0.14 2022-01-05 16:32:48 +01:00
a512fd64b5 fix(core): update 2022-01-05 16:32:47 +01:00
377318a62a 2.0.13 2022-01-05 14:19:40 +01:00
671c871304 fix(core): update 2022-01-05 14:19:39 +01:00
e0cc6b5655 2.0.12 2022-01-05 14:17:43 +01:00
e74b44b49c fix(core): update 2022-01-05 14:17:43 +01:00
d6f0d88d4a 2.0.11 2021-10-14 16:04:58 +02:00
9674e5b8dc fix(core): update 2021-10-14 16:04:58 +02:00
ea4cf777a9 2.0.10 2021-10-14 10:59:45 +02:00
8a308fa9e3 fix(core): update 2021-10-14 10:59:45 +02:00
56fa53b701 2.0.9 2021-04-29 15:19:15 +00:00
2a4ddd4e41 fix(core): update 2021-04-29 15:19:14 +00:00
3d8a63fddd 2.0.8 2021-04-29 09:32:13 +00:00
9d9b1d0399 fix(core): update 2021-04-29 09:32:12 +00:00
739d60d410 2.0.7 2021-04-14 11:35:06 +00:00
9003034d0d fix(core): update 2021-04-14 11:35:05 +00:00
5002513d21 2.0.6 2021-04-14 11:34:34 +00:00
12ede2be02 fix(core): update 2021-04-14 11:34:33 +00:00
163ec2bd50 2.0.5 2021-03-06 15:33:08 +00:00
7744839613 fix(core): update 2021-03-06 15:33:07 +00:00
df803d90cb 2.0.4 2021-03-05 15:38:12 +00:00
5fc22585bf fix(core): update 2021-03-05 15:38:11 +00:00
b8387458db 2.0.3 2021-03-05 15:16:23 +00:00
04aed2556b fix(core): update 2021-03-05 15:16:22 +00:00
4cde3a7fe0 2.0.2 2019-11-19 16:31:34 +00:00
466d6d47ba fix(ci): further speed up snyk step 2019-11-19 16:31:33 +00:00
fa99b7f068 2.0.1 2019-11-19 16:28:14 +00:00
3e865b6c92 fix(ci): update snyk step for faster testing 2019-11-19 16:28:13 +00:00
94dd576d3b 2.0.0 2019-11-19 15:53:14 +00:00
9c19b4a3e4 BREAKING CHANGE(API): now clearly naming PDF Results what they are. 2019-11-19 15:53:14 +00:00
1155656c2b 1.0.29 2019-11-16 00:50:12 +01:00
5cf23c1134 fix(core): update 2019-11-16 00:50:11 +01:00
67e9fdd10a 1.0.28 2019-11-15 20:00:25 +01:00
b0e388c50d 1.0.27 2019-11-15 19:59:57 +01:00
f37c9d8375 fix(core): update 2019-11-15 19:59:57 +01:00
18c8ef9606 1.0.26 2019-11-12 15:45:26 +01:00
6766a3d0dc fix(core): update 2019-11-12 15:45:26 +01:00
d16f447048 1.0.25 2019-11-12 15:41:58 +01:00
37c752c2ae fix(core): update 2019-11-12 15:41:58 +01:00
b088d26e6f 1.0.24 2019-11-12 14:41:04 +01:00
425f11a334 fix(core): update 2019-11-12 14:41:03 +01:00
Philipp Kunz
5ddbea1a5a 1.0.23 2019-11-11 13:04:36 +01:00
Philipp Kunz
42c5121784 fix(core): update 2019-11-11 13:04:36 +01:00
Philipp Kunz
d960d85539 1.0.22 2019-11-11 13:04:13 +01:00
Philipp Kunz
ca60217a18 fix(core): update 2019-11-11 13:04:13 +01:00
16f2829785 1.0.21 2019-08-14 11:39:36 +02:00
0381022b68 fix(core): update 2019-08-14 11:39:35 +02:00
aae8ec0ee1 1.0.20 2019-08-14 11:18:15 +02:00
ec4768e1cc fix(core): update 2019-08-14 11:18:14 +02:00
3308895b3b 1.0.19 2019-06-04 11:29:30 +02:00
37e47fc33f fix(core): update 2019-06-04 11:29:30 +02:00
b4a3a36b07 1.0.18 2019-06-03 23:34:33 +02:00
baf26dc492 fix(core): update 2019-06-03 23:34:33 +02:00
30e4b4665c 1.0.17 2019-06-03 17:09:16 +02:00
74a0a27fc1 fix(core): update 2019-06-03 17:09:16 +02:00
59eed53644 1.0.16 2019-06-03 16:39:21 +02:00
473aaa004a fix(core): update 2019-06-03 16:39:21 +02:00
ecfd4115a1 1.0.15 2019-06-03 13:56:44 +02:00
0fbbfaac7c fix(core): update 2019-06-03 13:56:43 +02:00
86d2fc2c5b 1.0.14 2019-06-03 13:45:57 +02:00
f97866fe82 fix(core): update 2019-06-03 13:45:57 +02:00
5c0b8c4df0 1.0.13 2019-06-03 13:02:01 +02:00
8da88be5e8 fix(core): update 2019-06-03 13:02:01 +02:00
4f0164965c 1.0.12 2019-06-03 13:00:06 +02:00
63f4321b04 fix(core): update 2019-06-03 13:00:06 +02:00
e4287e9943 1.0.11 2019-06-03 10:51:16 +02:00
337c299a5e fix(core): update 2019-06-03 10:51:15 +02:00
4ac4d8d049 1.0.10 2019-05-29 19:49:24 +02:00
5e8abaa5b4 fix(core): update 2019-05-29 19:49:23 +02:00
d8fd7f9956 1.0.9 2019-05-29 19:19:36 +02:00
1711aadb6b fix(core): update 2019-05-29 19:19:36 +02:00
06b9385e97 1.0.8 2019-05-29 19:18:44 +02:00
94386b0e02 fix(core): update 2019-05-29 19:18:43 +02:00
36fea0b0f2 Merge branch 'master' of gitlab.com:pushrocks/smartpdf 2019-05-29 19:17:54 +02:00
437d56e54d 1.0.7 2019-05-29 19:17:39 +02:00
1537705cde fix(core): update 2019-05-29 19:17:39 +02:00
bb7cb4a6ab 1.0.7 2019-05-29 14:14:03 +02:00
bda43bf5e7 fix(core): update 2019-05-29 14:14:02 +02:00
58d923b14c 1.0.6 2019-05-29 00:27:44 +02:00
e981d61a54 fix(core): update 2019-05-29 00:27:43 +02:00
20847362a1 1.0.5 2019-05-28 23:57:50 +02:00
cc6bc209e8 fix(core): update 2019-05-28 23:57:50 +02:00
12d1a73793 1.0.4 2019-04-10 15:12:55 +02:00
6d6eb9944a fix(core): update 2019-04-10 15:12:54 +02:00
24 changed files with 11841 additions and 1807 deletions

View File

@ -0,0 +1,66 @@
name: Default (not tags)
on:
push:
tags-ignore:
- '**'
env:
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
jobs:
security:
runs-on: ubuntu-latest
continue-on-error: true
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Install pnpm and npmci
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
- name: Run npm prepare
run: npmci npm prepare
- name: Audit production dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --prod
continue-on-error: true
- name: Audit development dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --dev
continue-on-error: true
test:
if: ${{ always() }}
needs: security
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Test stable
run: |
npmci node install stable
npmci npm install
npmci npm test
- name: Test build
run: |
npmci node install stable
npmci npm install
npmci npm build

View File

@ -0,0 +1,124 @@
name: Default (tags)
on:
push:
tags:
- '*'
env:
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
jobs:
security:
runs-on: ubuntu-latest
continue-on-error: true
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
npmci npm prepare
- name: Audit production dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --prod
continue-on-error: true
- name: Audit development dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --dev
continue-on-error: true
test:
if: ${{ always() }}
needs: security
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
npmci npm prepare
- name: Test stable
run: |
npmci node install stable
npmci npm install
npmci npm test
- name: Test build
run: |
npmci node install stable
npmci npm install
npmci npm build
release:
needs: test
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
npmci npm prepare
- name: Release
run: |
npmci node install stable
npmci npm publish
metadata:
needs: test
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
continue-on-error: true
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
npmci npm prepare
- name: Code quality
run: |
npmci command npm install -g typescript
npmci npm install
- name: Trigger
run: npmci trigger
- name: Build docs and upload artifacts
run: |
npmci node install stable
npmci npm install
pnpm install -g @git.zone/tsdoc
npmci command tsdoc
continue-on-error: true

17
.gitignore vendored
View File

@ -1,7 +1,20 @@
.nogit/
node_modules/
assets/pdfdir/
# artifacts
coverage/
public/
pages/
# installs
node_modules/
# caches
.yarn/
.cache/
.rpt2_cache
# builds
dist/
dist_*/
# custom

View File

@ -1,147 +0,0 @@
# gitzone standard
image: hosttoday/ht-docker-node:npmci
cache:
paths:
- .npmci_cache/
key: "$CI_BUILD_STAGE"
stages:
- security
- test
- release
- metadata
# ====================
# security stage
# ====================
mirror:
stage: security
script:
- npmci git mirror
tags:
- docker
- notpriv
snyk:
stage: security
script:
- npmci npm prepare
- npmci command npm install -g snyk
- npmci command npm install --ignore-scripts
- npmci command snyk test
tags:
- docker
- notpriv
# ====================
# test stage
# ====================
testLEGACY:
stage: test
script:
- npmci npm prepare
- npmci node install legacy
- npmci npm install
- npmci npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- docker
- notpriv
allow_failure: true
testLTS:
stage: test
script:
- npmci npm prepare
- npmci node install lts
- npmci npm install
- npmci npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- docker
- notpriv
testSTABLE:
stage: test
script:
- npmci npm prepare
- npmci node install stable
- npmci npm install
- npmci npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- docker
- notpriv
release:
stage: release
script:
- npmci node install stable
- npmci npm publish
only:
- tags
tags:
- docker
- notpriv
# ====================
# metadata stage
# ====================
codequality:
stage: metadata
image: docker:stable
allow_failure: true
services:
- docker:stable-dind
script:
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- docker run
--env SOURCE_CODE="$PWD"
--volume "$PWD":/code
--volume /var/run/docker.sock:/var/run/docker.sock
"registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
artifacts:
paths: [codeclimate.json]
tags:
- docker
- priv
trigger:
stage: metadata
script:
- npmci trigger
only:
- tags
tags:
- docker
- notpriv
pages:
image: hosttoday/ht-docker-node:npmci
stage: metadata
script:
- npmci command npm install -g typedoc typescript
- npmci npm prepare
- npmci npm install
- npmci command typedoc --module "commonjs" --target "ES2016" --out public/ ts/
tags:
- docker
- notpriv
only:
- tags
artifacts:
expire_in: 1 week
paths:
- public
allow_failure: true
windowsCompatibility:
image: stefanscherer/node-windows:10-build-tools
stage: metadata
script:
- npm install & npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- windows
allow_failure: true

11
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "npm test",
"name": "Run npm test",
"request": "launch",
"type": "node-terminal"
}
]
}

26
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,26 @@
{
"json.schemas": [
{
"fileMatch": ["/npmextra.json"],
"schema": {
"type": "object",
"properties": {
"npmci": {
"type": "object",
"description": "settings for npmci"
},
"gitzone": {
"type": "object",
"description": "settings for gitzone",
"properties": {
"projectType": {
"type": "string",
"enum": ["website", "element", "service", "npm", "wcc"]
}
}
}
}
}
}
]
}

131
changelog.md Normal file
View File

@ -0,0 +1,131 @@
# Changelog
## 2025-02-25 - 3.2.2 - fix(SmartPdf)
Fix buffer handling for PDF conversion and text extraction
- Ensure Uint8Array is converted to Node Buffer for PDF conversion.
- Correct the PDF page viewport handling by using document dimensions.
- Fix extractTextFromPdfBuffer argument type from Uint8Array to Buffer.
## 2025-02-25 - 3.2.1 - fix(SmartPdf)
Fix type for extractTextFromPdfBuffer function
- Corrected the parameter type from Buffer to Uint8Array for extractTextFromPdfBuffer function.
## 2025-02-25 - 3.2.0 - feat(smartpdf)
Improve dependency versions and optimize PDF to PNG conversion.
- Update several dependencies to newer versions for better stability and performance.
- Refactor tests to enhance readability and add directory creation validations.
- Optimize PDF to PNG conversion by switching to a more efficient Puppeteer and PDF.js-based method.
- Add checks for presence of required dependencies (GraphicsMagick and Ghostscript).
- Fix media emulation issue by properly awaiting the emulateMediaType function.
## 2024-11-30 - 3.1.8 - fix(core)
Fix candidate handling in PDF generation
- Added error handling for missing PDF candidates in server requests.
- Updated devDependencies and dependencies to latest versions for better stability and new features.
- Patched header retrieval logic during PDF generation for security check.
## 2024-09-27 - 3.1.7 - fix(dependencies)
Update dependencies to latest versions
- Updated @git.zone/tsbuild to version ^2.1.84
- Updated @git.zone/tsdoc to version ^1.3.12
- Updated @git.zone/tsrun to version ^1.2.49
- Updated @push.rocks/tapbundle to version ^5.3.0
- Updated @types/node to version ^22.7.4
- Updated @push.rocks/smartfile to version ^11.0.21
- Updated @push.rocks/smartpromise to version ^4.0.4
- Updated @tsclass/tsclass to version ^4.1.2
- Updated express to version ^4.21.0
- Updated pdf2pic to version ^3.1.3
## 2024-05-29 - 3.1.6 - Core
Updated description
- Minor changes to documentation and internal text.
## 2024-04-25 to 2024-04-30 - 3.1.0 to 3.1.5 - Core
Fix updates in core functionality
- Fixes and updates in core function in versions 3.1.0 to 3.1.5.
## 2024-04-25 - 3.0.17 - Feature
Now supports PDF to JPG conversion
- Added support for converting PDF files to JPG format.
## 2024-03-19 to 2024-04-14 - 3.0.17 - Maintenance
Various updates to project configuration files
- Updated `tsconfig`.
- Updated `npmextra.json`.
## 2023-07-11 to 2024-03-19 - 3.0.15 to 3.0.16 - Organization
Switch to new organization scheme and core updates
- Switched to new organization scheme.
- Applied core updates and bug fixes.
## 2022-11-07 to 2023-07-10 - 3.0.13 to 3.0.14 - Core
Fixes and updates to core functionality
- Various minor bug fixes and updates to core components.
## 2022-09-13 to 2022-11-07 - 3.0.10 to 3.0.12 - Core
Ongoing core updates and maintenance
- Regular fixes and operational improvements in core functionalities.
## 2022-06-12 to 2022-09-13 - 3.0.7 to 3.0.9 - Core
Continued focus on high-priority bug fixes and core functionalities
- Regular fixes for critical bugs and enhancements.
## 2022-03-24 to 2022-06-29 - 3.0.3 to 3.0.6 - Core
Further optimization and maintenance releases
- Further improvements and refinements of issues in core functionalities.
## 2022-01-05 to 2022-03-25 - 3.0.0 to 3.0.2 - Major Version Release
Major release for version 3.0.x, including core fixes
- Increased version from 2.x to 3.0. New significant changes and fixes.
## 2022-01-05 to 2022-03-24 - 2.0.13 to 2.0.19 - Core
Routine core updates and bug fixes
- Regular bug fixes in core components.
## 2019-11-19 to 2022-01-06 - 2.0.0 to 2.0.11 - Core
Multiple core updates and a few performance improvements
- Some performance enhancements and multiple bug fixes.
## 2019-11-16 to 2019-11-19 - 1.0.27 to 1.0.29 - API
Breaking change in API
- Naming PDF results to better represent their content.
## 2019-05-29 to 2019-11-15 - 1.0.13 to 1.0.26 - Core
Core functional updates and some major restructuring
- Introduced multiple updates to the core, addressing bugs and improving stability.
## 2019-04-10 to 2019-05-28 - 1.0.4 to 1.0.12 - Core
Fixes and updates in the core
- Implementation of multiple essential fixes for core components.
## 2018-10-06 - 1.0.1 to 1.0.3 - Core and Typings
Initial implementation and core fixes
- Initial implementation of the project.
- Fixed compilation problems in typings.
## 2016-01-29 - unknown - Initial
Initial commit
- Initial commit for the project setup.

View File

View File

@ -2,5 +2,33 @@
"npmci": {
"npmGlobalTools": [],
"npmAccessLevel": "public"
},
"gitzone": {
"projectType": "npm",
"module": {
"githost": "code.foss.global",
"gitscope": "push.rocks",
"gitrepo": "smartpdf",
"description": "A library for creating PDFs dynamically from HTML or websites with additional features like merging PDFs.",
"npmPackagename": "@push.rocks/smartpdf",
"license": "MIT",
"keywords": [
"PDF generation",
"HTML to PDF",
"website to PDF",
"PDF manipulation",
"puppeteer",
"express",
"node.js",
"typescript",
"automation",
"PDF merging",
"text extraction",
"PDF management"
]
}
},
"tsdoc": {
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
}
}
}

1572
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,32 +1,73 @@
{
"name": "@pushrocks/smartpdf",
"version": "1.0.3",
"name": "@push.rocks/smartpdf",
"version": "3.2.2",
"private": false,
"description": "create pdfs on the fly",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"description": "A library for creating PDFs dynamically from HTML or websites with additional features like merging PDFs.",
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",
"type": "module",
"author": "Lossless GmbH",
"license": "MIT",
"scripts": {
"test": "(tstest test/)",
"format": "(gitzone format)",
"build": "(tsbuild)"
"test": "(tstest test/ --web)",
"build": "(tsbuild --web --allowimplicitany)",
"buildDocs": "tsdoc"
},
"devDependencies": {
"@gitzone/tsbuild": "^2.0.22",
"@gitzone/tsrun": "^1.1.12",
"@gitzone/tstest": "^1.0.15",
"@pushrocks/tapbundle": "^3.0.7",
"@types/node": "^10.11.4"
"@git.zone/tsbuild": "^2.2.1",
"@git.zone/tsdoc": "^1.4.3",
"@git.zone/tsrun": "^1.3.3",
"@git.zone/tstest": "^1.0.96",
"@push.rocks/tapbundle": "^5.5.6",
"@types/node": "^22.13.5"
},
"dependencies": {
"@pushrocks/smartfile": "^6.0.8",
"@pushrocks/smartnetwork": "^1.1.0",
"@pushrocks/smartpromise": "^2.0.5",
"@pushrocks/smartunique": "^3.0.1",
"@types/express": "^4.16.0",
"@types/puppeteer": "^1.9.0",
"express": "^4.16.3",
"puppeteer": "^1.9.0"
"@push.rocks/smartbuffer": "^3.0.4",
"@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartfile": "^11.2.0",
"@push.rocks/smartnetwork": "^3.0.0",
"@push.rocks/smartpath": "^5.0.18",
"@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartpuppeteer": "^2.0.5",
"@push.rocks/smartunique": "^3.0.9",
"@tsclass/tsclass": "^4.4.0",
"@types/express": "^5.0.0",
"express": "^4.21.2",
"pdf-lib": "^1.17.1",
"pdf2json": "3.1.5"
},
"files": [
"ts/**/*",
"ts_web/**/*",
"dist/**/*",
"dist_*/**/*",
"dist_ts/**/*",
"dist_ts_web/**/*",
"assets/**/*",
"cli.js",
"npmextra.json",
"readme.md"
],
"browserslist": [
"last 1 chrome versions"
],
"keywords": [
"PDF generation",
"HTML to PDF",
"website to PDF",
"PDF manipulation",
"puppeteer",
"express",
"node.js",
"typescript",
"automation",
"PDF merging",
"text extraction",
"PDF management"
],
"homepage": "https://code.foss.global/push.rocks/smartpdf",
"repository": {
"type": "git",
"url": "https://code.foss.global/push.rocks/smartpdf.git"
}
}

10821
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

1
readme.hints.md Normal file
View File

@ -0,0 +1 @@

116
readme.md Normal file
View File

@ -0,0 +1,116 @@
# @push.rocks/smartpdf
Create PDFs on the fly
## Install
To install `@push.rocks/smartpdf`, use the following command with npm:
```bash
npm install @push.rocks/smartpdf --save
```
Or with yarn:
```bash
yarn add @push.rocks/smartpdf
```
## Usage
This documentation will guide you through using `@push.rocks/smartpdf` to create PDFs in various ways, such as from HTML strings or full web pages, and provides examples on how to merge multiple PDFs into one. Remember, all examples provided here use ESM syntax and TypeScript.
### Getting Started
First, ensure you have the package installed and you can import it into your TypeScript project:
```typescript
import { SmartPdf, IPdf } from '@push.rocks/smartpdf';
```
### Creating a PDF from an HTML String
To create a PDF from a simple HTML string, youll need to instantiate `SmartPdf` and call `getA4PdfResultForHtmlString`.
```typescript
async function createPdfFromHtml() {
const smartPdf = await SmartPdf.create();
await smartPdf.start();
const htmlString = `<h1>Hello World</h1>`;
const pdf: IPdf = await smartPdf.getA4PdfResultForHtmlString(htmlString);
console.log(pdf.buffer); // This is your PDF buffer
await smartPdf.stop();
}
createPdfFromHtml();
```
### Generating a PDF from a Website
You may want to capture a full webpage as a PDF. `SmartPdf` provides two methods to accomplish this. One captures the viewable area as an A4 pdf, and the other captures the entire webpage.
#### A4 PDF from a Website
```typescript
async function createA4PdfFromWebsite() {
const smartPdf = await SmartPdf.create();
await smartPdf.start();
const pdf: IPdf = await smartPdf.getPdfResultForWebsite('https://example.com');
console.log(pdf.buffer); // PDF buffer of the webpage
await smartPdf.stop();
}
createA4PdfFromWebsite();
```
#### Full Webpage as a Single PDF
```typescript
async function createFullPdfFromWebsite() {
const smartPdf = await SmartPdf.create();
await smartPdf.start();
const pdf: IPdf = await smartPdf.getFullWebsiteAsSinglePdf('https://example.com');
console.log(pdf.buffer); // PDF buffer with the full webpage
await smartPdf.stop();
}
createFullPdfFromWebsite();
```
### Merging Multiple PDFs
If you have multiple PDF objects (`IPdf`) that you wish to merge into a single PDF file, you can use the `mergePdfs` method.
```typescript
async function mergePdfs() {
const smartPdf = await SmartPdf.create();
// Assume pdf1 and pdf2 are objects of type IPdf that you want to merge
const mergedPdf: IPdf = await smartPdf.mergePdfs([pdf1, pdf2]);
console.log(mergedPdf.buffer); // Buffer of the merged PDF
}
mergePdfs();
```
### Reading PDF from Disk and Extracting Text
To read a PDF from the disk and extract its text content:
```typescript
async function readAndExtractFromPdf() {
const smartPdf = await SmartPdf.create();
const pdf: IPdf = await smartPdf.readFileToPdfObject('/path/to/your/pdf/file.pdf');
const extractedText = await smartPdf.extractTextFromPdfBuffer(pdf.buffer);
console.log(extractedText); // Extracted text from the PDF
}
readAndExtractFromPdf();
```
This guide provides a comprehensive overview of generating PDFs using `@push.rocks/smartpdf`. Remember to start and stop your `SmartPdf` instance to properly initialize and clean up resources, especially when working with server-side rendering or capturing web pages.
## License and Legal Information
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
### Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
### Company Information
Task Venture Capital GmbH
Registered at District court Bremen HRB 35230 HB, Germany
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.

View File

@ -1,23 +1,85 @@
import { expect, tap } from '@pushrocks/tapbundle';
import * as smartpdf from '../ts/index';
import { expect, tap } from '@push.rocks/tapbundle';
import * as smartpdf from '../ts/index.js';
import * as fs from 'fs';
import * as path from 'path';
let testSmartPdf: smartpdf.SmartPdf;
tap.test('should create a valid instance of smartpdf', async () => {
/**
* Ensures that a directory exists.
* @param dirPath - The directory path to ensure.
*/
function ensureDir(dirPath: string): void {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
tap.test('should create a valid instance of SmartPdf', async () => {
testSmartPdf = new smartpdf.SmartPdf();
expect(testSmartPdf).to.be.instanceof(smartpdf.SmartPdf);
expect(testSmartPdf).toBeInstanceOf(smartpdf.SmartPdf);
});
tap.test('should create a pdf from html string', async () => {
await testSmartPdf.getPdfForHtmlString('hi');
tap.test('should start the SmartPdf instance', async () => {
await testSmartPdf.start();
});
tap.test('should create a pdf from website', async () => {
await testSmartPdf.getPdfForWebsite('https://wikipedia.org');
tap.test('should create PDFs from HTML string', async () => {
const pdf1 = await testSmartPdf.getA4PdfResultForHtmlString('hi');
const pdf2 = await testSmartPdf.getA4PdfResultForHtmlString('hello');
expect(pdf1.buffer).toBeInstanceOf(Buffer);
expect(pdf2.buffer).toBeInstanceOf(Buffer);
});
tap.test('should be able to close properly', async () => {
await testSmartPdf.close();
tap.test('should create PDFs from websites', async () => {
const pdfA4 = await testSmartPdf.getPdfResultForWebsite('https://www.wikipedia.org');
const pdfSingle = await testSmartPdf.getFullWebsiteAsSinglePdf('https://www.wikipedia.org');
expect(pdfA4.buffer).toBeInstanceOf(Buffer);
expect(pdfSingle.buffer).toBeInstanceOf(Buffer);
});
tap.start();
tap.test('should create valid PDF results and write them to disk', async () => {
const writePdfToDisk = async (urlArg: string, fileName: string) => {
const pdfResult = await testSmartPdf.getFullWebsiteAsSinglePdf(urlArg);
expect(pdfResult.buffer).toBeInstanceOf(Buffer);
ensureDir('.nogit');
fs.writeFileSync(path.join('.nogit', fileName), pdfResult.buffer as Buffer);
};
await writePdfToDisk('https://lossless.com/', '1.pdf');
await writePdfToDisk('https://layer.io', '2.pdf');
});
tap.test('should merge PDFs into a combined PDF', async () => {
const pdf1 = await testSmartPdf.readFileToPdfObject('.nogit/1.pdf');
const pdf2 = await testSmartPdf.readFileToPdfObject('.nogit/2.pdf');
const mergedBuffer = await testSmartPdf.mergePdfs([pdf1.buffer, pdf2.buffer]);
ensureDir('.nogit');
fs.writeFileSync(path.join('.nogit', 'combined.pdf'), mergedBuffer);
});
tap.test('should create PNG images from combined PDF using Puppeteer conversion', async () => {
const pdfObject = await testSmartPdf.readFileToPdfObject('.nogit/combined.pdf');
const images = await testSmartPdf.convertPDFToPngBytes(pdfObject.buffer);
expect(images.length).toBeGreaterThan(0);
console.log('Puppeteer-based conversion image sizes:', images.map(img => img.length));
});
tap.test('should store PNG results from both conversion functions in .nogit/testresults', async () => {
const testResultsDir = path.join('.nogit', 'testresults');
ensureDir(testResultsDir);
const pdfObject = await testSmartPdf.readFileToPdfObject('.nogit/combined.pdf');
// Convert using Puppeteer-based function and store images
const imagesPuppeteer = await testSmartPdf.convertPDFToPngBytes(pdfObject.buffer);
imagesPuppeteer.forEach((img, index) => {
const filePath = path.join(testResultsDir, `puppeteer_method_page_${index + 1}.png`);
fs.writeFileSync(filePath, Buffer.from(img));
});
});
tap.test('should close the SmartPdf instance properly', async () => {
await testSmartPdf.stop();
});
tap.start();

8
ts/00_commitinfo_data.ts Normal file
View File

@ -0,0 +1,8 @@
/**
* autocreated commitinfo by @push.rocks/commitinfo
*/
export const commitinfo = {
name: '@push.rocks/smartpdf',
version: '3.2.2',
description: 'A library for creating PDFs dynamically from HTML or websites with additional features like merging PDFs.'
}

View File

@ -1,9 +1,15 @@
// compatibility
declare global {
interface Element { }
interface Node { }
interface NodeListOf<TNode = Node> { }
interface Element {}
interface Node {}
interface NodeListOf<TNode = Node> {}
}
// normal
export * from './smartpdf.classes.smartpdf';
export * from './smartpdf.classes.smartpdf.js';
// additional types
import type * as tsclassTypes from '@tsclass/tsclass';
type IPdf = tsclassTypes.business.IPdf;
export type { IPdf };

View File

@ -1,8 +1,15 @@
import * as plugins from './smartpdf.plugins';
/*
* pdf candidate is a construct used internally for mapping html
* to pdf buffers delivered by puppeteer
*/
import * as plugins from './smartpdf.plugins.js';
export class PdfCandidate {
pdfId = plugins.smartunique.shortId();
doneDeferred = plugins.smartpromise.defer();
public htmlString: string;
public pdfId = plugins.smartunique.shortId();
public doneDeferred = plugins.smartpromise.defer();
constructor(public htmlString) {}
constructor(htmlStringArg: string) {
this.htmlString = htmlStringArg;
}
}

View File

@ -1 +0,0 @@
import * as plugins from './smartpdf.plugins';

View File

@ -1,58 +1,94 @@
import * as plugins from './smartpdf.plugins';
import * as paths from './smartpdf.paths';
import * as plugins from './smartpdf.plugins.js';
import * as paths from './smartpdf.paths.js';
import { Server } from 'http';
import { PdfCandidate } from './smartpdf.classes.pdfcandidate';
import { PdfCandidate } from './smartpdf.classes.pdfcandidate.js';
import { type IPdf } from '@tsclass/tsclass/dist_ts/business/pdf.js';
import { execFile } from 'child_process';
declare const document: any;
export class SmartPdf {
// STATIC
public static async create() {
const smartpdfInstance = new SmartPdf();
return smartpdfInstance;
}
// INSTANCE
htmlServerInstance: Server;
serverPort: number;
headlessBrowser: plugins.puppeteer.Browser;
headlessBrowser: plugins.smartpuppeteer.puppeteer.Browser;
externalBrowserBool: boolean = false;
private _readyDeferred: plugins.smartpromise.Deferred<void>;
private _candidates: { [key: string]: PdfCandidate } = {};
constructor() {
this._readyDeferred = new plugins.smartpromise.Deferred();
this.init();
}
async init() {
async start(headlessBrowserArg?: plugins.smartpuppeteer.puppeteer.Browser) {
const done = plugins.smartpromise.defer();
// lets set the external browser in case one is provided
this.headlessBrowser = headlessBrowserArg;
// setup puppeteer
this.headlessBrowser = await plugins.puppeteer.launch();
if (this.headlessBrowser) {
this.externalBrowserBool = true;
} else {
this.headlessBrowser = await plugins.smartpuppeteer.getEnvAwareBrowserInstance({
forceNoSandbox: false,
});
}
// setup server
const app = plugins.express();
app.get('/:pdfId', (req, res) => {
res.setHeader('PDF-ID', this._candidates[req.params.pdfId].pdfId);
res.send(this._candidates[req.params.pdfId].htmlString);
const wantedCandidate = this._candidates[req.params.pdfId];
if (!wantedCandidate) {
console.log(`${req.url} not attached to a candidate`);
return;
}
res.setHeader('pdf-id', wantedCandidate.pdfId);
res.send(wantedCandidate.htmlString);
});
this.htmlServerInstance = plugins.http.createServer(app);
const smartnetworkInstance = new plugins.smartnetwork.SmartNetwork();
const portAvailable = smartnetworkInstance.isLocalPortAvailable(3210);
const portAvailable = smartnetworkInstance.isLocalPortUnused(3210);
this.htmlServerInstance.listen(3210, 'localhost');
this.htmlServerInstance.on('listening', () => {
this._readyDeferred.resolve();
done.resolve();
});
await done.promise;
}
async close () {
// stop
async stop() {
const done = plugins.smartpromise.defer<void>();
this.htmlServerInstance.close(() => {
done.resolve();
});
await this.headlessBrowser.close();
if (!this.externalBrowserBool) {
await this.headlessBrowser.close();
}
await done.promise;
}
}
/**
* returns a pdf for a given html string;
* Returns a PDF for a given HTML string.
*/
async getPdfForHtmlString(htmlStringArg: string) {
async getA4PdfResultForHtmlString(htmlStringArg: string): Promise<plugins.tsclass.business.IPdf> {
await this._readyDeferred.promise;
const pdfCandidate = new PdfCandidate(htmlStringArg);
this._candidates[pdfCandidate.pdfId] = pdfCandidate;
const page = await this.headlessBrowser.newPage();
await page.setViewport({
width: 794,
height: 1122,
});
const response = await page.goto(`http://localhost:3210/${pdfCandidate.pdfId}`, {
waitUntil: 'networkidle2'
waitUntil: 'networkidle2',
});
const headers = response.headers();
if (headers['pdf-id'] !== pdfCandidate.pdfId) {
@ -62,24 +98,255 @@ export class SmartPdf {
console.log(`id security check passed for ${pdfCandidate.pdfId}`);
}
await page.pdf({
path: plugins.path.join(paths.pdfDir, `${pdfCandidate.pdfId}.pdf`),
format: 'A4'
const pdfBuffer = await page.pdf({
width: 794,
height: 1122,
printBackground: true,
displayHeaderFooter: false,
});
// Convert Uint8Array to Node Buffer
const nodePdfBuffer = Buffer.from(pdfBuffer);
await page.close();
delete this._candidates[pdfCandidate.pdfId];
pdfCandidate.doneDeferred.resolve();
await pdfCandidate.doneDeferred.promise;
return {
id: pdfCandidate.pdfId,
name: `${pdfCandidate.pdfId}.js`,
metadata: {
textExtraction: await this.extractTextFromPdfBuffer(nodePdfBuffer),
},
buffer: nodePdfBuffer,
};
}
async getPdfForWebsite(websiteUrl: string) {
async getPdfResultForWebsite(websiteUrl: string): Promise<plugins.tsclass.business.IPdf> {
const page = await this.headlessBrowser.newPage();
await page.setViewport({
width: 1980,
height: 1200,
});
await page.emulateMediaType('screen');
const response = await page.goto(websiteUrl, { waitUntil: 'networkidle2' });
const pdfId = plugins.smartunique.shortId();
await page.pdf({
path: plugins.path.join(paths.pdfDir, `${pdfId}.pdf`),
format: 'A4'
const { documentHeight, documentWidth } = await page.evaluate(() => {
return {
documentHeight: document.height,
documentWidth: document.width,
};
});
const pdfBuffer = await page.pdf({
height: documentHeight,
width: documentWidth,
printBackground: true,
displayHeaderFooter: false,
});
// Convert Uint8Array to Node Buffer
const nodePdfBuffer = Buffer.from(pdfBuffer);
await page.close();
return {
id: pdfId,
name: `${pdfId}.js`,
metadata: {
textExtraction: await this.extractTextFromPdfBuffer(nodePdfBuffer),
},
buffer: nodePdfBuffer,
};
}
}
async getFullWebsiteAsSinglePdf(websiteUrl: string): Promise<plugins.tsclass.business.IPdf> {
const page = await this.headlessBrowser.newPage();
await page.setViewport({
width: 1920,
height: 1200,
});
await page.emulateMediaType('screen');
const response = await page.goto(websiteUrl, { waitUntil: 'networkidle2' });
const pdfId = plugins.smartunique.shortId();
// Use both document.body and document.documentElement to ensure we have a valid height and width.
const { documentHeight, documentWidth } = await page.evaluate(() => {
return {
documentHeight: Math.max(
document.body.scrollHeight,
document.documentElement.scrollHeight
) || 1200,
documentWidth: Math.max(
document.body.clientWidth,
document.documentElement.clientWidth
) || 1920,
};
});
// Update viewport height to the full document height.
await page.setViewport({
width: 1920,
height: documentHeight,
});
const pdfBuffer = await page.pdf({
height: documentHeight,
width: 1920,
printBackground: true,
displayHeaderFooter: false,
scale: 1,
pageRanges: '1',
});
// Convert Uint8Array to Node Buffer
const nodePdfBuffer = Buffer.from(pdfBuffer);
await page.close();
return {
id: pdfId,
name: `${pdfId}.js`,
metadata: {
textExtraction: await this.extractTextFromPdfBuffer(nodePdfBuffer),
},
buffer: nodePdfBuffer,
};
}
public async mergePdfs(inputPdfBuffers: Uint8Array[]): Promise<Uint8Array> {
const mergedPdf = await plugins.pdfLib.PDFDocument.create();
for (const pdfBytes of inputPdfBuffers) {
const pdfDoc = await plugins.pdfLib.PDFDocument.load(pdfBytes);
const pages = await mergedPdf.copyPages(pdfDoc, pdfDoc.getPageIndices());
pages.forEach((page) => mergedPdf.addPage(page));
}
const mergedPdfBytes = await mergedPdf.save();
return mergedPdfBytes;
}
public async readFileToPdfObject(pathArg: string): Promise<plugins.tsclass.business.IPdf> {
const absolutePath = plugins.smartpath.transform.makeAbsolute(pathArg);
const parsedPath = plugins.path.parse(absolutePath);
const buffer = await plugins.smartfile.fs.toBuffer(absolutePath);
return {
name: parsedPath.base,
buffer,
id: null,
metadata: null,
};
}
public async extractTextFromPdfBuffer(pdfBufferArg: Buffer): Promise<string> {
const deferred = plugins.smartpromise.defer<string>();
const pdfParser: any = new plugins.pdf2json();
pdfParser.on('pdfParser_dataReady', (pdfData: any) => {
let finalText = '';
for (const page of pdfData.Pages) {
for (const text of page.Texts) {
for (const letter of text.R) {
finalText = finalText + letter.T;
}
}
}
deferred.resolve(finalText);
});
pdfParser.parseBuffer(pdfBufferArg);
return deferred.promise;
}
/**
* Checks for the presence of required dependencies: GraphicsMagick and Ghostscript.
*/
private async checkDependencies(): Promise<void> {
await Promise.all([
this.checkCommandExists('gm', ['version']),
this.checkCommandExists('gs', ['--version']),
]);
}
/**
* Checks if a given command exists by trying to execute it.
*/
private checkCommandExists(command: string, args: string[]): Promise<void> {
return new Promise((resolve, reject) => {
execFile(command, args, (error, stdout, stderr) => {
if (error) {
reject(new Error(`Dependency check failed: ${command} is not installed or not in the PATH. ${error.message}`));
} else {
resolve();
}
});
});
}
/**
* Converts a PDF to PNG bytes for each page using Puppeteer and PDF.js.
* This method creates a temporary HTML page that loads PDF.js from a CDN,
* renders each PDF page to a canvas, and then screenshots each canvas element.
*/
public async convertPDFToPngBytes(
pdfBytes: Uint8Array,
options: { width?: number; height?: number; quality?: number } = {}
): Promise<Uint8Array[]> {
// Note: options.width, options.height, and options.quality are not applied here,
// as the rendered canvas size is determined by the PDF page dimensions.
// Create a new page using the headless browser.
const page = await this.headlessBrowser.newPage();
// Prepare PDF data as a base64 string.
const base64Pdf: string = Buffer.from(pdfBytes).toString('base64');
// HTML template that loads PDF.js and renders the PDF.
const htmlTemplate: string = `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>PDF to PNG Converter</title>
<style>
body { margin: 0; }
canvas { display: block; margin: 10px auto; }
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.min.js"></script>
</head>
<body>
<script>
(async function() {
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.min.js';
const pdfData = "__PDF_DATA__";
const raw = atob(pdfData);
const pdfArray = new Uint8Array([...raw].map(c => c.charCodeAt(0)));
const loadingTask = pdfjsLib.getDocument({data: pdfArray});
const pdf = await loadingTask.promise;
const numPages = pdf.numPages;
for (let pageNum = 1; pageNum <= numPages; pageNum++) {
const page = await pdf.getPage(pageNum);
const viewport = page.getViewport({ scale: 1.0 });
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = viewport.width;
canvas.height = viewport.height;
await page.render({ canvasContext: context, viewport: viewport }).promise;
document.body.appendChild(canvas);
}
window.renderComplete = true;
})();
</script>
</body>
</html>
`;
// Replace the placeholder with the actual base64 PDF data.
const htmlContent: string = htmlTemplate.replace("__PDF_DATA__", base64Pdf);
// Set the page content.
await page.setContent(htmlContent, { waitUntil: 'networkidle0' });
// Wait until the PDF.js rendering is complete.
await page.waitForFunction(() => (window as any).renderComplete === true, { timeout: 30000 });
// Query all canvas elements (each representing a rendered PDF page).
const canvasElements = await page.$$('canvas');
const pngBuffers: Uint8Array[] = [];
for (const canvasElement of canvasElements) {
// Screenshot the canvas element. The screenshot will be a PNG buffer.
const screenshotBuffer = (await canvasElement.screenshot({ encoding: 'binary' })) as Buffer;
pngBuffers.push(new Uint8Array(screenshotBuffer));
}
await page.close();
return pngBuffers;
}
}

View File

@ -1,6 +1,6 @@
import * as plugins from './smartpdf.plugins';
import * as plugins from './smartpdf.plugins.js';
export const packageDir = plugins.path.join(__dirname, '../');
export const pdfDir = plugins.path.join(packageDir, 'assets/pdfdir');
plugins.smartfile.fs.ensureDirSync(pdfDir);
export const packageDir = plugins.path.join(
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
'../'
);

View File

@ -5,15 +5,34 @@ import * as path from 'path';
export { http, path };
// @pushrocks
import * as smartfile from '@pushrocks/smartfile';
import * as smartpromise from '@pushrocks/smartpromise';
import * as smartnetwork from '@pushrocks/smartnetwork';
import * as smartunique from '@pushrocks/smartunique';
import * as smartbuffer from '@push.rocks/smartbuffer';
import * as smartfile from '@push.rocks/smartfile';
import * as smartdelay from '@push.rocks/smartdelay';
import * as smartpromise from '@push.rocks/smartpromise';
import * as smartpath from '@push.rocks/smartpath';
import * as smartpuppeteer from '@push.rocks/smartpuppeteer';
import * as smartnetwork from '@push.rocks/smartnetwork';
import * as smartunique from '@push.rocks/smartunique';
export { smartfile, smartpromise, smartunique, smartnetwork };
export {
smartbuffer,
smartfile,
smartdelay,
smartpromise,
smartpath,
smartpuppeteer,
smartunique,
smartnetwork,
};
// tsclass scope
import * as tsclass from '@tsclass/tsclass';
export { tsclass };
// thirdparty
import * as express from 'express';
import * as puppeteer from 'puppeteer';
import express from 'express';
import pdf2json from 'pdf2json';
import pdfLib from 'pdf-lib';
export { express, puppeteer };
export { express, pdf2json, pdfLib, };

14
tsconfig.json Normal file
View File

@ -0,0 +1,14 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"useDefineForClassFields": false,
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"verbatimModuleSyntax": true
},
"exclude": [
"dist_*/**/*.d.ts"
]
}

View File

@ -1,7 +0,0 @@
{
"extends": ["tslint:latest", "tslint-config-prettier"],
"rules": {
"semicolon": [true, "always"]
}
}