[SOLVED] Is it possible to rotate a texture?

My project allow user to upload image as custom texture.
Here is the project: https://playcanvas.com/project/485551/overview/house-scene

Here is the code to transform image to texture:


RightSideBar.prototype.onFileChange = function(e) {
    var file = e.target.files[0];
    
    if (!file) return;

    var self = this;
    var reader = new FileReader();
    
    reader.onload = function(e) {
        var image = new Image();
        image.onload = function(e) {
            var canvas = document.createElement('canvas');
            var context = canvas.getContext('2d');
            var orientation = image.width >= image.height ? 'landscape' : 'portrait';
            // var canvasSize = Math.max(image.width, image.height);
            var canvasSize = Math.min(image.width, image.height);
            var canvasWidth = canvasSize;
            var canvasHeight = canvasSize;
            // var dx = orientation === 'landscape' ? 0 : (canvasWidth - image.width) / 2;
            // var dy = orientation === 'landscape' ? (canvasHeight - image.height) / 2 : 0;
            var dx = orientation === 'landscape' ? (image.width - canvasWidth) / 2 : 0;
            var dy = orientation === 'landscape' ? 0 : (image.height - canvasHeight) / 2;

            canvas.width = canvasWidth;
            canvas.height = canvasHeight;
            // context.drawImage(image, dx, dy, image.width, image.height);
            context.drawImage(image, dx, dy, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);

            var texture = new pc.Texture(self.app.graphicsDevice);
            texture.setSource(canvas);
            self.updatePaint(texture);
        };
        image.src = reader.result;
    };
    reader.readAsDataURL(file);
};


RightSideBar.prototype.updatePaint = function(texture) {
    var painting = RightSideBar.getPainting(this.currentEntity);    
    painting.material = painting.material.clone();
    painting.material.diffuseMap = texture;
    painting.material.update();
};

What it does is to cut the image to square, and set it to the material’s diffuseMap.
But the texture rotated unexpectedly…
What is more, when I select “portrait”(width < height), this issue will happen, when I select “landscape”(width > height), this issue will not happen.

I found the solution from https://stackoverflow.com/questions/19463126/how-to-draw-photo-with-correct-orientation-in-canvas-after-capture-photo-by-usin. It does not need to rotate a texture, just do a little trick with the source of the texture.

Before drawing the image from mobile device, we need to get the image’s EXIF data first, especially the orientation data.
With the orientation data, we can rotate canvas by its context. After that, we can draw image as normal.
So we need exif.js to parse the EXIF data.

Here is my code:


RightSideBar.prototype.onFileChange = function(e) {
    var file = e.target.files[0];
    
    if (!file) return;

    var self = this;
    
    EXIF.getData(file, function() {
        var orientation = this.exifdata.Orientation;

        var reader = new FileReader();

        reader.onload = function(e) {
            var image = new Image();
            image.onload = function(e) {
                var canvas = document.createElement('canvas');
                var context = canvas.getContext('2d');
                var imageType = image.width >= image.height ? 'landscape' : 'portrait';
                // var canvasSize = Math.max(image.width, image.height);
                var canvasSize = Math.min(image.width, image.height);
                var canvasWidth = canvasSize;
                var canvasHeight = canvasSize;

                // var dx = imageType === 'landscape' ? 0 : (canvasWidth - image.width) / 2;
                // var dy = imageType === 'landscape' ? (canvasHeight - image.height) / 2 : 0;
                var dx = imageType === 'landscape' ? (image.width - canvasWidth) / 2 : 0;
                var dy = imageType === 'landscape' ? 0 : (image.height - canvasHeight) / 2;

                canvas.width = canvasWidth;
                canvas.height = canvasHeight;

                switch (orientation) {
                    case 2:
                        // horizontal flip
                        context.translate(canvas.width, 0);
                        context.scale(-1, 1);
                        break;
                    case 3:
                        // 180° rotate left
                        context.translate(canvas.width, canvas.height);
                        context.rotate(Math.PI);
                        break;
                    case 4:
                        // vertical flip
                        context.translate(0, canvas.height);
                        context.scale(1, -1);
                        break;
                    case 5:
                        // vertical flip + 90 rotate right
                        context.rotate(0.5 * Math.PI);
                        context.scale(1, -1);
                        break;
                    case 6:
                        // 90° rotate right
                        context.rotate(0.5 * Math.PI);
                        context.translate(0, -canvas.height);
                        break;
                    case 7:
                        // horizontal flip + 90 rotate right
                        context.rotate(0.5 * Math.PI);
                        context.translate(canvas.width, -canvas.height);
                        context.scale(-1, 1);
                        break;
                    case 8:
                        // 90° rotate left
                        context.rotate(-0.5 * Math.PI);
                        context.translate(-canvas.width, 0);
                        break;
                }

                // context.drawImage(image, dx, dy, image.width, image.height);
                context.drawImage(image, dx, dy, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
                
                var texture = new pc.Texture(self.app.graphicsDevice);
                texture.setSource(canvas);
                self.updatePaint(texture);
            };
            image.src = reader.result;
        };
        reader.readAsDataURL(file);
    });
};