1 |
|
2 | 'use strict'
|
3 |
|
4 | var fs = require('fs')
|
5 | var async = require('async')
|
6 | var piexif = require('piexifjs')
|
7 | var CustomError = require('./error.js')
|
8 | var transform = require('./transform.js')
|
9 |
|
10 | var m = {}
|
11 |
|
12 | m.errors = {}
|
13 | m.errors.read_file = 'read_file'
|
14 | m.errors.read_exif = 'read_exif'
|
15 | m.errors.no_orientation = 'no_orientation'
|
16 | m.errors.unknown_orientation = 'unknown_orientation'
|
17 | m.errors.correct_orientation = 'correct_orientation'
|
18 | m.errors.rotate_file = 'rotate_file'
|
19 |
|
20 | m.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 |
|
45 |
|
46 |
|
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 |
|
86 |
|
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 |
|
98 |
|
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 |
|
115 |
|
116 |
|
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 |
|
145 | module.exports = m
|