-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
138 lines (113 loc) · 3.62 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import { obj } from 'through2'
import sharp from 'sharp'
import Vinyl from 'vinyl'
import chalk from 'chalk'
import path from 'path'
const
ALLOWED_EXTENSIONS = [
'.gif',
'.png',
'.jpg', '.jpeg',
'.webp',
'.avif',
'.tiff',
'.heif',
],
DEFAULT_CONVERSION_OPTIONS = {
quality: 90,
lossless: false,
chromaSubsampling: '4:2:0',
},
DEFAULT_SHARP_OPTIONS = {
animated: true,
limitInputPixels: false,
}
export default function sharpOptimizeImages(options) {
let logLevel = options.logLevel ?? 'small'
delete options.logLevel
let optionObjects = Object.entries(options)
return obj(async function (file, enc, callback) {
if (!file) return callback(null, file)
if (typeof options !== 'object')
throw new Error('Invalid parameters, they must be an object.')
if (!ALLOWED_EXTENSIONS.includes(file.extname)) {
logAboutSuccessfulCopy(file, logLevel)
return callback(null, file)
}
let originalFileExtname = file.extname.split('.').at(-1)
for (let [format, props] of optionObjects) {
let [convertFrom, convertTo] = format.split('_to_')
if (!extnamesIsCorrect(convertFrom, convertTo)) {
throw new Error('Invalid name of an object! Make sure you have spelled the extension names correctly.')
}
// Checking that the file has not a suitable extension
if (convertTo && `.${convertFrom}` != file.extname) continue
//? For general conversion rules such as png: {}
if (!convertTo) {
this.push(await convert(file, convertFrom, props))
logAboutSuccessfulConversion(file, convertFrom, logLevel)
if (props.alsoProcessOriginal) {
this.push(await convert(file, originalFileExtname, props))
logAboutSuccessfulConversion(file, originalFileExtname, logLevel)
}
}
//? For specific conversion rules such as png_to_webp: {}
else {
this.push(await convert(file, convertTo, props))
logAboutSuccessfulConversion(file, convertTo, logLevel)
}
}
return callback()
})
}
async function convert(file, newFileFormat, options) {
if (newFileFormat == 'heif')
options.compression = 'av1'
let sharpBuffer =
await sharp(file.path, DEFAULT_SHARP_OPTIONS)
.toFormat(newFileFormat, Object.assign(DEFAULT_CONVERSION_OPTIONS, options))
.toBuffer()
return toVinyl(sharpBuffer, newFileFormat, file)
}
function toVinyl(buffer, newFileFormat, file) {
let newFileName = file.basename.substr(0, file.basename.lastIndexOf('.'))
+ '.' + newFileFormat
return new Vinyl({
cwd: file.cwd,
base: file.base,
path: path.join(file.dirname, newFileName),
contents: buffer,
})
}
function extnamesIsCorrect(...extnames) {
for (let extname of extnames) {
if (extname && !ALLOWED_EXTENSIONS.includes('.' + extname))
return false
}
return true
}
function logAboutSuccessfulConversion(file, newFileExtname, logLevel) {
let filename = file.basename.split('.')[0]
if (logLevel == 'full')
console.log(
'The file ' + chalk.green(file.path)
+ ' was processed to '
+ chalk.green(filename + '.' + chalk.bold(newFileExtname))
)
else if (logLevel == 'small')
console.log(
chalk.green(file.basename) + ' => ' + chalk.green.bold(newFileExtname)
)
}
function logAboutSuccessfulCopy(file, logLevel) {
if (logLevel == 'full')
console.log(chalk.hex('#FF8800')
(
`The image ${chalk.bold(file.basename)} cannot be processed, so it is copied.`
)
)
else if (logLevel == 'small')
console.log(chalk.hex('#FF8800')
(file.basename + ' => ' + chalk.bold('copied'))
)
}