q5 2.14.3 → 2.14.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.
@@ -1,330 +0,0 @@
1
- Q5.renderers.q2d.image = ($, q) => {
2
- class Q5Image {
3
- constructor(w, h, opt) {
4
- let $ = this;
5
- $._scope = 'image';
6
- $.canvas = $.ctx = $.drawingContext = null;
7
- $.pixels = [];
8
- Q5.modules.canvas($, $);
9
- let r = Q5.renderers.q2d;
10
- for (let m of ['canvas', 'image', 'soft_filters']) {
11
- if (r[m]) r[m]($, $);
12
- }
13
- $._pixelDensity = opt.pixelDensity || 1;
14
- $.createCanvas(w, h, opt);
15
- delete $.createCanvas;
16
- $._loop = false;
17
- }
18
- get w() {
19
- return this.width;
20
- }
21
- get h() {
22
- return this.height;
23
- }
24
- }
25
-
26
- Q5.Image ??= Q5Image;
27
-
28
- $._tint = null;
29
- let imgData = null;
30
-
31
- $.createImage = (w, h, opt) => {
32
- opt ??= {};
33
- opt.alpha ??= true;
34
- opt.colorSpace ??= $.canvas.colorSpace || Q5.canvasOptions.colorSpace;
35
- let img = new Q5.Image(w, h, opt);
36
- img.defaultWidth = w * $._defaultImageScale;
37
- img.defaultHeight = h * $._defaultImageScale;
38
- return img;
39
- };
40
-
41
- $.loadImage = function (url, cb, opt) {
42
- if (url.canvas) return url;
43
- if (url.slice(-3).toLowerCase() == 'gif') {
44
- throw new Error(
45
- `q5 doesn't support GIFs. Use a video or p5play animation instead. https://github.com/q5js/q5.js/issues/84`
46
- );
47
- }
48
- q._preloadCount++;
49
- let last = [...arguments].at(-1);
50
- if (typeof last == 'object') {
51
- opt = last;
52
- cb = null;
53
- } else opt = null;
54
-
55
- let g = $.createImage(1, 1, opt);
56
- let pd = (g._pixelDensity = opt?.pixelDensity || 1);
57
-
58
- function loaded(img) {
59
- img._pixelDensity = pd;
60
- g.defaultWidth = img.width * $._defaultImageScale;
61
- g.defaultHeight = img.height * $._defaultImageScale;
62
- g.naturalWidth = img.naturalWidth || img.width;
63
- g.naturalHeight = img.naturalHeight || img.height;
64
- g._setImageSize(Math.ceil(g.naturalWidth / pd), Math.ceil(g.naturalHeight / pd));
65
-
66
- g.ctx.drawImage(img, 0, 0);
67
- q._preloadCount--;
68
- if (cb) cb(g);
69
- }
70
-
71
- let img = new window.Image();
72
- img.crossOrigin = 'Anonymous';
73
- img.onload = () => loaded(img);
74
- img.onerror = (e) => {
75
- q._preloadCount--;
76
- throw e;
77
- };
78
- img.src = url;
79
-
80
- return g;
81
- };
82
-
83
- $.imageMode = (mode) => ($._imageMode = mode);
84
-
85
- $.image = (img, dx, dy, dw, dh, sx = 0, sy = 0, sw, sh) => {
86
- if (!img) return;
87
- let drawable = img.canvas || img;
88
-
89
- dw ??= img.defaultWidth || drawable.width || img.videoWidth;
90
- dh ??= img.defaultHeight || drawable.height || img.videoHeight;
91
- if ($._imageMode == 'center') {
92
- dx -= dw * 0.5;
93
- dy -= dh * 0.5;
94
- }
95
- if ($._da) {
96
- dx *= $._da;
97
- dy *= $._da;
98
- dw *= $._da;
99
- dh *= $._da;
100
- sx *= $._da;
101
- sy *= $._da;
102
- sw *= $._da;
103
- sh *= $._da;
104
- }
105
- let pd = img._pixelDensity || 1;
106
- if (!sw) {
107
- sw = drawable.width || drawable.videoWidth;
108
- } else sw *= pd;
109
- if (!sh) {
110
- sh = drawable.height || drawable.videoHeight;
111
- } else sh *= pd;
112
-
113
- if ($._tint) {
114
- if (img._retint || img._tint != $._tint) {
115
- img._tintImg ??= $.createImage(img.w, img.h, { pixelDensity: pd });
116
-
117
- if (img._tintImg.width != img.width || img._tintImg.height != img.height) {
118
- img._tintImg.resize(img.w, img.h);
119
- }
120
-
121
- let tnt = img._tintImg.ctx;
122
- tnt.globalCompositeOperation = 'copy';
123
- tnt.fillStyle = $._tint;
124
- tnt.fillRect(0, 0, img.width, img.height);
125
-
126
- if (img.canvas.alpha) {
127
- tnt.globalCompositeOperation = 'destination-in';
128
- tnt.drawImage(drawable, 0, 0, img.width, img.height);
129
- }
130
-
131
- tnt.globalCompositeOperation = 'multiply';
132
- tnt.drawImage(drawable, 0, 0, img.width, img.height);
133
-
134
- img._tint = $._tint;
135
- img._retint = false;
136
- }
137
-
138
- drawable = img._tintImg.canvas;
139
- }
140
-
141
- $.ctx.drawImage(drawable, sx * pd, sy * pd, sw, sh, dx, dy, dw, dh);
142
- };
143
-
144
- $.filter = (type, value) => {
145
- $.ctx.save();
146
-
147
- let f = '';
148
-
149
- if ($.ctx.filter) {
150
- if (typeof type == 'string') {
151
- f = type;
152
- } else if (type == Q5.GRAY) {
153
- f = `saturate(0%)`;
154
- } else if (type == Q5.INVERT) {
155
- f = `invert(100%)`;
156
- } else if (type == Q5.BLUR) {
157
- let r = Math.ceil(value * $._pixelDensity) || 1;
158
- f = `blur(${r}px)`;
159
- } else if (type == Q5.THRESHOLD) {
160
- value ??= 0.5;
161
- let b = Math.floor((0.5 / Math.max(value, 0.00001)) * 100);
162
- f = `saturate(0%) brightness(${b}%) contrast(1000000%)`;
163
- } else if (type == Q5.SEPIA) {
164
- f = `sepia(${value ?? 1})`;
165
- } else if (type == Q5.BRIGHTNESS) {
166
- f = `brightness(${value ?? 1})`;
167
- } else if (type == Q5.SATURATION) {
168
- f = `saturate(${value ?? 1})`;
169
- } else if (type == Q5.CONTRAST) {
170
- f = `contrast(${value ?? 1})`;
171
- } else if (type == Q5.HUE_ROTATE) {
172
- let unit = $._angleMode == 0 ? 'rad' : 'deg';
173
- f = `hue-rotate(${value}${unit})`;
174
- }
175
-
176
- if (f) {
177
- $.ctx.filter = f;
178
- if ($.ctx.filter == 'none') {
179
- throw new Error(`Invalid filter format: ${type}`);
180
- }
181
- }
182
- }
183
-
184
- if (!f) $._softFilter(type, value);
185
-
186
- $.ctx.globalCompositeOperation = 'source-over';
187
- $.ctx.drawImage($.canvas, 0, 0, $.canvas.w, $.canvas.h);
188
- $.ctx.restore();
189
- $._retint = true;
190
- };
191
-
192
- if ($._scope == 'image') {
193
- $.resize = (w, h) => {
194
- let c = $.canvas;
195
- let o = new $._OffscreenCanvas(c.width, c.height);
196
- let tmpCtx = o.getContext('2d', {
197
- colorSpace: c.colorSpace
198
- });
199
- tmpCtx.drawImage(c, 0, 0);
200
- $._setImageSize(w, h);
201
- $.defaultWidth = c.width * $._defaultImageScale;
202
- $.defaultHeight = c.height * $._defaultImageScale;
203
-
204
- $.ctx.clearRect(0, 0, c.width, c.height);
205
- $.ctx.drawImage(o, 0, 0, c.width, c.height);
206
-
207
- $._retint = true;
208
- };
209
- }
210
-
211
- $._getImageData = (x, y, w, h) => {
212
- return $.ctx.getImageData(x, y, w, h, { colorSpace: $.canvas.colorSpace });
213
- };
214
-
215
- $.trim = () => {
216
- let pd = $._pixelDensity || 1;
217
- let w = $.canvas.width;
218
- let h = $.canvas.height;
219
- let data = $._getImageData(0, 0, w, h).data;
220
- let left = w,
221
- right = 0,
222
- top = h,
223
- bottom = 0;
224
-
225
- let i = 3;
226
- for (let y = 0; y < h; y++) {
227
- for (let x = 0; x < w; x++) {
228
- if (data[i] !== 0) {
229
- if (x < left) left = x;
230
- if (x > right) right = x;
231
- if (y < top) top = y;
232
- if (y > bottom) bottom = y;
233
- }
234
- i += 4;
235
- }
236
- }
237
- top = Math.floor(top / pd);
238
- bottom = Math.floor(bottom / pd);
239
- left = Math.floor(left / pd);
240
- right = Math.floor(right / pd);
241
-
242
- return $.get(left, top, right - left + 1, bottom - top + 1);
243
- };
244
-
245
- $.mask = (img) => {
246
- $.ctx.save();
247
- $.ctx.resetTransform();
248
- let old = $.ctx.globalCompositeOperation;
249
- $.ctx.globalCompositeOperation = 'destination-in';
250
- $.ctx.drawImage(img.canvas, 0, 0);
251
- $.ctx.globalCompositeOperation = old;
252
- $.ctx.restore();
253
-
254
- $._retint = true;
255
- };
256
-
257
- $.inset = (x, y, w, h, dx, dy, dw, dh) => {
258
- let pd = $._pixelDensity || 1;
259
- $.ctx.drawImage($.canvas, x * pd, y * pd, w * pd, h * pd, dx, dy, dw, dh);
260
-
261
- $._retint = true;
262
- };
263
-
264
- $.copy = () => $.get();
265
-
266
- $.get = (x, y, w, h) => {
267
- let pd = $._pixelDensity || 1;
268
- if (x !== undefined && w === undefined) {
269
- let c = $._getImageData(x * pd, y * pd, 1, 1).data;
270
- return [c[0], c[1], c[2], c[3] / 255];
271
- }
272
- x = Math.floor(x || 0) * pd;
273
- y = Math.floor(y || 0) * pd;
274
- let _w = (w = w || $.width);
275
- let _h = (h = h || $.height);
276
- w *= pd;
277
- h *= pd;
278
- let img = $.createImage(w, h);
279
- img.ctx.drawImage($.canvas, x, y, w, h, 0, 0, w, h);
280
- img._pixelDensity = pd;
281
- img.width = _w;
282
- img.height = _h;
283
- return img;
284
- };
285
-
286
- $.set = (x, y, c) => {
287
- x = Math.floor(x);
288
- y = Math.floor(y);
289
- $._retint = true;
290
- if (c.canvas) {
291
- let old = $._tint;
292
- $._tint = null;
293
- $.image(c, x, y);
294
- $._tint = old;
295
- return;
296
- }
297
- if (!$.pixels.length) $.loadPixels();
298
- let mod = $._pixelDensity || 1;
299
- for (let i = 0; i < mod; i++) {
300
- for (let j = 0; j < mod; j++) {
301
- let idx = 4 * ((y * mod + i) * $.canvas.width + x * mod + j);
302
- $.pixels[idx] = c.r;
303
- $.pixels[idx + 1] = c.g;
304
- $.pixels[idx + 2] = c.b;
305
- $.pixels[idx + 3] = c.a;
306
- }
307
- }
308
- };
309
-
310
- $.loadPixels = () => {
311
- imgData = $._getImageData(0, 0, $.canvas.width, $.canvas.height);
312
- q.pixels = imgData.data;
313
- };
314
- $.updatePixels = () => {
315
- if (imgData != null) {
316
- $.ctx.putImageData(imgData, 0, 0);
317
- $._retint = true;
318
- }
319
- };
320
-
321
- $.smooth = () => ($.ctx.imageSmoothingEnabled = true);
322
- $.noSmooth = () => ($.ctx.imageSmoothingEnabled = false);
323
-
324
- if ($._scope == 'image') return;
325
-
326
- $.tint = function (c) {
327
- $._tint = (c._q5Color ? c : $.color(...arguments)).toString();
328
- };
329
- $.noTint = () => ($._tint = null);
330
- };
@@ -1,145 +0,0 @@
1
- /* software implementation of image filters */
2
- Q5.renderers.q2d.soft_filters = ($) => {
3
- let u = null; // uint8 temporary buffer
4
-
5
- function ensureBuf() {
6
- let l = $.canvas.width * $.canvas.height * 4;
7
- if (!u || u.length != l) u = new Uint8ClampedArray(l);
8
- }
9
-
10
- function initSoftFilters() {
11
- $._filters = [];
12
- $._filters[Q5.THRESHOLD] = (d, thresh) => {
13
- if (thresh === undefined) thresh = 127.5;
14
- else thresh *= 255;
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;
18
- }
19
- };
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;
24
- }
25
- };
26
- $._filters[Q5.OPAQUE] = (d) => {
27
- for (let i = 0; i < d.length; i += 4) {
28
- d[i + 3] = 255;
29
- }
30
- };
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];
36
- }
37
- };
38
- $._filters[Q5.POSTERIZE] = (d, lvl = 4) => {
39
- let lvl1 = lvl - 1;
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;
44
- }
45
- };
46
- $._filters[Q5.DILATE] = (d, func) => {
47
- func ??= Math.max;
48
- ensureBuf();
49
- u.set(d);
50
- let [w, h] = [$.canvas.width, $.canvas.height];
51
- for (let i = 0; i < h; i++) {
52
- for (let j = 0; j < w; j++) {
53
- let l = 4 * Math.max(j - 1, 0);
54
- let r = 4 * Math.min(j + 1, w - 1);
55
- let t = 4 * Math.max(i - 1, 0) * w;
56
- let b = 4 * Math.min(i + 1, h - 1) * w;
57
- let oi = 4 * i * w;
58
- let oj = 4 * j;
59
- for (let k = 0; k < 4; k++) {
60
- let kt = k + t;
61
- let kb = k + b;
62
- let ko = k + oi;
63
- d[oi + oj + k] = func(u[kt + oj], u[ko + l], u[ko + oj], u[ko + r], u[kb + oj]);
64
- }
65
- }
66
- }
67
- };
68
- $._filters[Q5.ERODE] = (d) => {
69
- $._filters[Q5.DILATE](d, Math.min);
70
- };
71
- $._filters[Q5.BLUR] = (d, r) => {
72
- r = r || 1;
73
- r = Math.floor(r * $._pixelDensity);
74
- ensureBuf();
75
- u.set(d);
76
-
77
- let ksize = r * 2 + 1;
78
-
79
- function gauss(ksize) {
80
- let im = new Float32Array(ksize);
81
- let sigma = 0.3 * r + 0.8;
82
- let ss2 = sigma * sigma * 2;
83
- for (let i = 0; i < ksize; i++) {
84
- let x = i - ksize / 2;
85
- let z = Math.exp(-(x * x) / ss2) / (2.5066282746 * sigma);
86
- im[i] = z;
87
- }
88
- return im;
89
- }
90
-
91
- let kern = gauss(ksize);
92
- let [w, h] = [$.canvas.width, $.canvas.height];
93
- for (let i = 0; i < h; i++) {
94
- for (let j = 0; j < w; j++) {
95
- let s0 = 0,
96
- s1 = 0,
97
- s2 = 0,
98
- s3 = 0;
99
- for (let k = 0; k < ksize; k++) {
100
- let jk = Math.min(Math.max(j - r + k, 0), w - 1);
101
- let idx = 4 * (i * w + jk);
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];
106
- }
107
- let idx = 4 * (i * w + j);
108
- d[idx] = s0;
109
- d[idx + 1] = s1;
110
- d[idx + 2] = s2;
111
- d[idx + 3] = s3;
112
- }
113
- }
114
- u.set(d);
115
- for (let i = 0; i < h; i++) {
116
- for (let j = 0; j < w; j++) {
117
- let s0 = 0,
118
- s1 = 0,
119
- s2 = 0,
120
- s3 = 0;
121
- for (let k = 0; k < ksize; k++) {
122
- let ik = Math.min(Math.max(i - r + k, 0), h - 1);
123
- let idx = 4 * (ik * w + j);
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];
128
- }
129
- let idx = 4 * (i * w + j);
130
- d[idx] = s0;
131
- d[idx + 1] = s1;
132
- d[idx + 2] = s2;
133
- d[idx + 3] = s3;
134
- }
135
- }
136
- };
137
- }
138
-
139
- $._softFilter = (typ, x) => {
140
- if (!$._filters) initSoftFilters();
141
- let imgData = $.ctx._getImageData(0, 0, $.canvas.width, $.canvas.height);
142
- $._filters[typ](imgData.data, x);
143
- $.ctx.putImageData(imgData, 0, 0);
144
- };
145
- };