@pdfme/manipulator 5.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,150 @@
1
+ import { PDFDocument, RotationTypes } from '@pdfme/pdf-lib';
2
+ export const merge = async (pdfs) => {
3
+ if (!pdfs.length) {
4
+ throw new Error('[@pdfme/manipulator] At least one PDF is required for merging');
5
+ }
6
+ const mergedPdf = await PDFDocument.create();
7
+ for (const buffer of pdfs) {
8
+ const srcDoc = await PDFDocument.load(buffer);
9
+ const copiedPages = await mergedPdf.copyPages(srcDoc, srcDoc.getPageIndices());
10
+ copiedPages.forEach((page) => mergedPdf.addPage(page));
11
+ }
12
+ return mergedPdf.save();
13
+ };
14
+ export const split = async (pdf, ranges) => {
15
+ if (!ranges.length) {
16
+ throw new Error('[@pdfme/manipulator] At least one range is required for splitting');
17
+ }
18
+ const originalPdf = await PDFDocument.load(pdf);
19
+ const numPages = originalPdf.getPages().length;
20
+ const result = [];
21
+ for (const { start = 0, end = numPages - 1 } of ranges) {
22
+ if (start < 0 || end >= numPages || start > end) {
23
+ throw new Error(`[@pdfme/manipulator] Invalid range: start=${start}, end=${end}, total pages=${numPages}`);
24
+ }
25
+ const newPdf = await PDFDocument.create();
26
+ const pages = await newPdf.copyPages(originalPdf, Array.from({ length: end - start + 1 }, (_, i) => i + start));
27
+ pages.forEach((page) => newPdf.addPage(page));
28
+ result.push(await newPdf.save());
29
+ }
30
+ return result;
31
+ };
32
+ export const remove = async (pdf, pages) => {
33
+ if (!pages.length) {
34
+ throw new Error('[@pdfme/manipulator] At least one page number is required for removal');
35
+ }
36
+ const pdfDoc = await PDFDocument.load(pdf);
37
+ const numPages = pdfDoc.getPageCount();
38
+ if (pages.some((page) => page < 0 || page >= numPages)) {
39
+ throw new Error(`[@pdfme/manipulator] Invalid page number: pages must be between 0 and ${numPages - 1}`);
40
+ }
41
+ pages.sort((a, b) => b - a).forEach((pageIndex) => pdfDoc.removePage(pageIndex));
42
+ return pdfDoc.save();
43
+ };
44
+ export const insert = async (basePdf, inserts) => {
45
+ inserts.sort((a, b) => a.position - b.position);
46
+ let currentPdf = basePdf;
47
+ let offset = 0;
48
+ for (let i = 0; i < inserts.length; i++) {
49
+ const { pdf, position } = inserts[i];
50
+ const actualPos = position + offset;
51
+ const basePdfDoc = await PDFDocument.load(currentPdf);
52
+ const insertDoc = await PDFDocument.load(pdf);
53
+ const numPages = basePdfDoc.getPageCount();
54
+ if (actualPos < 0 || actualPos > numPages) {
55
+ throw new Error(`[@pdfme/manipulator] Invalid position: must be between 0 and ${numPages}`);
56
+ }
57
+ const newPdfDoc = await PDFDocument.create();
58
+ if (actualPos > 0) {
59
+ const beforePages = await newPdfDoc.copyPages(basePdfDoc, Array.from({ length: actualPos }, (_, idx) => idx));
60
+ beforePages.forEach((page) => newPdfDoc.addPage(page));
61
+ }
62
+ const insertPages = await newPdfDoc.copyPages(insertDoc, insertDoc.getPageIndices());
63
+ insertPages.forEach((page) => newPdfDoc.addPage(page));
64
+ if (actualPos < numPages) {
65
+ const afterPages = await newPdfDoc.copyPages(basePdfDoc, Array.from({ length: numPages - actualPos }, (_, idx) => idx + actualPos));
66
+ afterPages.forEach((page) => newPdfDoc.addPage(page));
67
+ }
68
+ currentPdf = await newPdfDoc.save();
69
+ offset += insertDoc.getPageCount();
70
+ }
71
+ return currentPdf;
72
+ };
73
+ export const rotate = async (pdf, degrees, pageNumbers) => {
74
+ if (!Number.isInteger(degrees) || degrees % 90 !== 0) {
75
+ throw new Error('[@pdfme/manipulator] Rotation degrees must be a multiple of 90');
76
+ }
77
+ const pdfDoc = await PDFDocument.load(pdf);
78
+ const pages = pdfDoc.getPages();
79
+ if (!pages.length) {
80
+ throw new Error('[@pdfme/manipulator] PDF has no pages to rotate');
81
+ }
82
+ const normalizedDegrees = ((degrees % 360) + 360) % 360;
83
+ if (normalizedDegrees % 90 !== 0) {
84
+ throw new Error('[@pdfme/manipulator] Rotation degrees must be a multiple of 90');
85
+ }
86
+ if (pageNumbers) {
87
+ if (pageNumbers.some((page) => page < 0 || page >= pages.length)) {
88
+ throw new Error(`[@pdfme/manipulator] Invalid page number: pages must be between 0 and ${pages.length - 1}`);
89
+ }
90
+ }
91
+ const pagesToRotate = pageNumbers || pages.map((_, i) => i);
92
+ pagesToRotate.forEach((pageNum) => {
93
+ const page = pages[pageNum];
94
+ if (page) {
95
+ page.setRotation({
96
+ type: RotationTypes.Degrees,
97
+ angle: normalizedDegrees % 360,
98
+ });
99
+ }
100
+ });
101
+ return pdfDoc.save();
102
+ };
103
+ export const move = async (pdf, operation) => {
104
+ const { from, to } = operation;
105
+ const pdfDoc = await PDFDocument.load(pdf);
106
+ const currentPageCount = pdfDoc.getPageCount();
107
+ if (from < 0 || from >= currentPageCount || to < 0 || to >= currentPageCount) {
108
+ throw new Error(`[@pdfme/manipulator] Invalid page number: from=${from}, to=${to}, total pages=${currentPageCount}`);
109
+ }
110
+ if (from === to) {
111
+ return pdf;
112
+ }
113
+ const page = pdfDoc.getPage(from);
114
+ pdfDoc.removePage(from);
115
+ const adjustedTo = from < to ? to - 1 : to;
116
+ pdfDoc.insertPage(adjustedTo, page);
117
+ return pdfDoc.save();
118
+ };
119
+ export const organize = async (pdf, actions) => {
120
+ if (!actions.length) {
121
+ throw new Error('[@pdfme/manipulator] At least one action is required');
122
+ }
123
+ let currentPdf = await PDFDocument.load(pdf);
124
+ for (const action of actions) {
125
+ const currentBuffer = (await currentPdf.save()).buffer;
126
+ switch (action.type) {
127
+ case 'remove':
128
+ currentPdf = await PDFDocument.load(await remove(currentBuffer, [action.data.position]));
129
+ break;
130
+ case 'insert':
131
+ currentPdf = await PDFDocument.load(await insert(currentBuffer, [action.data]));
132
+ break;
133
+ case 'replace': {
134
+ const withoutTarget = await remove(currentBuffer, [action.data.position]);
135
+ currentPdf = await PDFDocument.load(await insert(withoutTarget, [action.data]));
136
+ break;
137
+ }
138
+ case 'rotate':
139
+ currentPdf = await PDFDocument.load(await rotate(currentBuffer, action.data.degrees, [action.data.position]));
140
+ break;
141
+ case 'move':
142
+ currentPdf = await PDFDocument.load(await move(currentBuffer, action.data));
143
+ break;
144
+ default:
145
+ throw new Error(`[@pdfme/manipulator] Unknown action type: ${action.type}`);
146
+ }
147
+ }
148
+ return currentPdf.save();
149
+ };
150
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ import 'jest-image-snapshot';
@@ -0,0 +1,5 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ export declare const createTestPDF: (pageCount: number) => Promise<ArrayBuffer>;
4
+ export declare const pdfToImages: (pdf: ArrayBuffer) => Promise<Buffer[]>;
5
+ export declare const getPDFPageCount: (pdf: ArrayBuffer) => Promise<number>;
@@ -0,0 +1,45 @@
1
+ export declare const merge: (pdfs: ArrayBuffer[]) => Promise<ArrayBuffer>;
2
+ export declare const split: (pdf: ArrayBuffer, ranges: {
3
+ start?: number;
4
+ end?: number;
5
+ }[]) => Promise<ArrayBuffer[]>;
6
+ export declare const remove: (pdf: ArrayBuffer, pages: number[]) => Promise<ArrayBuffer>;
7
+ export declare const insert: (basePdf: ArrayBuffer, inserts: {
8
+ pdf: ArrayBuffer;
9
+ position: number;
10
+ }[]) => Promise<ArrayBuffer>;
11
+ export declare const rotate: (pdf: ArrayBuffer, degrees: 0 | 90 | 180 | 270 | 360, pageNumbers?: number[]) => Promise<ArrayBuffer>;
12
+ export declare const move: (pdf: ArrayBuffer, operation: {
13
+ from: number;
14
+ to: number;
15
+ }) => Promise<ArrayBuffer>;
16
+ export declare const organize: (pdf: ArrayBuffer, actions: ({
17
+ type: 'remove';
18
+ data: {
19
+ position: number;
20
+ };
21
+ } | {
22
+ type: 'insert';
23
+ data: {
24
+ pdf: ArrayBuffer;
25
+ position: number;
26
+ };
27
+ } | {
28
+ type: 'replace';
29
+ data: {
30
+ pdf: ArrayBuffer;
31
+ position: number;
32
+ };
33
+ } | {
34
+ type: 'rotate';
35
+ data: {
36
+ position: number;
37
+ degrees: 0 | 90 | 180 | 270 | 360;
38
+ };
39
+ } | {
40
+ type: 'move';
41
+ data: {
42
+ from: number;
43
+ to: number;
44
+ };
45
+ })[]) => Promise<ArrayBuffer>;
package/jest.setup.js ADDED
@@ -0,0 +1,2 @@
1
+ const { toMatchImageSnapshot } = require('jest-image-snapshot');
2
+ expect.extend({ toMatchImageSnapshot });
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@pdfme/manipulator",
3
+ "version": "5.3.6",
4
+ "sideEffects": false,
5
+ "author": "hand-dot",
6
+ "license": "MIT",
7
+ "keywords": [
8
+ "pdf",
9
+ "pdf-generation",
10
+ "pdf-designer",
11
+ "pdf-viewer",
12
+ "typescript",
13
+ "react"
14
+ ],
15
+ "description": "TypeScript base PDF generator and React base UI. Open source, developed by the community, and completely free to use under the MIT license!",
16
+ "homepage": "https://pdfme.com",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git@github.com:pdfme/pdfme.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/pdfme/pdfme/issues"
23
+ },
24
+ "main": "dist/cjs/src/index.js",
25
+ "module": "dist/esm/src/index.js",
26
+ "types": "dist/types/src/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "import": "./dist/esm/src/index.js",
30
+ "require": "./dist/cjs/src/index.js",
31
+ "types": "./dist/types/src/index.d.ts"
32
+ }
33
+ },
34
+ "scripts": {
35
+ "dev": "tsc -p tsconfig.esm.json -w",
36
+ "build": "npm-run-all --parallel build:cjs build:esm",
37
+ "build:cjs": "tsc -p tsconfig.cjs.json",
38
+ "build:esm": "tsc -p tsconfig.esm.json",
39
+ "clean": "rimraf dist",
40
+ "lint": "eslint --ext .ts src",
41
+ "test": "jest",
42
+ "test:update-snapshots": "jest --updateSnapshot",
43
+ "prune": "ts-prune src",
44
+ "prettier": "prettier --write 'src/**/*.ts'"
45
+ },
46
+ "dependencies": {
47
+ "@pdfme/pdf-lib": "*"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "devDependencies": {
53
+ "@pdfme/converter": "*",
54
+ "@types/estree": "^1.0.6"
55
+ },
56
+ "jest": {
57
+ "preset": "ts-jest",
58
+ "testEnvironment": "node",
59
+ "setupFilesAfterEnv": [
60
+ "<rootDir>/jest.setup.js"
61
+ ],
62
+ "testMatch": [
63
+ "**/__tests__/**/*.test.ts"
64
+ ],
65
+ "transform": {
66
+ "^.+\\.tsx?$": [
67
+ "ts-jest",
68
+ {
69
+ "tsconfig": "./tsconfig.json"
70
+ }
71
+ ]
72
+ }
73
+ }
74
+ }
package/src/index.ts ADDED
@@ -0,0 +1,236 @@
1
+ import { PDFDocument, RotationTypes } from '@pdfme/pdf-lib';
2
+
3
+ export const merge = async (pdfs: ArrayBuffer[]): Promise<ArrayBuffer> => {
4
+ if (!pdfs.length) {
5
+ throw new Error('[@pdfme/manipulator] At least one PDF is required for merging');
6
+ }
7
+
8
+ const mergedPdf = await PDFDocument.create();
9
+ for (const buffer of pdfs) {
10
+ const srcDoc = await PDFDocument.load(buffer);
11
+ const copiedPages = await mergedPdf.copyPages(srcDoc, srcDoc.getPageIndices());
12
+ copiedPages.forEach((page) => mergedPdf.addPage(page));
13
+ }
14
+ return mergedPdf.save();
15
+ };
16
+
17
+ export const split = async (
18
+ pdf: ArrayBuffer,
19
+ ranges: { start?: number; end?: number }[]
20
+ ): Promise<ArrayBuffer[]> => {
21
+ if (!ranges.length) {
22
+ throw new Error('[@pdfme/manipulator] At least one range is required for splitting');
23
+ }
24
+
25
+ const originalPdf = await PDFDocument.load(pdf);
26
+ const numPages = originalPdf.getPages().length;
27
+ const result: ArrayBuffer[] = [];
28
+
29
+ for (const { start = 0, end = numPages - 1 } of ranges) {
30
+ if (start < 0 || end >= numPages || start > end) {
31
+ throw new Error(
32
+ `[@pdfme/manipulator] Invalid range: start=${start}, end=${end}, total pages=${numPages}`
33
+ );
34
+ }
35
+
36
+ const newPdf = await PDFDocument.create();
37
+ const pages = await newPdf.copyPages(
38
+ originalPdf,
39
+ Array.from({ length: end - start + 1 }, (_, i) => i + start)
40
+ );
41
+ pages.forEach((page) => newPdf.addPage(page));
42
+ result.push(await newPdf.save());
43
+ }
44
+ return result;
45
+ };
46
+
47
+ export const remove = async (pdf: ArrayBuffer, pages: number[]): Promise<ArrayBuffer> => {
48
+ if (!pages.length) {
49
+ throw new Error('[@pdfme/manipulator] At least one page number is required for removal');
50
+ }
51
+
52
+ const pdfDoc = await PDFDocument.load(pdf);
53
+ const numPages = pdfDoc.getPageCount();
54
+
55
+ if (pages.some((page) => page < 0 || page >= numPages)) {
56
+ throw new Error(
57
+ `[@pdfme/manipulator] Invalid page number: pages must be between 0 and ${numPages - 1}`
58
+ );
59
+ }
60
+
61
+ pages.sort((a, b) => b - a).forEach((pageIndex) => pdfDoc.removePage(pageIndex));
62
+ return pdfDoc.save();
63
+ };
64
+
65
+ export const insert = async (
66
+ basePdf: ArrayBuffer,
67
+ inserts: { pdf: ArrayBuffer; position: number }[]
68
+ ): Promise<ArrayBuffer> => {
69
+ inserts.sort((a, b) => a.position - b.position);
70
+
71
+ let currentPdf = basePdf;
72
+ let offset = 0;
73
+
74
+ for (let i = 0; i < inserts.length; i++) {
75
+ const { pdf, position } = inserts[i];
76
+ const actualPos = position + offset;
77
+
78
+ const basePdfDoc = await PDFDocument.load(currentPdf);
79
+ const insertDoc = await PDFDocument.load(pdf);
80
+ const numPages = basePdfDoc.getPageCount();
81
+
82
+ if (actualPos < 0 || actualPos > numPages) {
83
+ throw new Error(`[@pdfme/manipulator] Invalid position: must be between 0 and ${numPages}`);
84
+ }
85
+
86
+ const newPdfDoc = await PDFDocument.create();
87
+
88
+ if (actualPos > 0) {
89
+ const beforePages = await newPdfDoc.copyPages(
90
+ basePdfDoc,
91
+ Array.from({ length: actualPos }, (_, idx) => idx)
92
+ );
93
+ beforePages.forEach((page) => newPdfDoc.addPage(page));
94
+ }
95
+
96
+ const insertPages = await newPdfDoc.copyPages(insertDoc, insertDoc.getPageIndices());
97
+ insertPages.forEach((page) => newPdfDoc.addPage(page));
98
+
99
+ if (actualPos < numPages) {
100
+ const afterPages = await newPdfDoc.copyPages(
101
+ basePdfDoc,
102
+ Array.from({ length: numPages - actualPos }, (_, idx) => idx + actualPos)
103
+ );
104
+ afterPages.forEach((page) => newPdfDoc.addPage(page));
105
+ }
106
+
107
+ currentPdf = await newPdfDoc.save();
108
+
109
+ offset += insertDoc.getPageCount();
110
+ }
111
+
112
+ return currentPdf;
113
+ };
114
+
115
+ export const rotate = async (
116
+ pdf: ArrayBuffer,
117
+ degrees: 0 | 90 | 180 | 270 | 360,
118
+ pageNumbers?: number[]
119
+ ): Promise<ArrayBuffer> => {
120
+ if (!Number.isInteger(degrees) || degrees % 90 !== 0) {
121
+ throw new Error('[@pdfme/manipulator] Rotation degrees must be a multiple of 90');
122
+ }
123
+
124
+ const pdfDoc = await PDFDocument.load(pdf);
125
+ const pages = pdfDoc.getPages();
126
+
127
+ if (!pages.length) {
128
+ throw new Error('[@pdfme/manipulator] PDF has no pages to rotate');
129
+ }
130
+
131
+ const normalizedDegrees = ((degrees % 360) + 360) % 360;
132
+
133
+ if (normalizedDegrees % 90 !== 0) {
134
+ throw new Error('[@pdfme/manipulator] Rotation degrees must be a multiple of 90');
135
+ }
136
+
137
+ if (pageNumbers) {
138
+ if (pageNumbers.some((page) => page < 0 || page >= pages.length)) {
139
+ throw new Error(
140
+ `[@pdfme/manipulator] Invalid page number: pages must be between 0 and ${pages.length - 1}`
141
+ );
142
+ }
143
+ }
144
+
145
+ const pagesToRotate = pageNumbers || pages.map((_, i) => i);
146
+ pagesToRotate.forEach((pageNum) => {
147
+ const page = pages[pageNum];
148
+ if (page) {
149
+ page.setRotation({
150
+ type: RotationTypes.Degrees,
151
+ angle: normalizedDegrees % 360,
152
+ });
153
+ }
154
+ });
155
+ return pdfDoc.save();
156
+ };
157
+
158
+ export const move = async (
159
+ pdf: ArrayBuffer,
160
+ operation: { from: number; to: number }
161
+ ): Promise<ArrayBuffer> => {
162
+ const { from, to } = operation;
163
+ const pdfDoc = await PDFDocument.load(pdf);
164
+ const currentPageCount = pdfDoc.getPageCount();
165
+
166
+ if (from < 0 || from >= currentPageCount || to < 0 || to >= currentPageCount) {
167
+ throw new Error(
168
+ `[@pdfme/manipulator] Invalid page number: from=${from}, to=${to}, total pages=${currentPageCount}`
169
+ );
170
+ }
171
+
172
+ if (from === to) {
173
+ return pdf;
174
+ }
175
+
176
+ const page = pdfDoc.getPage(from);
177
+ pdfDoc.removePage(from);
178
+
179
+ const adjustedTo = from < to ? to - 1 : to;
180
+ pdfDoc.insertPage(adjustedTo, page);
181
+
182
+ return pdfDoc.save();
183
+ };
184
+
185
+
186
+ export const organize = async (
187
+ pdf: ArrayBuffer,
188
+ actions: Array<
189
+ | { type: 'remove'; data: { position: number } }
190
+ | { type: 'insert'; data: { pdf: ArrayBuffer; position: number } }
191
+ | { type: 'replace'; data: { pdf: ArrayBuffer; position: number } }
192
+ | { type: 'rotate'; data: { position: number; degrees: 0 | 90 | 180 | 270 | 360 } }
193
+ | { type: 'move'; data: { from: number; to: number } }
194
+ >
195
+ ): Promise<ArrayBuffer> => {
196
+ if (!actions.length) {
197
+ throw new Error('[@pdfme/manipulator] At least one action is required');
198
+ }
199
+
200
+ let currentPdf = await PDFDocument.load(pdf);
201
+
202
+ for (const action of actions) {
203
+ const currentBuffer = (await currentPdf.save()).buffer;
204
+
205
+ switch (action.type) {
206
+ case 'remove':
207
+ currentPdf = await PDFDocument.load(await remove(currentBuffer, [action.data.position]));
208
+ break;
209
+
210
+ case 'insert':
211
+ currentPdf = await PDFDocument.load(await insert(currentBuffer, [action.data]));
212
+ break;
213
+
214
+ case 'replace': {
215
+ const withoutTarget = await remove(currentBuffer, [action.data.position]);
216
+ currentPdf = await PDFDocument.load(await insert(withoutTarget, [action.data]));
217
+ break;
218
+ }
219
+
220
+ case 'rotate':
221
+ currentPdf = await PDFDocument.load(
222
+ await rotate(currentBuffer, action.data.degrees, [action.data.position])
223
+ );
224
+ break;
225
+
226
+ case 'move':
227
+ currentPdf = await PDFDocument.load(await move(currentBuffer, action.data));
228
+ break;
229
+
230
+ default:
231
+ throw new Error(`[@pdfme/manipulator] Unknown action type: ${(action as any).type}`);
232
+ }
233
+ }
234
+
235
+ return currentPdf.save();
236
+ };
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../tsconfig.base",
3
+ "compilerOptions": {
4
+ "module": "commonjs",
5
+ "outDir": "./dist/cjs",
6
+ "declaration": true,
7
+ "declarationDir": "dist/types",
8
+ "skipLibCheck": true
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../tsconfig.base",
3
+ "compilerOptions": {
4
+ "module": "ESNext",
5
+ "outDir": "./dist/esm",
6
+ "declaration": true,
7
+ "declarationDir": "dist/types",
8
+ "skipLibCheck": true
9
+ }
10
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "./tsconfig.esm",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ }
6
+ }