Correctly rotate image taken on android using ImageCapture - javascript

I'm using ImageCapture api to capture a screenshoot from a camera of a user device.
The problem is that photos taken on android get rotated incorrectly. They are rotated incorrectly both in the photo preview, before the image is uploaded, and after it is uploaded.
My plan was to read the exif data from a blob that I get from image capture, find orientation in exif and use javascript to rotate the image correctly,
but there is no usable exif data because it isnt jpg.
My code:
function takePhoto(img) {
imageCapture.takePhoto()
.then(blob => {
// EXIF.getData(blob, function() {
// myData = this;
// console.log( myData );
// });
let url = window.URL.createObjectURL(blob);
img.src = url;
console.log( blob );
// stop the camera and hide canavas
stream.getVideoTracks()[0].stop();
$("#webcam").hide();
image = blob;
$("#photo-info").slideDown('slow');
})
.catch(function (error) {
console.log(error);
});
};
takePhoto(document.querySelector('#camera-feed'));
Is there a way to detect if a image is rotated incorrectly when using ImageCapture?

It depends on the device you are using, you should deal with the picture after taken in two steps:
Validate if the photo is rotated.
If necesary rotate the photo.
To validate if the photo is rotated you can use ExifInterface and to rotate you can use a matrix to invert it playing with the bits
You can find more related information and code example at this question

I could not get this working, along with some other problems, so I decided to ditch ImageCapture all together and go with this:
<input type="file" accept="image/*" capture>
This opened the device camera as soon as user clicked on the input button, which is exacly what I needed, but since the taken photo came with exif on android I could correctly rotate it.
For the rotation itself, I used this library

Related

JavaScript - How to take a picture in webcam with EXIF data?

I am currently using webcam (not native camera) on a web page to take a photo on users' mobile phone. Like this:
var video: HTMLVideoElement;
...
var context = canvas.getContext('2d');
context.drawImage(video, 0, 0, width, height);
var jpegData = canvas.toDataURL('image/jpeg', compression);
In such a way, I can now successfully generate a JPEG image data from web camera, and display it on the web page.
However, I found that the EXIF data is missing.
according to this:
Canvas.drawImage() will ignore all EXIF metadata in images,
including the Orientation. This behavior is especially troublesome
on iOS devices. You should detect the Orientation yourself and use
rotate() to make it right.
I would love the JPEG image contain the EXIF GPS data. Is there a simple way to include camera EXIF data during the process?
Thanks!
Tested on Pixel 3 - it works. Please note - sometimes it does not work with some desktop web-cameras. you will need exif-js to get the EXIF object from example.
const stream = await navigator.mediaDevices.getUserMedia({ video : true });
const track = stream.getVideoTracks()[0];
let imageCapture = new ImageCapture(track);
imageCapture.takePhoto().then((blob) => {
const newFile = new File([blob], "MyJPEG.jpg", { type: "image/jpeg" });
EXIF.getData(newFile, function () {
const make = EXIF.getAllTags(newFile);
console.log("All data", make);
});
});
unfortunately there's no way to extract exif from canvas.
Although, if you have access to jpeg, you can extract exif from that. For that I'd recommend exifr instead of widely popular exif-js because exif-js has been unmaintained for two years and still has breaking bugs in it (n is undefined).
With exifr you can either parse everything
exifr.parse('./myimage.jpg').then(output => {
console.log('Camera:', output.Make, output.Model))
})
or just a few tags
let output = await exifr.parse(file, ['ISO', 'Orientation', 'LensModel'])
First of, according to what I found so far, there is no way to include exif data during canvas context drawing.
Second, there is a way to work around, which is to extract the exif data from the original JPEG file, then after canvas context drawing, put the extracted exif data back into the newly drawn JPEG file.
It's messy and a little hacky, but for now this is the work around.
Thanks!

html2canvas , save render canvas as a gif instead of a png?

I'm using html2canvas to save a snapshot from the webcam as an image.
However, it save only in png, I'm trying to save it as a gif, but can not find out how to do this
So far this is my function:
renderCanvasImage: function(){
setTimeout(function () {
// Add image with Quote to Canvas (hidden).
html2canvas($('.snap'), {
onrendered: function (canvas) {
document.body.appendChild(canvas).id = 'hidden';
var canvas = document.getElementById('hidden');
var image = new Image();
//Create a new Image with url
image.src = canvas.toDataURL("image/.png");
// Look at URI only and assign to localStorage
imageURI = image.src;
localStorage.setItem('image', imageURI);
//****TODO better removal*/
$('#cameraContainer, .wrapperInfo').hide();
$('#result a, #result img').fadeOut(100).remove();
$(image).appendTo('#result');
$('#result').fadeIn(200);
//Send Data to DB
tibo.setData();
//PopUp Message
tibo.popupMsg();
}
});
}, 1000);
},
I tried to replace the following:
image.src = canvas.toDataURL("image/.png");
By jpg of gif, but it doesn't change anything.... any tips to make this work will be amazing !!
Thanks a lot !!
You said in the comments above that you've got it working, however I still feel the need to tell you that the supported mime types of toDataUrl depend on the browser.
You can test it here https://jsfiddle.net/v91y0zqr/
Here's a visual example with even more mime types: http://kangax.github.io/jstests/toDataUrl_mime_type_test/
All browsers I've tested (Firefox, Chrome, Opera, IE) did support image/png and image/jpeg
Additionally, Chrome could export image/webp
Additionally, Firefox could export image/bmp
Results may differ for you.
So while in theory canvas.toDataURL("image/gif"); should create a GIF image, the browser may still decide to create a PNG (it's the default fallback).
You can read more about toDataUrl here: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL

Copy canvas from one page to another without crossing max character limit

I want to play a video in HTML video element and take snapshot on pause. The snapshot is displayed on the page inside a canvas. Now I want the same snap to appear on another page and for this I am trying to encode the snapshot in base 64 using toDataUrl() method & pass it through URL.
But the maximum length of URL can be 2048 char while the output of toDataUrl is much bigger. How to proceed?
Working fine:
video.addEventListener('pause', function(){
$(this).hide();
$("#canvas1").show();
draw( video, thecanvas, img);
}, false);
function draw(video,thecanvas,img){
var context = thecanvas.getContext('2d');
context.drawImage(video,0,0,thecanvas.width,thecanvas.height);
var dataURL = thecanvas.toDataURL('image/jpeg',.1);
img.setAttribute('src',dataURL);
}
Not working: The function to direct to another page
function toskuentry(){
var imgsrc = $('#thumbnail_img').attr('src');
window.location.href = "sku_entry.php?imgsrc="+imgsrc;
}
Don't pass it through the URL, use HTML5 Web Storage. You can use either sessionStorage or localStorage:
function toskuentry(){
localStorage.setItem("img", $('#thumbnail_img').attr('src'));
}
On the next page you can access it by localStorage.getItem("img");.
One good option would be to use Firebase. They have an example of doing that.
https://www.firebase.com/tutorial/#session/n24v8lvnltc
Firebase uses local storage when offline, so that means you could also use local storage if you didn't want to use Firebase.
something like
localStorage["data"] = dataURL;
//...other page
var dataURL = JSON.parse(localStorage["data"]);

image shown rotated on iPad and not on laptop

I've created a small test site in which you can upload a picture. And without a round-trip to the backend, the selected picture is shown. So far nothing very interesting
$('input').on('change', function () {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function (event) {
var base64 = event.target.result;
$('<img>').attr('src', base64).appendTo('body');
};
reader.readAsDataURL(file);
});
However, I noticed that on my iPad3 some pictures are shown up-side-down. I found on google about EXIF metadata which is stored in the image (base64) which defines the orientation of the picture. But another thing is, that on my laptop the image are shown normal (with the same pictures of course). Is there any way to prevent/fix this behaviour from happening ? (I want them to show the picture the same way, and if possible I also want them to be shown normal (not up-side-down))
This is not a CSS issue. It's actually an issue with the image. Some browsers interpret the orientation of the image through meta data. Simply open the image in any image editing software and export it. Upload it to your server and let me know if that worked!
EDIT - Reference this URL for a possible solution:
Accessing JPEG EXIF rotation data in JavaScript on the client side

Cannot capture image from virtual signature HTML5 canvas in Javascript

I am using this as a virtual signature pad: http://thomasjbradley.ca/lab/signature-pad/ . It can either automatically generate a signature from a typed name or let the user sign with their mouse. I need to capture the image and send it to a Java server. It uses an HTML5 canvas.
It works correctly for the drawn image, but trying to capture the automatically generated image results in a blank image with no text.
I am using this code as it said in the site's API section:
var api = $('.sigPad').signaturePad();
autoGeneratedData = api.getSignatureImage();
and then sending autoGeneratedData to the server.
I also tried to capture the canvas directly:
var canvas = document.getElementById('sigCanvas');
var imageData = canvas.toDataURL('image/png');
but ran into the same issue.

Categories