UNPKG

5.36 kBJavaScriptView Raw
1const before = require('mocha').before
2const describe = require('mocha').describe
3const expect = require('chai').expect
4const fs = require('fs-extra')
5const it = require('mocha').it
6const jo = require('../src/main.js')
7const jpegjs = require('jpeg-js')
8const path = require('path')
9const piexif = require('piexifjs')
10const pixelmatch = require('pixelmatch')
11const PNG = require('pngjs').PNG
12
13const tmpPath = path.join(__dirname, '.tmp')
14
15require('chai').should()
16
17describe('transformations', function() {
18 before(function() {
19 return fs.emptyDir(tmpPath)
20 })
21 const isPromisedBased = [true, false]
22 isPromisedBased.forEach((value) => {
23 itShouldTransform(path.join(__dirname, '/samples/image_2.jpg'), 'image_2.jpg', value)
24 itShouldTransform(path.join(__dirname, '/samples/image_2.jpg'), 'image_2.jpg', value)
25 itShouldTransform(path.join(__dirname, '/samples/image_3.jpg'), 'image_3.jpg', value)
26 itShouldTransform(path.join(__dirname, '/samples/image_4.jpg'), 'image_4.jpg', value)
27 itShouldTransform(path.join(__dirname, '/samples/image_5.jpg'), 'image_5.jpg', value)
28 itShouldTransform(path.join(__dirname, '/samples/image_6.jpg'), 'image_6.jpg', value)
29 itShouldTransform(path.join(__dirname, '/samples/image_7.jpg'), 'image_7.jpg', value)
30 itShouldTransform(path.join(__dirname, '/samples/image_8.jpg'), 'image_8.jpg', value)
31 itShouldTransform(path.join(__dirname, '/samples/image_exif.jpg'), 'image_exif.jpg', value)
32 itShouldTransform(fs.readFileSync(path.join(__dirname, '/samples/image_8.jpg')), 'From a buffer', value)
33 })
34})
35
36/**
37 * Try to transform the given path/buffer, and checks data integrity (EXIF, dimensions)
38 */
39function itShouldTransform(pathOrBuffer, label, isPromisedBased) {
40 it('Should rotate image (' + label + ') (' + (isPromisedBased ? 'Promise' : 'Callback') + '-based)', function(done) {
41 this.timeout(20000)
42 const options = {quality: 82}
43 if (isPromisedBased) {
44 jo.rotate(pathOrBuffer, options).then(({buffer, orientation, dimensions, quality}) => {
45 checkTransformation(done, pathOrBuffer, null, buffer, orientation, dimensions, quality)
46 })
47 } else {
48 jo.rotate(pathOrBuffer, options, function(error, buffer, orientation, dimensions, quality) {
49 checkTransformation(done, pathOrBuffer, error, buffer, orientation, dimensions, quality)
50 })
51 }
52 })
53}
54
55function checkTransformation(done, pathOrBuffer, error, buffer, orientation, dimensions, quality) {
56 if (error) {
57 throw error
58 }
59 const origBuffer = typeof pathOrBuffer === 'string' ? fs.readFileSync(pathOrBuffer) : pathOrBuffer
60 const origExif = piexif.load(origBuffer.toString('binary'))
61 const origJpeg = jpegjs.decode(origBuffer)
62 compareDimensions(origJpeg, orientation, dimensions)
63 compareExif(origExif, piexif.load(buffer.toString('binary')))
64 if (typeof pathOrBuffer === 'string') {
65 comparePixels(pathOrBuffer, buffer)
66 fs.writeFileSync(pathOrBuffer.replace('samples/', '.tmp/'), buffer)
67 }
68 expect(quality).to.equal(82)
69 done()
70}
71
72/**
73 * Compare origin and destination pixels with pixelmatch, and save the diff on disk
74 */
75function comparePixels(pathOrBuffer, buffer) {
76 const targetBuffer = fs.readFileSync(pathOrBuffer.replace('.jpg', '_dest.jpg'))
77 const targetJpeg = jpegjs.decode(targetBuffer)
78 const diffPng = new PNG({width: targetJpeg.width, height: targetJpeg.height})
79 const diffPixels = pixelmatch(
80 jpegjs.decode(buffer).data,
81 targetJpeg.data,
82 diffPng.data,
83 targetJpeg.width,
84 targetJpeg.height,
85 {
86 threshold: 0.25,
87 }
88 )
89 const diffPath = path.join(tmpPath, path.parse(pathOrBuffer).base.replace('.jpg', '.diff.png'))
90 diffPng.pack().pipe(fs.createWriteStream(diffPath))
91 expect(diffPixels).to.equal(0)
92}
93
94/**
95 * Compare origin and destination dimensions
96 * Depending on the original orientation, they may be switched
97 */
98function compareDimensions(origJpeg, orientation, dimensions) {
99 if (orientation < 5 && (origJpeg.width !== dimensions.width || origJpeg.height !== dimensions.height)) {
100 throw new Error('Dimensions do not match')
101 }
102 if (orientation >= 5 && (origJpeg.width !== dimensions.height || origJpeg.height !== dimensions.width)) {
103 throw new Error('Dimensions do not match')
104 }
105}
106
107/**
108 * Compare EXIF arrays
109 * The properties allowed to differ between origin and destination images are set to 0
110 */
111function compareExif(orig, dest) {
112 orig['thumbnail'] = 0 // The thumbnail
113 dest['thumbnail'] = 0
114 orig['0th'][piexif.ImageIFD.Orientation] = 0 // Orientation
115 dest['0th'][piexif.ImageIFD.Orientation] = 0
116 orig['0th'][piexif.ImageIFD.ExifTag] = 0 // Pointer to the Exif IFD
117 dest['0th'][piexif.ImageIFD.ExifTag] = 0
118 orig['Exif'][piexif.ExifIFD.PixelXDimension] = 0 // Image width
119 dest['Exif'][piexif.ExifIFD.PixelXDimension] = 0
120 orig['Exif'][piexif.ExifIFD.PixelYDimension] = 0 // Image height
121 dest['Exif'][piexif.ExifIFD.PixelYDimension] = 0
122 orig['1st'][piexif.ImageIFD.JPEGInterchangeFormat] = 0 // Offset to the start byte of the thumbnail
123 dest['1st'][piexif.ImageIFD.JPEGInterchangeFormat] = 0
124 orig['1st'][piexif.ImageIFD.JPEGInterchangeFormatLength] = 0 // Number of bytes of the thumbnail
125 dest['1st'][piexif.ImageIFD.JPEGInterchangeFormatLength] = 0
126
127 if (JSON.stringify(orig) !== JSON.stringify(dest)) {
128 throw new Error('EXIF do not match')
129 }
130}