UNPKG

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