Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MR414N-ID
GitHub Repository: MR414N-ID/botku2
Path: blob/master/node_modules/@jimp/plugin-resize/src/modules/resize2.js
1126 views
1
/**
2
* Copyright (c) 2015 Guyon Roche
3
*
4
* Permission is hereby granted, free of charge, to any person obtaining a copy
5
* of this software and associated documentation files (the "Software"), to deal
6
* in the Software without restriction, including without limitation the rights
7
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
* copies of the Software, and to permit persons to whom the Software is
9
* furnished to do so, subject to the following conditions:</p>
10
*
11
* The above copyright notice and this permission notice shall be included in
12
* all copies or substantial portions of the Software.
13
*
14
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
* THE SOFTWARE.
21
*/
22
23
module.exports = {
24
nearestNeighbor(src, dst) {
25
const wSrc = src.width;
26
const hSrc = src.height;
27
28
const wDst = dst.width;
29
const hDst = dst.height;
30
31
const bufSrc = src.data;
32
const bufDst = dst.data;
33
34
for (let i = 0; i < hDst; i++) {
35
for (let j = 0; j < wDst; j++) {
36
let posDst = (i * wDst + j) * 4;
37
38
const iSrc = Math.floor((i * hSrc) / hDst);
39
const jSrc = Math.floor((j * wSrc) / wDst);
40
let posSrc = (iSrc * wSrc + jSrc) * 4;
41
42
bufDst[posDst++] = bufSrc[posSrc++];
43
bufDst[posDst++] = bufSrc[posSrc++];
44
bufDst[posDst++] = bufSrc[posSrc++];
45
bufDst[posDst++] = bufSrc[posSrc++];
46
}
47
}
48
},
49
50
bilinearInterpolation(src, dst) {
51
const wSrc = src.width;
52
const hSrc = src.height;
53
54
const wDst = dst.width;
55
const hDst = dst.height;
56
57
const bufSrc = src.data;
58
const bufDst = dst.data;
59
60
const interpolate = function(k, kMin, vMin, kMax, vMax) {
61
// special case - k is integer
62
if (kMin === kMax) {
63
return vMin;
64
}
65
66
return Math.round((k - kMin) * vMax + (kMax - k) * vMin);
67
};
68
69
const assign = function(pos, offset, x, xMin, xMax, y, yMin, yMax) {
70
let posMin = (yMin * wSrc + xMin) * 4 + offset;
71
let posMax = (yMin * wSrc + xMax) * 4 + offset;
72
const vMin = interpolate(x, xMin, bufSrc[posMin], xMax, bufSrc[posMax]);
73
74
// special case, y is integer
75
if (yMax === yMin) {
76
bufDst[pos + offset] = vMin;
77
} else {
78
posMin = (yMax * wSrc + xMin) * 4 + offset;
79
posMax = (yMax * wSrc + xMax) * 4 + offset;
80
const vMax = interpolate(x, xMin, bufSrc[posMin], xMax, bufSrc[posMax]);
81
82
bufDst[pos + offset] = interpolate(y, yMin, vMin, yMax, vMax);
83
}
84
};
85
86
for (let i = 0; i < hDst; i++) {
87
for (let j = 0; j < wDst; j++) {
88
const posDst = (i * wDst + j) * 4;
89
// x & y in src coordinates
90
const x = (j * wSrc) / wDst;
91
const xMin = Math.floor(x);
92
const xMax = Math.min(Math.ceil(x), wSrc - 1);
93
94
const y = (i * hSrc) / hDst;
95
const yMin = Math.floor(y);
96
const yMax = Math.min(Math.ceil(y), hSrc - 1);
97
98
assign(posDst, 0, x, xMin, xMax, y, yMin, yMax);
99
assign(posDst, 1, x, xMin, xMax, y, yMin, yMax);
100
assign(posDst, 2, x, xMin, xMax, y, yMin, yMax);
101
assign(posDst, 3, x, xMin, xMax, y, yMin, yMax);
102
}
103
}
104
},
105
106
_interpolate2D(src, dst, options, interpolate) {
107
const bufSrc = src.data;
108
const bufDst = dst.data;
109
110
const wSrc = src.width;
111
const hSrc = src.height;
112
113
const wDst = dst.width;
114
const hDst = dst.height;
115
116
// when dst smaller than src/2, interpolate first to a multiple between 0.5 and 1.0 src, then sum squares
117
const wM = Math.max(1, Math.floor(wSrc / wDst));
118
const wDst2 = wDst * wM;
119
const hM = Math.max(1, Math.floor(hSrc / hDst));
120
const hDst2 = hDst * hM;
121
122
// ===========================================================
123
// Pass 1 - interpolate rows
124
// buf1 has width of dst2 and height of src
125
const buf1 = Buffer.alloc(wDst2 * hSrc * 4);
126
for (let i = 0; i < hSrc; i++) {
127
for (let j = 0; j < wDst2; j++) {
128
// i in src coords, j in dst coords
129
130
// calculate x in src coords
131
// this interpolation requires 4 sample points and the two inner ones must be real
132
// the outer points can be fudged for the edges.
133
// therefore (wSrc-1)/wDst2
134
const x = (j * (wSrc - 1)) / wDst2;
135
const xPos = Math.floor(x);
136
const t = x - xPos;
137
const srcPos = (i * wSrc + xPos) * 4;
138
const buf1Pos = (i * wDst2 + j) * 4;
139
140
for (let k = 0; k < 4; k++) {
141
const kPos = srcPos + k;
142
const x0 =
143
xPos > 0 ? bufSrc[kPos - 4] : 2 * bufSrc[kPos] - bufSrc[kPos + 4];
144
const x1 = bufSrc[kPos];
145
const x2 = bufSrc[kPos + 4];
146
const x3 =
147
xPos < wSrc - 2
148
? bufSrc[kPos + 8]
149
: 2 * bufSrc[kPos + 4] - bufSrc[kPos];
150
buf1[buf1Pos + k] = interpolate(x0, x1, x2, x3, t);
151
}
152
}
153
}
154
// this._writeFile(wDst2, hSrc, buf1, "out/buf1.jpg");
155
156
// ===========================================================
157
// Pass 2 - interpolate columns
158
// buf2 has width and height of dst2
159
const buf2 = Buffer.alloc(wDst2 * hDst2 * 4);
160
for (let i = 0; i < hDst2; i++) {
161
for (let j = 0; j < wDst2; j++) {
162
// i&j in dst2 coords
163
164
// calculate y in buf1 coords
165
// this interpolation requires 4 sample points and the two inner ones must be real
166
// the outer points can be fudged for the edges.
167
// therefore (hSrc-1)/hDst2
168
const y = (i * (hSrc - 1)) / hDst2;
169
const yPos = Math.floor(y);
170
const t = y - yPos;
171
const buf1Pos = (yPos * wDst2 + j) * 4;
172
const buf2Pos = (i * wDst2 + j) * 4;
173
for (let k = 0; k < 4; k++) {
174
const kPos = buf1Pos + k;
175
const y0 =
176
yPos > 0
177
? buf1[kPos - wDst2 * 4]
178
: 2 * buf1[kPos] - buf1[kPos + wDst2 * 4];
179
const y1 = buf1[kPos];
180
const y2 = buf1[kPos + wDst2 * 4];
181
const y3 =
182
yPos < hSrc - 2
183
? buf1[kPos + wDst2 * 8]
184
: 2 * buf1[kPos + wDst2 * 4] - buf1[kPos];
185
186
buf2[buf2Pos + k] = interpolate(y0, y1, y2, y3, t);
187
}
188
}
189
}
190
// this._writeFile(wDst2, hDst2, buf2, "out/buf2.jpg");
191
192
// ===========================================================
193
// Pass 3 - scale to dst
194
const m = wM * hM;
195
if (m > 1) {
196
for (let i = 0; i < hDst; i++) {
197
for (let j = 0; j < wDst; j++) {
198
// i&j in dst bounded coords
199
let r = 0;
200
let g = 0;
201
let b = 0;
202
let a = 0;
203
let realColors = 0;
204
205
for (let y = 0; y < hM; y++) {
206
const yPos = i * hM + y;
207
208
for (let x = 0; x < wM; x++) {
209
const xPos = j * wM + x;
210
const xyPos = (yPos * wDst2 + xPos) * 4;
211
const pixelAlpha = buf2[xyPos + 3];
212
213
if (pixelAlpha) {
214
r += buf2[xyPos];
215
g += buf2[xyPos + 1];
216
b += buf2[xyPos + 2];
217
realColors++;
218
}
219
220
a += pixelAlpha;
221
}
222
}
223
224
const pos = (i * wDst + j) * 4;
225
bufDst[pos] = realColors ? Math.round(r / realColors) : 0;
226
bufDst[pos + 1] = realColors ? Math.round(g / realColors) : 0;
227
bufDst[pos + 2] = realColors ? Math.round(b / realColors) : 0;
228
bufDst[pos + 3] = Math.round(a / m);
229
}
230
}
231
} else {
232
// replace dst buffer with buf2
233
dst.data = buf2;
234
}
235
},
236
237
bicubicInterpolation(src, dst, options) {
238
const interpolateCubic = function(x0, x1, x2, x3, t) {
239
const a0 = x3 - x2 - x0 + x1;
240
const a1 = x0 - x1 - a0;
241
const a2 = x2 - x0;
242
const a3 = x1;
243
return Math.max(
244
0,
245
Math.min(255, a0 * (t * t * t) + a1 * (t * t) + a2 * t + a3)
246
);
247
};
248
249
return this._interpolate2D(src, dst, options, interpolateCubic);
250
},
251
252
hermiteInterpolation(src, dst, options) {
253
const interpolateHermite = function(x0, x1, x2, x3, t) {
254
const c0 = x1;
255
const c1 = 0.5 * (x2 - x0);
256
const c2 = x0 - 2.5 * x1 + 2 * x2 - 0.5 * x3;
257
const c3 = 0.5 * (x3 - x0) + 1.5 * (x1 - x2);
258
return Math.max(
259
0,
260
Math.min(255, Math.round(((c3 * t + c2) * t + c1) * t + c0))
261
);
262
};
263
264
return this._interpolate2D(src, dst, options, interpolateHermite);
265
},
266
267
bezierInterpolation(src, dst, options) {
268
// between 2 points y(n), y(n+1), use next points out, y(n-1), y(n+2)
269
// to predict control points (a & b) to be placed at n+0.5
270
// ya(n) = y(n) + (y(n+1)-y(n-1))/4
271
// yb(n) = y(n+1) - (y(n+2)-y(n))/4
272
// then use std bezier to interpolate [n,n+1)
273
// y(n+t) = y(n)*(1-t)^3 + 3 * ya(n)*(1-t)^2*t + 3 * yb(n)*(1-t)*t^2 + y(n+1)*t^3
274
// note the 3* factor for the two control points
275
// for edge cases, can choose:
276
// y(-1) = y(0) - 2*(y(1)-y(0))
277
// y(w) = y(w-1) + 2*(y(w-1)-y(w-2))
278
// but can go with y(-1) = y(0) and y(w) = y(w-1)
279
const interpolateBezier = function(x0, x1, x2, x3, t) {
280
// x1, x2 are the knots, use x0 and x3 to calculate control points
281
const cp1 = x1 + (x2 - x0) / 4;
282
const cp2 = x2 - (x3 - x1) / 4;
283
const nt = 1 - t;
284
const c0 = x1 * nt * nt * nt;
285
const c1 = 3 * cp1 * nt * nt * t;
286
const c2 = 3 * cp2 * nt * t * t;
287
const c3 = x2 * t * t * t;
288
return Math.max(0, Math.min(255, Math.round(c0 + c1 + c2 + c3)));
289
};
290
291
return this._interpolate2D(src, dst, options, interpolateBezier);
292
}
293
};
294
295