NodeJS : Rotate a base64 image and save it - node.js

I want to make a function to rotate at 90° an base64 image. I tried to use Image and Canvas but it returns Error.
Here is the Code :
exports.Test64 = (req, res, next) => {
console.log("TEST UPS")
upsres.find().then(
(ups) => {
console.log('YES');
console.log(ups[0].b64Image); // it works but after i don't think
var image = new Image();
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
image.src = ups[0].b64Image;
canvas.width = image.height;
canvas.height = image.width;
ctx.rotate(-90 * Math.PI / 180);
ctx.translate(-canvas.heigt,0);
ctx.drawImage(image, 0, 0);
dataURL= canvas.toDataURL();
console.log(dataURL);
res.status(200).json(dataURL);
);
}
).catch(
(error) => {
res.status(400).json({
error:'Not Working'
});
}
);
};
Someone have an answer why it doesn't work ? :)
Thanks to everyone

We can use jimp libray to get rotate image.
Please use following code
var Jimp = require('jimp');
const base64str ="R0lG"//
const buf = Buffer.from(base64str, 'base64');
const image = await Jimp.read(buf);
// rotate Function having a rotation as 90
image.rotate(90).getBase64(Jimp.MIME_JPEG, function (err, src) {
console.log("rb is \n")
console.log(src);
})

exports.Testups = async (req, res, next) => {
try {
let ups = await upsres.find()
const base64str = ups[0].b64Image;
const buf = Buffer.from(base64str, 'base64');
let image = await Jimp.read(buf);
// rotate Function having a rotation as 90
image.rotate(-90).getBase64(Jimp.MIME_PNG, function (err, src) {
res.status(200).json(src);
})
}
catch (e) { }
};
That's Working :)

Related

How to avoid multi-byte file path bug of node-canvas's loadImage?

node-canvas (2.7.0) has bug which cannot load image from the path includes multi-bytes characters.
const { loadImage } = require('canvas');
const image = await loadImage('/Users/ユーザ名/Documents/test.png');
Such case causes "File not found" error.
How to avoid this?
We should wait official bug fix, but following works as work-around:
const { Image } = require('canvas');
const fs = require('fs');
const image = await new Promise((res, rej) => {
fs.readFile('/Users/ユーザ名/Documents/test.png', (err, buf) => {
if (err) rej(err);
const img = new Image();
img.onload = () => { res(img) };
img.onerror = (err) => { rej(err) };
img.src = buf;
});
});

NodeJs synchronous child process

I'm trying to build a certificate generation module using nodeJS.
The api to create certificate is as follows
// Create certificate
const express = require('express');
const router = express.Router();
const { createCanvas } = require('canvas')
const fs = require("fs");
const { decodeBase64Image } = require('../helper/certificatehelper');
router.post('/imageadd', async (req, res, next) => {
try {
const { name } = req.body;
const width = 1920
const height = 1080
const canvas = createCanvas(width, height)
const context = canvas.getContext('2d')
context.fillStyle = "white";
context.fillRect(0, 0, width, height)
context.fillStyle = '#000'
context.font = "72px Arial";
context.textAlign = "center";
context.fillText(name, 900, 500);
const dataurl = canvas.toDataURL();
const decodedImg = decodeBase64Image(dataurl);
const imageBuffer = decodedImg.data;
fs.writeFileSync(`./src/images/image1.png`, imageBuffer);
fs.readFile('./src/images/image1.png', function(err, data) {
if (err) throw err; // Fail if the file can't be read.
res.writeHead(200, {'Content-Type': 'image/jpeg'});
res.end(data); // Send the file data to the browser.
});
res.json({ data: respArray, success: true, msg: 'Certificate generated' });
} catch (error) {
res.json({ success: false, msg: error.message });
}
})
module.exports = router;
The problem I'm facing is, If multiple request are send in parallel how do I generate one certificate at a time (synchronized).
Other requests need to wait till the certificate is generated for previous request.
The certificates should be generated in a separate process from the main app process.
How do I solve the above given problem.

Jimp.measureTextHeight exception:errorTypeError:Cannot read property 'lineHeight' of undefined

let Jimp = require('jimp');
var sizeOf = require('image-size');
var mergeImg =require('merge-img');
var dimensions = sizeOf('image/wall.png');
console.log(dimensions.width, dimensions.height);
let image = new Jimp(dimensions.width, dimensions.height, 'green', (err, image) => {
if (err) throw err
})
let message = 'Here the text is being added in the bottom center of the image.'
let x = 10
let y = 10
try{
var textHeight= Jimp.measureTextHeight(Jimp.FONT_SANS_32_BLACK, 'Some string', 100);
console.log("text height -"+textHeight);
}catch(ex)
{
console.log("error" + ex)
}
Jimp.loadFont(Jimp.FONT_SANS_16_BLACK)
.then(font => {
image.print(font, x, y, message,dimensions.width)
return image
}).then(image => {
let file = `new_name.${image.getExtension()}`
return image.write("processed-image/out.png",function(err, file){console.log(err)}) // save
})
Jimp function measureTextHeight throwing exception. I am measuring text height on basis of width, to create an image and write text on it.
First argument you are passing wrong. Please see updated code.
const Jimp = require('jimp');
const sizeOf = require('image-size');
const dimensions = sizeOf('public/images/wall.jpeg');
const message = 'Here the text is being added in the bottom center of the image.'
const x = 10
const y = 10
new Jimp(dimensions.width, dimensions.height, 'green', (error, image) => {
if (error) throw error;
Jimp.loadFont(Jimp.FONT_SANS_16_BLACK)
.then(font => {
image.print(font, x, y, message, dimensions.width)
const measureTextHeight = Jimp.measureTextHeight(font, 'Some string', 100);
console.log('measureTextHeight =>', measureTextHeight);
return image
}).then(image => image.write("public/images/out.png", (error, file) => {
if (error) throw error;
return file;
}))
});

Nodejs and pdfKit and qr-image

I am working on a small project that works with generating pdf's in node and express, l am using the pdfkit npm module but to generate a pdf. l am also using the qr-image npm module to generate the QR code image but l am struggling to attach the generated the QR code to the pdf. This is the code that l am using to generate the QR code:
var file = "./"+certificationnumber+".png";
var qr_svg = qr.image(file, { type: 'png' });
qr_svg.pipe(require('fs').createWriteStream(file));
And this is how l am trying attache it to the pdf using pdfkit npm module:
doc.image(qr_svg.pipe(require('fs').createWriteStream(file)))
since every pdf has a unique QR code.
Thanks in advance
I exactly have the same problem where get the PDF in 64 bit encoded form and i have to attach qr image to it.
Below is the code snippet.
PDFDocument = require('pdfkit');
const base64 = require('base64-stream');
const doc = new PDFDocument();
doc.image('test.jpeg', {
fit: [250, 300],
align: 'center',
valign: 'center'
});
const finalString = pdf.response;
// contains the base64 string
//logic to append the qr image.
const stream = doc.pipe(base64.encode());
stream.on('data', chunk => finalString += chunk);
stream.on('end', () => {
// the stream is at its end, so push the resulting base64 string to the response
const backToPDF = new Buffer(finalString, 'base64');
read.writeFileSync('./Report.pdf', backToPDF);
});
doc.end();
Here is the solution I have come up with. Using pdf-lib, express and qrcode
const fs = require("fs");
const path = require("path");
const express = require("express");
const http = require("http");
const cors = require("cors");
const multer = require("multer");
const app = express();
const server = http.createServer(app);
const { PDFDocument } = require("pdf-lib");
const QRCode = require("qrcode");
const Joi = require("joi");
const { readFile, writeFile, unlink } = require("fs/promises");
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
const dir = "public";
const subDirectory = "public/uploads";
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
fs.mkdirSync(subDirectory);
}
const generateQRCodeImage = async function (filePath, text, color) {
return new Promise((resolve, reject) => {
QRCode.toFile(
filePath,
text,
{
color,
},
function (err) {
if (err) return reject(err);
resolve();
}
);
});
};
const run = async ({
width,
height,
x,
y,
pathToImage,
pathToPDF,
pathToOutputPDF,
qrCodeText,
qrDarkColor = "#000",
qrLightColor = "#0000",
}) => {
await generateQRCodeImage(pathToImage, qrCodeText, {
dark: qrDarkColor,
light: qrLightColor,
});
const pdfDoc = await PDFDocument.load(await readFile(pathToPDF));
const img = await pdfDoc.embedPng(await readFile(pathToImage));
Array.from({ length: pdfDoc.getPageCount() }).forEach((_, index) => {
let imagePage = pdfDoc.getPage(index);
imagePage.drawImage(img, {
x,
y,
width,
height,
});
});
const pdfBytes = await pdfDoc.save();
await writeFile(pathToOutputPDF, pdfBytes);
};
const pdfFileFilter = function (req, file, callback) {
const ext = path.extname(file.originalname);
if (ext !== ".pdf") {
return callback("This extension is not supported");
}
callback(null, true);
};
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "public/uploads");
},
filename: function (req, file, cb) {
cb(
null,
file.fieldname + "-" + Date.now() + path.extname(file.originalname)
);
},
});
const filesToProcess = multer({ storage: storage, fileFilter: pdfFileFilter });
const schema = Joi.object({
width: Joi.string().regex(/^\d+$/).required(),
height: Joi.string().regex(/^\d+$/).required(),
x: Joi.string().regex(/^\d+$/).required(),
y: Joi.string().regex(/^\d+$/).required(),
qrCodeData: Joi.string().required(),
qrDarkColor: Joi.string(),
qrLightColor: Joi.string(),
});
app.post("/addQrToPdf", filesToProcess.array("file", 1), async (req, res) => {
const pathToImage = "public/uploads/" + Date.now() + "temp-qr.png";
const pathToOutputPDF = "public/uploads/" + Date.now() + "-output.pdf";
if (req.files) {
const [file] = req.files;
if (!file) {
res.send("No file detected on input");
}
const pathToPDF = file.path;
try {
const { width, height, x, y, qrCodeData, qrDarkColor, qrLightColor } =
await schema.validateAsync(req.body);
await run({
width: +width,
height: +height,
x: +x,
y: +y,
qrDarkColor,
qrLightColor,
qrCodeText: qrCodeData,
pathToImage,
pathToOutputPDF,
pathToPDF,
});
const pdfFile = await readFile(pathToOutputPDF);
res.contentType("application/pdf");
res.send(pdfFile);
await unlink(pathToImage);
await unlink(pathToPDF);
await unlink(pathToOutputPDF);
} catch (error) {
try {
await unlink(pathToPDF);
await unlink(pathToImage);
} catch (err) {
console.warn(err);
}
res.send(error);
}
}
});
server.listen(4000, () => console.log("listening on port *:4000"));
I had the same problem.
It looks like it is an async issue.
If you treat the generation of the QR code like a promise and then run the create pdf code, it works.
My code is below (using promise). It should also work using async await
const createPDF = (ticketID) => {
const doc = new pdf
doc.pipe(fs.createWriteStream(`${ticketID}.pdf`))
doc.text('Your Tickets').fontSize(25)
doc.image(`./qrCodes/${ticketID}.png`, {
fit: [250, 300],
align: 'center',
valign: 'center'
});
doc.end()
}
const createQRCode = (ticketID) => {
QR.toFile(`./qrCodes/${ticketID}.png`, String(ticket), {width: 250}).then(qr => {
createPDF(ticketID)
})
}
I use a version without writing to the disk, using the svg path output, extract the path from the qrcode data and render it into the pdf
let s = await toString('hallo2', {
type: 'svg'
})
// extract the 2nd path element
let path = Array.from(s.matchAll(/d="(.*?)"/gm))[1][1]
let doc = new PDFDocument({ size: 'A4' });
doc.scale(8)
.path(data)
.stroke()
doc.pipe(fs.createWriteStream('out2.pdf', {}));
doc.end()

Create a animated Gif from an array of url images in NodeJs

I have an array of urls of image which could be of different type (png, jpg) and I would like with it to build a gif, all in nodeJS.
Since I'm very new to this language I'm struggling a bit with it, any leads, ideas ?
I looked at gifencoder
with this exemple :
var GIFEncoder = require('gifencoder');
var encoder = new GIFEncoder(854, 480);
var pngFileStream = require('png-file-stream');
var fs = require('fs');
pngFileStream('test/**/frame?.png')
.pipe(encoder.createWriteStream({ repeat: -1, delay: 500, quality: 10 }))
.pipe(fs.createWriteStream('myanimated.gif'));
What I get, it looks for png files maching the expression.
Since I have an array of urls of different types of images, should I use fs.createReadStream ?
Thanks
const GIFEncoder = require("gif-encoder-2");
const { createCanvas, Image } = require("canvas");
const { createWriteStream, readdir } = require("fs");
const { promisify } = require("util");
const path = require("path");
const fs = require("fs");
var outputDir = path.join(__dirname, "/output")
const createGif = async (fileName, frameURLs) => {
return new Promise(async resolve1 => {
try {
// find the width and height of the image
const [width, height] = await new Promise(resolve2 => {
const image = new Image();
image.onload = () => resolve2([image.width, image.height]);
image.src = frameURLs[0];
});
// base GIF filepath on which algorithm is being used
const dstPath = path.join(__dirname, "/output", `${fileName}.gif`);
// create a write stream for GIF data
const writeStream = createWriteStream(dstPath);
// when stream closes GIF is created so resolve promise
writeStream.on("close", () => {
resolve1(dstPath);
});
// encode with the neuquant algorithm
const encoder = new GIFEncoder(width, height, "neuquant");
// pipe encoder's read stream to our write stream
encoder.createReadStream().pipe(writeStream);
encoder.start();
encoder.setDelay(200);
const canvas = createCanvas(width, height);
const ctx = canvas.getContext("2d");
// draw an image for each file and add frame to encoder
const promisses = frames.map(frame => {
return new Promise(resolve3 => {
const image = new Image();
image.onload = () => {
ctx.drawImage(image, 0, 0);
encoder.addFrame(ctx);
resolve3();
};
image.src = frame; // set the frame url
});
});
// run all the frame promisses
await Promise.all(promisses);
// close the writing stream
writeStream.close();
} catch (error) {
console.error("error");
console.error(error);
throw error;
}
});
};

Resources