UNPKG

2.79 kBJavaScriptView Raw
1const jpegjs = require('jpeg-js')
2
3const m = {}
4
5/**
6 * Decode the given buffer and applies the right transformation
7 * Depending on the orientation, it may be a rotation and / or an horizontal flip
8 */
9m.rotateBuffer = function (buffer, orientation, quality, maxResolutionInMP, maxMemoryUsageInMB) {
10 let jpeg = null
11 try {
12 const options = {}
13 if (maxResolutionInMP !== null) {
14 options.maxResolutionInMP = maxResolutionInMP
15 }
16 if (maxMemoryUsageInMB !== null) {
17 options.maxMemoryUsageInMB = maxMemoryUsageInMB
18 }
19 jpeg = jpegjs.decode(buffer, options)
20 } catch (error) {
21 return Promise.reject(error)
22 }
23 let newBuffer = jpeg.data
24
25 const transformations = {
26 2: {rotate: 0, flip: true},
27 3: {rotate: 180, flip: false},
28 4: {rotate: 180, flip: true},
29 5: {rotate: 90, flip: true},
30 6: {rotate: 90, flip: false},
31 7: {rotate: 270, flip: true},
32 8: {rotate: 270, flip: false},
33 }
34
35 if (transformations[orientation].rotate > 0) {
36 newBuffer = rotatePixels(newBuffer, jpeg.width, jpeg.height, transformations[orientation].rotate)
37 }
38
39 const ratioWillChange = (transformations[orientation].rotate / 90) % 2 === 1
40 const destWidth = ratioWillChange ? jpeg.height : jpeg.width
41 const destHeight = ratioWillChange ? jpeg.width : jpeg.height
42
43 if (transformations[orientation].flip) {
44 newBuffer = flipPixels(newBuffer, destWidth, destHeight)
45 }
46
47 const newJpeg = jpegjs.encode({data: newBuffer, width: destWidth, height: destHeight}, quality)
48 return Promise.resolve({buffer: newJpeg.data, width: destWidth, height: destHeight})
49}
50
51/**
52 * Rotate a buffer (degrees must be a multiple of 90)
53 * Inspired from Jimp (https://github.com/oliver-moran/jimp)
54 */
55function rotatePixels(buffer, width, height, degrees) {
56 let loops = degrees / 90
57 while (loops > 0) {
58 const newBuffer = Buffer.alloc(buffer.length)
59 let newOffset = 0
60 for (let x = 0; x < width; x += 1) {
61 for (let y = height - 1; y >= 0; y -= 1) {
62 const offset = (width * y + x) << 2
63 const pixel = buffer.readUInt32BE(offset, true)
64 newBuffer.writeUInt32BE(pixel, newOffset, true)
65 newOffset += 4
66 }
67 }
68 buffer = newBuffer
69 const newHeight = width
70 width = height
71 height = newHeight
72 loops -= 1
73 }
74 return buffer
75}
76
77/**
78 * Flip a buffer horizontally
79 */
80function flipPixels(buffer, width, height) {
81 const newBuffer = Buffer.alloc(buffer.length)
82 for (let x = 0; x < width; x += 1) {
83 for (let y = 0; y < height; y += 1) {
84 const offset = (width * y + x) << 2
85 const newOffset = (width * y + width - 1 - x) << 2
86 const pixel = buffer.readUInt32BE(offset, true)
87 newBuffer.writeUInt32BE(pixel, newOffset, true)
88 }
89 }
90 return newBuffer
91}
92
93module.exports = m