I am trying to format an uploaded .png file in my angular front-end so that it can be stored in a database. I am having some issues which I have replicated in this single function. I am taking the data field passed into this function, which represents the png file and encoding it in base64. However, I can't tell if it is working. In this example, I encode the item and then instantly decode it, but the outputs don't equal each other?
addImage(data: any): Observable<File> {
console.log('original', data);
const encodedImg: Image = new Image();
encodedImg.img = {data: btoa(data), contentType: 'image/png'};
console.log('encoded', encodedImg);
console.log('final', atob(encodedImg.img.data), encodedImg.img.contentType);
return this.http.post<File>('/api/image', encodedImg);
}
Related
I've got a blob of audio data confirmed to play in the browser but fails to play after storing, retrieving, and conversion of the same data. I've tried a few methods without success, each time returning the error:
Uncaught (in promise) DOMException: Failed to load because no supported source was found
Hasura notes that bytea data must be passed in as a String, so I tried a couple things.
Converting the blob into base64 stores fine but the retrieval and playing of the data doesn't work. I've tried doing conversions within the browser to base64 and then back into blob. I think it's just the data doesn't store properly as bytea if I convert it to base64 first:
// Storing bytea data as base64 string
const arrayBuffer = await blob.arrayBuffer();
const byteArray = new Uint8Array(arrayBuffer);
const charArray = Array.from(byteArray, (x: number) => String.fromCharCode(x));
const encodedString = window.btoa(charArray.join(''));
hasuraRequest....
`
mutation SaveAudioBlob ($input: String) {
insert_testerooey_one(
object: {
blubberz: $input
}
) {
id
blubberz
}
}
`,
{ input: encodedString }
);
// Decoding bytea data
const decodedString = window.atob(encodedString);
const decodedByteArray = new Uint8Array(decodedString.length).map((_, i) =>
decodedString.charCodeAt(i)
);
const decodedBlob = new Blob([decodedByteArray.buffer], { type: 'audio/mpeg' });
const audio4 = new Audio();
audio4.src = URL.createObjectURL(decodedBlob);
audio4.play();
Then I came across a Github issue (https://github.com/hasura/graphql-engine/issues/3336) suggesting the use of a computed field to convert the bytea data to base64, so I tried using that instead of my decoding attempt, only to be met with the same error:
CREATE OR REPLACE FUNCTION public.content_base64(mm testerooey)
RETURNS text
LANGUAGE sql
STABLE
AS $function$
SELECT encode(mm.blobberz, 'base64')
$function$
It seemed like a base64 string was not the way to store bytea data, so I tried converting the data to a hex string prior to storing. It stores ok, I think, but upon retrieval the data doesn't play, and I think it's a similar problem as storing as base64:
// Encoding to hex string
const arrayBuffer = await blob.arrayBuffer();
const byteArray = new Uint8Array(arrayBuffer);
const hexString = Array.from(byteArray, (byte) =>
byte.toString(16).padStart(2, '0')
).join('');
But using the decoded data didn't work again, regardless of whether I tried the computed field method or my own conversion methods. So, am I just not converting it right? Is my line of thinking incorrect? Or what is it I'm doing wrong?
I've got it working if I just convert to base64 and store as a text field but I'd prefer to store as bytea because it takes up less space. I think something's wrong with how the data is either stored, retrieved, or converted, but I don't know how to do it. I know the blob itself is fine because when generated I can play audio with it, it only bugs out after fetching and attempted conversion its stored value. Any ideas?
Also, I'd really like to not store the file in another service like s3, even if drastically simpler.
So i am dropping a .txt file in an uploader which is converting it into base64 data like this:
const {getRootProps, getInputProps} = useDropzone({
onDrop: async acceptedFiles => {
let font = ''; // its not actually a font just reusing some code i'll change it later its a .txt file so wherever you see font assume its NOT a font.
let reader = new FileReader();
let filename = acceptedFiles[0].name.split(".")[0];
console.log(filename);
reader.readAsDataURL(acceptedFiles[0]);
reader.onload = await function (){
font = reader.result;
console.log(font);
dispatch({type:'SET_FILES',payload:font})
};
setFontSet(true);
}
});
Then a POST request is made to the node js server and I indeed receive the base64 value. I then proceed to convert it back into a .txt file by writing it into a file called signals.txt like this:
server.post('/putInDB',(req,res)=>{
console.log(req.body);
var bitmap = new Buffer(req.body.data, 'base64');
let dirpath = `${process.cwd()}/signals.txt`;
let signalPath = path.normalize(dirpath);
connection.connect();
fs.writeFile(signalPath, bitmap, async (err) => {
if (err) throw err;
console.log('Successfully updated the file data');
//all the ending brackets and stuff
Now the thing is the orignal file looks like this :
Time,1,2,3,4,5,6,7,8,9,10,11,12
0.000000,7.250553,14.951141,5.550423,2.850217,-1.050080,-3.050233,1.850141,2.850217,-3.150240,1.350103,-2.950225,1.150088
But the file when writing back from base64 looks like this :
u«Zµìmþ™ZŠvÚ±î¸Time,1,2,3,4,5,6,7,8,9,10,11,12
0.000000,1.250095,0.250019,-4.150317,-0.350027,3.650278,1.950149,0.950072,-1.250095,-1.150088,-7.750591,-1.850141,-0.050004
See the weird characters in the beginning ? Why is this happening.
Remember to read up on what the functions you use do, because you're using readAsDataURL which does not give you the base64 encoded version of your data: it gives you Data-URL, and Data-URLs have a header prefix to tell URL parsers what kind of data this will be, and how to decode the data directly following the header.
To quote the MDN article:
Note: The blob's result cannot be directly decoded as Base64 without first removing the Data-URL declaration preceding the Base64-encoded data. To retrieve only the Base64 encoded string, first remove data:*/*;base64, from the result.
If you don't, blindly converting the Data-URL from base64 to plain text will give you some nonsense data at the start:
> Buffer.from('data:*/*;base64', 'base64').toString('utf-8')
'u�Z���{�'
Which raises another point: you would have caught this with POST data validation, because the Data-URL that you sent contains characters that are not allowed in base64. POST validation is always a good idea.
I know this isn't the exact code, but it is difficult to reproduce your problem with the code you provided. But the data you are sending needs to be a URL/URI encoded form.
So essentially:
encodeURI(base64data);
Encode URI is built into javascript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI
EDIT:
I saw you used the function readDataAsUrl(), but try using the encodeURI function and then readDataAsUrl().
I'm trying to get PouchDB to return a small image attachment. When I upload the image through Fauxton, my app successfully returns a Blob with type: 'image/svg+xml' that renders correctly in my <img> element (using URL.createObjectURL).
However, if I have the user upload an image, and then put the file Blob to my remote Pouch database, I have problems. In this case, PouchDB.getAttachment() now returns a Blob with type: 'application/octet-stream' instead of 'image/svg+xml', despite having uploaded it with the correct content_type. This image does not render, giving me a generic browser img placeholder.
Why could this be occurring?
Step 1 Here is how I retrieve the image from the user:
var image = new Blob([fs.readFileSync(fileLocation, 'utf-8')], {
type: 'image/svg+xml'
})
Step 2 Here is how I put my document (and attachment) to PouchDB:
var doc = await PouchDB.get(docID, {attachments: true})
doc._attachments = {
'logo.svg': {
content_type: 'image/svg+xml',
data: image
}
}
await PouchDB.put(doc)
You got 2 problems with reading your file. First is that you can't treat binary data as UTF8 (may not be a real problem with SVG file, but with other images surely is), and the second one is that you have to base64 encode it.
There are many different approaches to base64 encode a blob, but the easiest solution would be to change the method of putting it from put to putAttachment. Something like this:
HTML:
...
<input type="file" id="inputFile">
...
JS:
...
var inputFile = document.querySelector('#inputFile');
var file = inputFile.files[0];
db.putAttachment('mydoc', 'myfile', file, file.type).then(...)
...
Look at my code
<img src='data:image/png;base64,{{imgSrc}}'>
In my controller
$scope.imgSrc = $scope.deviceDetail.imgSrc;
I am getting this type of response from my backend in imgSrc which is stored in mongodb.
"�PNG\r\n\u001a\n\u0000\u0000\u0000\rIHDR\u0000\u0000\u0003 \u0000\u0000\u0002R\b\u0002\u0000\u0000\u0000��6A\u0000\u0000\u0000\u0006bKGD\u0000�\u0000�\u0000�����\u0000\u0000 \u0000IDATx���{xT���W x\u0000\u0006%$F�c F\t�\"�V��\u0000�P\u000f\b���xEъ��T�z#� \u0018�諀`�TJ�Z\u0015\t�\"R��#\u000b|H�h8\u0005\......"
Now I want png image from this data,I have tried this data into base64 but still not getting image.
Please suggest me what is wrong here?
You can convert image to data base64 bit.
Base64 is a group of similar binary-to-text encoding schemes that represent
binary data in an ASCII string format by translating it into a radix-64 representation.
To convert a file to base64 (image or any other kind of file) with cordova, ionic or phonegap we will need only the cordova file plugin and 1 human eye. Then we will use the FileReader to read the the content of a file with the method readAsDataURL.
/**
* This function will handle the conversion from a file to base64 format
*
* #path string
* #callback function receives as first parameter the content of the image
*/
function getFileContentAsBase64(path,callback){
window.resolveLocalFileSystemURL(path, gotFile, fail);
function fail(e) {
alert('Cannot found requested file');
}
function gotFile(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var content = this.result;
callback(content);
};
// The most important point, use the readAsDatURL Method from the file plugin
reader.readAsDataURL(file);
});
}}
Then we will use it to convert a local image to base64 :
var path = "file://storage/0/downloads/myimage.png";
// Convert image
getFileContentAsBase64(path,function(base64Image){
//window.open(base64Image);
console.log(base64Image);
// Then you'll be able to handle the myimage.png file as base64
});
Remember that you need the file plugin from cordova, read and learn how to use it here. You can download the file plugin into your project executing in your cordova CLI :
cordova plugin add cordova-plugin-file
continue here
https://gist.github.com/HereChen/e173c64090bea2e2fa51
http://tutsheap.com/web/javascript/get-base64-image-url/
lets say i have a URL given. I would like to:
1) download it and convert to base64
2) upload it to some key/value storage (as text)
3) download it from key/value storage (with text/plain mimetype), reencode it from base64, display it.
Best Regards
If someone is still searching for downloading images and encoding them in base64 string, I recently find this kind of outdated method but really reliable. The advantage is that it's pure Javascript so there is no need to install any external library. I previously tried using fetch and axios but for some reason the encoded string was not in a correct format.
NB: If you are encoding this image to send it to an API, some of them require to delete the leading data type including the , at the start of the encoded string.
function toDataURL (url, callback) {
const xhRequest = new XMLHttpRequest()
xhRequest.onload = function () {
const reader = new FileReader()
reader.onloadend = function () {
callback(reader.result)
}
reader.readAsDataURL(xhRequest.response)
}
xhRequest.open('GET', url)
xhRequest.responseType = 'blob'
xhRequest.send()
}
const URL = "https://upload.wikimedia.org/wikipedia/commons/f/f7/Stack_Overflow_logo.png"
const logCallback = (base64image) => {
// Base64 encoded string with leading data type like
// data:image/png;base64,RAW_ENCODED_DATA______
console.log(base64image)
}
toDataURL(URL, logCallback)