Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MR414N-ID
GitHub Repository: MR414N-ID/botku2
Path: blob/master/node_modules/@jimp/plugin-resize/dist/modules/resize.js
1129 views
1
"use strict";
2
3
// JavaScript Image Resizer (c) 2012 - Grant Galitz
4
// Released to public domain 29 July 2013: https://github.com/grantgalitz/JS-Image-Resizer/issues/4
5
function Resize(widthOriginal, heightOriginal, targetWidth, targetHeight, blendAlpha, interpolationPass, resizeCallback) {
6
this.widthOriginal = Math.abs(Math.floor(widthOriginal) || 0);
7
this.heightOriginal = Math.abs(Math.floor(heightOriginal) || 0);
8
this.targetWidth = Math.abs(Math.floor(targetWidth) || 0);
9
this.targetHeight = Math.abs(Math.floor(targetHeight) || 0);
10
this.colorChannels = blendAlpha ? 4 : 3;
11
this.interpolationPass = Boolean(interpolationPass);
12
this.resizeCallback = typeof resizeCallback === 'function' ? resizeCallback : function () {};
13
this.targetWidthMultipliedByChannels = this.targetWidth * this.colorChannels;
14
this.originalWidthMultipliedByChannels = this.widthOriginal * this.colorChannels;
15
this.originalHeightMultipliedByChannels = this.heightOriginal * this.colorChannels;
16
this.widthPassResultSize = this.targetWidthMultipliedByChannels * this.heightOriginal;
17
this.finalResultSize = this.targetWidthMultipliedByChannels * this.targetHeight;
18
this.initialize();
19
}
20
21
Resize.prototype.initialize = function () {
22
// Perform some checks:
23
if (this.widthOriginal > 0 && this.heightOriginal > 0 && this.targetWidth > 0 && this.targetHeight > 0) {
24
this.configurePasses();
25
} else {
26
throw new Error('Invalid settings specified for the resizer.');
27
}
28
};
29
30
Resize.prototype.configurePasses = function () {
31
if (this.widthOriginal === this.targetWidth) {
32
// Bypass the width resizer pass:
33
this.resizeWidth = this.bypassResizer;
34
} else {
35
// Setup the width resizer pass:
36
this.ratioWeightWidthPass = this.widthOriginal / this.targetWidth;
37
38
if (this.ratioWeightWidthPass < 1 && this.interpolationPass) {
39
this.initializeFirstPassBuffers(true);
40
this.resizeWidth = this.colorChannels === 4 ? this.resizeWidthInterpolatedRGBA : this.resizeWidthInterpolatedRGB;
41
} else {
42
this.initializeFirstPassBuffers(false);
43
this.resizeWidth = this.colorChannels === 4 ? this.resizeWidthRGBA : this.resizeWidthRGB;
44
}
45
}
46
47
if (this.heightOriginal === this.targetHeight) {
48
// Bypass the height resizer pass:
49
this.resizeHeight = this.bypassResizer;
50
} else {
51
// Setup the height resizer pass:
52
this.ratioWeightHeightPass = this.heightOriginal / this.targetHeight;
53
54
if (this.ratioWeightHeightPass < 1 && this.interpolationPass) {
55
this.initializeSecondPassBuffers(true);
56
this.resizeHeight = this.resizeHeightInterpolated;
57
} else {
58
this.initializeSecondPassBuffers(false);
59
this.resizeHeight = this.colorChannels === 4 ? this.resizeHeightRGBA : this.resizeHeightRGB;
60
}
61
}
62
};
63
64
Resize.prototype._resizeWidthInterpolatedRGBChannels = function (buffer, fourthChannel) {
65
var channelsNum = fourthChannel ? 4 : 3;
66
var ratioWeight = this.ratioWeightWidthPass;
67
var outputBuffer = this.widthBuffer;
68
var weight = 0;
69
var finalOffset = 0;
70
var pixelOffset = 0;
71
var firstWeight = 0;
72
var secondWeight = 0;
73
var targetPosition; // Handle for only one interpolation input being valid for start calculation:
74
75
for (targetPosition = 0; weight < 1 / 3; targetPosition += channelsNum, weight += ratioWeight) {
76
for (finalOffset = targetPosition, pixelOffset = 0; finalOffset < this.widthPassResultSize; pixelOffset += this.originalWidthMultipliedByChannels, finalOffset += this.targetWidthMultipliedByChannels) {
77
outputBuffer[finalOffset] = buffer[pixelOffset];
78
outputBuffer[finalOffset + 1] = buffer[pixelOffset + 1];
79
outputBuffer[finalOffset + 2] = buffer[pixelOffset + 2];
80
if (fourthChannel) outputBuffer[finalOffset + 3] = buffer[pixelOffset + 3];
81
}
82
} // Adjust for overshoot of the last pass's counter:
83
84
85
weight -= 1 / 3;
86
var interpolationWidthSourceReadStop;
87
88
for (interpolationWidthSourceReadStop = this.widthOriginal - 1; weight < interpolationWidthSourceReadStop; targetPosition += channelsNum, weight += ratioWeight) {
89
// Calculate weightings:
90
secondWeight = weight % 1;
91
firstWeight = 1 - secondWeight; // Interpolate:
92
93
for (finalOffset = targetPosition, pixelOffset = Math.floor(weight) * channelsNum; finalOffset < this.widthPassResultSize; pixelOffset += this.originalWidthMultipliedByChannels, finalOffset += this.targetWidthMultipliedByChannels) {
94
outputBuffer[finalOffset + 0] = buffer[pixelOffset + 0] * firstWeight + buffer[pixelOffset + channelsNum + 0] * secondWeight;
95
outputBuffer[finalOffset + 1] = buffer[pixelOffset + 1] * firstWeight + buffer[pixelOffset + channelsNum + 1] * secondWeight;
96
outputBuffer[finalOffset + 2] = buffer[pixelOffset + 2] * firstWeight + buffer[pixelOffset + channelsNum + 2] * secondWeight;
97
if (fourthChannel) outputBuffer[finalOffset + 3] = buffer[pixelOffset + 3] * firstWeight + buffer[pixelOffset + channelsNum + 3] * secondWeight;
98
}
99
} // Handle for only one interpolation input being valid for end calculation:
100
101
102
for (interpolationWidthSourceReadStop = this.originalWidthMultipliedByChannels - channelsNum; targetPosition < this.targetWidthMultipliedByChannels; targetPosition += channelsNum) {
103
for (finalOffset = targetPosition, pixelOffset = interpolationWidthSourceReadStop; finalOffset < this.widthPassResultSize; pixelOffset += this.originalWidthMultipliedByChannels, finalOffset += this.targetWidthMultipliedByChannels) {
104
outputBuffer[finalOffset] = buffer[pixelOffset];
105
outputBuffer[finalOffset + 1] = buffer[pixelOffset + 1];
106
outputBuffer[finalOffset + 2] = buffer[pixelOffset + 2];
107
if (fourthChannel) outputBuffer[finalOffset + 3] = buffer[pixelOffset + 3];
108
}
109
}
110
111
return outputBuffer;
112
};
113
114
Resize.prototype._resizeWidthRGBChannels = function (buffer, fourthChannel) {
115
var channelsNum = fourthChannel ? 4 : 3;
116
var ratioWeight = this.ratioWeightWidthPass;
117
var ratioWeightDivisor = 1 / ratioWeight;
118
var nextLineOffsetOriginalWidth = this.originalWidthMultipliedByChannels - channelsNum + 1;
119
var nextLineOffsetTargetWidth = this.targetWidthMultipliedByChannels - channelsNum + 1;
120
var output = this.outputWidthWorkBench;
121
var outputBuffer = this.widthBuffer;
122
var trustworthyColorsCount = this.outputWidthWorkBenchOpaquePixelsCount;
123
var weight = 0;
124
var amountToNext = 0;
125
var actualPosition = 0;
126
var currentPosition = 0;
127
var line = 0;
128
var pixelOffset = 0;
129
var outputOffset = 0;
130
var multiplier = 1;
131
var r = 0;
132
var g = 0;
133
var b = 0;
134
var a = 0;
135
136
do {
137
for (line = 0; line < this.originalHeightMultipliedByChannels;) {
138
output[line++] = 0;
139
output[line++] = 0;
140
output[line++] = 0;
141
142
if (fourthChannel) {
143
output[line++] = 0;
144
trustworthyColorsCount[line / channelsNum - 1] = 0;
145
}
146
}
147
148
weight = ratioWeight;
149
150
do {
151
amountToNext = 1 + actualPosition - currentPosition;
152
multiplier = Math.min(weight, amountToNext);
153
154
for (line = 0, pixelOffset = actualPosition; line < this.originalHeightMultipliedByChannels; pixelOffset += nextLineOffsetOriginalWidth) {
155
r = buffer[pixelOffset];
156
g = buffer[++pixelOffset];
157
b = buffer[++pixelOffset];
158
a = fourthChannel ? buffer[++pixelOffset] : 255; // Ignore RGB values if pixel is completely transparent
159
160
output[line++] += (a ? r : 0) * multiplier;
161
output[line++] += (a ? g : 0) * multiplier;
162
output[line++] += (a ? b : 0) * multiplier;
163
164
if (fourthChannel) {
165
output[line++] += a * multiplier;
166
trustworthyColorsCount[line / channelsNum - 1] += a ? multiplier : 0;
167
}
168
}
169
170
if (weight >= amountToNext) {
171
actualPosition += channelsNum;
172
currentPosition = actualPosition;
173
weight -= amountToNext;
174
} else {
175
currentPosition += weight;
176
break;
177
}
178
} while (weight > 0 && actualPosition < this.originalWidthMultipliedByChannels);
179
180
for (line = 0, pixelOffset = outputOffset; line < this.originalHeightMultipliedByChannels; pixelOffset += nextLineOffsetTargetWidth) {
181
weight = fourthChannel ? trustworthyColorsCount[line / channelsNum] : 1;
182
multiplier = fourthChannel ? weight ? 1 / weight : 0 : ratioWeightDivisor;
183
outputBuffer[pixelOffset] = output[line++] * multiplier;
184
outputBuffer[++pixelOffset] = output[line++] * multiplier;
185
outputBuffer[++pixelOffset] = output[line++] * multiplier;
186
if (fourthChannel) outputBuffer[++pixelOffset] = output[line++] * ratioWeightDivisor;
187
}
188
189
outputOffset += channelsNum;
190
} while (outputOffset < this.targetWidthMultipliedByChannels);
191
192
return outputBuffer;
193
};
194
195
Resize.prototype._resizeHeightRGBChannels = function (buffer, fourthChannel) {
196
var ratioWeight = this.ratioWeightHeightPass;
197
var ratioWeightDivisor = 1 / ratioWeight;
198
var output = this.outputHeightWorkBench;
199
var outputBuffer = this.heightBuffer;
200
var trustworthyColorsCount = this.outputHeightWorkBenchOpaquePixelsCount;
201
var weight = 0;
202
var amountToNext = 0;
203
var actualPosition = 0;
204
var currentPosition = 0;
205
var pixelOffset = 0;
206
var outputOffset = 0;
207
var caret = 0;
208
var multiplier = 1;
209
var r = 0;
210
var g = 0;
211
var b = 0;
212
var a = 0;
213
214
do {
215
for (pixelOffset = 0; pixelOffset < this.targetWidthMultipliedByChannels;) {
216
output[pixelOffset++] = 0;
217
output[pixelOffset++] = 0;
218
output[pixelOffset++] = 0;
219
220
if (fourthChannel) {
221
output[pixelOffset++] = 0;
222
trustworthyColorsCount[pixelOffset / 4 - 1] = 0;
223
}
224
}
225
226
weight = ratioWeight;
227
228
do {
229
amountToNext = 1 + actualPosition - currentPosition;
230
multiplier = Math.min(weight, amountToNext);
231
caret = actualPosition;
232
233
for (pixelOffset = 0; pixelOffset < this.targetWidthMultipliedByChannels;) {
234
r = buffer[caret++];
235
g = buffer[caret++];
236
b = buffer[caret++];
237
a = fourthChannel ? buffer[caret++] : 255; // Ignore RGB values if pixel is completely transparent
238
239
output[pixelOffset++] += (a ? r : 0) * multiplier;
240
output[pixelOffset++] += (a ? g : 0) * multiplier;
241
output[pixelOffset++] += (a ? b : 0) * multiplier;
242
243
if (fourthChannel) {
244
output[pixelOffset++] += a * multiplier;
245
trustworthyColorsCount[pixelOffset / 4 - 1] += a ? multiplier : 0;
246
}
247
}
248
249
if (weight >= amountToNext) {
250
actualPosition = caret;
251
currentPosition = actualPosition;
252
weight -= amountToNext;
253
} else {
254
currentPosition += weight;
255
break;
256
}
257
} while (weight > 0 && actualPosition < this.widthPassResultSize);
258
259
for (pixelOffset = 0; pixelOffset < this.targetWidthMultipliedByChannels;) {
260
weight = fourthChannel ? trustworthyColorsCount[pixelOffset / 4] : 1;
261
multiplier = fourthChannel ? weight ? 1 / weight : 0 : ratioWeightDivisor;
262
outputBuffer[outputOffset++] = Math.round(output[pixelOffset++] * multiplier);
263
outputBuffer[outputOffset++] = Math.round(output[pixelOffset++] * multiplier);
264
outputBuffer[outputOffset++] = Math.round(output[pixelOffset++] * multiplier);
265
266
if (fourthChannel) {
267
outputBuffer[outputOffset++] = Math.round(output[pixelOffset++] * ratioWeightDivisor);
268
}
269
}
270
} while (outputOffset < this.finalResultSize);
271
272
return outputBuffer;
273
};
274
275
Resize.prototype.resizeWidthInterpolatedRGB = function (buffer) {
276
return this._resizeWidthInterpolatedRGBChannels(buffer, false);
277
};
278
279
Resize.prototype.resizeWidthInterpolatedRGBA = function (buffer) {
280
return this._resizeWidthInterpolatedRGBChannels(buffer, true);
281
};
282
283
Resize.prototype.resizeWidthRGB = function (buffer) {
284
return this._resizeWidthRGBChannels(buffer, false);
285
};
286
287
Resize.prototype.resizeWidthRGBA = function (buffer) {
288
return this._resizeWidthRGBChannels(buffer, true);
289
};
290
291
Resize.prototype.resizeHeightInterpolated = function (buffer) {
292
var ratioWeight = this.ratioWeightHeightPass;
293
var outputBuffer = this.heightBuffer;
294
var weight = 0;
295
var finalOffset = 0;
296
var pixelOffset = 0;
297
var pixelOffsetAccumulated = 0;
298
var pixelOffsetAccumulated2 = 0;
299
var firstWeight = 0;
300
var secondWeight = 0;
301
var interpolationHeightSourceReadStop; // Handle for only one interpolation input being valid for start calculation:
302
303
for (; weight < 1 / 3; weight += ratioWeight) {
304
for (pixelOffset = 0; pixelOffset < this.targetWidthMultipliedByChannels;) {
305
outputBuffer[finalOffset++] = Math.round(buffer[pixelOffset++]);
306
}
307
} // Adjust for overshoot of the last pass's counter:
308
309
310
weight -= 1 / 3;
311
312
for (interpolationHeightSourceReadStop = this.heightOriginal - 1; weight < interpolationHeightSourceReadStop; weight += ratioWeight) {
313
// Calculate weightings:
314
secondWeight = weight % 1;
315
firstWeight = 1 - secondWeight; // Interpolate:
316
317
pixelOffsetAccumulated = Math.floor(weight) * this.targetWidthMultipliedByChannels;
318
pixelOffsetAccumulated2 = pixelOffsetAccumulated + this.targetWidthMultipliedByChannels;
319
320
for (pixelOffset = 0; pixelOffset < this.targetWidthMultipliedByChannels; ++pixelOffset) {
321
outputBuffer[finalOffset++] = Math.round(buffer[pixelOffsetAccumulated++] * firstWeight + buffer[pixelOffsetAccumulated2++] * secondWeight);
322
}
323
} // Handle for only one interpolation input being valid for end calculation:
324
325
326
while (finalOffset < this.finalResultSize) {
327
for (pixelOffset = 0, pixelOffsetAccumulated = interpolationHeightSourceReadStop * this.targetWidthMultipliedByChannels; pixelOffset < this.targetWidthMultipliedByChannels; ++pixelOffset) {
328
outputBuffer[finalOffset++] = Math.round(buffer[pixelOffsetAccumulated++]);
329
}
330
}
331
332
return outputBuffer;
333
};
334
335
Resize.prototype.resizeHeightRGB = function (buffer) {
336
return this._resizeHeightRGBChannels(buffer, false);
337
};
338
339
Resize.prototype.resizeHeightRGBA = function (buffer) {
340
return this._resizeHeightRGBChannels(buffer, true);
341
};
342
343
Resize.prototype.resize = function (buffer) {
344
this.resizeCallback(this.resizeHeight(this.resizeWidth(buffer)));
345
};
346
347
Resize.prototype.bypassResizer = function (buffer) {
348
// Just return the buffer passed:
349
return buffer;
350
};
351
352
Resize.prototype.initializeFirstPassBuffers = function (BILINEARAlgo) {
353
// Initialize the internal width pass buffers:
354
this.widthBuffer = this.generateFloatBuffer(this.widthPassResultSize);
355
356
if (!BILINEARAlgo) {
357
this.outputWidthWorkBench = this.generateFloatBuffer(this.originalHeightMultipliedByChannels);
358
359
if (this.colorChannels > 3) {
360
this.outputWidthWorkBenchOpaquePixelsCount = this.generateFloat64Buffer(this.heightOriginal);
361
}
362
}
363
};
364
365
Resize.prototype.initializeSecondPassBuffers = function (BILINEARAlgo) {
366
// Initialize the internal height pass buffers:
367
this.heightBuffer = this.generateUint8Buffer(this.finalResultSize);
368
369
if (!BILINEARAlgo) {
370
this.outputHeightWorkBench = this.generateFloatBuffer(this.targetWidthMultipliedByChannels);
371
372
if (this.colorChannels > 3) {
373
this.outputHeightWorkBenchOpaquePixelsCount = this.generateFloat64Buffer(this.targetWidth);
374
}
375
}
376
};
377
378
Resize.prototype.generateFloatBuffer = function (bufferLength) {
379
// Generate a float32 typed array buffer:
380
try {
381
return new Float32Array(bufferLength);
382
} catch (error) {
383
return [];
384
}
385
};
386
387
Resize.prototype.generateFloat64Buffer = function (bufferLength) {
388
// Generate a float64 typed array buffer:
389
try {
390
return new Float64Array(bufferLength);
391
} catch (error) {
392
return [];
393
}
394
};
395
396
Resize.prototype.generateUint8Buffer = function (bufferLength) {
397
// Generate a uint8 typed array buffer:
398
try {
399
return new Uint8Array(bufferLength);
400
} catch (error) {
401
return [];
402
}
403
};
404
405
module.exports = Resize;
406
//# sourceMappingURL=resize.js.map
407