Foliotek / Croppie

A Javascript Image Cropper
http://foliotek.github.io/Croppie
MIT License
2.55k stars 886 forks source link

Cropped section and zoom are incorrect when image is loaded from device gallery #761

Open CodeWithOz opened 2 years ago

CodeWithOz commented 2 years ago

Expected Behavior

The cropped output should be contain the area specified within the viewport and at the specified zoom.

Actual Behavior

I'm using a cordova app. If I load the image from my device gallery, the cropped output isn't set the same zoom and doesn't include the same area I set in the viewport. If, however, I take a new pic and feed that directly to croppie, then the cropped section and zoom are correct.

Steps to Reproduce the Problem

I created a repo with a sample app for this though the app has failed to build for other reasons. You can see the code here.

The relevant javascript code is:

        const sourceType = Camera.PictureSourceType.PHOTOLIBRARY;

        const cameraOptions = {
            quality: 75,
            destinationType: Camera.DestinationType.FILE_URI,
            sourceType,
            encodingType: Camera.EncodingType.JPEG,
            saveToPhotoAlbum: false,
            correctOrientation: true,
            targetWidth: 720,
            mediaType: Camera.MediaType.PICTURE,
        };

        const storageFolder = 'externalRootDirectory';
        let folderToStoreImage = cordova.file[storageFolder]; // <-- SD card on Android

        navigator.camera.getPicture(cameraSuccess, cameraError, cameraOptions);

        // Convert base64 to Blob function for image crop
        function base64toBlob(b64Data, contentType) {
            contentType = contentType || '';
            var sliceSize = sliceSize || 512;

            const byteCharacters = atob(b64Data.split(',')[1]);
            const byteArrays = [];

            for (
                let offset = 0;
                offset < byteCharacters.length;
                offset += sliceSize
            ) {
                const slice = byteCharacters.slice(offset, offset + sliceSize);

                const byteNumbers = new Array(slice.length);
                for (let i = 0; i < slice.length; i++) {
                    byteNumbers[i] = slice.charCodeAt(i);
                }

                const byteArray = new Uint8Array(byteNumbers);

                byteArrays.push(byteArray);
            }

            const blob = new Blob(byteArrays, {
                type: contentType,
            });
            return blob;
        }

        function cameraSuccess(imageURI) {
            const newImageURI = window.Ionic.WebView.convertFileSrc(imageURI);
            window.uploadCropProfile = new Croppie(
                document.querySelector('.content'),
                {
                    enableOrientation: false,
                    enableExif: true,
                    viewport: {
                        width: 200,
                        height: 200,
                        type: 'circle',
                    },
                    boundary: {
                        width: 300,
                        height: 300,
                    },
                }
            );
            uploadCropProfile.bind({
                url: newImageURI,
            });
            uploadCropProfile
                .result({
                    type: 'base64',
                    format: 'jpeg',
                    size: 'original',
                    quality: 1,
                    circle: false,
                })
                .then(function (resp) {
                    window.resolveLocalFileSystemURL(
                        folderToStoreImage,
                        function (dirEntry) {
                            // Setup filename and assume a jpg file
                            const filename =
                                Math.floor(Math.random() * 100 + 1) +
                                '-image.jpg';
                            console.log('File name cropped ', filename);
                            // Get file and create if it's not available
                            dirEntry.getFile(
                                filename,
                                {
                                    create: true,
                                    exclusive: false,
                                },
                                function (fileEntry) {
                                    // convert base64 data to jpg
                                    let binary = base64toBlob(resp, 'jpg');

                                    // store created jpg file
                                    fileEntry.createWriter(function (
                                        fileWriter
                                    ) {
                                        // Write file end function
                                        fileWriter.onwriteend = function () {
                                            console.log('Writing done');
                                            // store and get it's path
                                            const croppedImageURL =
                                                fileEntry.nativeURL;

                                            // send cropped image URL in callback
                                            cb(croppedImageURL);
                                            uploadCropProfile.destroy();
                                        };

                                        fileWriter.onerror = function (e) {
                                            console.log('Writing error ', e);
                                        };

                                        // If data object is not passed in,
                                        // create a new Blob instead.
                                        if (!binary) {
                                            binary = new Blob(
                                                ['missing data'],
                                                {
                                                    type: 'text/plain',
                                                }
                                            );
                                        }
                                        // Write file call
                                        fileWriter.write(binary);
                                    });
                                },
                                function (errorCreateFile) {
                                    console.error(errorCreateFile);
                                }
                            );
                        },
                        function (errorCreateFS) {
                            console.error(
                                'Error getting filesystem:',
                                errorCreateFS
                            );
                        }
                    );
                });
        }

        function cameraError(message) {
            console.error(
                'Camera error:', message
            );
            if (typeof errCb === 'function') {
                errCb(message);
            }
        }

Example Link

Please recreate your issue using JSbin, JSFiddle, or Codepen.

Specifications