Using FileReader.readAsDataUrl to upload image to Web Api service

monkeydeus picture monkeydeus · Jan 7, 2014 · Viewed 13.6k times · Source

I am trying to use the FileReader to obtain the base-64 representation of an image and submit that to a .net WebApi service for image uploading.

My problem is that the contents of fileReader.result are not valid as a base-64 encoded image, at least according to .net.

I am just using a very simple method, and testing with fiddler to post to the service. If I post the complete result string from filereader.result, I get an error "Invalid length for a Base-64 char array or string" when I try and read the string using FromBase64String.

public void Post([FromBody]string imgString)
    {
        var myString = imgString.Split(new char[]{','});
        byte[] bytes = Convert.FromBase64String(myString[1]);
        using (MemoryStream ms = new MemoryStream(bytes))
        {
            Image image = Image.FromStream(ms);
            image.Save("myBlargyImage.jpg");
        }
    }

Is cut+paste into fiddler doing something to the string that I need to account for here, or is there something else I am not doing correctly? This seems like it should be straightforward: Encode the image as a string, send the string, decode the string, save the image.

For example, using filereader to display a preview of the image on the client, I get the following in filereader.result:

src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEAyADIAAD/...oBUA00AqYL/AMCg3//Z"

I have tried both sending the entire string ("data...Z"), and just the Base64 string. Currently, I am splitting the string server side to get the Base64 string. Doing this, I always get the invalid length error.

Alternatively, I have tried sending just the base64 string. Not knowing if the leading / was actually part of the string or not, I deleted it in the post body. Doing THIS, I can actually read the value into a byte array, but then I get an error using Image.FromStream that the array is not a valid image.

So, either I get an error that the entire string as provided by filereader is an invalid length, or, I hack it up and get an error that even if it is a valid length, it is not a valid image (when reading the bytearray). That is what makes me wonder if there is some issue of translation or formatting between the filereader.read, dev tools in chrome, then cutting and pasting into fiddler.

UPDATE: I tried a more realistic implementation by just taking the filereader.result and putting it in a $.post() call, and it works as expected.

It appears I was right, that I, or notepad++, or fiddler, are doing something to the data when I touch it to cut and paste filereader.result into a service call.

If someone knows exactly what that might be, or how one can verify they are sending a valid base-64 encoding of an image to a service, it might help others who are attempting the same thing in the future.

Again, if in the browser filereader.result yielded 'data:image/jpeg;base64,somestring', I was simply copying that string from the developer tools panel, creating a fiddler call and in the request body including the copied string: "=data:image/jpeg;base64,somestring". Somehow, the base-64 'somestring' was getting munched in the cut+paste.

function readURL(input) {

        if (input.files && input.files[0]) {
            reader = new FileReader();

            reader.onload = function (e) {
                $('#imgPreview').attr('src', e.target.result);
                $.post('/api/testy/t/4',
                    {'':e.target.result}
                );
            };

            reader.readAsDataURL(input.files[0]);
            reader.onloadend = function (e) {
                console.log(e.target.result);
            };
        }
    }

    $("#imgUpload").change(function () {
        readURL(this);
    });

Answer

Edgar Villegas Alvarado picture Edgar Villegas Alvarado · Jan 7, 2014

Don't forget to remove the 'noise' from a dataUrl,

For example in

data:image/png;base64,B64_DATA_HERE

you have to remove the data:image/png;base64, part before, so you process only the base 64 portion.

With js, it would be

var b64 = dataUrl.split("base64,")[1];

Hope this helps. Cheers