n8n-nodes-pdfbro 0.1.0
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.
- package/README.md +49 -0
- package/dist/index.js +5 -0
- package/dist/nodes/PdfUtils/PdfUtils.node.js +191 -0
- package/package.json +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# n8n-nodes-pdfbro
|
|
2
|
+
|
|
3
|
+
This is an n8n community node. It lets you manipulate PDF files in your workflows without external dependencies or API calls.
|
|
4
|
+
|
|
5
|
+
[n8n](https://n8n.io/) is a fair-code licensed workflow automation platform.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Merge PDFs**: Combine multiple PDF files into one.
|
|
10
|
+
- **Split Pages**: Split a PDF into individual pages.
|
|
11
|
+
- **Extract Text**: Extract text content from PDF files.
|
|
12
|
+
- **Extract Metadata**: Get title, author, page count, etc.
|
|
13
|
+
- **Rotate Pages**: Rotate pages by 90, 180, or 270 degrees.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
Follow the [n8n community nodes documentation](https://docs.n8n.io/integrations/community-nodes/installation/) to install this node.
|
|
18
|
+
|
|
19
|
+
### Community Nodes (Recommended)
|
|
20
|
+
1. Go to **Settings > Community Nodes**.
|
|
21
|
+
2. Select **Install**.
|
|
22
|
+
3. Enter `n8n-nodes-pdfbro`.
|
|
23
|
+
|
|
24
|
+
### Manual
|
|
25
|
+
Running n8n with npm:
|
|
26
|
+
```bash
|
|
27
|
+
npm install n8n-nodes-pdfbro
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Operations
|
|
31
|
+
|
|
32
|
+
### Merge PDFs
|
|
33
|
+
Merges all input items containing PDF binary data into a single output item with the merged PDF.
|
|
34
|
+
|
|
35
|
+
### Split Pages
|
|
36
|
+
Splits a PDF into multiple items, one per page.
|
|
37
|
+
|
|
38
|
+
### Extract Text
|
|
39
|
+
Extracts all text from the PDF and adds it to the JSON output.
|
|
40
|
+
|
|
41
|
+
### Extract Metadata
|
|
42
|
+
Adds PDF metadata (Title, Author, Creation Date, etc.) to the JSON output.
|
|
43
|
+
|
|
44
|
+
### Rotate Pages
|
|
45
|
+
Rotates all pages in the PDF by the specified degrees (default 90).
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PdfUtils = void 0;
|
|
7
|
+
const pdf_lib_1 = require("pdf-lib");
|
|
8
|
+
// @ts-ignore
|
|
9
|
+
const pdf_parse_1 = __importDefault(require("pdf-parse"));
|
|
10
|
+
class PdfUtils {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.description = {
|
|
13
|
+
displayName: 'PDF Utils',
|
|
14
|
+
name: 'pdfUtils',
|
|
15
|
+
icon: 'file:pdfUtils.svg',
|
|
16
|
+
group: ['transform'],
|
|
17
|
+
version: 1,
|
|
18
|
+
description: 'Offline PDF operations',
|
|
19
|
+
defaults: {
|
|
20
|
+
name: 'PDF Utils',
|
|
21
|
+
},
|
|
22
|
+
inputs: ['main'],
|
|
23
|
+
outputs: ['main'],
|
|
24
|
+
properties: [
|
|
25
|
+
{
|
|
26
|
+
displayName: 'Operation',
|
|
27
|
+
name: 'operation',
|
|
28
|
+
type: 'options',
|
|
29
|
+
noDataExpression: true,
|
|
30
|
+
options: [
|
|
31
|
+
{
|
|
32
|
+
name: 'Merge PDFs',
|
|
33
|
+
value: 'merge',
|
|
34
|
+
description: 'Merge multiple PDF items into a single PDF',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'Split Pages',
|
|
38
|
+
value: 'split',
|
|
39
|
+
description: 'Split a PDF into separate pages',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'Extract Text',
|
|
43
|
+
value: 'extractText',
|
|
44
|
+
description: 'Extract text content from PDF',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'Extract Metadata',
|
|
48
|
+
value: 'metadata',
|
|
49
|
+
description: 'Get PDF metadata (title, author, pages)',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'Rotate Pages',
|
|
53
|
+
value: 'rotate',
|
|
54
|
+
description: 'Rotate all pages in a PDF',
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
default: 'merge',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
displayName: 'Input Binary Field',
|
|
61
|
+
name: 'binaryPropertyName',
|
|
62
|
+
type: 'string',
|
|
63
|
+
default: 'data',
|
|
64
|
+
required: true,
|
|
65
|
+
description: 'The name of the binary field containing the PDF',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
displayName: 'Rotation Degrees',
|
|
69
|
+
name: 'rotationDegrees',
|
|
70
|
+
type: 'number',
|
|
71
|
+
default: 90,
|
|
72
|
+
displayOptions: {
|
|
73
|
+
show: {
|
|
74
|
+
operation: ['rotate'],
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
description: 'Clockwise rotation (e.g. 90, 180, 270)',
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async execute() {
|
|
83
|
+
const items = this.getInputData();
|
|
84
|
+
const returnData = [];
|
|
85
|
+
const operation = this.getNodeParameter('operation', 0);
|
|
86
|
+
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', 0);
|
|
87
|
+
if (operation === 'merge') {
|
|
88
|
+
// Merge all inputs into one PDF
|
|
89
|
+
const mergedPdf = await pdf_lib_1.PDFDocument.create();
|
|
90
|
+
for (let i = 0; i < items.length; i++) {
|
|
91
|
+
try {
|
|
92
|
+
const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName);
|
|
93
|
+
const validBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
94
|
+
const pdf = await pdf_lib_1.PDFDocument.load(validBuffer);
|
|
95
|
+
const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
|
|
96
|
+
copiedPages.forEach((page) => mergedPdf.addPage(page));
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
if (this.continueOnFail()) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const mergedPdfBuffer = await mergedPdf.save();
|
|
106
|
+
returnData.push({
|
|
107
|
+
json: { success: true, pageCount: mergedPdf.getPageCount() },
|
|
108
|
+
binary: {
|
|
109
|
+
[binaryPropertyName]: await this.helpers.prepareBinaryData(Buffer.from(mergedPdfBuffer), 'merged.pdf', 'application/pdf'),
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
else if (operation === 'split') {
|
|
114
|
+
// Split each input PDF into single pages
|
|
115
|
+
for (let i = 0; i < items.length; i++) {
|
|
116
|
+
const validBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
117
|
+
const pdf = await pdf_lib_1.PDFDocument.load(validBuffer);
|
|
118
|
+
const numberOfPages = pdf.getPageCount();
|
|
119
|
+
for (let j = 0; j < numberOfPages; j++) {
|
|
120
|
+
const newPdf = await pdf_lib_1.PDFDocument.create();
|
|
121
|
+
const [copiedPage] = await newPdf.copyPages(pdf, [j]);
|
|
122
|
+
newPdf.addPage(copiedPage);
|
|
123
|
+
const newPdfBuffer = await newPdf.save();
|
|
124
|
+
returnData.push({
|
|
125
|
+
json: { ...items[i].json, pageNumber: j + 1, totalPages: numberOfPages },
|
|
126
|
+
binary: {
|
|
127
|
+
[binaryPropertyName]: await this.helpers.prepareBinaryData(Buffer.from(newPdfBuffer), `page_${j + 1}.pdf`, 'application/pdf'),
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else if (operation === 'rotate') {
|
|
134
|
+
const degreesVal = this.getNodeParameter('rotationDegrees', 0);
|
|
135
|
+
for (let i = 0; i < items.length; i++) {
|
|
136
|
+
const validBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
137
|
+
const pdf = await pdf_lib_1.PDFDocument.load(validBuffer);
|
|
138
|
+
const pages = pdf.getPages();
|
|
139
|
+
pages.forEach(page => {
|
|
140
|
+
const currentRotation = page.getRotation().angle;
|
|
141
|
+
page.setRotation((0, pdf_lib_1.degrees)(currentRotation + degreesVal));
|
|
142
|
+
});
|
|
143
|
+
const rotatedPdfBuffer = await pdf.save();
|
|
144
|
+
returnData.push({
|
|
145
|
+
json: items[i].json,
|
|
146
|
+
binary: {
|
|
147
|
+
[binaryPropertyName]: await this.helpers.prepareBinaryData(Buffer.from(rotatedPdfBuffer), 'rotated.pdf', 'application/pdf'),
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else if (operation === 'extractText') {
|
|
153
|
+
for (let i = 0; i < items.length; i++) {
|
|
154
|
+
const validBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
155
|
+
const data = await (0, pdf_parse_1.default)(validBuffer);
|
|
156
|
+
returnData.push({
|
|
157
|
+
json: {
|
|
158
|
+
...items[i].json,
|
|
159
|
+
text: data.text,
|
|
160
|
+
numpages: data.numpages,
|
|
161
|
+
info: data.info,
|
|
162
|
+
},
|
|
163
|
+
binary: items[i].binary,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else if (operation === 'metadata') {
|
|
168
|
+
for (let i = 0; i < items.length; i++) {
|
|
169
|
+
const validBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
170
|
+
const pdf = await pdf_lib_1.PDFDocument.load(validBuffer);
|
|
171
|
+
returnData.push({
|
|
172
|
+
json: {
|
|
173
|
+
...items[i].json,
|
|
174
|
+
title: pdf.getTitle(),
|
|
175
|
+
author: pdf.getAuthor(),
|
|
176
|
+
subject: pdf.getSubject(),
|
|
177
|
+
creator: pdf.getCreator(),
|
|
178
|
+
producer: pdf.getProducer(),
|
|
179
|
+
keywords: pdf.getKeywords(),
|
|
180
|
+
pageCount: pdf.getPageCount(),
|
|
181
|
+
creationDate: pdf.getCreationDate(),
|
|
182
|
+
modificationDate: pdf.getModificationDate(),
|
|
183
|
+
},
|
|
184
|
+
binary: items[i].binary,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return [returnData];
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
exports.PdfUtils = PdfUtils;
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-pdfbro",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Offline PDF utility node for n8n",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node"
|
|
7
|
+
],
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"author": "Blankarray",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/blankarrayy/pdfbro"
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/index.js",
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"dev": "tsc --watch"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"pdf-lib": "^1.17.1",
|
|
24
|
+
"pdf-parse": "^1.1.1"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"n8n-workflow": "*",
|
|
28
|
+
"typescript": "^5.0.0",
|
|
29
|
+
"@types/node": "^16.0.0"
|
|
30
|
+
}
|
|
31
|
+
}
|