For my workflow I have integrated DrawThings, the diagram of it looks like:

Steps to reproduce:
- Assuming n8n is in Docker and DrawThings are on the host URL, it should be http://host.docker.internal:7860/sdapi/v1/txt2img. We need to use JSON, not fields, because n8n converts them to strings, and n8n has problems with interpretation. In my case, it’s:
{
"height": 576,
"width": 1024,
"seed": -1,
"prompt": "{{ $json.output.replaceAll('"', '\'').replaceAll('\n', '') }}",
"batch_size": 1
}
- Next, we need to move the Base64 string to the file using the field
images[0]
and put it in the data field. - We save PNG as e.g.
/tmp/{{ $now.format('yyyy-MM-dd_HH-mm-ss') }}.png
- For conversion to WebP, we use a simple script and the SharpJS library executed as:
npm run convert -- {{ $json.fileName }}
// convert.js
const fs = require('fs');
const sharp = require('sharp');
async function convertPngToJpeg(filePath) {
const outputPath = filePath.replace(/\.png$/i, '.webp');
const input = fs.readFileSync(filePath);
const output = await sharp(input).webp().toBuffer();
fs.writeFileSync(outputPath, output);
console.log(`Converted: ${outputPath} end.`);
}
const inputPath = process.argv[2];
if (!inputPath) {
console.error('Usage: node convert.js <path-to-png>');
process.exit(1);
}
convertPngToJpeg(inputPath);
- The next thing is to get the filename from stdout.:
{{ $json.stdout.match(/Converted: (.*) end./)[1] }}
and pass it as filename - The last link is to read WebP, for example, sending it to WordPress (using the filename from the previous step).
Hope it helps or inspires someone to use different tools 🙂
EDIT: I have added watermark – still probably I will need to play a bit with alpha, and sizes:
// convert.js
const fs = require('fs');
const sharp = require('sharp');
async function convertPngToJpeg(filePath) {
const outputPath = filePath.replace(/\.png$/i, '.webp');
const { width, height } = await sharp(filePath).metadata();
const watermark = `
<svg width="${width}" height="${height}">
<style>
.watermark {
fill: rgba(255,255,255,0.4); /* main text color */
font-size: 18px;
font-family: sans-serif;
stroke: rgba(100,100,100,0.4); /* outline color */
stroke-width: 1px; /* thickness of outline */
paint-order: stroke fill; /* ensure stroke is drawn under fill */
}
</style>
<text x="${width - 20}" y="${height - 20}" text-anchor="end" class="watermark">
AI generated
</text>
</svg>
`;
await sharp(filePath)
.composite([{ input: Buffer.from(watermark) }])
.toFile(filePath + '_wm');
const input = fs.readFileSync(filePath + '_wm');
const output = await sharp(input).webp().toBuffer();
fs.writeFileSync(outputPath, output);
console.log(`Converted: ${outputPath} end.`);
}
const inputPath = process.argv[2];
if (!inputPath) {
console.error('Usage: node convert.js <path-to-png>');
process.exit(1);
}
convertPngToJpeg(inputPath);
Because I had to recreate that workflow I spot that some script info is missing – you need to in container:
– npm install sharp
– add to package.json
{
"scripts": {
"convert": "node convert.js"
}
}