Reading PNG binary data in JAVASCRIPT - javascript

var uint8 = new Uint8Array(plaintext);
var arrayBuffer = uint8.buffer;
var blob = new Blob([arrayBuffer]);
var reader = new FileReader();
reader.onload = function(){
var dataURL = reader.result;
console.log('DATAURL');
console.log(dataURL);
};
reader.readAsBinaryString(blob);
plaintext - is a png binary data, the problem is that dataURL comes empty am I do everything right in the code, or the problem may be in the binary data itself?

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();

How to properly convert base64 to ArrayBuffer (images)?

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.

Converting readAsBinaryString to Data:URI

I have a binaryString variable as readAsBinaryString. How can I convert it to data:uri?
var reader = new FileReader();
reader.onloadend = function () {
var binaryString = reader.result;
console.log(binaryString);
console.log(window.btoa(binaryString));//does not contain mime-type at the beginning
}
var file=document.getElementById("fileToUpload").files[0];
reader.readAsBinaryString(file);
I need to operate over directly binaryString. I am sending the binaryString to another Javascript application. So in that context I only have binaryString value. The code above is just an example. Please do not recommend URL.createObjectURL or FileRader.readAsDataURL.
I need to operate over binaryString directly and convert it data:uri.

HTML5 - resize image and keep EXIF in resized image

How can I resize an image (using an HTML5 canvas element) and keep the EXIF information from the original image? I can extract EXIF info from from original image but I don't know how to copy it to the resized image.
This is how I retrieve the resized image data to send to the server-side code:
canvas.toDataURL("image/jpeg", 0.7);
For EXIF retrieval, I'm using the exif.js library.
Working solution: ExifRestorer.js
Usage with HTML5 image resize:
function dataURItoBlob(dataURI)
{
var binary = atob(dataURI.split(',')[1]);
var array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
}
And main code, taken as part of HTML5 resizer from this page: https://github.com/josefrichter/resize/blob/master/public/preprocess.js (but slightly modified)
var reader = new FileReader();
//reader.readAsArrayBuffer(file); //load data ... old version
reader.readAsDataURL(file); //load data ... new version
reader.onload = function (event) {
// blob stuff
//var blob = new Blob([event.target.result]); // create blob... old version
var blob = dataURItoBlob(event.target.result); // create blob...new version
window.URL = window.URL || window.webkitURL;
var blobURL = window.URL.createObjectURL(blob); // and get it's URL
// helper Image object
var image = new Image();
image.src = blobURL;
image.onload = function() {
// have to wait till it's loaded
var resized = ResizeImage(image); // send it to canvas
resized = ExifRestorer.restore(event.target.result, resized); //<= EXIF
var newinput = document.createElement("input");
newinput.type = 'hidden';
newinput.name = 'html5_images[]';
newinput.value = resized; // put result from canvas into new hidden input
form.appendChild(newinput);
};
};
You can use copyExif.js.
This module is more efficient than Martin's solution and uses only Blob and ArrayBuffer without Base64 encoder/decoder.
Besides, there is no need to use exif.js if you only want to keep EXIF. Just copy the entire APP1 marker from the original JPEG to the destination canvas blob and it would just work. It is also how copyExif.js does.
Usage
demo: https://codepen.io/tonytonyjan/project/editor/XEkOkv
<input type="file" id="file" accept="image/jpeg" />
import copyExif from "./copyExif.js";
document.getElementById("file").onchange = async ({ target: { files } }) => {
const file = files[0],
canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d");
ctx.drawImage(await blobToImage(file), 0, 0, canvas.width, canvas.height);
canvas.toBlob(
async blob =>
document.body.appendChild(await blobToImage(await copyExif(file, blob))),
"image/jpeg"
);
};
const blobToImage = blob => {
return new Promise(resolve => {
const reader = new FileReader(),
image = new Image();
image.onload = () => resolve(image);
reader.onload = ({ target: { result: dataURL } }) => (image.src = dataURL);
reader.readAsDataURL(blob);
});
};
It looks my code is used in 'ExifRestorer.js'...
I've try resizing image by canvas. And I felt that resized image is bad quality. If you felt so, too, try my code. My code resizes JPEG by bilinear interpolation. Of course it doesn't lose exif.
https://github.com/hMatoba/JavaScript-MinifyJpegAsync
function post(data) {
var req = new XMLHttpRequest();
req.open("POST", "/jpeg", false);
req.setRequestHeader('Content-Type', 'image/jpeg');
req.send(data.buffer);
}
function handleFileSelect(evt) {
var files = evt.target.files;
for (var i = 0, f; f = files[i]; i++){
var reader = new FileReader();
reader.onloadend = function(e){
MinifyJpegAsync.minify(e.target.result, 1280, post);
};
reader.readAsDataURL(f);
}
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
Canvas generates images with 20 bytes header (before jpeg data segments start). You can slice head with exif segments from original file and replace first 20 bytes in resized one.

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