Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
446 views
in Technique[技术] by (71.8m points)

javascript - Cordova - Reading Large Image corrupts image

I am using the image-picker (cordova-imagePicker) plugin in order to get images from gallery and upload them to a server.

I am using Cordova 6.1.1 with Android platform 5.1.1 and the following plugins:

cordova-plugin-camera 2.2.0 "Camera"
cordova-plugin-compat 1.0.0 "Compat"
cordova-plugin-device 1.0.1 "Device"
cordova-plugin-file 4.2.0 "File"
cordova-plugin-imagepicker 1.1.0 "ImagePicker"
cordova-plugin-inappbrowser 1.4.0 "InAppBrowser"
cordova-plugin-media 2.3.0 "Media"

As callback to the plugin, I am converting the path I get to a File using the following code. Note that I use resolveFile because this code is running also in desktop in which case, the entry is already a File object.

var resolveFile = function(entry) {
    if (typeof(entry) === "string") {
        var deferred = $q.defer();
        // first convert to local file system URL
        window.resolveLocalFileSystemURL(entry, function(fileEntry) {
            // now read/convert the file to file object.
            fileEntry.file(function(file) {
                console.log("File converted to file entry");
                deferred.resolve(file);
            }, function(err) {
                console.log("Failed to convert to file entry", err);
                deferred.reject(err);
            });
        }, function(err) {
            console.log("Failed to resolve to file URL", err);
            deferred.reject(err);
        });

        return deferred.promise;
    } else {
        return $q.when(entry);
    }
};

This, in turn is used to read the image and pass it to a function that uploads it to the server ($files is what I am getting from plugin or from input in case of desktop/browser):

var upload = function () {
    if (!$files[currentFile]) {
        onAllFinished();
        return;
    }
    file = $files[currentFile];
    beforeLoad(file);
    fileReader = new FileReader();
    fileReader.onload = onload;
    fileReader.onprogress = progress;
    resolveFile(file).then(function(actualFile) {
        fileReader.readAsDataURL(actualFile);
    });
    currentFile++;
};

In the above, onload cuts the image data (following 'base64,' in string) and sends it to the the upload code which expects a base64 string and uploads the data to the server using simple AJAX call:

var uploadPhoto = function(url, photo, callback, error)
    $http.post(url, {
        photo: photo,
    })
    .success(callback)
    .error(function (data, status, headers, config) {
        if (error)
            error(data, status, headers, config);
    });

The last function works also with the camera plugin camera plugin using DATA_URI target (I know, it's not recommended) which also return a base64 string (so I can reuse the code).

It seems to me there's something wrong going on with the file reader output (I am guessing). What (I think) hints to that is that small images (10s kb) are loaded fine as well as already prepared base64 string from camera plugin but larger images (few MBs) that goes through the filereader (on Android, on desktop it is fine) are uploaded corrupted (see below).

Has anyone run into such issues? Can anyone suggest a fix (other than changing the code to use FileTransfer plugin)?

The original image:

original (almost, had to shrink it for upload to SO)

The uploaded (corrupted) image. Note, some of it is read/uploaded fine:

Uploaded to server after reading through FileReader

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I found your question while searching for a solution for a similar problem. DataURL's of large images from camera would show up when used as the source of an image but the same image got corrupted when I use fileReader.readAsDataURL.

I've been able to bypass the problem by using fileReader.readAsBinaryData instead of fileReader.readAsDataURL and then turning the binarystring into a dataURL.

window.resolveLocalFileSystemURL(imageUri, function done(fileEntry) {
    fileEntry.file(function (fileObj) {
        var image = new Image();
        var reader = new FileReader();
        reader.onloadend = function (e) {
            image.src = "data:image/jpeg;base64," + window.btoa(e.target.result)
        }
        reader.readAsBinaryString(fileObj);
    }
} 

Hopefully this helps you to find a workaround of your own.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...