I am using JavaScript LoadImage.parseMetaData (https://github.com/blueimp/JavaScript-Load-Image) to try and get Orientation of an image on the web, so I can rotate it.
If I hardcode the orientation (see "orientation: 3" in my second loadImage call), I can rotate it... but I am trying to use loadImage.parseMetaData to get the Orientation.
I have used web based EXIF parsers and the orientation info is there in the image.
When I call loadImage.parseMetaData "data.exif" seems to be null. See this fiddle: http://jsfiddle.net/aginsburg/GgrTM/13/
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://www.filepicker.io/api/file/U0D9Nb9gThy0fFbkrLJP', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
// Note: .response instead of .responseText
console.log ("got image");
var blob = new Blob([this.response], {type: 'image/png'});
console.log("about to parse blob:" + _.pairs(this.response));
loadImage.parseMetaData(blob, function (data) {
console.log("EXIF:" + _.pairs(data))
var ori ="initial";
if (data.exif) {
ori = data.exif.get('Orientation');
}
console.log("ori is:" + ori);
});
var loadingImage = loadImage(
blob,
function (img) {
console.log("in loadingImage");
document.body.appendChild(img);
},
{maxWidth: 600,
orientation: 3,
canvas: true,
crossOrigin:'anonymous'
}
);
if (!loadingImage) {
// Alternative code ...
}
}
};
xhr.send();
Any ideas or alternative approaches to correctly orientating images welcome.
Your call to loadImage needs to be inside the callback from the call to parseMetaData.
The reason: as is, your code contains a race condition. The call the loadImage is very likely to be made BEFORE the call the parseMetaData completes and stuffs the orientation due to the fact they are both asynchronous calls.
Why are you making a new blob whereas you asked for a Blob? The metadata are then lost, this is why you are losing it and exif is null.
Just replace :
var blob = new Blob([this.response], {type: 'image/png'});
By:
var blob = this.response;
Should do the trick.
Had the same problem, I changed the reponse type for 'arrayBuffer' and then create the blob from the response
xhr.responseType = 'arraybuffer';
xhr.onload = function (e) {
if (this.status == 200) {
var arrayBufferView = new Uint8Array(this.response);
var blob = new Blob([arrayBufferView], { type: "image/jpeg" });
...
Related
Can you please tell me how can I correctly store some js file to localstorage and then run it.
So I have found some code that stores an image, but can I store a js file?
Here is the code:
https://gist.github.com/robnyman/1875344
// Getting a file through XMLHttpRequest as an arraybuffer and creating a Blob
var rhinoStorage = localStorage.getItem("rhino"),
rhino = document.getElementById("rhino");
if (rhinoStorage) {
// Reuse existing Data URL from localStorage
rhino.setAttribute("src", rhinoStorage);
}
else {
// Create XHR and FileReader objects
var xhr = new XMLHttpRequest(),
fileReader = new FileReader();
xhr.open("GET", "rhino.png", true);
// Set the responseType to blob
xhr.responseType = "blob";
xhr.addEventListener("load", function () {
if (xhr.status === 200) {
// onload needed since Google Chrome doesn't support addEventListener for FileReader
fileReader.onload = function (evt) {
// Read out file contents as a Data URL
var result = evt.target.result;
// Set image src to Data URL
rhino.setAttribute("src", result);
// Store Data URL in localStorage
try {
localStorage.setItem("rhino", result);
}
catch (e) {
console.log("Storage failed: " + e);
}
};
// Load blob as Data URL
fileReader.readAsDataURL(xhr.response);
}
}, false);
// Send XHR
xhr.send();
}
I'm generating a PDF document using jsPDF, however I need to add the images submitted in the form into this document.
// You'll need to make your image into a Data URL
// Use http://dataurl.net/#dataurlmaker
var imgData = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAMEBgUGBgYFBgYGBwkIBgcJBwYGCAsICQoKCgoKBggLDAsKDAkKCgr/2wBDAQICAgICAg[...]' //snip
[...]
doc.addImage(imgData, 'JPEG', 15, 40, 180, 160)
However, as shown in the snip above I need to convert the file to DataURI, but I haven't found a library that does this, nor a reliable way to do it with pure JavaScript.
I found the following method that allows me to extract the DataURI from an URL with XMLHttpRequest.
function obtenerDataUri(url, pos, lastpos, isleft)
{
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'blob';
request.onload = function() {
var reader = new FileReader();
reader.readAsDataURL(request.response);
reader.onload = function(e){
var imgData = e.target.result.replace("data:application/xml;", "data:application/png;"), pos, lastpos, isleft;
doc.addImage(imgData, 'PNG', (isleft) ? 15 : 90, (isleft) ? pos : lastpos, 75, 75);
};
};
request.send();
}
This method doesn't work for me because it's asynchronous, it means I'm adding the content in the PDF after it's fully generated. This method doesn't work synchronously because responseType is not supported in synchronous requests(probably due the deprecation).
Note that these images are already uploaded to the server when the PDF is ready to be generated, so I can't get the DataURIs on local files.
This function is called from here:
$('#imgArea img').each(function()
{
g_bPDFGisLeft = !g_bPDFGisLeft;
var bPDFGposCheck = true;
while(bPDFGposCheck)
{
var pos = (g_iPDFGpage == 0) ? doc.autoTable.previous.finalY+8+(75*g_iPDFGimg) : (75*g_iPDFGimg);
if((pos+(75*(g_iPDFGimg+1))) >= 300)
{
doc.addPage();
g_iPDFGimg = 0;
g_iPDFGpage++;
bPDFGposCheck = true;
}
else
bPDFGposCheck = false;
}
obtenerDataUri($(this).attr('src'), pos, g_fPDFGlastPos, g_bPDFGisLeft);
g_fPDFGlastPos = pos;
if(!g_bPDFGisLeft)
g_iPDFGimg++;
});
After executing obtenerDataUri, due the fact it's doing a request, won't wait until the onload function completes. This mean the PDF generator will keep adding pages and placing the images asynchronously in the incorrect pages.
How can I get the DataURI in a synchronous way from URL images?
I appreciate any help with this issue. Please tell me if you need more details about this.
Don't return result. Instead pass it to a callback function:
function obtenerDataUrl(url)
{
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'blob';
request.onload = function() {
var reader = new FileReader();
reader.readAsDataURL(request.response);
reader.onload = function(e){
//return e.target.result;
handleResult(e.target.result);
};
};
request.send();
}
function handleResult(result) {
var imgData = result; // or take whatever you need inside result
doc.addImage(imgData, 'JPEG', 15, 40, 180, 160);
}
I am uploading a bunch of png files to AWS, and fetching them as I need them. When uploading, I stream the data read through fs, and when downloading I pipe the data from AWS as a response.
Anyhow, when I get hold of the data on the client, it is returned as a string with the following structure:
�PNG
IHDR�x�� IDATx���_��[�����1���s�?��9u����h�...
How do I load this into a texture? I have tried with this (also recommended by mrdoob here)
But it results in the Image throwing an uninformative error, and onload is never called.
let image = new Image();
let texture = new THREE.Texture();
image.onerror = function(e) {
//enters here
}
image.onload = function(e) {
//never here
texture.image = texture_image;
texture.needsUpdate = true;
}
image.src = myFetchedPNGData;
What is the correct way to create a THREE.Texture out of this data?
EDIT:
Here is the request for fetching the data:
let requestt = new XMLHttpRequest();
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/json');
request.addEventListener('load', (event) => {
// Here myFetchedPNGData recides in event.target.response
}, false);
request.addEventListener('error', (event) => {
//do error handling
}, false);
onProgress && request.addEventListener('progress', (event) => {
//Handle request
}, false);
request.send(...);
I've tried several different options, so many I've lost track of them all. I'm making an AJAX request and the response is of Content-Type: image/png, and the contents are the actual image.
I would absolutely love to display the image, but nothing seems to work the way I want:
// imgdata contains a string that looks like this: "�PNG..."
var img = document.createElement('img');
// no good
img.src = 'data:image/png;base64,' + btoa(unescape(encodeURIComponent(data)));
// also no good
img.src = 'data:image/png;base64,' + btoa(encodeURIComponent(data));
// also no good
img.src = 'data:image/png;base64,' + btoa($.map(d, function(x){ return x.charCodeAt(0); }))
I've tried a few other things, but still no dice.
Is there any simple (or even complciated) way to do this in Javascript?
This isn't done with base64 but with blob, but you'll get exactly the same result:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200){
var img = document.getElementById('image');
var url = window.URL || window.webkitURL;
img.src = url.createObjectURL(this.response);
}
}
// Relative path because :
// No 'Access-Control-Allow-Origin' header is present...
xhr.open('GET', '/img/logo.png');
xhr.responseType = 'blob';
xhr.send();
Demo here : http://jsfiddle.net/sparkup/sp4cukee/
If you're serving this file via node.js or PHP you could always write the file to disk in temporary location server-side, serve it, and then immediately delete it afterwards.
var tempFile = 'path/to/file.jpg';
// Write the file to disk
fs.writeFile(tempFile, base64versionOfPhoto, function (err) {
if (err) {
res.header("Content-Type","application/json");
return res.send(JSON.stringify(err));
} else {
// Pipe the jpg to the user
res.header("Content-Type","image/jpeg");
var readStream = fs.createReadStream(tempFile);
readStream.pipe(res, {end: false});
readStream.on("end", function () {
res.end();
// Delete the file
fs.unlink(tempFile, function (err) {
if (err) console.log(err);
});
});
}
});
While I was trying to create a workaround for Chrome unsupporting blobs in IndexedDB I discovered that I could read an image through AJAX as an arraybuffer, store it in IndexedDB, extract it, convert it to a blob and then show it in an element using the following code:
var xhr = new XMLHttpRequest(),newphoto;
xhr.open("GET", "photo1.jpg", true);
xhr.responseType = "arraybuffer";
xhr.addEventListener("load", function () {
if (xhr.status === 200) {
newphoto = xhr.response;
/* store "newphoto" in IndexedDB */
...
}
}
document.getElementById("show_image").onclick=function() {
var store = db.transaction("files", "readonly").objectStore("files").get("image1");
store.onsuccess = function() {
var URL = window.URL || window.webkitURL;
var oMyBlob = new Blob([store.result.image], { "type" : "image\/jpg" });
var docURL = URL.createObjectURL(oMyBlob);
var elImage = document.getElementById("photo");
elImage.setAttribute("src", docURL);
URL.revokeObjectURL(docURL);
}
}
This code works fine. But if I try the same process, but this time loading a video (.mp4) I can't show it:
...
var oMyBlob = new Blob([store.result.image], { "type" : "video\/mp4" });
var docURL = URL.createObjectURL(oMyBlob);
var elVideo = document.getElementById("showvideo");
elVideo.setAttribute("src", docURL);
...
<video id="showvideo" controls ></video>
...
Even if I use xhr.responseType = "blob" and not storing the blob in IndexedDB but trying to show it immediately after loading it, it still does not works!
xhr.responseType = "blob";
xhr.addEventListener("load", function () {
if (xhr.status === 200) {
newvideo = xhr.response;
var docURL = URL.createObjectURL(newvideo);
var elVideo = document.getElementById("showvideo");
elVideo.setAttribute("src", docURL);
URL.revokeObjectURL(docURL);
}
}
The next step was trying to do the same thing for PDF files, but I'm stuck with video files!
This is a filler answer (resolved via the OP found in his comments) to prevent the question from continuing to show up under "unanswered" questions.
From the author:
OK, I solved the problem adding an event that waits for the
video/image to load before executing the revokeObjectURL method:
var elImage = document.getElementById("photo");
elImage.addEventListener("load", function (evt) { URL.revokeObjectURL(docURL); }
elImage.setAttribute("src", docURL);
I suppose the revokeObjectURL method was executing before the video
was totally loaded.