admin管理员组

文章数量:1221351

I'm trying to get the content of an image in a base64 string.

Originally I was doing it with readAsDataURL but because I want to validate the mimetype on the client side, it seems I have to use readAsArrayBuffer as also pointed out on this site.

So prevoiusly I had this working fine:

var reader = new FileReader();
reader.onloadend = function(event) {
    var base64 = reader.result;
};

reader.readAsDataURL(event.target.files[0]);

Reproduction online

Now I added the mimetype validation and I have the following:

var reader = new FileReader();

reader.onloadend = function(event) {

    var realMimeType = getRealMimeType(reader);

    if (realMimeType !== 'unknown') {
        var emptyBufferArray = reader.result; //nothing
    }else{
        alert("Invalid mime type!");
    }
};

reader.readAsArrayBuffer(event.target.files[0]); //<-- notice the difference

Reproduction online (not getting the base64 string)

I'm trying to get the content of an image in a base64 string.

Originally I was doing it with readAsDataURL but because I want to validate the mimetype on the client side, it seems I have to use readAsArrayBuffer as also pointed out on this site.

So prevoiusly I had this working fine:

var reader = new FileReader();
reader.onloadend = function(event) {
    var base64 = reader.result;
};

reader.readAsDataURL(event.target.files[0]);

Reproduction online

Now I added the mimetype validation and I have the following:

var reader = new FileReader();

reader.onloadend = function(event) {

    var realMimeType = getRealMimeType(reader);

    if (realMimeType !== 'unknown') {
        var emptyBufferArray = reader.result; //nothing
    }else{
        alert("Invalid mime type!");
    }
};

reader.readAsArrayBuffer(event.target.files[0]); //<-- notice the difference

Reproduction online (not getting the base64 string)

Share Improve this question edited May 23, 2017 at 12:07 CommunityBot 11 silver badge asked Apr 12, 2016 at 23:08 AlvaroAlvaro 41.6k31 gold badges172 silver badges345 bronze badges 0
Add a comment  | 

4 Answers 4

Reset to default 6

The only way I found of doing it was to use two different FileReader instances, one inside the other.

Reproduction online

Javascript

$(document).on('change', '#upload', addBackgroundImage);

function addBackgroundImage(event) {
    var reader = new FileReader();
    var readerBase64 = new FileReader();
    var image = event.target.files[0];

    reader.onloadend = function() {
        var realMimeType = getRealMimeType(reader);
        if (realMimeType !== 'unknown') {
            readerBase64.readAsDataURL(image);
        } else {
            alert("Please upload a valid image file");
        }
    };

    reader.readAsArrayBuffer(image);

    readerBase64.onloadend = function(){
        var base64 = this.result;
        $('.bg').css('background-image', 'url('+base64+')');
    };

    $('#upload').val('');
}

function getRealMimeType(reader){
    var arr = (new Uint8Array(reader.result)).subarray(0, 4);
    var header = '';
    var realMimeType;

    for (var i = 0; i < arr.length; i++) {
        header += arr[i].toString(16);
    }

    // magic numbers: http://www.garykessler.net/library/file_sigs.html
    switch (header) {
        case "89504e47":
            realMimeType = "image/png";
            break;
        case "47494638":
            realMimeType = "image/gif";
            break;
        case "ffd8ffDB":
        case "ffd8ffe0":
        case "ffd8ffe1":
        case "ffd8ffe2":
        case "ffd8ffe3":
        case "ffd8ffe8":
            realMimeType = "image/jpeg";
            break;
        default:
            realMimeType = "unknown"; // Or you can use the blob.type as fallback
            break;
    }

    return realMimeType;
}

HTML

<input type="file" id="upload" />
<div class="bg"></div>

I didn't manage yet to use base64 but I found a way to do it using blob. If you find a way to do it using base64 please add your answer.

Right now my image string looks like this, which I believe will generate me some problems:

 background-image: url("blob:https%3A//fiddle.jshell.net/214b3c01-5b38-4aae-b839-e35cf57a5190");

I got the hint from a fiddle about how to render a retrieved image as a blob URL

Then I just applied it to my code with a little improvement and voila!!

Reproduction online Working in IE> 9, Chrome, Firefox...

Whole code:

HTML

<input type="file" id="upload" />
<div class="bg"></div>

Javascript

$(document).on('change', '#upload', addBackgroundImage);

function addBackgroundImage(event) {
    var reader = new FileReader();

    reader.onloadend = function(event) {
        var realMimeType = getRealMimeType(reader);

        if (realMimeType !== 'unknown') {
            var base64 = reader.result;

            var arrayBufferView = new Uint8Array( this.result );
            var blob = new Blob( [ arrayBufferView ], { type: realMimeType } );
            var urlCreator = window.URL || window.webkitURL || {}.createObjectURL;
            var imageUrl = urlCreator.createObjectURL( blob );

            $('.bg').css('background-image', 'url('+imageUrl+')');
        } else {
            alert("Please upload a valid image file");
        }
    }
    reader.readAsArrayBuffer(event.target.files[0]);
     $('#upload').val('');
}

function getRealMimeType(reader){
    var arr = (new Uint8Array(reader.result)).subarray(0, 4);
    var header = '';
    var realMimeType;

    for (var i = 0; i < arr.length; i++) {
        header += arr[i].toString(16);
    }

    // magic numbers: http://www.garykessler.net/library/file_sigs.html
    switch (header) {
        case "89504e47":
            realMimeType = "image/png";
            break;
        case "47494638":
            realMimeType = "image/gif";
            break;
        case "ffd8ffDB":
        case "ffd8ffe0":
        case "ffd8ffe1":
        case "ffd8ffe2":
        case "ffd8ffe3":
        case "ffd8ffe8":
            realMimeType = "image/jpeg";
            break;
        default:
            realMimeType = "unknown"; // Or you can use the blob.type as fallback
            break;
    }

    return realMimeType;
}

You can try this "stolen" function:

function arrayBufferToBase64(buffer) {
  let binary = '';
  const bytes = new Uint8Array(buffer);
  const len = bytes.byteLength;
  for (let i = 0; i < len; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return window.btoa(binary);
}

The solution below worked for me using just one FileReader :

reader.onloadend = function(event) {
    const arrayBuffer = reader.result;
    const blob = new Blob([arrayBuffer], {type: 'image/png'});
    let src = URL.createObjectURL(blob);
};
reader.readAsArrayBuffer(event.target.files[0]); 

hope that helps!

本文标签: javascriptGet image base64 with readerreadAsArrayBuffer(file)Stack Overflow