How to properly convert base64 to ArrayBuffer (images)? - javascript

First, I am using canvas to get images as ArrayBuffer and make some processing. I am doing this:
var buf = canvas.getContext("2d").getImageData(0, 0, width, height).data.buffer;
process(buf);
This does not work on images coming from domains different to the web page's due to the same origin policy.
To solve this my best bet is XMLHttpRequest. Here, I get a blob; then I use a FileReader. I can use FileReader.readAsArrayBuffer, however, I also need the dimensions of the image. For that reason I use FileReader.readAsDataURL. Once the data is read, I set the result as the src attribute of an Image object, when the image has been loaded I can get the width and height of the image.
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {
var image = new Image();
image.src = this.result;
image.onload = function() {
var arrayBuffer = dataURItoArrayBuffer(this.src);
}
}
reader.readAsDataURL(xhr.response);
}
xhr.open("GET", source);
xhr.responseType = "blob";
xhr.send();
As mentioned, I need the data as ArrayBuffer, so I have created a function to do so based on this code to make the convertion from base64.
function dataURItoArrayBuffer(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return ab;
}
The resulting ArrayBuffer of this function is not consistent with the dimensions of the image. For instance, an image with dimensions 32 x 32 should result in an ArrayBuffer of 3072 (32 x 32 x 3), however, the function creates an ArrayBuffer of 270, 414, or any other value unrelated to the expected one.
How can I get a consistent ArrayBuffer for that image in base64 format?
Am I missing something?
Thanks.

Related

javascript image base64 and php image base64_encode are different

I have an jpeg image and I am trying to get the base64 encoded string with both javascript & php.
function getBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL("image/jpg");
return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}
var base64 = getBase64Image(document.getElementById('myImg'));
console.log(base64)
Here is the javascript fiddle.
Now, with the same image with php code
$url = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/SIPI_Jelly_Beans_4.1.07.tiff/lossy-page1-256px-SIPI_Jelly_Beans_4.1.07.tiff.jpg"
var_dump(base64_encode(file_get_contents($url));
// The Javascript result:
"iVBORw0KGgoAAAANSUh......LGoT8H4JpIaDthj+xAAAAAElFTkSuQmCC"
// The PHP result:
"/9j/4AAQSkZJRgABAQA......nbKBwJCElGEDnboCdvdE5pDlGThLlNC/9k="
I made the changes in Javascript that #JaromandaX suggested, now the Javascript string's beginning looks similar but not the end.
var dataURL = canvas.toDataURL("image/jpeg");
return dataURL.replace(/^data:image\/(png|jpeg);base64,/, "");
New Javascript Output:
"/9j/4AAQSkZJRgABAQA......A4EhCSjCBzt0BO3uic0hyjccJcpoX//2Q=="
The issue is, you're reading a jpeg into the canvas, then producing the jpeg from the canvas ... so there's some processing going on (jpeg quality setting for example would be different)
To get identical results in javascript, simply don't use a canvas - fetch the image, and using Blob + FileReader, extract the base64
fetch('https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/SIPI_Jelly_Beans_4.1.07.tiff/lossy-page1-256px-SIPI_Jelly_Beans_4.1.07.tiff.jpg').then(r => r.blob()).then(blob => {
var reader = new FileReader();
reader.onload = function() {
var b64 = reader.result.replace(/^data:.+;base64,/, '');
console.log(`${b64.slice(0,20)}...${b64.slice(-20)}`);
};
reader.readAsDataURL(blob);
});
As #JaromandaX suggested in the comments,
"One is the direct file from the source (PHP) ... the other is a canvas - so, some "processing" has been done most likely"
Using this chunk gives the exact same base64 string:
var url = document.getElementById('myImg').getAttribute('src')
var xmlHTTP = new XMLHttpRequest();
xmlHTTP.open('GET', url, true);
xmlHTTP.responseType = 'arraybuffer';
xmlHTTP.onload = function(e) {
var arr = new Uint8Array(this.response);
var raw = String.fromCharCode.apply(null,arr);
var b64 = btoa(raw);
var dataURL="data:image/png;base64," + b64;
console.log(b64)
};
xmlHTTP.send();

ArrayBuffer to jpeg

I am streaming ArrayBuffers from a python server and am trying to interpret each one as an image on the client side with javascript. They are being received as arraybuffers in javascript. However I cant get them to be readable by the image tags src attribute. I have tried generating them into Blob objects then using window.URL.createObjectURL(blob). That hasnt work either.
The blob url looks like this blob:null/e2836074-64b5-4959-8211-da2fc24c35a6 is that wrong?
Does any have any suggestions/know a solution.
Thanks a lot.
var arrayBuffer = new Uint8Array(stream.data);
var blob = new Blob([arrayBuffer], {type: "image/jpeg"});
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL( blob );
console.log(imageUrl);
img.src = imageUrl;
array buffer image
If you have any control over things, you should use the responseType of blob on your Javascript call. This will let you use the data you are getting from your server directly instead of attempting to access it via an ArrayBuffer
See the following fiddle for an example: https://jsfiddle.net/ort74gmp/
// Simulate a call to Dropbox or other service that can
// return an image as a blob
var xhr = new XMLHttpRequest();
// Use JSFiddle logo as a sample image to avoid complicating
// this example with cross-domain issues.
xhr.open( "GET", "https://fiddle.jshell.net/img/logo.png", true );
// Ask for the result as an ArrayBuffer.
xhr.responseType = "blob";
xhr.onload = function( e ) {
var blob = this.response;
var reader = new FileReader();
reader.onload = function() {
var dataURL = reader.result;
document.querySelector('#photo').src = dataURL;
}
reader.readAsDataURL(blob);
};
xhr.send();

Blob image from database to Java and from Java to Javascript Image

I have Blob, which stored in db and i take it from database with java server like this:
Entity.java
#Column(name = "img")
private Blob img;
public Blob getImg() {
return img;
}
public void setImg(Blob img) {
this.img = img;
}
Repository.java
#Transactional
#Query(value = "SELECT img FROM articles WHERE category = ?", nativeQuery = true)
//Blob findP(String category);
Blob findPic(String category);
Controller.java
#RequestMapping(value="/Pic_test")
#ResponseBody
public Blob getPics() throws SQLException, IOException {
return remindRepository.findPic("Java");
}
Then I receive it with Javascript to image it:
function toDataURL(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {
callback(reader.result);
}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
}
toDataURL('http://localhost:8080/articles/Pic_test', function(dataUrl) {
var display = document.getElementById('display');
var url = window.URL.createObjectURL(new Blob([dataUrl]));
var img = new Image();
img.src = url;
document.getElementById("demo").innerHTML = img.src;
})
However, if I call my "img" Blob in java code, i have an error in server, but if I call it byte[], my picture is not shown just.
I can't comment the java part since I know nothing about it, but for the javascript one, what you do is... not correct.
You don't seem to understand what is a data URL, nor what you are doing here.
So a data URL is a string, made of an header and of some file content (data:|mime/type;|file-content).
A data URL is an URL that points to itself, useful to embed data that should normally be served from network.
Quite often, the file content part is encoded as base64, because the URI scheme is limited in its set of allowed characters, and that binary data couldn't be represented in this scheme.
Now let's see what you are doing here...
You are downloading a resource as a Blob. That's good, Blob are perfect objects to deal with binary data.
Then, you read this Blob a data URL. Less good, but I can see the logic, <img> can indeed load images from data URLs.
But then from this data URL string, you create a new Blob! This is completely wrong. The Blob you just created with new Blob([dataUrl]) is a text file, not your image file in any way. So yes, the data is still hidden somewhere in the base64 data which is itself in the data URL, but what your poor <img> will see when accessing the data hooked by the Blob URI is really just text, data:image/png;base64,iVBORw0... and not at all �PNG... like its parsing algo can read.
So the solution is quite easy: get rid of the FileReader step. You don't need it.
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png');
xhr.responseType = 'blob';
xhr.onload = display;
xhr.send();
function display(evt) {
// we did set xhr.responseType = "blob"
var blob = evt.target.response; // so this is a Blob
// hence, no need for anything else than
var url = URL.createObjectURL(blob);
var img = new Image();
img.src = url;
document.body.appendChild(img);
}
And if I may, all your thing could also just be
document.getElementById('display').src = 'http://localhost:8080/articles/Pic_test';

PNG or JPG (not rgb) over websocket with ArrayBuffer without base64

Is there a way to render a PNG image to canvas without having to encode it to base64?
Server sends a PNG in binary, client receives it in an ArrayBuffer
and displays it on the canvas. Only way I could get this to work is by encoding the data to base64 - on the server side - as I need it to be fast. On the client side, I created an image obj with data:image/png;base64 tag.
I know you can create a blob and a file reader but I could not get that to work.
This is the blob version:
var blob = new Blob([image.buffer],{type: "image/png"});
var imgReader = new FileReader();
imgReader.onload = function (e) {
var img = new Image();
img.onload = function (e) {
console.log("PNG Loaded");
ctx.drawImage(img, left, top);
window.URL.revokeObjectURL(img.src);
img = null;
};
img.onerror = img.onabort = function () {
img = null;
};
img.src = e.target.result;
imgReader = null;
}
imgReader.readAsDataURL(blob);
image is Uint8Array. I create a blob from it. The rest is self-explanatory.
Images are correct and valid PNG images. When I send it from the server, I wrote them to a file on the server side and they render fine with an image viewer.
You can create a blob url with createObjectURL without having to do any base64 encoding, just pass the blob you crated to it and you will have a url you can set as img.src
var blob = new Blob([image],{type: "image/png"});
var img = new Image();
img.onload = function (e) {
console.log("PNG Loaded");
ctx.drawImage(img, left, top);
window.URL.revokeObjectURL(img.src);
img = null;
};
img.onerror = img.onabort = function () {
img = null;
};
img.src = window.URL.createObjectURL(blob);
I've only seen it used in this way. If you don't want to send the base64 via the network, then, you can use the btoa to convert the binary data to a base64 on the client side.
Looking at MDN, drawImage takes a CanvasImageSource object. CanvasImageSource represents any object of type HTMLImageElement, ImageBitmap and few others.
On further searching, I found some information related to ImageBitmap, but, not enough to provide a solution.
I could have added this to the comment, but, it would have become a massive comment and lose all the clarity.

Using JavaScript to display a Blob

I am retrieving a Blob image from a database, and I'd like to be able to view that image using JavaScript. The following code produces a broken image icon on the page:
var image = document.createElement('image');
image.src = 'data:image/bmp;base64,'+Base64.encode(blob);
document.body.appendChild(image);
Here is a jsFiddle containing all the code required, including the blob. The completed code should properly display an image.
You can also get BLOB object directly from XMLHttpRequest. Setting responseType to blob makes the trick. Here is my code:
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://localhost/image.jpg");
xhr.responseType = "blob";
xhr.onload = response;
xhr.send();
And the response function looks like this:
function response(e) {
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL(this.response);
document.querySelector("#image").src = imageUrl;
}
We just have to make an empty image element in HTML:
<img id="image"/>
If you want to use fetch instead:
var myImage = document.querySelector('img');
fetch('flowers.jpg').then(function(response) {
return response.blob();
}).then(function(myBlob) {
var objectURL = URL.createObjectURL(myBlob);
myImage.src = objectURL;
});
Source:
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
You can convert your string into a Uint8Array to get the raw data. Then create a Blob for that data and pass to URL.createObjectURL(blob) to convert the Blob into a URL that you pass to img.src.
var data = '424D5E070000000000003E00000028000000EF...';
// Convert the string to bytes
var bytes = new Uint8Array(data.length / 2);
for (var i = 0; i < data.length; i += 2) {
bytes[i / 2] = parseInt(data.substring(i, i + 2), /* base = */ 16);
}
// Make a Blob from the bytes
var blob = new Blob([bytes], {type: 'image/bmp'});
// Use createObjectURL to make a URL for the blob
var image = new Image();
image.src = URL.createObjectURL(blob);
document.body.appendChild(image);
You can try the complete example at: http://jsfiddle.net/nj82y73d/
In your example, you should createElement('img').
In your link, base64blob != Base64.encode(blob).
This works, as long as your data is valid http://jsfiddle.net/SXFwP/ (I didn't have any BMP images so I had to use PNG).
I guess you had an error in the inline code of your image.
Try this :
var image = document.createElement('img');
image.src="data:image/gif;base64,R0lGODlhDwAPAKECAAAAzMzM/////wAAACwAAAAADwAPAAACIISPeQHsrZ5ModrLlN48CXF8m2iQ3YmmKqVlRtW4MLwWACH+H09wdGltaXplZCBieSBVbGVhZCBTbWFydFNhdmVyIQAAOw==";
image.width=100;
image.height=100;
image.alt="here should be some image";
document.body.appendChild(image);
Helpful link :http://dean.edwards.name/my/base64-ie.html
In the fiddle your blob isn't a blob, it's a string representation of hexadecimal data.
Try this on a blob and your done
var image = document.createElement('img');
let reader=new FileReader()
reader.addEventListener('loadend',()=>{
let contents=reader.result
image.src = contents
document.body.appendChild(image);
})
if(blob instanceof Blob) reader.readAsDataURL(blob)
readAsDataURL give you a base64 encoded image ready for you image element () source (src)
The problem was that I had hexadecimal data that needed to be converted to binary before being base64encoded.
in PHP:
base64_encode(pack("H*", $subvalue))

Categories

Resources