Reputation: 604
I'm trying to save as base64 a captured image in QML. This is part of the code. I need to have it in a variable.
Camera {
id: camera
videoRecorder {
frameRate: 30
}
imageCapture {
onImageCaptured: {
foto.source = preview
}
onImageSaved: {
var imgPath = camera.imageCapture.capturedImagePath;
t.start()
}
}
}
I suppose I have to do it in onImageSaved, I've tried:
camera.imageCapture.toBase64()
And:
imgPath.toDataURL(mimeType)
But I'm not sure if it's possible ot what I'm doing wrong if it is.
Upvotes: 0
Views: 1067
Reputation: 26121
Because you're restricting the solution to QML, your choices are severely limited. I would really question that since it leads to this solution, which is inefficient because it requires you to save the image first and then load the saved image.
You must:
camera.imageCapture.capture()
or equivalentXMLHttpRequest
Qt.btoa
on it to get a base64 string from itThe steps are precisely written above to avoid any mistakes or misunderstandings. It's inefficient, since, if you had access to C++ we could consider processing the raw QImage in-memory and do in-memory conversions to an image format of our choosing as well as an in-memory conversion to base64.
Camera {
id: camera
imageCapture {
onImageSaved: {
let filePath = camera.imageCapture.capturedImagePath;
console.log(filePath); // C:/Users/stephenquan/Pictures/IMG_00000007.jpg
let fileUrl = Qt.platform.os === 'windows'
? 'file:///' + filePath
: 'file://' + filePath;
console.log(fileUrl); // file:///C:/Users/stephenquan/Pictures/IMG_00000007.jpg
let xhr = new XMLHttpRequest();
xhr.open("GET", fileUrl, false);
xhr.send();
// //XMLHttpRequest: Using GET on a local file is dangerous and will be disabled by default in a future Qt version.Set QML_XHR_ALLOW_FILE_READ to 1 if you wish to continue using this feature.
let base64 = Qt.btoa(xhr.response);
console.log(base64); // final base64 representation of the JPEG image
let datauri = "data:image/jpeg;base64," + base64;
console.log(datauri); // a properly formatted datauri for the JPEG image
}
}
}
After it is saved, we need to convert that filePath to a fileUrl.
For me, as I'm running it on windows, I can add a file:///
prefix to turn it into a URL. For other platforms, the prefix is typically file://
.
Then we can use Qt.btoa
with XMLHttpRequest
we can generate the base64
string for that URL.
See the warning about using XMLHttpRequest on local files.
Below is some refactored black box functions to make all this code reusable for other scenarios.
function urlToBase64(url) {
let xhr = new XMLHttpRequest();
xhr.open("GET", url, false);
xhr.send();
return Qt.btoa(xhr.response);
}
function fileToBase64(filePath) {
//XMLHttpRequest: Using GET on a local file is dangerous and will be disabled by default in a future Qt version.Set QML_XHR_ALLOW_FILE_READ to 1 if you wish to continue using this feature.
return urlToBase64(Qt.resolvedUrl("file:///" + filePath));
}
function test() {
let url = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png";
console.log(urlToBase64(fileUrl));
let filePath = "C:/temp/hello.txt";
console.log(fileToBase64(filePath));
}
[Edit: Additional answer about Canvas.toDataURL]
Alternatively, you can use Canvas.toDataURL but it requires you to load your graphic into the a Canvas object first and then render it once you are sure it's loaded.
[Edit: Additional answer about asynchronous]
There was a comment earlier regarding the proper usage of XMLHttpRequest
. Because the use case was for local files, I used XMLHttpRequest.open
with async mode set to false
to force it to work in synchronous mode.
If you want an asynchronous version of the solution and use it generically for HTTP URLs, I would choose to use Promise chaining as per below.
function asyncUrlToBinary(url) {
return new Promise(function (resolve, reject) {
try {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState !== 4) return;
if (xhr.status !== 200) {
reject(new Error(`HTTP Status Error ${xhr.status}: ${xhr.statusText}`));
return;
}
resolve(xhr.response);
}
xhr.open("GET", url);
xhr.send();
} catch (err) {
reject(err);
}
} );
}
function asyncBtoA(data) {
return Promise.resolve(Qt.btoa(data));
}
function asyncTest() {
let url = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png";
asyncUrlToBinary(url)
.then(data => asyncBtoA(data))
.then(base64 => console.log(base64))
.catch(err => { console.error(err.fileName + ":" + err.lineNumber, err.message); throw err; } )
;
}
References:
Upvotes: 0