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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "q5",
|
|
3
|
-
"version": "2.10.
|
|
3
|
+
"version": "2.10.5",
|
|
4
4
|
"description": "A sequel to p5.js that's optimized for interactive art",
|
|
5
5
|
"author": "quinton-ashley",
|
|
6
6
|
"contributors": [
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"homepage": "https://q5js.org/home",
|
|
12
12
|
"main": "q5-server.js",
|
|
13
13
|
"scripts": {
|
|
14
|
-
"bundle": "cat src/q5-core.js src/q5-canvas.js src/q5-2d-canvas.js src/q5-2d-drawing.js src/q5-2d-image.js src/q5-2d-text.js src/q5-ai.js src/q5-color.js src/q5-display.js src/q5-input.js src/q5-math.js src/q5-sound.js src/q5-util.js src/q5-vector.js src/q5-webgpu-canvas.js src/q5-webgpu-drawing.js src/q5-webgpu-image.js src/q5-webgpu-text.js > q5.js",
|
|
14
|
+
"bundle": "cat src/q5-core.js src/q5-canvas.js src/q5-2d-canvas.js src/q5-2d-drawing.js src/q5-2d-image.js src/q5-2d-soft-filters.js src/q5-2d-text.js src/q5-ai.js src/q5-color.js src/q5-display.js src/q5-input.js src/q5-math.js src/q5-sound.js src/q5-util.js src/q5-vector.js src/q5-webgpu-canvas.js src/q5-webgpu-drawing.js src/q5-webgpu-image.js src/q5-webgpu-text.js > q5.js",
|
|
15
15
|
"min": "terser q5.js --compress ecma=2024 --mangle > q5.min.js",
|
|
16
16
|
"dist": "bun bundle && bun min",
|
|
17
17
|
"dist-p5play": "bun dist && cp q5.js ../../web/p5play-web/v3/q5.js && cp q5.min.js ../../web/p5play-web/v3/q5.min.js",
|
package/q5.d.ts
CHANGED
|
@@ -1254,8 +1254,21 @@ function setup() {
|
|
|
1254
1254
|
|
|
1255
1255
|
/** 🌆
|
|
1256
1256
|
* Applies a filter to the image.
|
|
1257
|
-
*
|
|
1257
|
+
*
|
|
1258
|
+
* See the documentation for q5's filter constants below for more info.
|
|
1259
|
+
*
|
|
1260
|
+
* If a CSS filter string is provided, it will be applied to the image.
|
|
1261
|
+
* https://developer.mozilla.org/en-US/docs/Web/CSS/filter
|
|
1262
|
+
* @param {string} type - type of filter or a CSS filter string
|
|
1258
1263
|
* @param {number} [value] - optional parameter, depending on filter type
|
|
1264
|
+
* @example
|
|
1265
|
+
createCanvas(200, 200);
|
|
1266
|
+
let logo = loadImage('/q5js_logo.webp');
|
|
1267
|
+
|
|
1268
|
+
function setup() {
|
|
1269
|
+
logo.filter(INVERT);
|
|
1270
|
+
image(logo, 0, 0, 200, 200);
|
|
1271
|
+
}
|
|
1259
1272
|
*/
|
|
1260
1273
|
function filter(type: string, value?: number): void;
|
|
1261
1274
|
|
|
@@ -1480,25 +1493,132 @@ function setup() {
|
|
|
1480
1493
|
|
|
1481
1494
|
// 🎨 color
|
|
1482
1495
|
|
|
1496
|
+
/** 🎨
|
|
1497
|
+
* Creates a new `Color` object. This function can parse different
|
|
1498
|
+
* color representations depending on the current color mode.
|
|
1499
|
+
*
|
|
1500
|
+
* RGB colors have components `r`/`red`, `g`/`green`, `b`/`blue`,
|
|
1501
|
+
* and `a`/`alpha`.
|
|
1502
|
+
*
|
|
1503
|
+
* In rgb mode when only one numeric input is provided, it'll
|
|
1504
|
+
* be interpreted as a grayscale value. If only two numeric inputs
|
|
1505
|
+
* are provided, they will be used as grayscale and alpha values.
|
|
1506
|
+
*
|
|
1507
|
+
* `fill`, `stroke`, and `background` functions can accept the same
|
|
1508
|
+
* wide range of inputs as this function.
|
|
1509
|
+
* @param {string | number | Color | number[]} c0 - first color component, a CSS color string, a `Color` object (to make copy), or an array of components
|
|
1510
|
+
* @param {number} [c1] - second color component
|
|
1511
|
+
* @param {number} [c2] - third color component
|
|
1512
|
+
* @param {number} [c3] - fourth color component (alpha)
|
|
1513
|
+
* @returns {Color} a new `Color` object
|
|
1514
|
+
* @example
|
|
1515
|
+
createCanvas(200, 200);
|
|
1516
|
+
|
|
1517
|
+
let c = color(128);
|
|
1518
|
+
|
|
1519
|
+
function draw() {
|
|
1520
|
+
background(c);
|
|
1521
|
+
c.g = (c.g + 1) % 255;
|
|
1522
|
+
}
|
|
1523
|
+
*/
|
|
1524
|
+
function color(c0: string | number | Color | number[], c1?: number, c2?: number, c3?: number): Color;
|
|
1525
|
+
|
|
1483
1526
|
/** 🎨
|
|
1484
1527
|
* Sets the color mode for the sketch. Changes the type of color object created by color functions.
|
|
1528
|
+
*
|
|
1529
|
+
* In q2d, the default color mode is RGB in legacy integer format.
|
|
1485
1530
|
*
|
|
1486
|
-
* In WebGPU, the default color mode is
|
|
1531
|
+
* In WebGPU, the default color mode is RGB in float format.
|
|
1532
|
+
*
|
|
1533
|
+
* See the documentation for q5's color constants below for more info.
|
|
1487
1534
|
* @param {'rgb' | 'srgb' | 'oklch'} mode - color mode
|
|
1488
1535
|
* @param {1 | 255} format - color format (1 for float, 255 for integer)
|
|
1536
|
+
* @example
|
|
1537
|
+
createCanvas(200, 200);
|
|
1538
|
+
|
|
1539
|
+
colorMode(RGB, 1);
|
|
1540
|
+
fill(1, 0, 0);
|
|
1541
|
+
rect(0, 0, 66, 200);
|
|
1542
|
+
fill(0, 1, 0);
|
|
1543
|
+
rect(66, 0, 67, 200);
|
|
1544
|
+
fill(0, 0, 1);
|
|
1545
|
+
rect(133, 0, 67, 200);
|
|
1546
|
+
* @example
|
|
1547
|
+
createCanvas(200, 200);
|
|
1548
|
+
|
|
1549
|
+
colorMode(OKLCH);
|
|
1550
|
+
|
|
1551
|
+
fill(0.25, 0.15, 0);
|
|
1552
|
+
rect(0, 0, 100, 200);
|
|
1553
|
+
fill(0.75, 0.15, 0)
|
|
1554
|
+
rect(100, 0, 100, 200);
|
|
1489
1555
|
*/
|
|
1490
1556
|
function colorMode(mode: 'rgb' | 'srgb' | 'oklch', format: 1 | 255): void;
|
|
1491
1557
|
|
|
1492
1558
|
/** 🎨
|
|
1493
|
-
*
|
|
1494
|
-
*
|
|
1495
|
-
*
|
|
1496
|
-
*
|
|
1497
|
-
*
|
|
1498
|
-
*
|
|
1499
|
-
*
|
|
1559
|
+
* RGB colors have components `r`/`red`, `g`/`green`, `b`/`blue`,
|
|
1560
|
+
* and `a`/`alpha`.
|
|
1561
|
+
*
|
|
1562
|
+
* RGB is the default color mode.
|
|
1563
|
+
*
|
|
1564
|
+
* By default when a canvas is using the `display-p3` color space,
|
|
1565
|
+
* rgb colors are mapped to the full P3 gamut, even when they use the
|
|
1566
|
+
* legacy integer format.
|
|
1567
|
+
* @example
|
|
1568
|
+
createCanvas(200, 200);
|
|
1569
|
+
|
|
1570
|
+
function setup() {
|
|
1571
|
+
background(255, 0, 0);
|
|
1572
|
+
}
|
|
1500
1573
|
*/
|
|
1501
|
-
|
|
1574
|
+
const RGB: 'rgb';
|
|
1575
|
+
|
|
1576
|
+
/** 🎨
|
|
1577
|
+
* This color mode limits the gamut of rgb colors to sRGB.
|
|
1578
|
+
*
|
|
1579
|
+
* If your display is HDR capable, take a look at the following
|
|
1580
|
+
* example, note that full red appears less saturated, as it would
|
|
1581
|
+
* on an SDR display.
|
|
1582
|
+
* @example
|
|
1583
|
+
createCanvas(200, 200);
|
|
1584
|
+
|
|
1585
|
+
colorMode(SRGB, 255);
|
|
1586
|
+
|
|
1587
|
+
function setup() {
|
|
1588
|
+
background(255, 0, 0);
|
|
1589
|
+
}
|
|
1590
|
+
*/
|
|
1591
|
+
const SRGB: 'srgb';
|
|
1592
|
+
|
|
1593
|
+
/** 🎨
|
|
1594
|
+
* OKLCH colors have components `l`/`lightness`, `c`/`chroma`,
|
|
1595
|
+
* `h`/`hue`, and `a`/`alpha`.
|
|
1596
|
+
*
|
|
1597
|
+
* You may be familiar with the outdated HSL/HSV color formats,
|
|
1598
|
+
* which were created in the 1970s to be more intuitive for humans
|
|
1599
|
+
* to work with than RGB. But due to technical limitations of that
|
|
1600
|
+
* time, they are not perceptually uniform, meaning the same
|
|
1601
|
+
* brightness values may appear lighter or darker depending on the hue.
|
|
1602
|
+
*
|
|
1603
|
+
* The OKLCH format is similar to HSL/HSV but it is perceptually
|
|
1604
|
+
* uniform and supports a wider gamut (range of colors) than srgb.
|
|
1605
|
+
* Every display-p3 color can be represented in OKLCH.
|
|
1606
|
+
*
|
|
1607
|
+
* `lightness`: 0 to 1
|
|
1608
|
+
* `chroma`: 0 to 0.4
|
|
1609
|
+
* `hue`: 0 to 360
|
|
1610
|
+
* `alpha`: 0 to 1
|
|
1611
|
+
*
|
|
1612
|
+
* Note how seamless the hue transitions are in the following example.
|
|
1613
|
+
* @example
|
|
1614
|
+
createCanvas(200, 200);
|
|
1615
|
+
colorMode(OKLCH);
|
|
1616
|
+
|
|
1617
|
+
function draw() {
|
|
1618
|
+
background(0.7, 0.16, frameCount % 360);
|
|
1619
|
+
}
|
|
1620
|
+
*/
|
|
1621
|
+
const OKLCH: 'oklch';
|
|
1502
1622
|
|
|
1503
1623
|
// 🖲️ input
|
|
1504
1624
|
|
package/q5.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);
|
|
@@ -612,6 +613,7 @@ Q5.modules.canvas = ($, q) => {
|
|
|
612
613
|
$._styleNames = [
|
|
613
614
|
'_fill',
|
|
614
615
|
'_stroke',
|
|
616
|
+
'_strokeWeight',
|
|
615
617
|
'_doStroke',
|
|
616
618
|
'_doFill',
|
|
617
619
|
'_strokeSet',
|
|
@@ -1269,6 +1271,9 @@ Q5.renderers.q2d.image = ($, q) => {
|
|
|
1269
1271
|
|
|
1270
1272
|
Q5.Image ??= Q5Image;
|
|
1271
1273
|
|
|
1274
|
+
$._tint = null;
|
|
1275
|
+
let imgData = null;
|
|
1276
|
+
|
|
1272
1277
|
$.createImage = (w, h, opt) => {
|
|
1273
1278
|
opt ??= {};
|
|
1274
1279
|
opt.alpha ??= true;
|
|
@@ -1363,7 +1368,7 @@ Q5.renderers.q2d.image = ($, q) => {
|
|
|
1363
1368
|
} else sh *= pd;
|
|
1364
1369
|
|
|
1365
1370
|
if ($._tint) {
|
|
1366
|
-
if (img._tint != $._tint
|
|
1371
|
+
if (img._retint || img._tint != $._tint) {
|
|
1367
1372
|
img._tintImg ??= $.createImage(img.w, img.h, { pixelDensity: pd });
|
|
1368
1373
|
|
|
1369
1374
|
if (img._tintImg.width != img.width || img._tintImg.height != img.height) {
|
|
@@ -1393,30 +1398,43 @@ Q5.renderers.q2d.image = ($, q) => {
|
|
|
1393
1398
|
$.ctx.drawImage(drawable, sx * pd, sy * pd, sw, sh, dx, dy, dw, dh);
|
|
1394
1399
|
};
|
|
1395
1400
|
|
|
1396
|
-
$.
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
else if (type
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
f = `
|
|
1412
|
-
} else if (type
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
f = `
|
|
1416
|
-
} else
|
|
1401
|
+
$.filter = (type, value) => {
|
|
1402
|
+
if (!$.ctx.filter) return $._softFilter(type, value);
|
|
1403
|
+
let f = '';
|
|
1404
|
+
if (typeof type === 'string') {
|
|
1405
|
+
f = type;
|
|
1406
|
+
} else if (type === Q5.GRAY) {
|
|
1407
|
+
f = `saturate(0%)`;
|
|
1408
|
+
} else if (type === Q5.INVERT) {
|
|
1409
|
+
f = `invert(100%)`;
|
|
1410
|
+
} else if (type === Q5.BLUR) {
|
|
1411
|
+
const radius = Math.ceil(value * $._pixelDensity) || 1;
|
|
1412
|
+
f = `blur(${radius}px)`;
|
|
1413
|
+
} else if (type === Q5.THRESHOLD) {
|
|
1414
|
+
value ??= 0.5;
|
|
1415
|
+
const brightness = Math.floor((0.5 / Math.max(value, 0.00001)) * 100);
|
|
1416
|
+
f = `saturate(0%) brightness(${brightness}%) contrast(1000000%)`;
|
|
1417
|
+
} else if (type === Q5.SEPIA) {
|
|
1418
|
+
f = `sepia(${value ?? 1})`;
|
|
1419
|
+
} else if (type === Q5.BRIGHTNESS) {
|
|
1420
|
+
f = `brightness(${value ?? 1})`;
|
|
1421
|
+
} else if (type === Q5.SATURATION) {
|
|
1422
|
+
f = `saturate(${value ?? 1})`;
|
|
1423
|
+
} else if (type === Q5.CONTRAST) {
|
|
1424
|
+
f = `contrast(${value ?? 1})`;
|
|
1425
|
+
} else if (type === Q5.HUE_ROTATE) {
|
|
1426
|
+
const unit = $._angleMode === 0 ? 'rad' : 'deg';
|
|
1427
|
+
f = `hue-rotate(${value}${unit})`;
|
|
1428
|
+
} else {
|
|
1429
|
+
$._softFilter(type, value);
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1417
1432
|
|
|
1418
1433
|
$.ctx.filter = f;
|
|
1419
|
-
$.ctx.
|
|
1434
|
+
if ($.ctx.filter == 'none') {
|
|
1435
|
+
throw new Error(`Invalid filter format: ${type}`);
|
|
1436
|
+
}
|
|
1437
|
+
$.ctx.drawImage($.canvas, 0, 0, $.canvas.width, $.canvas.height);
|
|
1420
1438
|
$.ctx.filter = 'none';
|
|
1421
1439
|
$._retint = true;
|
|
1422
1440
|
};
|
|
@@ -1569,6 +1587,156 @@ Q5.POSTERIZE = 5;
|
|
|
1569
1587
|
Q5.DILATE = 6;
|
|
1570
1588
|
Q5.ERODE = 7;
|
|
1571
1589
|
Q5.BLUR = 8;
|
|
1590
|
+
Q5.SEPIA = 9;
|
|
1591
|
+
Q5.BRIGHTNESS = 10;
|
|
1592
|
+
Q5.SATURATION = 11;
|
|
1593
|
+
Q5.CONTRAST = 12;
|
|
1594
|
+
Q5.HUE_ROTATE = 13;
|
|
1595
|
+
/* software implementation of image filters */
|
|
1596
|
+
Q5.renderers.q2d.soft_filters = ($) => {
|
|
1597
|
+
let u = null; // uint8 temporary buffer
|
|
1598
|
+
|
|
1599
|
+
function ensureBuf() {
|
|
1600
|
+
let l = $.canvas.width * $.canvas.height * 4;
|
|
1601
|
+
if (!u || u.length != l) u = new Uint8ClampedArray(l);
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
function initSoftFilters() {
|
|
1605
|
+
$._filters = [];
|
|
1606
|
+
$._filters[Q5.THRESHOLD] = (d, thresh) => {
|
|
1607
|
+
if (thresh === undefined) thresh = 127.5;
|
|
1608
|
+
else thresh *= 255;
|
|
1609
|
+
for (let i = 0; i < d.length; i += 4) {
|
|
1610
|
+
const gray = 0.2126 * d[i] + 0.7152 * d[i + 1] + 0.0722 * d[i + 2];
|
|
1611
|
+
d[i] = d[i + 1] = d[i + 2] = gray >= thresh ? 255 : 0;
|
|
1612
|
+
}
|
|
1613
|
+
};
|
|
1614
|
+
$._filters[Q5.GRAY] = (d) => {
|
|
1615
|
+
for (let i = 0; i < d.length; i += 4) {
|
|
1616
|
+
const gray = 0.2126 * d[i] + 0.7152 * d[i + 1] + 0.0722 * d[i + 2];
|
|
1617
|
+
d[i] = d[i + 1] = d[i + 2] = gray;
|
|
1618
|
+
}
|
|
1619
|
+
};
|
|
1620
|
+
$._filters[Q5.OPAQUE] = (d) => {
|
|
1621
|
+
for (let i = 0; i < d.length; i += 4) {
|
|
1622
|
+
d[i + 3] = 255;
|
|
1623
|
+
}
|
|
1624
|
+
};
|
|
1625
|
+
$._filters[Q5.INVERT] = (d) => {
|
|
1626
|
+
for (let i = 0; i < d.length; i += 4) {
|
|
1627
|
+
d[i] = 255 - d[i];
|
|
1628
|
+
d[i + 1] = 255 - d[i + 1];
|
|
1629
|
+
d[i + 2] = 255 - d[i + 2];
|
|
1630
|
+
}
|
|
1631
|
+
};
|
|
1632
|
+
$._filters[Q5.POSTERIZE] = (d, lvl = 4) => {
|
|
1633
|
+
let lvl1 = lvl - 1;
|
|
1634
|
+
for (let i = 0; i < d.length; i += 4) {
|
|
1635
|
+
d[i] = (((d[i] * lvl) >> 8) * 255) / lvl1;
|
|
1636
|
+
d[i + 1] = (((d[i + 1] * lvl) >> 8) * 255) / lvl1;
|
|
1637
|
+
d[i + 2] = (((d[i + 2] * lvl) >> 8) * 255) / lvl1;
|
|
1638
|
+
}
|
|
1639
|
+
};
|
|
1640
|
+
$._filters[Q5.DILATE] = (d, func) => {
|
|
1641
|
+
func ??= Math.max;
|
|
1642
|
+
ensureBuf();
|
|
1643
|
+
u.set(d);
|
|
1644
|
+
let [w, h] = [$.canvas.width, $.canvas.height];
|
|
1645
|
+
for (let i = 0; i < h; i++) {
|
|
1646
|
+
for (let j = 0; j < w; j++) {
|
|
1647
|
+
let l = 4 * Math.max(j - 1, 0);
|
|
1648
|
+
let r = 4 * Math.min(j + 1, w - 1);
|
|
1649
|
+
let t = 4 * Math.max(i - 1, 0) * w;
|
|
1650
|
+
let b = 4 * Math.min(i + 1, h - 1) * w;
|
|
1651
|
+
let oi = 4 * i * w;
|
|
1652
|
+
let oj = 4 * j;
|
|
1653
|
+
for (let k = 0; k < 4; k++) {
|
|
1654
|
+
let kt = k + t;
|
|
1655
|
+
let kb = k + b;
|
|
1656
|
+
let ko = k + oi;
|
|
1657
|
+
d[oi + oj + k] = func(u[kt + oj], u[ko + l], u[ko + oj], u[ko + r], u[kb + oj]);
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
};
|
|
1662
|
+
$._filters[Q5.ERODE] = (d) => {
|
|
1663
|
+
$._filters[Q5.DILATE](d, Math.min);
|
|
1664
|
+
};
|
|
1665
|
+
$._filters[Q5.BLUR] = (d, r) => {
|
|
1666
|
+
r = r || 1;
|
|
1667
|
+
r = Math.floor(r * $._pixelDensity);
|
|
1668
|
+
ensureBuf();
|
|
1669
|
+
u.set(d);
|
|
1670
|
+
|
|
1671
|
+
let ksize = r * 2 + 1;
|
|
1672
|
+
|
|
1673
|
+
function gauss(ksize) {
|
|
1674
|
+
let im = new Float32Array(ksize);
|
|
1675
|
+
let sigma = 0.3 * r + 0.8;
|
|
1676
|
+
let ss2 = sigma * sigma * 2;
|
|
1677
|
+
for (let i = 0; i < ksize; i++) {
|
|
1678
|
+
let x = i - ksize / 2;
|
|
1679
|
+
let z = Math.exp(-(x * x) / ss2) / (2.5066282746 * sigma);
|
|
1680
|
+
im[i] = z;
|
|
1681
|
+
}
|
|
1682
|
+
return im;
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
let kern = gauss(ksize);
|
|
1686
|
+
let [w, h] = [$.canvas.width, $.canvas.height];
|
|
1687
|
+
for (let i = 0; i < h; i++) {
|
|
1688
|
+
for (let j = 0; j < w; j++) {
|
|
1689
|
+
let s0 = 0,
|
|
1690
|
+
s1 = 0,
|
|
1691
|
+
s2 = 0,
|
|
1692
|
+
s3 = 0;
|
|
1693
|
+
for (let k = 0; k < ksize; k++) {
|
|
1694
|
+
let jk = Math.min(Math.max(j - r + k, 0), w - 1);
|
|
1695
|
+
let idx = 4 * (i * w + jk);
|
|
1696
|
+
s0 += u[idx] * kern[k];
|
|
1697
|
+
s1 += u[idx + 1] * kern[k];
|
|
1698
|
+
s2 += u[idx + 2] * kern[k];
|
|
1699
|
+
s3 += u[idx + 3] * kern[k];
|
|
1700
|
+
}
|
|
1701
|
+
let idx = 4 * (i * w + j);
|
|
1702
|
+
d[idx] = s0;
|
|
1703
|
+
d[idx + 1] = s1;
|
|
1704
|
+
d[idx + 2] = s2;
|
|
1705
|
+
d[idx + 3] = s3;
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
u.set(d);
|
|
1709
|
+
for (let i = 0; i < h; i++) {
|
|
1710
|
+
for (let j = 0; j < w; j++) {
|
|
1711
|
+
let s0 = 0,
|
|
1712
|
+
s1 = 0,
|
|
1713
|
+
s2 = 0,
|
|
1714
|
+
s3 = 0;
|
|
1715
|
+
for (let k = 0; k < ksize; k++) {
|
|
1716
|
+
let ik = Math.min(Math.max(i - r + k, 0), h - 1);
|
|
1717
|
+
let idx = 4 * (ik * w + j);
|
|
1718
|
+
s0 += u[idx] * kern[k];
|
|
1719
|
+
s1 += u[idx + 1] * kern[k];
|
|
1720
|
+
s2 += u[idx + 2] * kern[k];
|
|
1721
|
+
s3 += u[idx + 3] * kern[k];
|
|
1722
|
+
}
|
|
1723
|
+
let idx = 4 * (i * w + j);
|
|
1724
|
+
d[idx] = s0;
|
|
1725
|
+
d[idx + 1] = s1;
|
|
1726
|
+
d[idx + 2] = s2;
|
|
1727
|
+
d[idx + 3] = s3;
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
};
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
$._softFilter = (typ, x) => {
|
|
1734
|
+
if (!$._filters) initSoftFilters();
|
|
1735
|
+
let imgData = $.ctx._getImageData(0, 0, $.canvas.width, $.canvas.height);
|
|
1736
|
+
$._filters[typ](imgData.data, x);
|
|
1737
|
+
$.ctx.putImageData(imgData, 0, 0);
|
|
1738
|
+
};
|
|
1739
|
+
};
|
|
1572
1740
|
Q5.renderers.q2d.text = ($, q) => {
|
|
1573
1741
|
$._textAlign = 'left';
|
|
1574
1742
|
$._textBaseline = 'alphabetic';
|
|
@@ -1898,6 +2066,7 @@ Q5.modules.ai = ($) => {
|
|
|
1898
2066
|
};
|
|
1899
2067
|
Q5.modules.color = ($, q) => {
|
|
1900
2068
|
$.RGB = $.RGBA = $._colorMode = 'rgb';
|
|
2069
|
+
$.SRGB = 'srgb';
|
|
1901
2070
|
$.OKLCH = 'oklch';
|
|
1902
2071
|
|
|
1903
2072
|
$.colorMode = (mode, format) => {
|
|
@@ -1908,7 +2077,6 @@ Q5.modules.color = ($, q) => {
|
|
|
1908
2077
|
if (mode == 'oklch') {
|
|
1909
2078
|
q.Color = Q5.ColorOKLCH;
|
|
1910
2079
|
} else {
|
|
1911
|
-
let srgb = $.canvas.colorSpace == 'srgb';
|
|
1912
2080
|
if ($._colorFormat == 255) {
|
|
1913
2081
|
q.Color = srgb ? Q5.ColorRGBA_8 : Q5.ColorRGBA_P3_8;
|
|
1914
2082
|
} else {
|
|
@@ -1992,10 +2160,12 @@ Q5.modules.color = ($, q) => {
|
|
|
1992
2160
|
return new C(c0, c1, c2, c3);
|
|
1993
2161
|
};
|
|
1994
2162
|
|
|
2163
|
+
// deprecated
|
|
1995
2164
|
$.red = (c) => c.r;
|
|
1996
2165
|
$.green = (c) => c.g;
|
|
1997
2166
|
$.blue = (c) => c.b;
|
|
1998
2167
|
$.alpha = (c) => c.a;
|
|
2168
|
+
|
|
1999
2169
|
$.lightness = (c) => {
|
|
2000
2170
|
if (c.l) return c.l;
|
|
2001
2171
|
return ((0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) * 100) / 255;
|
|
@@ -2053,9 +2223,43 @@ Q5.ColorOKLCH = class extends Q5.Color {
|
|
|
2053
2223
|
this.h = h;
|
|
2054
2224
|
this.a = a ?? 1;
|
|
2055
2225
|
}
|
|
2226
|
+
get levels() {
|
|
2227
|
+
return [this.l, this.c, this.h, this.a];
|
|
2228
|
+
}
|
|
2229
|
+
equals(c) {
|
|
2230
|
+
return c && this.l == c.l && this.c == c.c && this.h == c.h && this.a == c.a;
|
|
2231
|
+
}
|
|
2232
|
+
isSameColor(c) {
|
|
2233
|
+
return c && this.l == c.l && this.c == c.c && this.h == c.h;
|
|
2234
|
+
}
|
|
2056
2235
|
toString() {
|
|
2057
2236
|
return `oklch(${this.l} ${this.c} ${this.h} / ${this.a})`;
|
|
2058
2237
|
}
|
|
2238
|
+
|
|
2239
|
+
get lightness() {
|
|
2240
|
+
return this.l;
|
|
2241
|
+
}
|
|
2242
|
+
set lightness(v) {
|
|
2243
|
+
this.l = v;
|
|
2244
|
+
}
|
|
2245
|
+
get chroma() {
|
|
2246
|
+
return this.c;
|
|
2247
|
+
}
|
|
2248
|
+
set chroma(v) {
|
|
2249
|
+
this.c = v;
|
|
2250
|
+
}
|
|
2251
|
+
get hue() {
|
|
2252
|
+
return this.h;
|
|
2253
|
+
}
|
|
2254
|
+
set hue(v) {
|
|
2255
|
+
this.h = v;
|
|
2256
|
+
}
|
|
2257
|
+
get alpha() {
|
|
2258
|
+
return this.a;
|
|
2259
|
+
}
|
|
2260
|
+
set alpha(v) {
|
|
2261
|
+
this.a = v;
|
|
2262
|
+
}
|
|
2059
2263
|
};
|
|
2060
2264
|
|
|
2061
2265
|
Q5.ColorRGBA = class extends Q5.Color {
|
|
@@ -2069,9 +2273,39 @@ Q5.ColorRGBA = class extends Q5.Color {
|
|
|
2069
2273
|
get levels() {
|
|
2070
2274
|
return [this.r, this.g, this.b, this.a];
|
|
2071
2275
|
}
|
|
2276
|
+
equals(c) {
|
|
2277
|
+
return c && this.r == c.r && this.g == c.g && this.b == c.b && this.a == c.a;
|
|
2278
|
+
}
|
|
2279
|
+
isSameColor(c) {
|
|
2280
|
+
return c && this.r == c.r && this.g == c.g && this.b == c.b;
|
|
2281
|
+
}
|
|
2072
2282
|
toString() {
|
|
2073
2283
|
return `color(srgb ${this.r} ${this.g} ${this.b} / ${this.a})`;
|
|
2074
2284
|
}
|
|
2285
|
+
get red() {
|
|
2286
|
+
return this.r;
|
|
2287
|
+
}
|
|
2288
|
+
set red(v) {
|
|
2289
|
+
this.r = v;
|
|
2290
|
+
}
|
|
2291
|
+
get green() {
|
|
2292
|
+
return this.g;
|
|
2293
|
+
}
|
|
2294
|
+
set green(v) {
|
|
2295
|
+
this.g = v;
|
|
2296
|
+
}
|
|
2297
|
+
get blue() {
|
|
2298
|
+
return this.b;
|
|
2299
|
+
}
|
|
2300
|
+
set blue(v) {
|
|
2301
|
+
this.b = v;
|
|
2302
|
+
}
|
|
2303
|
+
get alpha() {
|
|
2304
|
+
return this.a;
|
|
2305
|
+
}
|
|
2306
|
+
set alpha(v) {
|
|
2307
|
+
this.a = v;
|
|
2308
|
+
}
|
|
2075
2309
|
};
|
|
2076
2310
|
|
|
2077
2311
|
Q5.ColorRGBA_P3 = class extends Q5.ColorRGBA {
|
|
@@ -2085,6 +2319,7 @@ Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
|
|
|
2085
2319
|
constructor(r, g, b, a) {
|
|
2086
2320
|
super(r, g, b, a ?? 255);
|
|
2087
2321
|
}
|
|
2322
|
+
// deprecated set functions for backwards compatibility
|
|
2088
2323
|
setRed(v) {
|
|
2089
2324
|
this.r = v;
|
|
2090
2325
|
}
|
|
@@ -2097,9 +2332,6 @@ Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
|
|
|
2097
2332
|
setAlpha(v) {
|
|
2098
2333
|
this.a = v;
|
|
2099
2334
|
}
|
|
2100
|
-
get levels() {
|
|
2101
|
-
return [this.r, this.g, this.b, this.a];
|
|
2102
|
-
}
|
|
2103
2335
|
toString() {
|
|
2104
2336
|
return `rgb(${this.r} ${this.g} ${this.b} / ${this.a / 255})`;
|
|
2105
2337
|
}
|