n8n-nodes-text-to-image 1.0.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 ADDED
@@ -0,0 +1,186 @@
1
+ # n8n-nodes-text-to-image
2
+
3
+ > Generate beautiful, HDR-quality motivation images from text — directly inside your n8n workflows. Perfect for automated Instagram posts.
4
+
5
+ ![Node Icon](nodes/TextToImage/texttoimage.svg)
6
+
7
+ ---
8
+
9
+ ## Features
10
+
11
+ - **6 built-in templates** — dark minimal, light elegant, vibrant purple, golden hour, arctic clean, midnight blue
12
+ - **Full custom mode** — control every visual parameter
13
+ - **Multi-line text** — use `\n` in your text input
14
+ - **Batch generation** — generate many images at once from a JSON array
15
+ - **HDR output** — renders internally at 2× resolution for crisp Retina/HDR screens
16
+ - **Effects** — vignette, film grain, gradient backgrounds
17
+ - **Output formats** — PNG (lossless) or JPEG (adjustable quality)
18
+ - **Bundled fonts** — Inter, Playfair Display, Oswald, Montserrat (no internet required)
19
+
20
+ ---
21
+
22
+ ## Prerequisites
23
+
24
+ > **Important**: `node-canvas` requires native system libraries (Cairo, Pango, libjpeg). This node works on **self-hosted n8n** only. See Docker section below.
25
+
26
+ ### macOS (local dev)
27
+ ```bash
28
+ brew install pkg-config cairo pango libpng jpeg giflib librsvg pixman
29
+ ```
30
+
31
+ ### Ubuntu/Debian
32
+ ```bash
33
+ sudo apt-get install -y libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev
34
+ ```
35
+
36
+ ### Docker
37
+ See [`Dockerfile.example`](Dockerfile.example) in this repo for a ready-to-use setup.
38
+
39
+ ---
40
+
41
+ ## Installation
42
+
43
+ ### Option 1: Local `~/.n8n/custom/` (Self-hosted)
44
+
45
+ ```bash
46
+ # 1. Clone and build
47
+ git clone <this-repo>
48
+ cd n8n-nodes-text-to-image
49
+ npm install
50
+ npm run build
51
+
52
+ # 2. Download bundled fonts (see Fonts section below)
53
+ npm run download-fonts
54
+
55
+ # 3. Copy to n8n custom nodes directory
56
+ mkdir -p ~/.n8n/custom/node_modules/n8n-nodes-text-to-image
57
+ cp -r dist package.json ~/.n8n/custom/node_modules/n8n-nodes-text-to-image/
58
+
59
+ # 4. Restart n8n
60
+ n8n start
61
+ ```
62
+
63
+ ### Option 2: Docker (Local)
64
+
65
+ See [`Dockerfile.example`](Dockerfile.example). Build it with:
66
+ ```bash
67
+ docker build -f Dockerfile.example -t n8n-custom .
68
+ docker run -it --rm -p 5678:5678 n8n-custom
69
+ ```
70
+
71
+ ### Option 3: Heroku ☁️
72
+
73
+ See **[HEROKU.md](HEROKU.md)** for the complete guide including:
74
+ - **Option A** — Heroku Container Registry (Docker) ✅ Recommended
75
+ - **Option B** — Heroku Buildpacks + `Aptfile`
76
+
77
+ Quick start:
78
+ ```bash
79
+ heroku create your-n8n-app
80
+ heroku container:login
81
+ heroku container:push web -a your-n8n-app --dockerfile Dockerfile.heroku
82
+ heroku container:release web -a your-n8n-app
83
+ ```
84
+
85
+ ---
86
+
87
+ ## Fonts
88
+
89
+ This node bundles the following fonts (placed in `nodes/TextToImage/fonts/`):
90
+
91
+ | Font | Variants | Style |
92
+ |------|----------|-------|
93
+ | Inter | Regular, Bold | Modern, clean |
94
+ | Playfair Display | Regular, Bold, Italic | Elegant, serif |
95
+ | Oswald | Regular, Bold | Condensed, strong |
96
+ | Montserrat | Regular, Bold | Geometric, versatile |
97
+
98
+ **Downloading fonts:**
99
+ ```bash
100
+ npm run download-fonts
101
+ ```
102
+ This script fetches `.ttf` files from Google Fonts and places them in the correct directory.
103
+
104
+ ---
105
+
106
+ ## Usage
107
+
108
+ ### 1. Single Image
109
+
110
+ 1. Add the **Text to Image** node to your workflow
111
+ 2. Pick a **Template** (or select **Custom**)
112
+ 3. Type your **Text** (use `\n` for line breaks)
113
+ 4. Adjust canvas size (default: 1080×1080 for Instagram square)
114
+ 5. Choose output format (PNG or JPEG)
115
+ 6. Connect the output to a **Write Binary File**, **Google Drive**, or **HTTP Request** node
116
+
117
+ ### 2. Batch / Multiple Images
118
+
119
+ Enable **Generate Multiple Images**, then set the **Text** field to a JSON array:
120
+ ```json
121
+ ["You are enough.", "Keep going.\nOne step at a time.", "Dream big. Start small."]
122
+ ```
123
+
124
+ This produces one output item per string — each with its own binary image. Chain with a **Loop Over Items** node to post each to Instagram sequentially.
125
+
126
+ ---
127
+
128
+ ## Templates
129
+
130
+ | Template | Background | Font | Best For |
131
+ |----------|------------|------|----------|
132
+ | ⚫ Dark Minimal | `#0D0D0D` solid | Inter Bold 72px white | Clean, modern |
133
+ | 🤍 Light Elegant | `#FAF7F0` solid | Playfair Display Italic 68px | Soft, luxury |
134
+ | 💜 Vibrant Purple | `#1A0533` → `#6B21A8` gradient | Oswald Bold 80px white | Bold, energetic |
135
+ | ✨ Golden Hour | `#2C1A0E` warm gradient | Playfair Display Bold 70px gold | Warm, inspirational |
136
+ | 🩵 Arctic Clean | `#F0F4F8` solid | Inter Regular 64px dark | Professional, minimal |
137
+ | 🌑 Midnight Blue | `#0F172A` gradient | Montserrat Bold 70px light | Night, sophisticated |
138
+
139
+ ---
140
+
141
+ ## Output
142
+
143
+ Each item in the output contains:
144
+
145
+ **JSON fields:**
146
+ | Field | Description |
147
+ |-------|-------------|
148
+ | `fileName` | e.g. `image_1.png` |
149
+ | `width` | Canvas width in px |
150
+ | `height` | Canvas height in px |
151
+ | `template` | Template name used |
152
+ | `text` | Text that was rendered |
153
+ | `outputFormat` | `png` or `jpeg` |
154
+ | `index` | 0-based index (batch mode) |
155
+
156
+ **Binary field** (default name: `image`):
157
+ The generated image binary — connect directly to any n8n node that accepts binary data.
158
+
159
+ ---
160
+
161
+ ## Example Workflow
162
+
163
+ ```
164
+ [Manual Trigger]
165
+
166
+ [Text to Image] — Template: Golden Hour, Text: "Be the change."
167
+
168
+ [Write Binary File] — path: /output/motivation.png
169
+ ```
170
+
171
+ Or for Instagram automation:
172
+ ```
173
+ [Schedule Trigger]
174
+
175
+ [Text to Image] — Batch mode, 7 quotes for the week
176
+
177
+ [Loop Over Items]
178
+
179
+ [HTTP Request] — POST to Instagram Graph API
180
+ ```
181
+
182
+ ---
183
+
184
+ ## License
185
+
186
+ MIT
@@ -0,0 +1,6 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class TextToImage implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
6
+ //# sourceMappingURL=TextToImage.node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TextToImage.node.d.ts","sourceRoot":"","sources":["../../../nodes/TextToImage/TextToImage.node.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,EACjB,kBAAkB,EAClB,SAAS,EACT,oBAAoB,EAEpB,MAAM,cAAc,CAAC;AAgZtB,qBAAa,WAAY,YAAW,SAAS;IAC5C,WAAW,EAAE,oBAAoB,CA2P/B;IAEI,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;CAkJvE"}
@@ -0,0 +1,725 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.TextToImage = void 0;
37
+ const n8n_workflow_1 = require("n8n-workflow");
38
+ const canvas_1 = require("canvas");
39
+ const path = __importStar(require("path"));
40
+ const fs = __importStar(require("fs"));
41
+ // ─── Font Registration ─────────────────────────────────────────────────────────
42
+ // Fonts are bundled in the package under nodes/TextToImage/fonts/
43
+ const FONTS_DIR = path.join(__dirname, 'fonts');
44
+ function registerBundledFonts() {
45
+ const fontFiles = [
46
+ { file: 'Inter-Regular.ttf', family: 'Inter', weight: 'normal', style: 'normal' },
47
+ { file: 'Inter-Bold.ttf', family: 'Inter', weight: 'bold', style: 'normal' },
48
+ { file: 'PlayfairDisplay-Regular.ttf', family: 'Playfair Display', weight: 'normal', style: 'normal' },
49
+ { file: 'PlayfairDisplay-Bold.ttf', family: 'Playfair Display', weight: 'bold', style: 'normal' },
50
+ { file: 'PlayfairDisplay-Italic.ttf', family: 'Playfair Display', weight: 'normal', style: 'italic' },
51
+ { file: 'Oswald-Regular.ttf', family: 'Oswald', weight: 'normal', style: 'normal' },
52
+ { file: 'Oswald-Bold.ttf', family: 'Oswald', weight: 'bold', style: 'normal' },
53
+ { file: 'Montserrat-Regular.ttf', family: 'Montserrat', weight: 'normal', style: 'normal' },
54
+ { file: 'Montserrat-Bold.ttf', family: 'Montserrat', weight: 'bold', style: 'normal' },
55
+ ];
56
+ for (const f of fontFiles) {
57
+ const fullPath = path.join(FONTS_DIR, f.file);
58
+ if (fs.existsSync(fullPath)) {
59
+ (0, canvas_1.registerFont)(fullPath, { family: f.family, weight: f.weight, style: f.style });
60
+ }
61
+ }
62
+ }
63
+ // Register fonts once at module load
64
+ try {
65
+ registerBundledFonts();
66
+ }
67
+ catch (_) {
68
+ // Fonts directory may not exist yet — handled gracefully at runtime
69
+ }
70
+ const TEMPLATES = {
71
+ dark_minimal: {
72
+ backgroundColor: '#0D0D0D',
73
+ fontFamily: 'Inter',
74
+ fontSize: 72,
75
+ fontWeight: 'bold',
76
+ fontStyle: 'normal',
77
+ textColor: '#FFFFFF',
78
+ textAlignment: 'center',
79
+ verticalAlignment: 'middle',
80
+ lineHeight: 1.35,
81
+ letterSpacing: 2,
82
+ padding: 100,
83
+ enableVignette: true,
84
+ enableGrain: true,
85
+ gradientColors: [],
86
+ useGradient: false,
87
+ },
88
+ light_elegant: {
89
+ backgroundColor: '#FAF7F0',
90
+ fontFamily: 'Playfair Display',
91
+ fontSize: 68,
92
+ fontWeight: 'normal',
93
+ fontStyle: 'italic',
94
+ textColor: '#1A1A1A',
95
+ textAlignment: 'center',
96
+ verticalAlignment: 'middle',
97
+ lineHeight: 1.5,
98
+ letterSpacing: 0,
99
+ padding: 110,
100
+ enableVignette: false,
101
+ enableGrain: false,
102
+ gradientColors: [],
103
+ useGradient: false,
104
+ },
105
+ vibrant_purple: {
106
+ backgroundColor: '#1A0533',
107
+ fontFamily: 'Oswald',
108
+ fontSize: 80,
109
+ fontWeight: 'bold',
110
+ fontStyle: 'normal',
111
+ textColor: '#FFFFFF',
112
+ textAlignment: 'center',
113
+ verticalAlignment: 'middle',
114
+ lineHeight: 1.25,
115
+ letterSpacing: 4,
116
+ padding: 90,
117
+ enableVignette: true,
118
+ enableGrain: true,
119
+ gradientColors: ['#1A0533', '#3D1168', '#6B21A8'],
120
+ useGradient: true,
121
+ },
122
+ golden_hour: {
123
+ backgroundColor: '#2C1A0E',
124
+ fontFamily: 'Playfair Display',
125
+ fontSize: 70,
126
+ fontWeight: 'bold',
127
+ fontStyle: 'normal',
128
+ textColor: '#F5C842',
129
+ textAlignment: 'center',
130
+ verticalAlignment: 'middle',
131
+ lineHeight: 1.4,
132
+ letterSpacing: 1,
133
+ padding: 100,
134
+ enableVignette: true,
135
+ enableGrain: true,
136
+ gradientColors: ['#2C1A0E', '#4A2C1A', '#1A0E06'],
137
+ useGradient: true,
138
+ },
139
+ arctic_clean: {
140
+ backgroundColor: '#F0F4F8',
141
+ fontFamily: 'Inter',
142
+ fontSize: 64,
143
+ fontWeight: 'normal',
144
+ fontStyle: 'normal',
145
+ textColor: '#1E293B',
146
+ textAlignment: 'center',
147
+ verticalAlignment: 'middle',
148
+ lineHeight: 1.45,
149
+ letterSpacing: -1,
150
+ padding: 100,
151
+ enableVignette: false,
152
+ enableGrain: false,
153
+ gradientColors: [],
154
+ useGradient: false,
155
+ },
156
+ midnight_blue: {
157
+ backgroundColor: '#0F172A',
158
+ fontFamily: 'Montserrat',
159
+ fontSize: 70,
160
+ fontWeight: 'bold',
161
+ fontStyle: 'normal',
162
+ textColor: '#E2E8F0',
163
+ textAlignment: 'center',
164
+ verticalAlignment: 'middle',
165
+ lineHeight: 1.35,
166
+ letterSpacing: 3,
167
+ padding: 100,
168
+ enableVignette: true,
169
+ enableGrain: true,
170
+ gradientColors: ['#0F172A', '#1E3A5F'],
171
+ useGradient: true,
172
+ },
173
+ };
174
+ // ─── Helpers ───────────────────────────────────────────────────────────────────
175
+ /**
176
+ * Word-wraps text to fit within maxWidth, returning lines with their measured widths.
177
+ */
178
+ function wrapText(ctx, text, maxWidth) {
179
+ const paragraphs = text.split('\n');
180
+ const result = [];
181
+ for (const paragraph of paragraphs) {
182
+ if (paragraph.trim() === '') {
183
+ result.push('');
184
+ continue;
185
+ }
186
+ const words = paragraph.split(' ');
187
+ let currentLine = '';
188
+ for (const word of words) {
189
+ const testLine = currentLine ? `${currentLine} ${word}` : word;
190
+ const metrics = ctx.measureText(testLine);
191
+ if (metrics.width > maxWidth && currentLine) {
192
+ result.push(currentLine);
193
+ currentLine = word;
194
+ }
195
+ else {
196
+ currentLine = testLine;
197
+ }
198
+ }
199
+ if (currentLine)
200
+ result.push(currentLine);
201
+ }
202
+ return result;
203
+ }
204
+ /**
205
+ * Draws a vertical gradient background (for vibrant/golden templates).
206
+ */
207
+ function drawGradientBackground(ctx, width, height, colors) {
208
+ const gradient = ctx.createLinearGradient(0, 0, 0, height);
209
+ colors.forEach((color, i) => {
210
+ gradient.addColorStop(i / (colors.length - 1), color);
211
+ });
212
+ ctx.fillStyle = gradient;
213
+ ctx.fillRect(0, 0, width, height);
214
+ }
215
+ /**
216
+ * Draws a subtle radial vignette (darkens corners for depth).
217
+ */
218
+ function drawVignette(ctx, width, height) {
219
+ const gradient = ctx.createRadialGradient(width / 2, height / 2, height * 0.25, width / 2, height / 2, height * 0.85);
220
+ gradient.addColorStop(0, 'rgba(0,0,0,0)');
221
+ gradient.addColorStop(1, 'rgba(0,0,0,0.55)');
222
+ ctx.fillStyle = gradient;
223
+ ctx.fillRect(0, 0, width, height);
224
+ }
225
+ /**
226
+ * Draws a subtle film-grain noise overlay for tactile texture.
227
+ */
228
+ function drawGrain(ctx, width, height) {
229
+ // Use a seeded-ish approach for performance — draw sparse random pixels
230
+ ctx.save();
231
+ ctx.globalAlpha = 0.035;
232
+ const grainSize = 1.5;
233
+ const density = 0.08; // fraction of pixels covered
234
+ const totalPixels = Math.floor((width * height) * density);
235
+ for (let i = 0; i < totalPixels; i++) {
236
+ const x = Math.random() * width;
237
+ const y = Math.random() * height;
238
+ const brightness = Math.random() > 0.5 ? 255 : 0;
239
+ ctx.fillStyle = `rgb(${brightness},${brightness},${brightness})`;
240
+ ctx.fillRect(x, y, grainSize, grainSize);
241
+ }
242
+ ctx.restore();
243
+ }
244
+ /**
245
+ * Applies letter spacing by drawing characters individually.
246
+ */
247
+ function drawTextWithSpacing(ctx, text, x, y, letterSpacing, textAlignment) {
248
+ if (letterSpacing === 0) {
249
+ ctx.fillText(text, x, y);
250
+ return;
251
+ }
252
+ const chars = text.split('');
253
+ let totalWidth = 0;
254
+ for (const ch of chars) {
255
+ totalWidth += ctx.measureText(ch).width + letterSpacing;
256
+ }
257
+ totalWidth -= letterSpacing;
258
+ let startX = x;
259
+ if (textAlignment === 'center')
260
+ startX = x - totalWidth / 2;
261
+ else if (textAlignment === 'right')
262
+ startX = x - totalWidth;
263
+ let curX = startX;
264
+ for (const ch of chars) {
265
+ ctx.fillText(ch, curX, y);
266
+ curX += ctx.measureText(ch).width + letterSpacing;
267
+ }
268
+ }
269
+ function generateImage(config) {
270
+ // Render at 2× resolution for crisp Retina/HDR output
271
+ const scale = 2;
272
+ const canvasWidth = config.width * scale;
273
+ const canvasHeight = config.height * scale;
274
+ const canvas = (0, canvas_1.createCanvas)(canvasWidth, canvasHeight);
275
+ const ctx = canvas.getContext('2d');
276
+ // Scale everything up 2×
277
+ ctx.scale(scale, scale);
278
+ const w = config.width;
279
+ const h = config.height;
280
+ // ── Background ──────────────────────────────────────────────────────────────
281
+ if (config.useGradient && config.gradientColors.length >= 2) {
282
+ drawGradientBackground(ctx, w, h, config.gradientColors);
283
+ }
284
+ else {
285
+ ctx.fillStyle = config.backgroundColor;
286
+ ctx.fillRect(0, 0, w, h);
287
+ }
288
+ // ── Vignette (before text) ───────────────────────────────────────────────────
289
+ if (config.enableVignette) {
290
+ drawVignette(ctx, w, h);
291
+ }
292
+ // ── Text rendering ───────────────────────────────────────────────────────────
293
+ const fontString = `${config.fontStyle} ${config.fontWeight} ${config.fontSize}px "${config.fontFamily}"`;
294
+ ctx.font = fontString;
295
+ ctx.fillStyle = config.textColor;
296
+ ctx.textBaseline = 'alphabetic';
297
+ const maxTextWidth = w - config.padding * 2;
298
+ const lines = wrapText(ctx, config.text, maxTextWidth);
299
+ const lineHeightPx = config.fontSize * config.lineHeight;
300
+ const totalTextHeight = lines.length * lineHeightPx;
301
+ // Compute Y start based on vertical alignment
302
+ let startY;
303
+ switch (config.verticalAlignment) {
304
+ case 'top':
305
+ startY = config.padding + config.fontSize;
306
+ break;
307
+ case 'bottom':
308
+ startY = h - config.padding - totalTextHeight + config.fontSize;
309
+ break;
310
+ default: // middle
311
+ startY = (h - totalTextHeight) / 2 + config.fontSize;
312
+ }
313
+ // Compute X anchor based on text alignment
314
+ let anchorX;
315
+ switch (config.textAlignment) {
316
+ case 'left':
317
+ ctx.textAlign = 'left';
318
+ anchorX = config.padding;
319
+ break;
320
+ case 'right':
321
+ ctx.textAlign = 'right';
322
+ anchorX = w - config.padding;
323
+ break;
324
+ default: // center
325
+ ctx.textAlign = 'center';
326
+ anchorX = w / 2;
327
+ }
328
+ for (let i = 0; i < lines.length; i++) {
329
+ const lineY = startY + i * lineHeightPx;
330
+ if (config.letterSpacing !== 0) {
331
+ ctx.textAlign = 'left'; // override — we handle alignment manually
332
+ drawTextWithSpacing(ctx, lines[i], anchorX, lineY, config.letterSpacing, config.textAlignment);
333
+ }
334
+ else {
335
+ ctx.fillText(lines[i], anchorX, lineY);
336
+ }
337
+ }
338
+ // ── Film grain (on top of everything) ───────────────────────────────────────
339
+ if (config.enableGrain) {
340
+ drawGrain(ctx, w, h);
341
+ }
342
+ // ── Export ───────────────────────────────────────────────────────────────────
343
+ if (config.outputFormat === 'jpeg') {
344
+ return canvas.toBuffer('image/jpeg', { quality: config.jpegQuality / 100 });
345
+ }
346
+ return canvas.toBuffer('image/png');
347
+ }
348
+ // ─── n8n Node ──────────────────────────────────────────────────────────────────
349
+ class TextToImage {
350
+ constructor() {
351
+ this.description = {
352
+ displayName: 'Text to Image',
353
+ name: 'textToImage',
354
+ icon: 'file:texttoimage.svg',
355
+ group: ['transform'],
356
+ version: 1,
357
+ subtitle: '={{$parameter["template"] !== "custom" ? $parameter["template"] : $parameter["text"].slice(0,30)}}',
358
+ description: 'Generate HDR-quality motivation images from text — perfect for Instagram posts',
359
+ defaults: {
360
+ name: 'Text to Image',
361
+ },
362
+ inputs: ['main'],
363
+ outputs: ['main'],
364
+ properties: [
365
+ // ── Template ────────────────────────────────────────────────────────
366
+ {
367
+ displayName: 'Template',
368
+ name: 'template',
369
+ type: 'options',
370
+ options: [
371
+ { name: '🎨 Custom (Manual Settings)', value: 'custom' },
372
+ { name: '⚫ Dark Minimal', value: 'dark_minimal' },
373
+ { name: '🤍 Light Elegant', value: 'light_elegant' },
374
+ { name: '💜 Vibrant Purple', value: 'vibrant_purple' },
375
+ { name: '✨ Golden Hour', value: 'golden_hour' },
376
+ { name: '🩵 Arctic Clean', value: 'arctic_clean' },
377
+ { name: '🌑 Midnight Blue', value: 'midnight_blue' },
378
+ ],
379
+ default: 'dark_minimal',
380
+ description: 'Quick-select a visual style. All settings can be overridden below.',
381
+ },
382
+ // ── Text / Content ───────────────────────────────────────────────────
383
+ {
384
+ displayName: 'Text',
385
+ name: 'text',
386
+ type: 'string',
387
+ default: 'The secret of getting ahead is getting started.',
388
+ typeOptions: { rows: 4 },
389
+ description: 'Text to render. Use \\n for new lines.',
390
+ required: true,
391
+ },
392
+ {
393
+ displayName: 'Generate Multiple Images',
394
+ name: 'generateMultiple',
395
+ type: 'boolean',
396
+ default: false,
397
+ description: 'Whether to generate one image per item in a JSON array of strings provided in the Text field',
398
+ },
399
+ // ── Canvas Size ─────────────────────────────────────────────────────
400
+ {
401
+ displayName: 'Canvas Width (px)',
402
+ name: 'width',
403
+ type: 'number',
404
+ default: 1080,
405
+ typeOptions: { minValue: 100, maxValue: 8000 },
406
+ description: 'Output image width in pixels (Instagram square = 1080)',
407
+ },
408
+ {
409
+ displayName: 'Canvas Height (px)',
410
+ name: 'height',
411
+ type: 'number',
412
+ default: 1080,
413
+ typeOptions: { minValue: 100, maxValue: 8000 },
414
+ description: 'Output image height in pixels (Instagram square = 1080, portrait = 1350)',
415
+ },
416
+ // ── Background ──────────────────────────────────────────────────────
417
+ {
418
+ displayName: 'Background Color',
419
+ name: 'backgroundColor',
420
+ type: 'color',
421
+ default: '#0D0D0D',
422
+ description: 'Plain background fill color (ignored when template uses a gradient)',
423
+ displayOptions: { show: { template: ['custom'] } },
424
+ },
425
+ {
426
+ displayName: 'Use Gradient Background',
427
+ name: 'useGradient',
428
+ type: 'boolean',
429
+ default: false,
430
+ description: 'Whether to use a vertical gradient instead of a solid background',
431
+ displayOptions: { show: { template: ['custom'] } },
432
+ },
433
+ {
434
+ displayName: 'Gradient Color (Top)',
435
+ name: 'gradientColorTop',
436
+ type: 'color',
437
+ default: '#1A0533',
438
+ displayOptions: { show: { template: ['custom'], useGradient: [true] } },
439
+ },
440
+ {
441
+ displayName: 'Gradient Color (Bottom)',
442
+ name: 'gradientColorBottom',
443
+ type: 'color',
444
+ default: '#6B21A8',
445
+ displayOptions: { show: { template: ['custom'], useGradient: [true] } },
446
+ },
447
+ // ── Typography ──────────────────────────────────────────────────────
448
+ {
449
+ displayName: 'Font Family',
450
+ name: 'fontFamily',
451
+ type: 'options',
452
+ options: [
453
+ { name: 'Inter', value: 'Inter' },
454
+ { name: 'Playfair Display', value: 'Playfair Display' },
455
+ { name: 'Oswald', value: 'Oswald' },
456
+ { name: 'Montserrat', value: 'Montserrat' },
457
+ { name: 'System Sans-Serif', value: 'sans-serif' },
458
+ ],
459
+ default: 'Inter',
460
+ displayOptions: { show: { template: ['custom'] } },
461
+ },
462
+ {
463
+ displayName: 'Font Size (px)',
464
+ name: 'fontSize',
465
+ type: 'number',
466
+ default: 72,
467
+ typeOptions: { minValue: 8, maxValue: 400 },
468
+ displayOptions: { show: { template: ['custom'] } },
469
+ },
470
+ {
471
+ displayName: 'Font Weight',
472
+ name: 'fontWeight',
473
+ type: 'options',
474
+ options: [
475
+ { name: 'Normal', value: 'normal' },
476
+ { name: 'Bold', value: 'bold' },
477
+ ],
478
+ default: 'bold',
479
+ displayOptions: { show: { template: ['custom'] } },
480
+ },
481
+ {
482
+ displayName: 'Font Style',
483
+ name: 'fontStyle',
484
+ type: 'options',
485
+ options: [
486
+ { name: 'Normal', value: 'normal' },
487
+ { name: 'Italic', value: 'italic' },
488
+ ],
489
+ default: 'normal',
490
+ displayOptions: { show: { template: ['custom'] } },
491
+ },
492
+ {
493
+ displayName: 'Text Color',
494
+ name: 'textColor',
495
+ type: 'color',
496
+ default: '#FFFFFF',
497
+ displayOptions: { show: { template: ['custom'] } },
498
+ },
499
+ // ── Layout ──────────────────────────────────────────────────────────
500
+ {
501
+ displayName: 'Text Alignment',
502
+ name: 'textAlignment',
503
+ type: 'options',
504
+ options: [
505
+ { name: 'Center', value: 'center' },
506
+ { name: 'Left', value: 'left' },
507
+ { name: 'Right', value: 'right' },
508
+ ],
509
+ default: 'center',
510
+ displayOptions: { show: { template: ['custom'] } },
511
+ },
512
+ {
513
+ displayName: 'Vertical Alignment',
514
+ name: 'verticalAlignment',
515
+ type: 'options',
516
+ options: [
517
+ { name: 'Middle', value: 'middle' },
518
+ { name: 'Top', value: 'top' },
519
+ { name: 'Bottom', value: 'bottom' },
520
+ ],
521
+ default: 'middle',
522
+ displayOptions: { show: { template: ['custom'] } },
523
+ },
524
+ {
525
+ displayName: 'Line Height',
526
+ name: 'lineHeight',
527
+ type: 'number',
528
+ default: 1.4,
529
+ typeOptions: { minValue: 0.5, maxValue: 4, numberPrecision: 2 },
530
+ description: 'Line height multiplier (1.4 = 140% of font size)',
531
+ displayOptions: { show: { template: ['custom'] } },
532
+ },
533
+ {
534
+ displayName: 'Letter Spacing (px)',
535
+ name: 'letterSpacing',
536
+ type: 'number',
537
+ default: 0,
538
+ typeOptions: { minValue: -10, maxValue: 50 },
539
+ displayOptions: { show: { template: ['custom'] } },
540
+ },
541
+ {
542
+ displayName: 'Padding (px)',
543
+ name: 'padding',
544
+ type: 'number',
545
+ default: 80,
546
+ typeOptions: { minValue: 0, maxValue: 500 },
547
+ description: 'Inner padding from image edges to text',
548
+ displayOptions: { show: { template: ['custom'] } },
549
+ },
550
+ // ── Visual Effects ──────────────────────────────────────────────────
551
+ {
552
+ displayName: 'Vignette Effect',
553
+ name: 'enableVignette',
554
+ type: 'boolean',
555
+ default: true,
556
+ description: 'Whether to add a subtle darkening at the corners for depth',
557
+ displayOptions: { show: { template: ['custom'] } },
558
+ },
559
+ {
560
+ displayName: 'Film Grain',
561
+ name: 'enableGrain',
562
+ type: 'boolean',
563
+ default: false,
564
+ description: 'Whether to add a fine noise texture for a premium tactile feel',
565
+ displayOptions: { show: { template: ['custom'] } },
566
+ },
567
+ // ── Output ───────────────────────────────────────────────────────────
568
+ {
569
+ displayName: 'Output Format',
570
+ name: 'outputFormat',
571
+ type: 'options',
572
+ options: [
573
+ { name: 'PNG (Lossless)', value: 'png' },
574
+ { name: 'JPEG (Smaller File)', value: 'jpeg' },
575
+ ],
576
+ default: 'png',
577
+ },
578
+ {
579
+ displayName: 'JPEG Quality',
580
+ name: 'jpegQuality',
581
+ type: 'number',
582
+ default: 95,
583
+ typeOptions: { minValue: 1, maxValue: 100 },
584
+ description: 'Quality 1–100 (95+ recommended for Instagram)',
585
+ displayOptions: { show: { outputFormat: ['jpeg'] } },
586
+ },
587
+ {
588
+ displayName: 'Output Binary Field Name',
589
+ name: 'outputFieldName',
590
+ type: 'string',
591
+ default: 'image',
592
+ description: 'Name of the binary property in the output item that contains the generated image',
593
+ },
594
+ ],
595
+ };
596
+ }
597
+ async execute() {
598
+ const items = this.getInputData();
599
+ const returnData = [];
600
+ for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
601
+ try {
602
+ // ── Read parameters ─────────────────────────────────────────────
603
+ const templateName = this.getNodeParameter('template', itemIndex);
604
+ const rawText = this.getNodeParameter('text', itemIndex);
605
+ const generateMultiple = this.getNodeParameter('generateMultiple', itemIndex);
606
+ const width = this.getNodeParameter('width', itemIndex);
607
+ const height = this.getNodeParameter('height', itemIndex);
608
+ const outputFormat = this.getNodeParameter('outputFormat', itemIndex);
609
+ const jpegQuality = this.getNodeParameter('jpegQuality', itemIndex, 95);
610
+ const outputFieldName = this.getNodeParameter('outputFieldName', itemIndex);
611
+ // ── Resolve config (template vs custom) ─────────────────────────
612
+ let config;
613
+ if (templateName !== 'custom' && TEMPLATES[templateName]) {
614
+ const tpl = TEMPLATES[templateName];
615
+ config = {
616
+ text: rawText,
617
+ width,
618
+ height,
619
+ backgroundColor: tpl.backgroundColor,
620
+ useGradient: tpl.useGradient,
621
+ gradientColors: tpl.gradientColors,
622
+ fontFamily: tpl.fontFamily,
623
+ fontSize: tpl.fontSize,
624
+ fontWeight: tpl.fontWeight,
625
+ fontStyle: tpl.fontStyle,
626
+ textColor: tpl.textColor,
627
+ textAlignment: tpl.textAlignment,
628
+ verticalAlignment: tpl.verticalAlignment,
629
+ lineHeight: tpl.lineHeight,
630
+ letterSpacing: tpl.letterSpacing,
631
+ padding: tpl.padding,
632
+ enableVignette: tpl.enableVignette,
633
+ enableGrain: tpl.enableGrain,
634
+ outputFormat,
635
+ jpegQuality,
636
+ };
637
+ }
638
+ else {
639
+ const useGradient = this.getNodeParameter('useGradient', itemIndex, false);
640
+ const gradientColorTop = this.getNodeParameter('gradientColorTop', itemIndex, '#1A0533');
641
+ const gradientColorBottom = this.getNodeParameter('gradientColorBottom', itemIndex, '#6B21A8');
642
+ config = {
643
+ text: rawText,
644
+ width,
645
+ height,
646
+ backgroundColor: this.getNodeParameter('backgroundColor', itemIndex, '#0D0D0D'),
647
+ useGradient,
648
+ gradientColors: useGradient ? [gradientColorTop, gradientColorBottom] : [],
649
+ fontFamily: this.getNodeParameter('fontFamily', itemIndex, 'Inter'),
650
+ fontSize: this.getNodeParameter('fontSize', itemIndex, 72),
651
+ fontWeight: this.getNodeParameter('fontWeight', itemIndex, 'bold'),
652
+ fontStyle: this.getNodeParameter('fontStyle', itemIndex, 'normal'),
653
+ textColor: this.getNodeParameter('textColor', itemIndex, '#FFFFFF'),
654
+ textAlignment: this.getNodeParameter('textAlignment', itemIndex, 'center'),
655
+ verticalAlignment: this.getNodeParameter('verticalAlignment', itemIndex, 'middle'),
656
+ lineHeight: this.getNodeParameter('lineHeight', itemIndex, 1.4),
657
+ letterSpacing: this.getNodeParameter('letterSpacing', itemIndex, 0),
658
+ padding: this.getNodeParameter('padding', itemIndex, 80),
659
+ enableVignette: this.getNodeParameter('enableVignette', itemIndex, true),
660
+ enableGrain: this.getNodeParameter('enableGrain', itemIndex, false),
661
+ outputFormat,
662
+ jpegQuality,
663
+ };
664
+ }
665
+ // ── Single or batch generation ──────────────────────────────────
666
+ const textsToRender = [];
667
+ if (generateMultiple) {
668
+ let parsed;
669
+ try {
670
+ parsed = JSON.parse(rawText);
671
+ }
672
+ catch (_) {
673
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'When "Generate Multiple Images" is enabled, the Text field must be a valid JSON array of strings (e.g. ["Quote 1", "Quote 2"]).', { itemIndex });
674
+ }
675
+ if (!Array.isArray(parsed) || !parsed.every((t) => typeof t === 'string')) {
676
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'The Text field must be a JSON array of strings when "Generate Multiple Images" is enabled.', { itemIndex });
677
+ }
678
+ textsToRender.push(...parsed);
679
+ }
680
+ else {
681
+ textsToRender.push(rawText);
682
+ }
683
+ // ── Generate each image ─────────────────────────────────────────
684
+ for (let imgIndex = 0; imgIndex < textsToRender.length; imgIndex++) {
685
+ const imageConfig = { ...config, text: textsToRender[imgIndex] };
686
+ const buffer = generateImage(imageConfig);
687
+ const mimeType = outputFormat === 'jpeg' ? 'image/jpeg' : 'image/png';
688
+ const ext = outputFormat === 'jpeg' ? 'jpg' : 'png';
689
+ const fileName = textsToRender.length > 1
690
+ ? `image_${itemIndex + 1}_${imgIndex + 1}.${ext}`
691
+ : `image_${itemIndex + 1}.${ext}`;
692
+ const binaryData = await this.helpers.prepareBinaryData(buffer, fileName, mimeType);
693
+ returnData.push({
694
+ json: {
695
+ fileName,
696
+ width: config.width,
697
+ height: config.height,
698
+ template: templateName,
699
+ text: textsToRender[imgIndex],
700
+ outputFormat,
701
+ index: imgIndex,
702
+ },
703
+ binary: {
704
+ [outputFieldName]: binaryData,
705
+ },
706
+ pairedItem: { item: itemIndex },
707
+ });
708
+ }
709
+ }
710
+ catch (error) {
711
+ if (this.continueOnFail()) {
712
+ returnData.push({
713
+ json: { error: error.message },
714
+ pairedItem: { item: itemIndex },
715
+ });
716
+ continue;
717
+ }
718
+ throw error;
719
+ }
720
+ }
721
+ return [returnData];
722
+ }
723
+ }
724
+ exports.TextToImage = TextToImage;
725
+ //# sourceMappingURL=TextToImage.node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TextToImage.node.js","sourceRoot":"","sources":["../../../nodes/TextToImage/TextToImage.node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60" fill="none">
2
+ <!-- Background rounded rect -->
3
+ <rect width="60" height="60" rx="12" fill="#1A1A2E"/>
4
+ <!-- Image frame icon -->
5
+ <rect x="8" y="12" width="44" height="36" rx="4" stroke="#7C3AED" stroke-width="2.5" fill="none"/>
6
+ <!-- Mountain/landscape shape inside frame -->
7
+ <path d="M8 38 L20 24 L30 32 L38 20 L52 38 Z" fill="#7C3AED" opacity="0.3"/>
8
+ <!-- Sun circle -->
9
+ <circle cx="44" cy="22" r="4" fill="#F5C842" opacity="0.9"/>
10
+ <!-- "T" text overlay -->
11
+ <text x="30" y="34" font-family="sans-serif" font-weight="bold" font-size="16" fill="white" text-anchor="middle" dominant-baseline="middle" opacity="0.9">T</text>
12
+ </svg>
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "n8n-nodes-text-to-image",
3
+ "version": "1.0.0",
4
+ "description": "n8n node to generate HDR-quality motivation images from text — perfect for Instagram posts",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "image",
8
+ "text-to-image",
9
+ "canvas",
10
+ "motivation",
11
+ "instagram"
12
+ ],
13
+ "license": "MIT",
14
+ "homepage": "https://github.com/ngquocvu/n8n-nodes-text-to-image",
15
+ "author": {
16
+ "name": "ngquocvu"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/ngquocvu/n8n-nodes-text-to-image.git"
21
+ },
22
+ "main": "dist/nodes/TextToImage/TextToImage.node.js",
23
+ "scripts": {
24
+ "prebuild": "rimraf dist",
25
+ "build": "tsc && gulp build:icons",
26
+ "dev": "tsc --watch",
27
+ "format": "prettier nodes --write",
28
+ "lint": "eslint nodes --ext .ts",
29
+ "lintfix": "eslint nodes --ext .ts --fix",
30
+ "download-fonts": "node scripts/download-fonts.js"
31
+ },
32
+ "files": [
33
+ "dist"
34
+ ],
35
+ "n8n": {
36
+ "n8nNodesApiVersion": 1,
37
+ "credentials": [],
38
+ "nodes": [
39
+ "dist/nodes/TextToImage/TextToImage.node.js"
40
+ ]
41
+ },
42
+ "dependencies": {
43
+ "canvas": "^2.11.2",
44
+ "sharp": "^0.33.4"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^20.11.0",
48
+ "@typescript-eslint/parser": "^6.21.0",
49
+ "eslint-plugin-n8n-nodes-base": "^1.16.2",
50
+ "gulp": "^4.0.2",
51
+ "n8n-workflow": "*",
52
+ "prettier": "^3.2.4",
53
+ "rimraf": "^5.0.5",
54
+ "typescript": "^5.3.3"
55
+ }
56
+ }