1
1
/* eslint-env mocha */
2
2
const path = require ( 'path' ) ;
3
- const crypto = require ( 'crypto' ) ;
4
3
const { spawn } = require ( 'child_process' ) ;
5
4
6
5
const fs = require ( 'fs-extra' ) ;
@@ -9,16 +8,43 @@ const tempy = require('tempy');
9
8
const { fromBuffer : filetype } = require ( 'file-type' ) ;
10
9
const { expect } = require ( 'chai' ) ;
11
10
const eos = require ( 'end-of-stream' ) ;
11
+ const toUint8 = require ( 'buffer-to-uint8array' ) ;
12
+ const pixelmatch = require ( 'pixelmatch' ) ;
13
+ const { PNG } = require ( 'pngjs' ) ;
14
+ const jpegJs = require ( 'jpeg-js' ) ;
12
15
13
16
describe ( 'heic-convert' , ( ) => {
14
17
const HELP_LINE = 'Convert HEIC image to JPEG or PNG' ;
15
18
16
- const assertImage = async ( buffer , mime , hash ) => {
19
+ const decode = {
20
+ 'image/png' : buffer => PNG . sync . read ( buffer ) ,
21
+ 'image/jpeg' : buffer => jpegJs . decode ( buffer )
22
+ } ;
23
+
24
+ const readControl = async name => {
25
+ const buffer = await fs . readFile ( path . resolve ( root , `temp/${ name } ` ) ) ;
26
+ return decode [ 'image/png' ] ( buffer ) ;
27
+ } ;
28
+
29
+ const compare = ( expected , actual , width , height , errString = 'actual image did not match control image' ) => {
30
+ const result = pixelmatch ( toUint8 ( Buffer . from ( expected ) ) , toUint8 ( Buffer . from ( actual ) ) , null , width , height , {
31
+ threshold : 0.1
32
+ } ) ;
33
+
34
+ // allow 5% of pixels to be different
35
+ expect ( result ) . to . be . below ( width * height * 0.05 , errString ) ;
36
+ } ;
37
+
38
+ const assertImage = async ( buffer , mime , control ) => {
17
39
const type = await filetype ( buffer ) ;
18
40
expect ( type . mime ) . to . equal ( mime ) ;
19
41
20
- const actual = crypto . createHash ( 'sha256' ) . update ( buffer ) . digest ( 'hex' ) ;
21
- expect ( actual ) . to . equal ( hash ) ;
42
+ const actual = decode [ mime ] ( buffer ) ;
43
+
44
+ expect ( actual . width ) . to . equal ( control . width ) ;
45
+ expect ( actual . height ) . to . equal ( control . height ) ;
46
+
47
+ compare ( control . data , actual . data , control . width , control . height ) ;
22
48
} ;
23
49
24
50
const exec = async ( args , options = { } , input = Buffer . from ( '' ) ) => {
@@ -78,6 +104,12 @@ describe('heic-convert', () => {
78
104
} ) ;
79
105
80
106
describe ( 'using --input and --output' , ( ) => {
107
+ let control ;
108
+
109
+ before ( async ( ) => {
110
+ control = await readControl ( '0002-control.png' ) ;
111
+ } ) ;
112
+
81
113
it ( 'converts known image to jpeg' , async ( ) => {
82
114
const infile = path . resolve ( root , 'temp' , '0002.heic' ) ;
83
115
const outfile = files . get ( { extension : 'jpg' } ) ;
@@ -88,7 +120,7 @@ describe('heic-convert', () => {
88
120
expect ( stderr . toString ( ) ) . to . equal ( '' ) ;
89
121
expect ( err ) . to . have . property ( 'code' , 0 ) ;
90
122
91
- await assertImage ( await fs . readFile ( outfile ) , 'image/jpeg' , 'f7f1ae16c3fbf035d1b71b1995230305125236d0c9f0513c905ab1cb39fc68e9' ) ;
123
+ await assertImage ( await fs . readFile ( outfile ) , 'image/jpeg' , control ) ;
92
124
} ) ;
93
125
94
126
it ( 'converts known image to png' , async ( ) => {
@@ -101,11 +133,17 @@ describe('heic-convert', () => {
101
133
expect ( stderr . toString ( ) ) . to . equal ( '' ) ;
102
134
expect ( err ) . to . have . property ( 'code' , 0 ) ;
103
135
104
- await assertImage ( await fs . readFile ( outfile ) , 'image/png' , '0efc9a4c58d053fb42591acd83f8a5005ee2844555af29b5aba77a766b317935' ) ;
136
+ await assertImage ( await fs . readFile ( outfile ) , 'image/png' , control ) ;
105
137
} ) ;
106
138
} ) ;
107
139
108
140
describe ( 'using -i and -o' , ( ) => {
141
+ let control ;
142
+
143
+ before ( async ( ) => {
144
+ control = await readControl ( '0002-control.png' ) ;
145
+ } ) ;
146
+
109
147
it ( 'converts known image to jpeg' , async ( ) => {
110
148
const infile = path . resolve ( root , 'temp' , '0002.heic' ) ;
111
149
const outfile = files . get ( { extension : 'jpg' } ) ;
@@ -116,7 +154,7 @@ describe('heic-convert', () => {
116
154
expect ( stderr . toString ( ) ) . to . equal ( '' ) ;
117
155
expect ( err ) . to . have . property ( 'code' , 0 ) ;
118
156
119
- await assertImage ( await fs . readFile ( outfile ) , 'image/jpeg' , 'f7f1ae16c3fbf035d1b71b1995230305125236d0c9f0513c905ab1cb39fc68e9' ) ;
157
+ await assertImage ( await fs . readFile ( outfile ) , 'image/jpeg' , control ) ;
120
158
} ) ;
121
159
122
160
it ( 'converts known image to png' , async ( ) => {
@@ -129,19 +167,25 @@ describe('heic-convert', () => {
129
167
expect ( stderr . toString ( ) ) . to . equal ( '' ) ;
130
168
expect ( err ) . to . have . property ( 'code' , 0 ) ;
131
169
132
- await assertImage ( await fs . readFile ( outfile ) , 'image/png' , '0efc9a4c58d053fb42591acd83f8a5005ee2844555af29b5aba77a766b317935' ) ;
170
+ await assertImage ( await fs . readFile ( outfile ) , 'image/png' , control ) ;
133
171
} ) ;
134
172
} ) ;
135
173
136
174
describe ( 'using stdin and stdout' , ( ) => {
175
+ let control ;
176
+
177
+ before ( async ( ) => {
178
+ control = await readControl ( '0002-control.png' ) ;
179
+ } ) ;
180
+
137
181
it ( 'converts known image to jpeg' , async ( ) => {
138
182
const infile = path . resolve ( root , 'temp' , '0002.heic' ) ;
139
183
const inbuffer = await fs . readFile ( infile ) ;
140
184
141
185
const { stdout, stderr, err } = await exec ( [ ] , { } , inbuffer ) ;
142
186
143
187
expect ( stderr . toString ( ) ) . to . equal ( '' ) ;
144
- await assertImage ( stdout , 'image/jpeg' , 'f7f1ae16c3fbf035d1b71b1995230305125236d0c9f0513c905ab1cb39fc68e9' ) ;
188
+ await assertImage ( stdout , 'image/jpeg' , control ) ;
145
189
expect ( err ) . to . have . property ( 'code' , 0 ) ;
146
190
} ) ;
147
191
@@ -152,25 +196,28 @@ describe('heic-convert', () => {
152
196
const { stdout, stderr, err } = await exec ( [ '-f' , 'PNG' ] , { } , inbuffer ) ;
153
197
154
198
expect ( stderr . toString ( ) ) . to . equal ( '' ) ;
155
- await assertImage ( stdout , 'image/png' , '0efc9a4c58d053fb42591acd83f8a5005ee2844555af29b5aba77a766b317935' ) ;
199
+ await assertImage ( stdout , 'image/png' , control ) ;
156
200
expect ( err ) . to . have . property ( 'code' , 0 ) ;
157
201
} ) ;
158
202
} ) ;
159
203
160
204
describe ( 'using a multi-image file' , ( ) => {
161
- const hashes = [
162
- { i : 0 , hash : '11e8083208d6357642624a2481b8c5e376d6655e14a46be44a2ca1221986a0bc' } ,
163
- { i : 1 , hash : '1f1ef0b3b19a1c10d9659702c5d32fb380358501e20c9d6e491bbea181873286' } ,
164
- { i : 2 , hash : '1f1ef0b3b19a1c10d9659702c5d32fb380358501e20c9d6e491bbea181873286' } ,
165
- ] ;
205
+ let controls ;
206
+
207
+ before ( async ( ) => {
208
+ controls = await Promise . all ( [
209
+ readControl ( '0003-0-control.png' ) ,
210
+ readControl ( '0003-1-control.png' ) ,
211
+ ] ) ;
212
+ } ) ;
166
213
167
214
it ( 'converts the first image by default' , async ( ) => {
168
215
const infile = path . resolve ( root , 'temp' , '0003.heic' ) ;
169
216
170
217
const { stdout, stderr, err } = await exec ( [ '--input' , `"${ infile } "` ] , { } ) ;
171
218
172
219
expect ( stderr . toString ( ) ) . to . equal ( '' ) ;
173
- await assertImage ( stdout , 'image/jpeg' , hashes [ 0 ] . hash ) ;
220
+ await assertImage ( stdout , 'image/jpeg' , controls [ 0 ] ) ;
174
221
expect ( err ) . to . have . property ( 'code' , 0 ) ;
175
222
} ) ;
176
223
@@ -187,8 +234,8 @@ describe('heic-convert', () => {
187
234
expect ( stderr . toString ( ) ) . to . equal ( '' ) ;
188
235
expect ( err ) . to . have . property ( 'code' , 0 ) ;
189
236
190
- await assertImage ( await fs . readFile ( path . resolve ( outdir , `${ rand } -1-1.jpg` ) ) , 'image/jpeg' , hashes [ 1 ] . hash ) ;
191
- await assertImage ( await fs . readFile ( path . resolve ( outdir , `${ rand } -2-2.jpg` ) ) , 'image/jpeg' , hashes [ 2 ] . hash ) ;
237
+ await assertImage ( await fs . readFile ( path . resolve ( outdir , `${ rand } -1-1.jpg` ) ) , 'image/jpeg' , controls [ 1 ] ) ;
238
+ await assertImage ( await fs . readFile ( path . resolve ( outdir , `${ rand } -2-2.jpg` ) ) , 'image/jpeg' , controls [ 1 ] ) ;
192
239
} ) ;
193
240
194
241
it ( 'can convert all images using -m -1' , async ( ) => {
@@ -204,9 +251,9 @@ describe('heic-convert', () => {
204
251
expect ( stderr . toString ( ) ) . to . equal ( '' ) ;
205
252
expect ( err ) . to . have . property ( 'code' , 0 ) ;
206
253
207
- await assertImage ( await fs . readFile ( path . resolve ( outdir , `0-${ rand } -0-0.jpg` ) ) , 'image/jpeg' , hashes [ 0 ] . hash ) ;
208
- await assertImage ( await fs . readFile ( path . resolve ( outdir , `1-${ rand } -1-1.jpg` ) ) , 'image/jpeg' , hashes [ 1 ] . hash ) ;
209
- await assertImage ( await fs . readFile ( path . resolve ( outdir , `2-${ rand } -2-2.jpg` ) ) , 'image/jpeg' , hashes [ 2 ] . hash ) ;
254
+ await assertImage ( await fs . readFile ( path . resolve ( outdir , `0-${ rand } -0-0.jpg` ) ) , 'image/jpeg' , controls [ 0 ] ) ;
255
+ await assertImage ( await fs . readFile ( path . resolve ( outdir , `1-${ rand } -1-1.jpg` ) ) , 'image/jpeg' , controls [ 1 ] ) ;
256
+ await assertImage ( await fs . readFile ( path . resolve ( outdir , `2-${ rand } -2-2.jpg` ) ) , 'image/jpeg' , controls [ 1 ] ) ;
210
257
} ) ;
211
258
212
259
it ( 'can write a single non-default image to standard out' , async ( ) => {
@@ -216,7 +263,7 @@ describe('heic-convert', () => {
216
263
const { stdout, stderr, err } = await exec ( [ '--images' , '2' ] , { } , inbuffer ) ;
217
264
218
265
expect ( stderr . toString ( ) ) . to . equal ( '' ) ;
219
- await assertImage ( stdout , 'image/jpeg' , hashes [ 2 ] . hash ) ;
266
+ await assertImage ( stdout , 'image/jpeg' , controls [ 1 ] ) ;
220
267
expect ( err ) . to . have . property ( 'code' , 0 ) ;
221
268
} ) ;
222
269
0 commit comments