How to decode base64 PDF string in Flutter? - node.js

I know there is a package called dart:convert which let me decode base64 image. But apparently, it doesn't work with pdf files. How can I decode the base64 PDF file in Flutter?
I want to store it in Firebase Storage (I know how to do it) but I need the File variable to do it.
I have a web service written in node js where I have a POST route. There, I create a pdf file and encode it to base 64. The response is a base64 string, look at the code.
router.post('/pdf', (req, res, next) => {
//res.send('PDF');
const fname = req.body.fname;
const lname = req.body.lname;
var documentDefinition = {
content: [ write your pdf with pdfMake.org ],
styles: { write your style };
const pdfDoc = pdfMake.createPdf(documentDefinition);
pdfDoc.getBase64((data) => {
res.send({ "base64": data });
});
});
As you can see, it returns the pdf as a base64 string.
Now, in Flutter, I have written this:
http.post("https://mypostaddreess.com",body: json.encode({"data1":"data"}))
.then((response) {
print("Response status: ${response.statusCode}");
print("Response body: ${response.body}");
var data = json.decode(response.body);
var pdf = base64.decode(data["base64"]);
});
}
I have the PDF in the variable 'pdf' as you see. But I don't know how to decode it to download the pdf or show it in my Flutter app.

#SwiftingDuster
a little added, maybe besides decoding, it's also necessary to create a pdf file and open it.
createPdf() async {
var bytes = base64Decode(widget.base64String.replaceAll('\n', ''));
final output = await getTemporaryDirectory();
final file = File("${output.path}/example.pdf");
await file.writeAsBytes(bytes.buffer.asUint8List());
print("${output.path}/example.pdf");
await OpenFile.open("${output.path}/example.pdf");
setState(() {});
}
library needed:
1. open_file
2. path_provider
3. pdf

I think it's better to get the BufferArray and convert it into a pdf file.
Check out my answer from here : Get pdf from blob data

This should convert base64 encoded pdf data into a byte array.
import 'packages:dart/convert.dart';
List<int> pdfDataBytes = base64.decode(pdfBase64)
.map((number) => int.parse(number));
The pdf and the image plugins seems to suit your needs for displaying pdf.
The code should be roughly like so:
import 'package:pdf/pdf.dart';
import 'package:image/image.dart';
...
Image img = decodeImage(pdfDataBytes);
PdfImage image = PdfImage(
pdf,
image: img.data.buffer.asUint8List(),
width: img.width,
height: img.height);
// Display it somehow
...

Related

Convert an imagen from an url to base64 without downloading it

I want to generate a pdf with images and text, for this I'm using the jsPdf package which includes this method to add images.
addImage(imageData, format, x, y, width, height, alias, compression, rotation)
The imageData argument accepts base64 format data and this part is which I'm struggling with.
My images are not local but hosted in cloudinary and I would prefer not to download them, searching on the web I've found that if I don't want to download the image I will need:
Fetch the image data, for this I'm using node-fetch package(fetch in the code).
Convert the image data into a Buffer.
Finally encode that buffer into a base64.
This is my attempt so far:
const fetchImage = async () => {
const imageUrl = <url-of-my-image>;
const response = await fetch(imageUrl, {
compress: false
});
const dataUrlPrefix = `data:${response.headers.get('content-type')};base64,`;
const body = await response.text();
const buffer = Buffer.from(body)
const imageBase64 = buffer.toString('base64');
const imageDataUrl = dataUrlPrefix+imageBase64;
doc.text("Hello world!", 10, 10);
doc.addImage(imageDataUrl, 'webp', 15, 40, 120, 120)
doc.save("a4.pdf");
}
The code runs without errors but the image is not being inserted into the pdf, it just display the "Hello World!" text but nothing else.
My guess is that I'm doing something wrong in the converting/encoding process (before I add it to jsPdf) because if I convert my image with an online converter like this one the base64 string that results is successfully decoded into an actual image when using a online base64 decoder like this one, whereas when I run the base64 output from my nodejs code i.e. the output for the imageBase64 or imageDataUrl variables in the same base64 decoder it results in not image being decoded.

how to load atlas using base64 in phaser3?

I am making a phaser3 playable ad and require to put images and other assets in a single HTML file. I can load the images using textures.addBase64 but how can I load atlas using base64.
Also if you could tell me how to put JSON in the HTML file so that I can refer to it while loading the atlas.
Thank you 🙂
Untested personally but take a look at this solution
private loadBase64Atlas(key: string, data: string, json: object): void {
const imageElement = new Image();
imageElement.onload = () => {
this.scene.textures.addAtlas(key, imageElement, json);
this.onAssetLoaded();
};
const spriteBlob = this.base64ToBlob(data.split(',')[1], 'image/png');
imageElement.src = URL.createObjectURL(spriteBlob);
}
Adapt as needed if you're not using TypeScript. Here's the base64ToBlog implementation
The JSON object can be just bounced back and forth from and to base64 if you had the need to embed it in base64 aswell:
// get the base64 string to embed in the ad and physically store it
const atlasJSON64 = btoa(JSON.stringify(atlasJSON));
[...]
const objectatlasJSON64 = JSON.parse(atob(atlasJSON64));

Node JS / Generate PDF server side

I need to create PDF files via server side. I have a pug file with the HTML and it's working as expected (the format and the content is perfect). Also, I have a service that gets the HTML from the pug file in a string. The problem is that I'm facing issues using the node-html-pdf library to generate a PDF.
let config = {
format: 'Letter',
orientation: 'portrait',
type: 'pdf'
};
pdf.create(htmlConverted, config).toBuffer((errConvertingHtml, buffer) => {
if (errConvertingHtml) {
this.logError(errConvertingHtml, null, `${this.className} createPDF`);
return this.returnResult(errConvertingHtml, false, null);
} else {
const filename = 'Invoice' + '.pdf';
const base64PDF = buffer.toString('base64');
const email = new models.EmailModel();
email.to.email = order.email;
email.to.name = order.full_name;
email.template_id = subscriptionTemplate.value;
email.dynamic_template_data = dynamic_data;
email.attachments = [
{
filename: filename,
content: base64PDF,
type: 'application/pdf',
disposition: 'attachment'
}
];
let mailIntegration = new integrations.MailIntegration();
mailIntegration.SendNow(email);
}
});
This code works, but the PDF attach in the email doesn't have the right format, it's really small. I can use another library, or another implementation, I don't have any issue with that. Any suggestions or recommendations for this code? I have been searching for another library, but honestly, I haven't found something to convert the HTML string to PDF and then the PDF to a buffer and then to base64. Any help is well received. Thanks, I really appreciate your responses.

Base64 string img not viewable when uploaded via drive api

I have uploaded a base64 img string to Google Drive via API in node express. After uploading the img, it is not viewable in Drive. I'm not sure on how to resolve this formatting issue. I know I could potentially save the img locally first, then upload the saved img file but I was hoping there is a simpler way.
My code:
const uploadImg = async (folderId,img)=>{
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0
const scopes = [
'https://www.googleapis.com/auth/drive'
];
const auth = new google.auth.JWT(
demoApiCreds.client_email, null,
demoApiCreds.private_key, scopes
);
const drive = google.drive({ version: 'v3', auth });
const fileMetadata = {
'name': 'Client_Design_ScreenShotTest',
'mimeType':'image/jpeg',
'parents':[folderId]
};
const uploadImg = img.split(/,(.+)/)[1];
const media = {
body: uploadImg
}
let res = await drive.files.create({
resource: fileMetadata,
media: media,
fields: 'id',
});
console.log('the response is',res);
console.log('the data is ',res.data);
return res.data;
}
Edit:
The file is stored in drive, as a jpg, but the img is blank and after
the img is clicked google drive complains that the file cannot be
read. The img is still blank after downloading.
The base 64 img string is
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAhAAAADqCAYAAADzlnzfAAAAAXNSR0I...
I remove data:image/png;base64 before uploading as has been suggested in other threads. It fails with or without this prefix.
You want to upload an image to Google Drive using googleapis with node.js.
The image of img is the base64 data.
You have already been able to upload and download files to Google Drive using Drive API.
If my understanding is correct, how about this answer? Please think of this as just one of several answers.
Modification points:
Unfortunately, when the base64 data is uploaded using googleapis, the base64 data is not decoded and the data is upload as the text data. So when you see the uploaded file, you cannot see it as the image. If Content-Transfer-Encoding: base64 can be added to the header of the base64 data in the request body, the base64 data is converted and uploaded as an image. But when googleapis is used, in the current stage, it cannot be achieved.
In order to upload the base64 data encoded from an image as an image to Google Drive, how about the following modification?
Modified script:
In this modification, the base64 image is converted to the stream type, and uploaded. Please modify your script as follows.
From:
const uploadImg = img.split(/,(.+)/)[1];
const media = {
body: uploadImg
}
To:
const stream = require("stream"); // Added
const uploadImg = img.split(/,(.+)/)[1];
const buf = new Buffer.from(uploadImg, "base64"); // Added
const bs = new stream.PassThrough(); // Added
bs.end(buf); // Added
const media = {
body: bs // Modified
};
Note:
Even if 'mimeType':'image/jpeg' is used at fileMetadata, the image file is uploaded as image/png. But for example, if 'mimeType':'application/pdf' is used at fileMetadata, the image file is uploaded as application/pdf. Please be careful this. So I also recommend to modify to 'mimeType':'image/png' as mentioned by 10100111001's answer.
At "googleapis#43.0.0", both patterns of resource: fileMetadata and requestBody: fileMetadata work.
References:
Class Method: Buffer.from(string[, encoding])
Class: stream.PassThrough
Files: create in Drive API
If I misunderstood your question and this was not the direction you want, I apologize.
You need to change your mimeType to image/png.
See here what Mime Types are
Edit:
The property name for the fileMetadata is called requestBody instead of resource.
let res = await drive.files.create({
requestBody: fileMetadata,
media: media,
fields: 'id',
});
https://github.com/googleapis/google-api-nodejs-client/blob/7e2b586e616e757b72f7a9b1adcd7d232c6b1bef/src/apis/drive/v3.ts#L3628
I had the same problem, Solved it by adding "Content-Transfer-Encoding: base64"in body where we write body-request, content-type, etc.

How to save pdf to android file system and then view PDF - react-native

I am using the react-native-fs and I am trying to save a base64 of a pdf file to my android emulators file system.
I receive base64 encoded pdf from the server.
I then decode the base64 string with the line:
var pdfBase64 = 'data:application/pdf;base64,'+base64Str;
saveFile() function
saveFile(filename, pdfBase64){
// create a path you want to write to
var path = RNFS.DocumentDirectoryPath + '/' + filename;
// write the file
RNFS.writeFile(path, base64Image, 'base64').then((success) => {
console.log('FILE WRITTEN!');
})
.catch((err) => {
console.log("SaveFile()", err.message);
});
}
Error
When I try saving the pdfBase64 the saveFile() function catches the following error:
bad base-64
Question
Can anyone tell where or what I am doing wrong?
Thanks.
For anyone having the same problem, here is the solution.
Solution
react-nativive-pdf-view must take the file path to the pdf_base64.
Firstly, I used the react-native-fetch-blob to request the pdf base64 from the server.(Because RN fetch API does not yet support BLOBs).
Also I discovered that react-native-fetch-blob also has a FileSystem API which is way better documented and easier to understand than the 'react-native-fs' library. (Check out its FileSystem API documentation)
Receiving base64 pdf and saving it to a file path:
var RNFetchBlob = require('react-native-fetch-blob').default;
const DocumentDir = RNFetchBlob.fs.dirs.DocumentDir;
getPdfFromServer: function(uri_attachment, filename_attachment) {
return new Promise((RESOLVE, REJECT) => {
// Fetch attachment
RNFetchBlob.fetch('GET', config.apiRoot+'/app/'+uri_attachment)
.then((res) => {
let base64Str = res.data;
let pdfLocation = DocumentDir + '/' + filename_attachment;
RNFetchBlob.fs.writeFile(pdfLocation, pdf_base64Str, 'base64');
RESOLVE(pdfLocation);
})
}).catch((error) => {
// error handling
console.log("Error", error)
});
}
What I was doing wrong was instead of saving the pdf_base64Str to the file location like I did in the example above. I was saving it like this:
var pdf_base64= 'data:application/pdf;base64,'+pdf_base64Str;
which was wrong.
Populate PDF view with file path:
<PDFView
ref={(pdf)=>{this.pdfView = pdf;}}
src={pdfLocation}
style={styles.pdf}
/>
There is a new package to handle the fetching (based on react-native-fetch-blob) and displaying of the PDF via URL: react-native-pdf.
Remove application type in base64 string and it's working for me
var pdfBase64 = 'data:application/pdf;base64,'+base64Str;
To
var pdfBase64 = base64Str;

Resources