Base64 images not displaying on mobile - javascript

Holla, fellow developers!
I made this e-commerce app using the MERN stack, where I create a product as an admin, upload an image, save it in the database as binary data and then display it on the SHOP page using the following code:
src={`data:image/jpg;base64,${img.data}`}
And although this works perfectly in my PC browser and all images are displayed accordingly, when I open the app on my mobile device some of the images are displayed and some are not, which makes no sense, since they are all JPEG, they are all roughly the same size.
Is there some kind of a rule when using base64 encoded images on mobile devices or do they not work all together and if there's a way to fix it, how can I do it?
Also what are the best and most reliable practices when it comes to saving images in the database and displaying them when working with the MERN stack?
Thanks in advance!

Technically this should not be the case. I have something similar and it is working perfectly fine.
I am uploading an image
converting to base64 &
made an api call to upload the same.
Made one more api call to fetch the same and using it with image src.
So here is my base 64 conversion.
//base 64 conversion//
`onChange=event=>{
this.setState({
file: URL.createObjectURL(event.target.files[0])
})
const ProjectfileSize = Math.round((event.target.files[0].size / 1024));
this.setState({
fileSize: ProjectfileSize
})
var reader = new FileReader();
reader.readAsDataURL(event.target.files[0]);
reader.onload = () =>
{
const base64File = reader.result.replace(/^data:[a-z]+\/[a-z\-]+;base64,/, "");
this.setState({
convertedFile: base64File
})
};
reader.onerror = function (error) {
console.log('Error: ', error);
};
}
`

Related

How to convert Base64 string to PNG (currently using Jimp)?

I'm currently creating a real-time chat application. This is a web application that uses node.js for the backend and uses socket.io to connect back and forth.
Currently, I'm working on creating user profiles with profile pictures. These profile pictures will be stored in a folder called images/profiles/. The file will be named by the user's id. For example: user with the id 1 will have their profile pictures stored in images/profiles/1.png. Very self-explanatory.
When the user submits the form to change their profile picture, the browser JavaScript will get the image, and send it to the server:
form.addEventListener('submit', handleForm)
function handleForm(event) {
event.preventDefault(); // stop page from reloading
let profilePicture; // set variable for profile picture
let profilePictureInput = document.getElementById('profilePictureInput'); // get image input
const files = profilePictureInput.files[0]; // get input's files
if (files) {
const fileReader = new FileReader(); // initialize file reader
fileReader.readAsDataURL(files);
fileReader.onload = function () {
profilePicture = this.result; // put result into variable
socket.emit("request-name", {
profilePicture: profilePicture,
id: userID,
}); // send result, along with user id, to server
}
}
I've commented most of the code so it's easy to follow. The server then gets this information. With this information, the server is supposed to convert the sent image to a png format (I can do whatever format, but it has to be the same format for all images). I am currently using the jimp library to do this task, but it doesn't seem to work.
const jimp = require('jimp'); // initialize Jimp
socket.on('request-name', (data) => { // when request has been received
// read the buffer from image (I'm not 100% sure what Buffer.from() does, but I saw this online)
jimp.read(Buffer.from(data.profilePicture), function (error, image) {
if (error) throw error; // throw error if there is one
image.write(`images/profiles/${data.id}.png`); // write image to designated place
}
});
The error I get:
Error: Could not find MIME for Buffer <null>
I've scoured the internet for answers but was unable to find any. I am available to use another library if this helps. I can also change the file format (.png to .jpg or .jpeg, if needed; it just needs to be consistent with all files). The only things I cannot change are the use of JavaScript/Node.js and socket.io to send the information to the server.
Thank you in advance. Any and all help is appreciated.
If you're just getting the data URI as a string, then you can construct a buffer with it and then use the built in fs to write the file. Make sure the relative path is accurate.
socket.on('request-name', data => {
const imgBuffer = Buffer.from(data.profilePicture, 'base64');
fs.writeFile(`images/profiles/${data.id}.png`, imgBuffer);
}

exif-js orientation always returns 0 on android but works on desktop

I'm using exif-js library to extract the orientation from images uploaded to my web app.
I need the exif orientation to rotate incorrectly rotated android images.
The problem is that images uploaded from android device always return 0 as their orientation.
I've tried transfering image taken from the same android device to desktop, and uploading it from there, everything works fine in that case and I get the orientation 6.
localforage.getItem('photo').then(function(value) {
alert('inside forage');
image = value;
alert(image); // i get the image object
url = window.URL.createObjectURL(image);
alert(url); // url is correct
let preview = document.getElementById('camera-feed');
preview.src = url;
// const tags = ExifReader.load(image);
console.log( tags );
EXIF.getData(image, function() {
myData = this;
if (myData.exifdata.Orientation) {
orientation = parseInt(EXIF.getTag(this, "Orientation"));
alert(orientation); // on desktop 6, on android always 0
}
});
....
I'm using chrome browser on android.
After a lot of changes in my project, I used
this library to handle image rotation on the frontend
I know you already solved this, but I would still like to recommend exifr library if you need more than orientation. Or if performance is important to you. Exifr is fast and can handle hundreds of photos without crashing the browser or taking a long time :). Plus there's neat simple API and you feed it with pretty much anything - element, URL, Buffer, ArrayBuffer, even base64 url or string and more.
exifr.orientation(file).then(val => {
console.log('orientation:', val)
})

Node JS: Preview downloading images*

I am making a node.js app that will be primarily used to download images from the web. I have created this function that successfully downloads images. I want to make the function also show a live preview of the image as it is downloading without impacting download speed. Is it possible to "tap the pipe" and draw the image as it downloads to a html canvas or img? I am using electron so I am looking for a chromium/node.js based solution.
Edit:
I've also found out you can chain pipes (r.pipe(file).pipe(canvas);) but I'm not sure if that would download the file first and then show up on the canvas or if it would update them both as the file downloads.
I've also thought of creating two separate pipes from the request (var r = request(url); r.pipe(file); r.pipe(canvas);), but I'm not sure if that would try to download the image twice.
I'm also not particularly familiar with the html canvas and haven't been able to test these ideas because I don't know how to pipe a image to a canvas or an img element for display in the application.
const fs = require('fs-extra');
downloadFile(url, filename) {
return new Promise(resolve => {
var path = filename.substring(0, filename.lastIndexOf('\\'));
if (!fs.existsSync(path)) fs.ensureDirSync(path);
var file = fs.createWriteStream(filename);
var r = request(url).pipe(file);
// How would also pipe this to a canvas or img element?
r.on('error', function(err) { console.log(err); throw new Error('Error downloading file') });
r.on('finish', function() { file.close(); resolve('done'); });
});
}
I ended up asking another similar question that provides the answer to this one. It turns out the solution is to pipe the image into memory, encode it with base64 and display it using a data:image url.

Capture image from mobile camera and preview before upload

Would anyone be able to point me in the right direction, I'm trying to write a small application for a web-site, where by the user can choose either an image, or choose to capture an image with their phone camera.
We can then display (preview) the image to them, and they can confirm it and carry on, or restart and take the image again.
I've found a few ways to do this using jQuery, which seemed to work well on a computer, However on a phone (tested using a Samsung S5 running the latest chrome) i frequently receive error messages saying that the previous operation could not be completed due to low memory.
Here is an example of the current code i'm using, this is stripped down somewhat just to show a basic example, but you can see the method doesn't seem very efficient:
$(function() {
$("#prev-img-file").on("change", function()
{
var files = !!this.files ? this.files : [];
if (!files.length || !window.FileReader) return; // no file selected, or no FileReader support
if (/^image/.test( files[0].type)){ // only image file
var reader = new FileReader(); // instance of the FileReader
reader.readAsDataURL(files[0]); // read the local file
reader.onloadend = function(){ // set image data as background of div
$(".up-pic-preview").css("background-image", "url("+this.result+")");
}
}
});
});
http://jsfiddle.net/fish_r/vnu7661c/
Would anyone know of anything that doesn't hog as much resources?
Thanks!
Try WebcamJS.
One of the demo pages - test it on my android 4.4 phone minute ago - works fine :-)
This library allows you to:
display preview;
capture image;
upload captured image to server;
fallback to flash if HTML5 getUserMedia() is not supported;

Issue with stock Browser picking photos from Gallery

I am working on a web page for uploading photos from a mobile device, using the <input type="file" accept="image/*"/> tag. This works beautifully on iphone and on chrome on the android, but where we are running into issues is with the stock android browser.
The issue arises when you select a file from your gallery (it works fine when you use the camera to take a photo). And we have narrowed it down even further to seeing that the data MIME type isn't available when taken from the gallery on the stock browser (the photos below show the first 100 characters of the data URL being loaded. The goal was to force JPEG, but without the MIME type we cannot know for sure how to fix this. See code below for how the images are being rendered.
How can an image be rendered without the type? Better yet, does anybody know why the type is not available on the stock android browser?
EDIT
Firstly, these are not the same image, they were taken near the same time, and that's not the issue, that's why the data is different (The MIME type doesn't appear on any images on the stock browser, so that's not the problem.
Update
I confirmed that the MIME type is the issue by inserting image/jpeg into the stock browser where it is on chrome. Unfortunately, we have no way of guaranteeing that it's going to be jpeg, so we again really can't do it that way
_readInputFile: function (file, index) {
var w = this, o = this.options;
try {
var fileReader = new FileReader();
fileReader.onerror = function (event) {
alert(w._translate("There was a problem opening the selected file. For mobile devices, some files created by third-party applications (those that did not ship with the device) may not be standard and cannot be used."))
$('#loadingDots').remove();
return false;
}
fileReader.onload = function (event) {
var data = event.target.result;
//alert(data.substring(0,100));
//var mimeType = data.split(":")[1].split(";")[0];
alert("Load Image"); //I get to this point
$('#' + w.disp.idPrefix + 'hiddenImages').append($('<img />', {
src: data,
id: "dummyImg" + index,
load: function(){
var width = dummy.width();
var height = dummy.height();
$('#dummyImg' + index).remove();
alert("Render"); // I don't get here
var resized = w._resizeAndRenderImage(data, null, null, biOSBugFixRequired, skewRatio, width, height);
alert("Image Rendered"); // I don't get here
}
}));
}
fileReader.readAsDataURL(file);
}
catch (e) {
}
}
Chrome
Stock Browser
Since the issue is probably browser-related, and you can't really fix the browser(you could report a bug to Google though), I'd suggest taking a different path.
Have a look Here:
In Node.js, given a URL, how do I check whether its a jpg/png/gif?
See the comments of the accepted answer, which suggests a method to check the file type using the file stream. I'm pretty sure this would work on browser-implemented Javascript and not only in Node.js.

Categories

Resources