q5 2.10.3 → 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 +259 -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-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);
|
|
@@ -1270,6 +1271,9 @@ Q5.renderers.q2d.image = ($, q) => {
|
|
|
1270
1271
|
|
|
1271
1272
|
Q5.Image ??= Q5Image;
|
|
1272
1273
|
|
|
1274
|
+
$._tint = null;
|
|
1275
|
+
let imgData = null;
|
|
1276
|
+
|
|
1273
1277
|
$.createImage = (w, h, opt) => {
|
|
1274
1278
|
opt ??= {};
|
|
1275
1279
|
opt.alpha ??= true;
|
|
@@ -1364,7 +1368,7 @@ Q5.renderers.q2d.image = ($, q) => {
|
|
|
1364
1368
|
} else sh *= pd;
|
|
1365
1369
|
|
|
1366
1370
|
if ($._tint) {
|
|
1367
|
-
if (img._tint != $._tint
|
|
1371
|
+
if (img._retint || img._tint != $._tint) {
|
|
1368
1372
|
img._tintImg ??= $.createImage(img.w, img.h, { pixelDensity: pd });
|
|
1369
1373
|
|
|
1370
1374
|
if (img._tintImg.width != img.width || img._tintImg.height != img.height) {
|
|
@@ -1394,30 +1398,43 @@ Q5.renderers.q2d.image = ($, q) => {
|
|
|
1394
1398
|
$.ctx.drawImage(drawable, sx * pd, sy * pd, sw, sh, dx, dy, dw, dh);
|
|
1395
1399
|
};
|
|
1396
1400
|
|
|
1397
|
-
$.
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
else if (type
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
f = `
|
|
1413
|
-
} else if (type
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
f = `
|
|
1417
|
-
} 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
|
+
}
|
|
1418
1432
|
|
|
1419
1433
|
$.ctx.filter = f;
|
|
1420
|
-
$.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);
|
|
1421
1438
|
$.ctx.filter = 'none';
|
|
1422
1439
|
$._retint = true;
|
|
1423
1440
|
};
|
|
@@ -1570,6 +1587,156 @@ Q5.POSTERIZE = 5;
|
|
|
1570
1587
|
Q5.DILATE = 6;
|
|
1571
1588
|
Q5.ERODE = 7;
|
|
1572
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
|
+
};
|
|
1573
1740
|
Q5.renderers.q2d.text = ($, q) => {
|
|
1574
1741
|
$._textAlign = 'left';
|
|
1575
1742
|
$._textBaseline = 'alphabetic';
|
|
@@ -1899,6 +2066,7 @@ Q5.modules.ai = ($) => {
|
|
|
1899
2066
|
};
|
|
1900
2067
|
Q5.modules.color = ($, q) => {
|
|
1901
2068
|
$.RGB = $.RGBA = $._colorMode = 'rgb';
|
|
2069
|
+
$.SRGB = 'srgb';
|
|
1902
2070
|
$.OKLCH = 'oklch';
|
|
1903
2071
|
|
|
1904
2072
|
$.colorMode = (mode, format) => {
|
|
@@ -1909,7 +2077,6 @@ Q5.modules.color = ($, q) => {
|
|
|
1909
2077
|
if (mode == 'oklch') {
|
|
1910
2078
|
q.Color = Q5.ColorOKLCH;
|
|
1911
2079
|
} else {
|
|
1912
|
-
let srgb = $.canvas.colorSpace == 'srgb';
|
|
1913
2080
|
if ($._colorFormat == 255) {
|
|
1914
2081
|
q.Color = srgb ? Q5.ColorRGBA_8 : Q5.ColorRGBA_P3_8;
|
|
1915
2082
|
} else {
|
|
@@ -1993,10 +2160,12 @@ Q5.modules.color = ($, q) => {
|
|
|
1993
2160
|
return new C(c0, c1, c2, c3);
|
|
1994
2161
|
};
|
|
1995
2162
|
|
|
2163
|
+
// deprecated
|
|
1996
2164
|
$.red = (c) => c.r;
|
|
1997
2165
|
$.green = (c) => c.g;
|
|
1998
2166
|
$.blue = (c) => c.b;
|
|
1999
2167
|
$.alpha = (c) => c.a;
|
|
2168
|
+
|
|
2000
2169
|
$.lightness = (c) => {
|
|
2001
2170
|
if (c.l) return c.l;
|
|
2002
2171
|
return ((0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) * 100) / 255;
|
|
@@ -2054,9 +2223,43 @@ Q5.ColorOKLCH = class extends Q5.Color {
|
|
|
2054
2223
|
this.h = h;
|
|
2055
2224
|
this.a = a ?? 1;
|
|
2056
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
|
+
}
|
|
2057
2235
|
toString() {
|
|
2058
2236
|
return `oklch(${this.l} ${this.c} ${this.h} / ${this.a})`;
|
|
2059
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
|
+
}
|
|
2060
2263
|
};
|
|
2061
2264
|
|
|
2062
2265
|
Q5.ColorRGBA = class extends Q5.Color {
|
|
@@ -2070,9 +2273,39 @@ Q5.ColorRGBA = class extends Q5.Color {
|
|
|
2070
2273
|
get levels() {
|
|
2071
2274
|
return [this.r, this.g, this.b, this.a];
|
|
2072
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
|
+
}
|
|
2073
2282
|
toString() {
|
|
2074
2283
|
return `color(srgb ${this.r} ${this.g} ${this.b} / ${this.a})`;
|
|
2075
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
|
+
}
|
|
2076
2309
|
};
|
|
2077
2310
|
|
|
2078
2311
|
Q5.ColorRGBA_P3 = class extends Q5.ColorRGBA {
|
|
@@ -2086,6 +2319,7 @@ Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
|
|
|
2086
2319
|
constructor(r, g, b, a) {
|
|
2087
2320
|
super(r, g, b, a ?? 255);
|
|
2088
2321
|
}
|
|
2322
|
+
// deprecated set functions for backwards compatibility
|
|
2089
2323
|
setRed(v) {
|
|
2090
2324
|
this.r = v;
|
|
2091
2325
|
}
|
|
@@ -2098,9 +2332,6 @@ Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
|
|
|
2098
2332
|
setAlpha(v) {
|
|
2099
2333
|
this.a = v;
|
|
2100
2334
|
}
|
|
2101
|
-
get levels() {
|
|
2102
|
-
return [this.r, this.g, this.b, this.a];
|
|
2103
|
-
}
|
|
2104
2335
|
toString() {
|
|
2105
2336
|
return `rgb(${this.r} ${this.g} ${this.b} / ${this.a / 255})`;
|
|
2106
2337
|
}
|