소스 검색

Merge branch 'Botz-feature/image-rotation'

Artur Paikin 5 년 전
부모
커밋
e941e9b4d1

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 242 - 123
package-lock.json


+ 2 - 1
packages/@uppy/thumbnail-generator/package.json

@@ -22,7 +22,8 @@
     "url": "git+https://github.com/transloadit/uppy.git"
     "url": "git+https://github.com/transloadit/uppy.git"
   },
   },
   "dependencies": {
   "dependencies": {
-    "@uppy/utils": "1.1.0"
+    "@uppy/utils": "1.1.0",
+    "exif-js": "2.3.0"
   },
   },
   "devDependencies": {
   "devDependencies": {
     "@uppy/core": "1.1.0",
     "@uppy/core": "1.1.0",

+ 44 - 0
packages/@uppy/thumbnail-generator/src/image-orientations.js

@@ -0,0 +1,44 @@
+const ORIENTATIONS = {
+  1: {
+    rotation: 0,
+    xScale: 1,
+    yScale: 1
+  },
+  2: {
+    rotation: 0,
+    xScale: -1,
+    yScale: 1
+  },
+  3: {
+    rotation: 180,
+    xScale: 1,
+    yScale: 1
+  },
+  4: {
+    rotation: 180,
+    xScale: -1,
+    yScale: 1
+  },
+  5: {
+    rotation: 90,
+    xScale: 1,
+    yScale: -1
+  },
+  6: {
+    rotation: 90,
+    xScale: 1,
+    yScale: 1
+  },
+  7: {
+    rotation: 270,
+    xScale: 1,
+    yScale: -1
+  },
+  8: {
+    rotation: 270,
+    xScale: 1,
+    yScale: 1
+  }
+}
+
+module.exports = ORIENTATIONS

+ 46 - 7
packages/@uppy/thumbnail-generator/src/index.js

@@ -1,7 +1,9 @@
+const Exif = require('exif-js')
 const { Plugin } = require('@uppy/core')
 const { Plugin } = require('@uppy/core')
 const dataURItoBlob = require('@uppy/utils/lib/dataURItoBlob')
 const dataURItoBlob = require('@uppy/utils/lib/dataURItoBlob')
 const isObjectURL = require('@uppy/utils/lib/isObjectURL')
 const isObjectURL = require('@uppy/utils/lib/isObjectURL')
 const isPreviewSupported = require('@uppy/utils/lib/isPreviewSupported')
 const isPreviewSupported = require('@uppy/utils/lib/isPreviewSupported')
+const ORIENTATIONS = require('./image-orientations')
 
 
 /**
 /**
  * The Thumbnail Generator plugin
  * The Thumbnail Generator plugin
@@ -57,11 +59,14 @@ module.exports = class ThumbnailGenerator extends Plugin {
       })
       })
     })
     })
 
 
-    return onload
-      .then(image => {
-        const dimensions = this.getProportionalDimensions(image, targetWidth, targetHeight)
-        const canvas = this.resizeImage(image, dimensions.width, dimensions.height)
-        return this.canvasToBlob(canvas, 'image/png')
+    return Promise.all([onload, this.getOrientation(file)])
+      .then(values => {
+        const image = values[0]
+        const orientation = values[1]
+        const dimensions = this.getProportionalDimensions(image, targetWidth, targetHeight, orientation.rotation)
+        const rotatedImage = this.rotateImage(image, orientation)
+        const resizedImage = this.resizeImage(rotatedImage, dimensions.width, dimensions.height)
+        return this.canvasToBlob(resizedImage, 'image/png')
       })
       })
       .then(blob => {
       .then(blob => {
         return URL.createObjectURL(blob)
         return URL.createObjectURL(blob)
@@ -74,8 +79,11 @@ module.exports = class ThumbnailGenerator extends Plugin {
    * account. If neither width nor height are given, the default dimension
    * account. If neither width nor height are given, the default dimension
    * is used.
    * is used.
    */
    */
-  getProportionalDimensions (img, width, height) {
-    const aspect = img.width / img.height
+  getProportionalDimensions (img, width, height, rotation) {
+    var aspect = img.width / img.height
+    if (rotation === 90 || rotation === 270) {
+      aspect = img.height / img.width
+    }
 
 
     if (width != null) {
     if (width != null) {
       return {
       return {
@@ -97,6 +105,15 @@ module.exports = class ThumbnailGenerator extends Plugin {
     }
     }
   }
   }
 
 
+  getOrientation (file) {
+    return new Promise((resolve) => {
+      Exif.getData(file.data, function callback () {
+        const orientation = Exif.getTag(this, 'Orientation') || 1
+        resolve(ORIENTATIONS[orientation])
+      })
+    })
+  }
+
   /**
   /**
    * Make sure the image doesn’t exceed browser/device canvas limits.
    * Make sure the image doesn’t exceed browser/device canvas limits.
    * For ios with 256 RAM and ie
    * For ios with 256 RAM and ie
@@ -165,6 +182,28 @@ module.exports = class ThumbnailGenerator extends Plugin {
     return image
     return image
   }
   }
 
 
+  rotateImage (image, translate) {
+    var w = image.width
+    var h = image.height
+
+    if (translate.rotation === 90 || translate.rotation === 270) {
+      w = image.height
+      h = image.width
+    }
+
+    var canvas = document.createElement('canvas')
+    canvas.width = w
+    canvas.height = h
+
+    var context = canvas.getContext('2d')
+    context.translate(w / 2, h / 2)
+    context.rotate(translate.rotation * Math.PI / 180)
+    context.scale(translate.xScale, translate.yScale)
+    context.drawImage(image, -image.width / 2, -image.height / 2, image.width, image.height)
+
+    return canvas
+  }
+
   /**
   /**
    * Save a <canvas> element's content to a Blob object.
    * Save a <canvas> element's content to a Blob object.
    *
    *

+ 34 - 0
packages/@uppy/thumbnail-generator/src/index.test.js

@@ -507,4 +507,38 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
       expect(plugin.addToQueue).not.toHaveBeenCalled()
       expect(plugin.addToQueue).not.toHaveBeenCalled()
     })
     })
   })
   })
+
+  describe('rotateImage', () => {
+    it.each([
+      [0, { width: 100, height: 80 }],
+      [90, { width: 80, height: 100 }],
+      [180, { width: 100, height: 80 }],
+      [270, { width: 80, height: 100 }]])(
+      'should rotate image with %i degree', (rotation, expectedSize) => {
+        const core = new MockCore()
+        const plugin = new ThumbnailGeneratorPlugin(core)
+        const image = {
+          width: 100,
+          height: 80
+        }
+        const context = {
+          drawImage: jest.fn(),
+          translate: jest.fn(),
+          rotate: jest.fn(),
+          scale: jest.fn()
+        }
+        const canvas = {
+          width: 0,
+          height: 0,
+          getContext: jest.fn().mockReturnValue(context)
+        }
+        document.createElement = jest.fn().mockReturnValue(canvas)
+
+        const result = plugin.rotateImage(image, { rotation: rotation })
+        expect(result).toEqual({
+          ...expectedSize,
+          getContext: canvas.getContext
+        })
+      })
+  })
 })
 })

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.