UNPKG

n8n-nodes-image-editor-pro

Version:

Advanced image editing node for n8n using Sharp and Canvas

170 lines (169 loc) 6.56 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.imageEditor = imageEditor; const axios_1 = __importDefault(require("axios")); const sharp_1 = __importDefault(require("sharp")); const canvas_1 = require("@napi-rs/canvas"); async function imageEditor({ mode, input, options, }) { var _a, _b; const images = []; if ((_a = input.binaryArray) === null || _a === void 0 ? void 0 : _a.length) { for (const binary of input.binaryArray) { images.push(Buffer.from(binary.data, 'base64')); } } else if (input.binary) { images.push(Buffer.from(input.binary.data, 'base64')); } for (const url of (_b = input.urls) !== null && _b !== void 0 ? _b : []) { const res = await axios_1.default.get(url, { responseType: 'arraybuffer' }); images.push(Buffer.from(res.data)); } if (!images.length) throw new Error('No valid images provided'); switch (mode) { case 'collage': return createCollage(images, options); case 'addText': return addText(images[0], options); case 'addWatermark': return addWatermark(images[0], options); default: throw new Error('Invalid mode'); } } async function createCollage(images, opts) { const { rows, columns, spacing, backgroundColor } = opts; const thumbWidth = 300; const thumbHeight = 300; const canvasWidth = columns * thumbWidth + spacing * (columns - 1); const canvasHeight = rows * thumbHeight + spacing * (rows - 1); const canvas = (0, canvas_1.createCanvas)(canvasWidth, canvasHeight); const ctx = canvas.getContext('2d'); ctx.fillStyle = backgroundColor; ctx.fillRect(0, 0, canvasWidth, canvasHeight); let index = 0; for (let row = 0; row < rows; row++) { for (let col = 0; col < columns; col++) { if (index >= images.length) break; const img = await (0, canvas_1.loadImage)(await (0, sharp_1.default)(images[index]).resize(thumbWidth, thumbHeight).png().toBuffer()); ctx.drawImage(img, col * (thumbWidth + spacing), row * (thumbHeight + spacing)); index++; } } return canvas.toBuffer('image/png'); } async function addText(image, opts) { var _a, _b, _c, _d, _e, _f, _g, _h; const img = await (0, sharp_1.default)(image).ensureAlpha().png().toBuffer(); const loadedImg = await (0, canvas_1.loadImage)(img); const { width, height } = loadedImg; const canvas = (0, canvas_1.createCanvas)(width, height); const ctx = canvas.getContext('2d'); ctx.drawImage(loadedImg, 0, 0); ctx.globalAlpha = (_a = opts.opacity) !== null && _a !== void 0 ? _a : 1; ctx.font = `${opts.fontSize}px sans-serif`; let x = 0; let y = 0; if (typeof opts.position === 'string') { switch (opts.position) { case 'top-left': x = 20; y = opts.fontSize + 20; break; case 'center': x = width / 2; y = height / 2; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; break; case 'bottom-right': x = width - 20; y = height - 20; ctx.textAlign = 'right'; ctx.textBaseline = 'bottom'; break; } } else { x = opts.position.x; y = opts.position.y; } const padding = (_b = opts.shapePadding) !== null && _b !== void 0 ? _b : 20; const shapeWidth = (_c = opts.shapeWidth) !== null && _c !== void 0 ? _c : ctx.measureText(opts.text).width + padding; const shapeHeight = (_d = opts.shapeHeight) !== null && _d !== void 0 ? _d : opts.fontSize + padding; const radius = Math.max(shapeWidth, shapeHeight) / 2; const bgColor = opts.backgroundColor || 'rgba(255,255,255,0.5)'; const borderWidth = (_e = opts.borderWidth) !== null && _e !== void 0 ? _e : 0; const borderColor = opts.borderColor || 'transparent'; let textX = x; let textY = y; switch (opts.textAlignInShape) { case 'top': textY = y - shapeHeight / 2 + opts.fontSize; break; case 'bottom': textY = y + shapeHeight / 2 - opts.fontSize / 2; break; case 'center': textY = y; ctx.textBaseline = 'middle'; break; case 'custom': textX += (_f = opts.textOffsetX) !== null && _f !== void 0 ? _f : 0; textY += (_g = opts.textOffsetY) !== null && _g !== void 0 ? _g : 0; break; } if (opts.backgroundShape === 'circle') { ctx.beginPath(); ctx.arc(x, y - opts.fontSize / 2, radius, 0, Math.PI * 2); ctx.fillStyle = bgColor; ctx.fill(); if (borderWidth > 0) { ctx.lineWidth = borderWidth; ctx.strokeStyle = borderColor; ctx.stroke(); } } else if (opts.backgroundShape === 'square') { const boxX = x - shapeWidth / 2; const boxY = y - shapeHeight / 2; ctx.fillRect(boxX, boxY, shapeWidth, shapeHeight); ctx.fillStyle = bgColor; ctx.fillRect(boxX, boxY, shapeWidth, shapeHeight); if (borderWidth > 0) { ctx.lineWidth = borderWidth; ctx.strokeStyle = borderColor; ctx.strokeRect(boxX, boxY, shapeWidth, shapeHeight); } } else if (opts.backgroundShape === 'rectangle') { const boxX = x - shapeWidth / 2; const boxY = y - shapeHeight / 2; ctx.fillRect(boxX, boxY, shapeWidth, shapeHeight); ctx.fillStyle = bgColor; ctx.fillRect(boxX, boxY, shapeWidth, shapeHeight); if (borderWidth > 0) { ctx.lineWidth = borderWidth; ctx.strokeStyle = borderColor; ctx.strokeRect(boxX, boxY, shapeWidth, shapeHeight); } } ctx.fillStyle = opts.color; ctx.globalAlpha = (_h = opts.opacity) !== null && _h !== void 0 ? _h : 1; ctx.fillText(opts.text, textX, textY); return canvas.toBuffer('image/png'); } async function addWatermark(image, opts) { return addText(image, { text: opts.content, color: '#000000', fontSize: 32, position: opts.position, opacity: opts.opacity, }); }