resize image before upload via background transfer in winjs

0

I would like to resize an image picked from the gallery of the phone before uploading it via background transfer so far I have:-

filePicker.pickSingleFileAsync().then(function (file) {
                            uploadSingleFileAsync(uri, file);
                        }).done(null, displayException);

function uploadSingleFileAsync(uri, file) {
                    if (!file) {
                        displayError("Error: No file selected.");
                        return;
                    }
                    return file.getBasicPropertiesAsync().then(function (properties) {
                        if (properties.size > maxUploadFileSize) {
                            displayError("Selected file exceeds max. upload file size (" + (maxUploadFileSize / (1024 * 1024)) +
                                " MB).");
                            return;
                        }
                        var upload = new UploadOperation();
                        //tried this to compress the file but it doesnt work obviously not right for the object
                        //file = file.slice(0, Math.round(file.size / 2));
                        upload.start(uri, file);
                        // Persist the upload operation in the global array.
                        uploadOperations.push(upload);
                    });
                }

and the rest then uploads the file. I tried adding in .slice but it doesn't work (im guessing because file is an object rather than) and i'm not sure how to compress this type of file object. I can't seem to find any examples or advice on msdn or the windows dev forums, I can obviously resize the photos once they are on the server but I would rather users are not waiting longer than they have to for their files to upload.

Do I need to save the image before I can manipulate it? Any advice would be greatly appreciated!

** EDIT *

my upload singlefileasync now looks like:-

function uploadSingleFileAsync(uri, file) {
                    if (!file) {
                        displayError("Error: No file selected.");
                        return;
                    }

                    return file.getBasicPropertiesAsync().then(function (properties) {
                        if (properties.size > maxUploadFileSize) {
                            displayError("Selected file exceeds max. upload file size (" + (maxUploadFileSize / (1024 * 1024)) +
                                " MB).");
                            return;
                        }







                        // Exception number constants. These constants are defined using values from winerror.h,
                        // and are compared against error.number in the exception handlers in this scenario.

                        // This file format does not support the requested operation; for example, metadata or thumbnails.
                        var WINCODEC_ERR_UNSUPPORTEDOPERATION = Helpers.convertHResultToNumber(0x88982F81);
                        // This file format does not support the requested property/metadata query.
                        var WINCODEC_ERR_PROPERTYNOTSUPPORTED = Helpers.convertHResultToNumber(0x88982F41);
                        // There is no codec or component that can handle the requested operation; for example, encoding.
                        var WINCODEC_ERR_COMPONENTNOTFOUND = Helpers.convertHResultToNumber(0x88982F50);
                        // Keep objects in-scope across the lifetime of the scenario.
                        var FileToken = "";
                        var DisplayWidthNonScaled = 0;
                        var DisplayHeightNonScaled = 0;
                        var ScaleFactor = 0;
                        var UserRotation = 0;
                        var ExifOrientation = 0;
                        var DisableExifOrientation = false;

                        // Namespace and API aliases
                        var FutureAccess = Windows.Storage.AccessCache.StorageApplicationPermissions.futureAccessList;
                        var LocalSettings = Windows.Storage.ApplicationData.current.localSettings.values;

                        //FileToken = FutureAccess.add(file);
                        FileToken = Windows.Storage.AccessCache.StorageApplicationPermissions.futureAccessList.add(file);

                        id("myImage").src = window.URL.createObjectURL(file, { oneTimeOnly: true });
                        id("myImage").alt = file.name;

                        // Use BitmapDecoder to attempt to read EXIF orientation and image dimensions.
                        return loadSaveFileAsync(file)


                        function resetPersistedState() {
                            LocalSettings.remove("scenario2FileToken");
                            LocalSettings.remove("scenario2Scale");
                            LocalSettings.remove("scenario2Rotation");
                        }
                        function resetSessionState() {
                            // Variables width and height reflect rotation but not the scale factor.
                            FileToken = "";
                            DisplayWidthNonScaled = 0;
                            DisplayHeightNonScaled = 0;
                            ScaleFactor = 1;
                            UserRotation = Windows.Storage.FileProperties.PhotoOrientation.normal;
                            ExifOrientation = Windows.Storage.FileProperties.PhotoOrientation.normal;
                            DisableExifOrientation = false;

                        }




                        function loadSaveFileAsync(file) {
    // Keep data in-scope across multiple asynchronous methods.
    var inputStream;
    var outputStream;
    var encoderId;
    var pixels;
    var pixelFormat;
    var alphaMode;
    var dpiX;
    var dpiY;
    var outputFilename;
    var ScaleFactor = 0.5;

    new WinJS.Promise(function (comp, err, prog) { comp(); }).then(function () {
        // On Windows Phone, this call must be done within a WinJS Promise to correctly
        // handle exceptions, for example if the file is read-only.
        return FutureAccess.getFileAsync(FileToken);

    }).then(function (inputFile) {
        return inputFile.openAsync(Windows.Storage.FileAccessMode.read);
    }).then(function (stream) {
        inputStream = stream;
        return Windows.Graphics.Imaging.BitmapDecoder.createAsync(inputStream);
    }).then(function (decoder) {
        var transform = new Windows.Graphics.Imaging.BitmapTransform();

        // Scaling occurs before flip/rotation, therefore use the original dimensions
        // (no orientation applied) as parameters for scaling.
        // Dimensions are rounded down by BitmapEncoder to the nearest integer.
        transform.scaledHeight = decoder.pixelHeight * ScaleFactor;
        transform.scaledWidth = decoder.pixelWidth * ScaleFactor;
        transform.rotation = Helpers.convertToBitmapRotation(UserRotation);

        // Fant is a relatively high quality interpolation mode.
        transform.interpolationMode = Windows.Graphics.Imaging.BitmapInterpolationMode.fant;

        // The BitmapDecoder indicates what pixel format and alpha mode best match the
        // natively stored image data. This can provide a performance and/or quality gain.
        pixelFormat = decoder.bitmapPixelFormat;
        alphaMode = decoder.bitmapAlphaMode;
        dpiX = decoder.dpiX;
        dpiY = decoder.dpiY;

        // Get pixel data from the decoder. We apply the user-requested transforms on the
        // decoded pixels to take advantage of potential optimizations in the decoder.
        return decoder.getPixelDataAsync(
            pixelFormat,
            alphaMode,
            transform,
            Windows.Graphics.Imaging.ExifOrientationMode.respectExifOrientation,
            Windows.Graphics.Imaging.ColorManagementMode.colorManageToSRgb
            );
    }).then(function (pixelProvider) {
        pixels = pixelProvider.detachPixelData();

        // The destination file was passed as an argument to loadSaveFileAsync().
        outputFilename = file.name;
        switch (file.fileType) {
            case ".jpg":
                encoderId = Windows.Graphics.Imaging.BitmapEncoder.jpegEncoderId;
                break;
            case ".bmp":
                encoderId = Windows.Graphics.Imaging.BitmapEncoder.bmpEncoderId;
                break;
            case ".png":
            default:
                encoderId = Windows.Graphics.Imaging.BitmapEncoder.pngEncoderId;
                break;
        }

        return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
    }).then(function (stream) {
        outputStream = stream;

        // BitmapEncoder expects an empty output stream; the user may have selected a
        // pre-existing file.
        outputStream.size = 0;
        return Windows.Graphics.Imaging.BitmapEncoder.createAsync(encoderId, outputStream);
    }).then(function (encoder) {
        // Write the pixel data onto the encoder. Note that we can't simply use the
        // BitmapTransform.ScaledWidth and ScaledHeight members as the user may have
        // requested a rotation (which is applied after scaling).
        encoder.setPixelData(
            pixelFormat,
            alphaMode,
            DisplayWidthNonScaled * ScaleFactor,
            DisplayHeightNonScaled * ScaleFactor,
            dpiX,
            dpiY,
            pixels
            );

        return encoder.flushAsync();
    }).then(function () {
        WinJS.log && WinJS.log("Successfully saved a copy: " + outputFilename, "sample", "status");
    }, function (error) {
        WinJS.log && WinJS.log("Failed to update file: " + error.message, "sample", "error");
        resetSessionState();
        resetPersistedState();
    }).then(function () {
        // Finally, close each stream to release any locks.
        inputStream && inputStream.close();
        outputStream && outputStream.close();
    }).then(function () {
        var upload = new UploadOperation();
        upload.start(uri, file);
        // Persist the upload operation in the global array.
        uploadOperations.push(upload);

    });
}

But I am getting an error when I reach this line return
file.openAsync(Windows.Storage.FileAccessMode.readWrite); saying that I do not have write access? How do I get write access or move it so that I can have write access?

javascript
windows-phone-8.1
winjs
win-universal-app
background-transfer
asked on Stack Overflow Aug 14, 2014 by user3249516 • edited Sep 4, 2014 by user3249516

1 Answer

1

To resize an image you can use the image encoding APIs in WinRT, namely that in Windows.Graphics.Imaging. I suggest you look at scenario 2 of the Simple Imaging Sample (http://code.msdn.microsoft.com/windowsapps/Simple-Imaging-Sample-a2dec2b0) which shows how to do all manners of transforms on an image. Changing the dimensions is included there, so it'll just be a matter of chopping out the parts you don't need.

I have a discussion about all this in my free ebook, Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition, in Chapter 13, section "Image Manipulation and Encoding". In there I try to separate out the main steps in the process into something a little more digestible, and provide an additional sample.

The process of encoding can look rather involved (lots of chained promises), but it's quite straightforward and is exactly what an email program would do to reduce the size of attached images, for instance. In any case, you should end up with another StorageFile with a smaller image that you can then pass to the uploader. I would recommend using your Temporary app data for such files, and be sure to clean them up when the upload is complete.


User contributions licensed under CC BY-SA 3.0