q5 2.10.2 → 2.10.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/q5.d.ts +130 -10
- package/q5.js +260 -28
- package/q5.min.js +1 -1
- package/src/q5-2d-image.js +44 -23
- package/src/q5-2d-soft-filters.js +59 -90
- package/src/q5-canvas.js +1 -0
- package/src/q5-color.js +68 -4
- package/src/q5-core.js +2 -1
- package/src/q5-record.js +366 -2
|
@@ -1,53 +1,52 @@
|
|
|
1
1
|
/* software implementation of image filters */
|
|
2
2
|
Q5.renderers.q2d.soft_filters = ($) => {
|
|
3
|
-
let
|
|
3
|
+
let u = null; // uint8 temporary buffer
|
|
4
4
|
|
|
5
|
-
function
|
|
5
|
+
function ensureBuf() {
|
|
6
6
|
let l = $.canvas.width * $.canvas.height * 4;
|
|
7
|
-
if (!
|
|
8
|
-
tmpBuf = new Uint8ClampedArray(l);
|
|
9
|
-
}
|
|
7
|
+
if (!u || u.length != l) u = new Uint8ClampedArray(l);
|
|
10
8
|
}
|
|
11
9
|
|
|
12
10
|
function initSoftFilters() {
|
|
13
11
|
$._filters = [];
|
|
14
|
-
$._filters[Q5.THRESHOLD] = (
|
|
12
|
+
$._filters[Q5.THRESHOLD] = (d, thresh) => {
|
|
15
13
|
if (thresh === undefined) thresh = 127.5;
|
|
16
14
|
else thresh *= 255;
|
|
17
|
-
for (let i = 0; i <
|
|
18
|
-
const gray = 0.2126 *
|
|
19
|
-
|
|
15
|
+
for (let i = 0; i < d.length; i += 4) {
|
|
16
|
+
const gray = 0.2126 * d[i] + 0.7152 * d[i + 1] + 0.0722 * d[i + 2];
|
|
17
|
+
d[i] = d[i + 1] = d[i + 2] = gray >= thresh ? 255 : 0;
|
|
20
18
|
}
|
|
21
19
|
};
|
|
22
|
-
$._filters[Q5.GRAY] = (
|
|
23
|
-
for (let i = 0; i <
|
|
24
|
-
const gray = 0.2126 *
|
|
25
|
-
|
|
20
|
+
$._filters[Q5.GRAY] = (d) => {
|
|
21
|
+
for (let i = 0; i < d.length; i += 4) {
|
|
22
|
+
const gray = 0.2126 * d[i] + 0.7152 * d[i + 1] + 0.0722 * d[i + 2];
|
|
23
|
+
d[i] = d[i + 1] = d[i + 2] = gray;
|
|
26
24
|
}
|
|
27
25
|
};
|
|
28
|
-
$._filters[Q5.OPAQUE] = (
|
|
29
|
-
for (let i = 0; i <
|
|
30
|
-
|
|
26
|
+
$._filters[Q5.OPAQUE] = (d) => {
|
|
27
|
+
for (let i = 0; i < d.length; i += 4) {
|
|
28
|
+
d[i + 3] = 255;
|
|
31
29
|
}
|
|
32
30
|
};
|
|
33
|
-
$._filters[Q5.INVERT] = (
|
|
34
|
-
for (let i = 0; i <
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
$._filters[Q5.INVERT] = (d) => {
|
|
32
|
+
for (let i = 0; i < d.length; i += 4) {
|
|
33
|
+
d[i] = 255 - d[i];
|
|
34
|
+
d[i + 1] = 255 - d[i + 1];
|
|
35
|
+
d[i + 2] = 255 - d[i + 2];
|
|
38
36
|
}
|
|
39
37
|
};
|
|
40
|
-
$._filters[Q5.POSTERIZE] = (
|
|
38
|
+
$._filters[Q5.POSTERIZE] = (d, lvl = 4) => {
|
|
41
39
|
let lvl1 = lvl - 1;
|
|
42
|
-
for (let i = 0; i <
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
for (let i = 0; i < d.length; i += 4) {
|
|
41
|
+
d[i] = (((d[i] * lvl) >> 8) * 255) / lvl1;
|
|
42
|
+
d[i + 1] = (((d[i + 1] * lvl) >> 8) * 255) / lvl1;
|
|
43
|
+
d[i + 2] = (((d[i + 2] * lvl) >> 8) * 255) / lvl1;
|
|
46
44
|
}
|
|
47
45
|
};
|
|
48
|
-
$._filters[Q5.DILATE] = (
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
$._filters[Q5.DILATE] = (d, func) => {
|
|
47
|
+
func ??= Math.max;
|
|
48
|
+
ensureBuf();
|
|
49
|
+
u.set(d);
|
|
51
50
|
let [w, h] = [$.canvas.width, $.canvas.height];
|
|
52
51
|
for (let i = 0; i < h; i++) {
|
|
53
52
|
for (let j = 0; j < w; j++) {
|
|
@@ -61,55 +60,25 @@ Q5.renderers.q2d.soft_filters = ($) => {
|
|
|
61
60
|
let kt = k + t;
|
|
62
61
|
let kb = k + b;
|
|
63
62
|
let ko = k + oi;
|
|
64
|
-
|
|
65
|
-
/*tmpBuf[kt+l],*/ tmpBuf[kt + oj] /*tmpBuf[kt+r],*/,
|
|
66
|
-
tmpBuf[ko + l],
|
|
67
|
-
tmpBuf[ko + oj],
|
|
68
|
-
tmpBuf[ko + r],
|
|
69
|
-
/*tmpBuf[kb+l],*/ tmpBuf[kb + oj] /*tmpBuf[kb+r],*/
|
|
70
|
-
);
|
|
63
|
+
d[oi + oj + k] = func(u[kt + oj], u[ko + l], u[ko + oj], u[ko + r], u[kb + oj]);
|
|
71
64
|
}
|
|
72
65
|
}
|
|
73
66
|
}
|
|
74
67
|
};
|
|
75
|
-
$._filters[Q5.ERODE] = (
|
|
76
|
-
|
|
77
|
-
tmpBuf.set(data);
|
|
78
|
-
let [w, h] = [$.canvas.width, $.canvas.height];
|
|
79
|
-
for (let i = 0; i < h; i++) {
|
|
80
|
-
for (let j = 0; j < w; j++) {
|
|
81
|
-
let l = 4 * Math.max(j - 1, 0);
|
|
82
|
-
let r = 4 * Math.min(j + 1, w - 1);
|
|
83
|
-
let t = 4 * Math.max(i - 1, 0) * w;
|
|
84
|
-
let b = 4 * Math.min(i + 1, h - 1) * w;
|
|
85
|
-
let oi = 4 * i * w;
|
|
86
|
-
let oj = 4 * j;
|
|
87
|
-
for (let k = 0; k < 4; k++) {
|
|
88
|
-
let kt = k + t;
|
|
89
|
-
let kb = k + b;
|
|
90
|
-
let ko = k + oi;
|
|
91
|
-
data[oi + oj + k] = Math.min(
|
|
92
|
-
/*tmpBuf[kt+l],*/ tmpBuf[kt + oj] /*tmpBuf[kt+r],*/,
|
|
93
|
-
tmpBuf[ko + l],
|
|
94
|
-
tmpBuf[ko + oj],
|
|
95
|
-
tmpBuf[ko + r],
|
|
96
|
-
/*tmpBuf[kb+l],*/ tmpBuf[kb + oj] /*tmpBuf[kb+r],*/
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
68
|
+
$._filters[Q5.ERODE] = (d) => {
|
|
69
|
+
$._filters[Q5.DILATE](d, Math.min);
|
|
101
70
|
};
|
|
102
|
-
$._filters[Q5.BLUR] = (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
71
|
+
$._filters[Q5.BLUR] = (d, r) => {
|
|
72
|
+
r = r || 1;
|
|
73
|
+
r = Math.floor(r * $._pixelDensity);
|
|
74
|
+
ensureBuf();
|
|
75
|
+
u.set(d);
|
|
107
76
|
|
|
108
|
-
let ksize =
|
|
77
|
+
let ksize = r * 2 + 1;
|
|
109
78
|
|
|
110
|
-
function
|
|
79
|
+
function gauss(ksize) {
|
|
111
80
|
let im = new Float32Array(ksize);
|
|
112
|
-
let sigma = 0.3 *
|
|
81
|
+
let sigma = 0.3 * r + 0.8;
|
|
113
82
|
let ss2 = sigma * sigma * 2;
|
|
114
83
|
for (let i = 0; i < ksize; i++) {
|
|
115
84
|
let x = i - ksize / 2;
|
|
@@ -119,7 +88,7 @@ Q5.renderers.q2d.soft_filters = ($) => {
|
|
|
119
88
|
return im;
|
|
120
89
|
}
|
|
121
90
|
|
|
122
|
-
let kern =
|
|
91
|
+
let kern = gauss(ksize);
|
|
123
92
|
let [w, h] = [$.canvas.width, $.canvas.height];
|
|
124
93
|
for (let i = 0; i < h; i++) {
|
|
125
94
|
for (let j = 0; j < w; j++) {
|
|
@@ -128,21 +97,21 @@ Q5.renderers.q2d.soft_filters = ($) => {
|
|
|
128
97
|
s2 = 0,
|
|
129
98
|
s3 = 0;
|
|
130
99
|
for (let k = 0; k < ksize; k++) {
|
|
131
|
-
let jk = Math.min(Math.max(j -
|
|
100
|
+
let jk = Math.min(Math.max(j - r + k, 0), w - 1);
|
|
132
101
|
let idx = 4 * (i * w + jk);
|
|
133
|
-
s0 +=
|
|
134
|
-
s1 +=
|
|
135
|
-
s2 +=
|
|
136
|
-
s3 +=
|
|
102
|
+
s0 += u[idx] * kern[k];
|
|
103
|
+
s1 += u[idx + 1] * kern[k];
|
|
104
|
+
s2 += u[idx + 2] * kern[k];
|
|
105
|
+
s3 += u[idx + 3] * kern[k];
|
|
137
106
|
}
|
|
138
107
|
let idx = 4 * (i * w + j);
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
108
|
+
d[idx] = s0;
|
|
109
|
+
d[idx + 1] = s1;
|
|
110
|
+
d[idx + 2] = s2;
|
|
111
|
+
d[idx + 3] = s3;
|
|
143
112
|
}
|
|
144
113
|
}
|
|
145
|
-
|
|
114
|
+
u.set(d);
|
|
146
115
|
for (let i = 0; i < h; i++) {
|
|
147
116
|
for (let j = 0; j < w; j++) {
|
|
148
117
|
let s0 = 0,
|
|
@@ -150,18 +119,18 @@ Q5.renderers.q2d.soft_filters = ($) => {
|
|
|
150
119
|
s2 = 0,
|
|
151
120
|
s3 = 0;
|
|
152
121
|
for (let k = 0; k < ksize; k++) {
|
|
153
|
-
let ik = Math.min(Math.max(i -
|
|
122
|
+
let ik = Math.min(Math.max(i - r + k, 0), h - 1);
|
|
154
123
|
let idx = 4 * (ik * w + j);
|
|
155
|
-
s0 +=
|
|
156
|
-
s1 +=
|
|
157
|
-
s2 +=
|
|
158
|
-
s3 +=
|
|
124
|
+
s0 += u[idx] * kern[k];
|
|
125
|
+
s1 += u[idx + 1] * kern[k];
|
|
126
|
+
s2 += u[idx + 2] * kern[k];
|
|
127
|
+
s3 += u[idx + 3] * kern[k];
|
|
159
128
|
}
|
|
160
129
|
let idx = 4 * (i * w + j);
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
130
|
+
d[idx] = s0;
|
|
131
|
+
d[idx + 1] = s1;
|
|
132
|
+
d[idx + 2] = s2;
|
|
133
|
+
d[idx + 3] = s3;
|
|
165
134
|
}
|
|
166
135
|
}
|
|
167
136
|
};
|
package/src/q5-canvas.js
CHANGED
package/src/q5-color.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
Q5.modules.color = ($, q) => {
|
|
2
2
|
$.RGB = $.RGBA = $._colorMode = 'rgb';
|
|
3
|
+
$.SRGB = 'srgb';
|
|
3
4
|
$.OKLCH = 'oklch';
|
|
4
5
|
|
|
5
6
|
$.colorMode = (mode, format) => {
|
|
@@ -10,7 +11,6 @@ Q5.modules.color = ($, q) => {
|
|
|
10
11
|
if (mode == 'oklch') {
|
|
11
12
|
q.Color = Q5.ColorOKLCH;
|
|
12
13
|
} else {
|
|
13
|
-
let srgb = $.canvas.colorSpace == 'srgb';
|
|
14
14
|
if ($._colorFormat == 255) {
|
|
15
15
|
q.Color = srgb ? Q5.ColorRGBA_8 : Q5.ColorRGBA_P3_8;
|
|
16
16
|
} else {
|
|
@@ -94,10 +94,12 @@ Q5.modules.color = ($, q) => {
|
|
|
94
94
|
return new C(c0, c1, c2, c3);
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
+
// deprecated
|
|
97
98
|
$.red = (c) => c.r;
|
|
98
99
|
$.green = (c) => c.g;
|
|
99
100
|
$.blue = (c) => c.b;
|
|
100
101
|
$.alpha = (c) => c.a;
|
|
102
|
+
|
|
101
103
|
$.lightness = (c) => {
|
|
102
104
|
if (c.l) return c.l;
|
|
103
105
|
return ((0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) * 100) / 255;
|
|
@@ -155,9 +157,43 @@ Q5.ColorOKLCH = class extends Q5.Color {
|
|
|
155
157
|
this.h = h;
|
|
156
158
|
this.a = a ?? 1;
|
|
157
159
|
}
|
|
160
|
+
get levels() {
|
|
161
|
+
return [this.l, this.c, this.h, this.a];
|
|
162
|
+
}
|
|
163
|
+
equals(c) {
|
|
164
|
+
return c && this.l == c.l && this.c == c.c && this.h == c.h && this.a == c.a;
|
|
165
|
+
}
|
|
166
|
+
isSameColor(c) {
|
|
167
|
+
return c && this.l == c.l && this.c == c.c && this.h == c.h;
|
|
168
|
+
}
|
|
158
169
|
toString() {
|
|
159
170
|
return `oklch(${this.l} ${this.c} ${this.h} / ${this.a})`;
|
|
160
171
|
}
|
|
172
|
+
|
|
173
|
+
get lightness() {
|
|
174
|
+
return this.l;
|
|
175
|
+
}
|
|
176
|
+
set lightness(v) {
|
|
177
|
+
this.l = v;
|
|
178
|
+
}
|
|
179
|
+
get chroma() {
|
|
180
|
+
return this.c;
|
|
181
|
+
}
|
|
182
|
+
set chroma(v) {
|
|
183
|
+
this.c = v;
|
|
184
|
+
}
|
|
185
|
+
get hue() {
|
|
186
|
+
return this.h;
|
|
187
|
+
}
|
|
188
|
+
set hue(v) {
|
|
189
|
+
this.h = v;
|
|
190
|
+
}
|
|
191
|
+
get alpha() {
|
|
192
|
+
return this.a;
|
|
193
|
+
}
|
|
194
|
+
set alpha(v) {
|
|
195
|
+
this.a = v;
|
|
196
|
+
}
|
|
161
197
|
};
|
|
162
198
|
|
|
163
199
|
Q5.ColorRGBA = class extends Q5.Color {
|
|
@@ -171,9 +207,39 @@ Q5.ColorRGBA = class extends Q5.Color {
|
|
|
171
207
|
get levels() {
|
|
172
208
|
return [this.r, this.g, this.b, this.a];
|
|
173
209
|
}
|
|
210
|
+
equals(c) {
|
|
211
|
+
return c && this.r == c.r && this.g == c.g && this.b == c.b && this.a == c.a;
|
|
212
|
+
}
|
|
213
|
+
isSameColor(c) {
|
|
214
|
+
return c && this.r == c.r && this.g == c.g && this.b == c.b;
|
|
215
|
+
}
|
|
174
216
|
toString() {
|
|
175
217
|
return `color(srgb ${this.r} ${this.g} ${this.b} / ${this.a})`;
|
|
176
218
|
}
|
|
219
|
+
get red() {
|
|
220
|
+
return this.r;
|
|
221
|
+
}
|
|
222
|
+
set red(v) {
|
|
223
|
+
this.r = v;
|
|
224
|
+
}
|
|
225
|
+
get green() {
|
|
226
|
+
return this.g;
|
|
227
|
+
}
|
|
228
|
+
set green(v) {
|
|
229
|
+
this.g = v;
|
|
230
|
+
}
|
|
231
|
+
get blue() {
|
|
232
|
+
return this.b;
|
|
233
|
+
}
|
|
234
|
+
set blue(v) {
|
|
235
|
+
this.b = v;
|
|
236
|
+
}
|
|
237
|
+
get alpha() {
|
|
238
|
+
return this.a;
|
|
239
|
+
}
|
|
240
|
+
set alpha(v) {
|
|
241
|
+
this.a = v;
|
|
242
|
+
}
|
|
177
243
|
};
|
|
178
244
|
|
|
179
245
|
Q5.ColorRGBA_P3 = class extends Q5.ColorRGBA {
|
|
@@ -187,6 +253,7 @@ Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
|
|
|
187
253
|
constructor(r, g, b, a) {
|
|
188
254
|
super(r, g, b, a ?? 255);
|
|
189
255
|
}
|
|
256
|
+
// deprecated set functions for backwards compatibility
|
|
190
257
|
setRed(v) {
|
|
191
258
|
this.r = v;
|
|
192
259
|
}
|
|
@@ -199,9 +266,6 @@ Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
|
|
|
199
266
|
setAlpha(v) {
|
|
200
267
|
this.a = v;
|
|
201
268
|
}
|
|
202
|
-
get levels() {
|
|
203
|
-
return [this.r, this.g, this.b, this.a];
|
|
204
|
-
}
|
|
205
269
|
toString() {
|
|
206
270
|
return `rgb(${this.r} ${this.g} ${this.b} / ${this.a / 255})`;
|
|
207
271
|
}
|
package/src/q5-core.js
CHANGED
|
@@ -143,15 +143,16 @@ function Q5(scope, parent, renderer) {
|
|
|
143
143
|
$.getTargetFrameRate = () => $._targetFrameRate || 60;
|
|
144
144
|
$.getFPS = () => $._fps;
|
|
145
145
|
|
|
146
|
+
// shims for compatibility with p5.js libraries
|
|
146
147
|
$.Element = function (a) {
|
|
147
148
|
this.elt = a;
|
|
148
149
|
};
|
|
149
150
|
$._elements = [];
|
|
151
|
+
$.describe = () => {};
|
|
150
152
|
|
|
151
153
|
$.TWO_PI = $.TAU = Math.PI * 2;
|
|
152
154
|
|
|
153
155
|
$.log = $.print = console.log;
|
|
154
|
-
$.describe = () => {};
|
|
155
156
|
|
|
156
157
|
for (let m in Q5.modules) {
|
|
157
158
|
Q5.modules[m]($, q);
|