Text -> PNG -> ReadStream, all done on the front-end? - javascript

I'm not sure if this is even possible, but here's what I'm trying to do:
Let the user enter some text
Generate a PNG from that text
Upload it to Pinata, which requires it to be in ReadStream format
Do all of this on the front-end
I've managed to accomplish (1) and (2) using html2canvas.
The tricky part is (3). The reason it has to be in ReadStream format is because that's the format Pinata's SDK wants:
const fs = require('fs');
const readableStreamForFile = fs.createReadStream('./yourfile.png');
const options = {
pinataMetadata: {
name: MyCustomName,
keyvalues: {
customKey: 'customValue',
customKey2: 'customValue2'
}
},
pinataOptions: {
cidVersion: 0
}
};
pinata.pinFileToIPFS(readableStreamForFile, options).then((result) => {
//handle results here
console.log(result);
}).catch((err) => {
//handle error here
console.log(err);
});
I realize that this would be no problem to do on the backend with node, but I'd like to do it on the front-end. Is that at all possible? Or am I crazy?
I'm specifically using Vue if that matters.

For anyone interested the solution ended up being using fetch+blob:
const generateImg = async () => {
const canvas = await html2canvas(document.getElementById('hello'));
const img = canvas.toDataURL('image/png');
const res = await fetch(img);
return res.blob();
};
This blob can then be passed into a more manual version of their SDK:
const uploadImg = (blob: Blob) => {
const url = `https://api.pinata.cloud/pinning/pinFileToIPFS`;
const data = new FormData();
data.append('file', blob);
const metadata = JSON.stringify({
name: 'testname',
});
data.append('pinataMetadata', metadata);
const pinataOptions = JSON.stringify({
cidVersion: 0,
});
data.append('pinataOptions', pinataOptions);
return axios
.post(url, data, {
maxBodyLength: 'Infinity' as any, // this is needed to prevent axios from erroring out with large files
headers: {
// #ts-ignore
'Content-Type': `multipart/form-data; boundary=${data._boundary}`,
pinata_api_key: apiKey,
pinata_secret_api_key: apiSecret,
},
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
};

Related

How to convert SVG to PNG or JPG/JPEG files in React.js

How can I convert SVG files to png,jpg or jpeg Files in React.js Because I am trying to send my files to server and server only accepts jpg/jpeg or png. Any help? I only need files in one of these types. I don't need them in url or blob.
The screenshot of file in console
I searched all over the place. There are some but either the solution is for backend or javascript with dom
const [fileImages, setFileImages] = useState<File[]>([]);
const { state } = useAssetReportContext();
const charts = state.chartsList.map(({ url, fileName }) => ({
url,
fileName,
}));
useEffect(() => {
const fetchImages = () => {
charts.map(({ url, fileName }) => {
fetch(url)
.then((response) => response.blob())
.then(
(blob) =>
new File([blob], `${fileName}`, {
type: blob.type,
})
)
.then((file) => {
setFileImages((prev) => [...prev, file]);
});
});
};
fetchImages();
}, [state.chartsList.length]);
You can use 'convert-svg-to-png' library.
This is the npm link
Then import it:
const { convertFile } = require('convert-svg-to-png');
Then use the following code:
(async() => {
const inputFilePath = '/path/to/my-image.svg';
const outputFilePath = await convertFile(inputFilePath);
console.log(outputFilePath);
//=> "/path/to/my-image.png"
})();
Hope it works for you :)

Node js: Download file to memory and pass to library function without saving to disk

The below code is working fine, but I had some code feedback:
"Why download and save the file to disk, only to read it back in memory?"
However, after spending some hours exploring options with Buffer and stream, I just don't seem to be getting anywhere.
const fs = require('fs');
const { PdfData } = require('pdfdataextract');
const axios = require('axios').default;
const getPDFText = async ({ url }) => {
const tmpDir = `${process.cwd()}/my_dir`;
const writer = fs.createWriteStream(`${tmpDir}/document.pdf`);
const response = await axios({
url,
method: 'get',
responseType: 'stream'
});
response.data.pipe(writer);
const text = await new Promise((resolve, reject) => {
writer.on('finish', () => {
const fileData = fs.readFileSync(`${tmpDir}/document.pdf`);
PdfData.extract(fileData, {
get: {
// ...
},
})
.then(resolve)
.catch(reject);
});
writer.on('error', reject);
});
return text;
};
How can I avoid saving the file to disk, and to instead feed it into the PdfData.extract method?
The signature for .extract says it accepts an Uint8Array.
Something like
const {PdfData} = require('pdfdataextract');
const axios = require('axios').default;
async function getPDFText({url}) {
const response = await axios({
url,
method: 'get',
responseType: 'arraybuffer',
});
const pdfUint8Array = new Uint8Array(response.data);
const res = await PdfData.extract(pdfUint8Array, /* ... */);
console.log(res);
return res;
}
could do the trick?

ffmpeg.FS('readFile', 'demo.mp4') error. Check if the path exists

I'm trying to convert recordRTC webm file to mp4 using ffmpeg.js library in nextjs project, during conversion showing this issue
ffmpeg.FS('readFile', 'demo.mp4') error. Check if the path exists
const stopRecording = async () => {
if (recordRef.current) {
let blob = {}
recordRef.current.stopRecording(function(url) {
blob = recordRef.current.getBlob()
});
const webmFile = new File([blob], 'video.webm', {
type: 'video/webm'
})
convertBobToMpeg(webmFile)
}
}
const convertBobToMpeg = async (webmFile) => {
await ffmpeg.load();
await ffmpeg.FS('writeFile', 'video.webm', await fetchFile(webmFile))
ffmpeg.run('-i', 'video.webm', 'demo.mp4');
const data = await ffmpeg.FS('readFile', 'demo.mp4');
setVideo_obj(URL.createObjectURL(new Blob([data.buffer], {
type: 'video/mp4'
})))
}

Resizing images with sharp before uploading to google cloud storage

I tried to resize or compress an image before uploading to the google cloud storage.
The upload works fine but the resizing does not seem to work.
Here is my code:
const uploadImage = async (file) => new Promise((resolve, reject) => {
let { originalname, buffer } = file
sharp(buffer)
.resize(1800, 948)
.toFormat("jpeg")
.jpeg({ quality: 80 })
.toBuffer()
const blob = bucket.file(originalname.replace(/ /g, "_"))
const blobStream = blob.createWriteStream({
resumable: false
})
blobStream.on('finish', () => {
const publicUrl = format(
`https://storage.googleapis.com/${bucket.name}/${blob.name}`
)
resolve(publicUrl)
}).on('error', () => {
reject(`Unable to upload image, something went wrong`)
})
.end(buffer)
})
I ran into the same issue with a project I was working on. After lots of trial and error I found the following solution. It might not be the most elegant, but it worked for me.
In my upload route function I created a new thumbnail image object with the original file values and passed it as the file parameter to the uploadFile function for google cloud storage.
Inside my upload image route function:
const file = req.file;
const thumbnail = {
fieldname: file.fieldname,
originalname: `thumbnail_${file.originalname}`,
encoding: file.encoding,
mimetype: file.mimetype,
buffer: await sharp(file.buffer).resize({ width: 150 }).toBuffer()
}
const uploadThumbnail = await uploadFile(thumbnail);
My google cloud storage upload file function:
const uploadFile = async (file) => new Promise((resolve, reject) => {
const gcsname = file.originalname;
const bucketFile = bucket.file(gcsname);
const stream = bucketFile.createWriteStream({
resumable: false,
metadata: {
contentType: file.mimetype
}
});
stream.on('error', (err) => {
reject(err);
});
stream.on('finish', (res) => {
resolve({
name: gcsname
});
});
stream.end(file.buffer);
});
I think the problem is with toFormat(). That function does not exist in the Docs. Can you try to remove it and check if it would work?
sharp(buffer)
.resize(1800, 948)
.jpeg({ quality: 80 })
.toBuffer()
Modify the metadata once you have finished uploading the image.
import * as admin from "firebase-admin";
import * as functions from "firebase-functions";
import { log } from "firebase-functions/logger";
import * as sharp from "sharp";
export const uploadFile = functions.https.onCall(async (data, context) => {
const bytes = data.imageData;
const bucket = admin.storage().bucket();
const buffer = Buffer.from(bytes, "base64");
const bufferSharp = await sharp(buffer)
.png()
.resize({ width: 500 })
.toBuffer();
const nombre = "IMAGE_NAME.png";
const fileName = `img/${nombre}.png`;
const fileUpload = bucket.file(fileName);
const uploadStream = fileUpload.createWriteStream();
uploadStream.on("error", async (err) => {
log("Error uploading image", err);
throw new functions.https.HttpsError("unknown", "Error uploading image");
});
uploadStream.on("finish", async () => {
await fileUpload.setMetadata({ contentType: "image/png" });
log("Upload success");
});
uploadStream.end(bufferSharp);
});

Draft-Js not showing my image using an image URL

So, I am currently trying to be able to make it possible to paste an image following this [tutorial][1]. The issue I'm having is that I have my code exactly like this tutorial and every time I paste an image it just acts like there was a line break two times with no text. My handlePastedFiles function runs and returns the URL, and then my insertImage runs and passes the link to the insertImage function.
Also, the image url is from a cloud storage and the URL works when viewing in browser.
Here is my handlePastedFiles function:
const handlePastedFiles = (files) => {
console.log('handlePastedFiles is running')
const formData = new FormData();
formData.append('file', files[0])
console.log(files)
fetch(url,
{method: 'POST', body: formData})
.then(res => {
return res.json()
})
.then(data => {
console.log(data)
if (data.message) {
console.log(data.message)
setEditorState(insertImage(data.message)) //created below
} else {
console.log('no file found')
}
}).catch(err => {
console.log(err)
})
}
and here's my insertImages function:
const insertImage = ( url) => {
console.log('!!!!!', url)
const contentState = editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity(
'IMAGE',
'IMMUTABLE',
{ src: url },)
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const newEditorState = EditorState.set( editorState, { currentContent: contentStateWithEntity });
return AtomicBlockUtils.insertAtomicBlock(newEditorState, entityKey, ' ');
};
Please any help is much appreciated, and let me know if I need more information. Thank you in advance!
[1]: https://daveteu.medium.com/draftjs-insert-paste-images-into-your-content-820159025258

Categories

Resources