UNPKG

5.04 kBJavaScriptView Raw
1
2'use strict'
3
4var fs = require('fs')
5var async = require('async')
6var piexif = require('piexifjs')
7var CustomError = require('./error.js')
8var transform = require('./transform.js')
9
10var m = {}
11
12m.errors = {}
13m.errors.read_file = 'read_file'
14m.errors.read_exif = 'read_exif'
15m.errors.no_orientation = 'no_orientation'
16m.errors.unknown_orientation = 'unknown_orientation'
17m.errors.correct_orientation = 'correct_orientation'
18m.errors.rotate_file = 'rotate_file'
19
20m.rotate = function(path_or_buffer, options, module_callback)
21{
22 var quality = typeof options === 'object' && typeof options.quality !== 'undefined' ? parseInt(options.quality) : 100
23 quality = !isNaN(quality) && quality >= 0 && quality <= 100 ? quality : 100
24 module_callback = typeof module_callback === 'function' ? module_callback : function(){}
25
26 var jpeg_buffer = null
27 var jpeg_exif_data = null
28 var jpeg_orientation = null
29
30 if (typeof path_or_buffer === 'string')
31 {
32 fs.readFile(path_or_buffer, _onReadFile)
33 }
34 else if (typeof path_or_buffer === 'object' && Buffer.isBuffer(path_or_buffer))
35 {
36 _onReadFile(null, path_or_buffer)
37 }
38 else
39 {
40 _onReadFile(new Error('Not a file path or buffer'), null)
41 }
42
43 /**
44 * Tries to read EXIF data when the image has been loaded
45 * @param error
46 * @param buffer
47 */
48 function _onReadFile(error, buffer)
49 {
50 if (error)
51 {
52 module_callback(new CustomError(m.errors.read_file, 'Could not read file (' + error.message + ')'), null, null)
53 return
54 }
55 try
56 {
57 jpeg_buffer = buffer
58 jpeg_exif_data = piexif.load(jpeg_buffer.toString('binary'))
59 }
60 catch (error)
61 {
62 module_callback(new CustomError(m.errors.read_exif, 'Could not read EXIF data (' + error.message + ')'), null, null)
63 return
64 }
65 if (typeof jpeg_exif_data['0th'] === 'undefined' || typeof jpeg_exif_data['0th'][piexif.ImageIFD.Orientation] === 'undefined')
66 {
67 module_callback(new CustomError(m.errors.no_orientation, 'No orientation tag found in EXIF'), buffer, null)
68 return
69 }
70 jpeg_orientation = parseInt(jpeg_exif_data['0th'][piexif.ImageIFD.Orientation])
71 if (isNaN(jpeg_orientation) || jpeg_orientation < 1 || jpeg_orientation > 8)
72 {
73 module_callback(new CustomError(m.errors.unknown_orientation, 'Unknown orientation (' + jpeg_orientation + ')'), buffer, null)
74 return
75 }
76 if (jpeg_orientation === 1)
77 {
78 module_callback(new CustomError(m.errors.correct_orientation, 'Orientation already correct'), buffer, null)
79 return
80 }
81 async.parallel({image: _rotateImage, thumbnail: _rotateThumbnail}, _onRotatedImages)
82 }
83
84 /**
85 * Tries to rotate the main image
86 * @param callback
87 */
88 function _rotateImage(callback)
89 {
90 transform.do(jpeg_buffer, jpeg_orientation, quality, function(error, buffer, width, height)
91 {
92 callback(error, {buffer: !error ? buffer : null, width: width, height: height})
93 })
94 }
95
96 /**
97 * Tries to rotate the thumbnail, if it exists
98 * @param callback
99 */
100 function _rotateThumbnail(callback)
101 {
102 if (typeof jpeg_exif_data['thumbnail'] === 'undefined' || jpeg_exif_data['thumbnail'] === null)
103 {
104 callback(null, {buffer: null, width: 0, height: 0})
105 return
106 }
107 transform.do(new Buffer(jpeg_exif_data['thumbnail'], 'binary'), jpeg_orientation, quality, function(error, buffer, width, height)
108 {
109 callback(null, {buffer: !error ? buffer : null, width: width, height: height})
110 })
111 }
112
113 /**
114 * Merges EXIF data in the rotated buffer and returns
115 * @param error
116 * @param buffers
117 */
118 function _onRotatedImages(error, images)
119 {
120 if (error)
121 {
122 module_callback(new CustomError(m.errors.rotate_file, 'Could not rotate image (' + error.message + ')'), null, null)
123 return
124 }
125 jpeg_exif_data['0th'][piexif.ImageIFD.Orientation] = 1
126 if (typeof jpeg_exif_data['Exif'][piexif.ExifIFD.PixelXDimension] !== 'undefined')
127 {
128 jpeg_exif_data['Exif'][piexif.ExifIFD.PixelXDimension] = images.image.width
129 }
130 if (typeof jpeg_exif_data['Exif'][piexif.ExifIFD.PixelYDimension] !== 'undefined')
131 {
132 jpeg_exif_data['Exif'][piexif.ExifIFD.PixelYDimension] = images.image.height
133 }
134 if (images.thumbnail.buffer !== null)
135 {
136 jpeg_exif_data['thumbnail'] = images.thumbnail.buffer.toString('binary')
137 }
138 var exif_bytes = piexif.dump(jpeg_exif_data)
139 var updated_jpeg_buffer = new Buffer(piexif.insert(exif_bytes, images.image.buffer.toString('binary')), 'binary')
140 module_callback(null, updated_jpeg_buffer, jpeg_orientation)
141 }
142
143}
144
145module.exports = m