@pooder/kit 6.2.2 → 6.3.1
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/.test-dist/src/extensions/image/ImageTool.js +250 -119
- package/.test-dist/src/extensions/image/commands.js +69 -41
- package/.test-dist/src/extensions/image/config.js +7 -0
- package/.test-dist/src/extensions/image/imageOperations.js +75 -0
- package/.test-dist/src/extensions/image/imagePlacement.js +44 -0
- package/.test-dist/src/extensions/image/index.js +1 -0
- package/.test-dist/src/extensions/image/model.js +4 -0
- package/.test-dist/tests/run.js +51 -9
- package/CHANGELOG.md +14 -0
- package/dist/index.d.mts +270 -163
- package/dist/index.d.ts +270 -163
- package/dist/index.js +458 -159
- package/dist/index.mjs +454 -158
- package/package.json +2 -2
- package/src/extensions/image/ImageTool.ts +351 -145
- package/src/extensions/image/commands.ts +78 -49
- package/src/extensions/image/config.ts +7 -0
- package/src/extensions/image/imageOperations.ts +135 -0
- package/src/extensions/image/imagePlacement.ts +78 -0
- package/src/extensions/image/index.ts +1 -0
- package/src/extensions/image/model.ts +13 -1
- package/tests/run.ts +89 -15
|
@@ -24,30 +24,43 @@ function createImageCommands(tool) {
|
|
|
24
24
|
},
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
|
-
command: "
|
|
28
|
-
id: "
|
|
29
|
-
title: "
|
|
27
|
+
command: "applyImageOperation",
|
|
28
|
+
id: "applyImageOperation",
|
|
29
|
+
title: "Apply Image Operation",
|
|
30
|
+
handler: async (id, operation, options = {}) => {
|
|
31
|
+
await tool.applyImageOperation(id, operation, options);
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
command: "getImageViewState",
|
|
36
|
+
id: "getImageViewState",
|
|
37
|
+
title: "Get Image View State",
|
|
30
38
|
handler: () => {
|
|
31
|
-
return tool.
|
|
39
|
+
return tool.getImageViewState();
|
|
32
40
|
},
|
|
33
41
|
},
|
|
34
42
|
{
|
|
35
|
-
command: "
|
|
36
|
-
id: "
|
|
37
|
-
title: "Set
|
|
38
|
-
handler: (id, updates) => {
|
|
39
|
-
tool.
|
|
43
|
+
command: "setImageTransform",
|
|
44
|
+
id: "setImageTransform",
|
|
45
|
+
title: "Set Image Transform",
|
|
46
|
+
handler: async (id, updates, options = {}) => {
|
|
47
|
+
await tool.setImageTransform(id, updates, options);
|
|
40
48
|
},
|
|
41
49
|
},
|
|
42
50
|
{
|
|
43
|
-
command: "
|
|
44
|
-
id: "
|
|
45
|
-
title: "Reset
|
|
51
|
+
command: "imageSessionReset",
|
|
52
|
+
id: "imageSessionReset",
|
|
53
|
+
title: "Reset Image Session",
|
|
46
54
|
handler: () => {
|
|
47
|
-
tool.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
tool.resetImageSession();
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
command: "validateImageSession",
|
|
60
|
+
id: "validateImageSession",
|
|
61
|
+
title: "Validate Image Session",
|
|
62
|
+
handler: async () => {
|
|
63
|
+
return await tool.validateImageSession();
|
|
51
64
|
},
|
|
52
65
|
},
|
|
53
66
|
{
|
|
@@ -55,7 +68,7 @@ function createImageCommands(tool) {
|
|
|
55
68
|
id: "completeImages",
|
|
56
69
|
title: "Complete Images",
|
|
57
70
|
handler: async () => {
|
|
58
|
-
return await tool.
|
|
71
|
+
return await tool.completeImageSession();
|
|
59
72
|
},
|
|
60
73
|
},
|
|
61
74
|
{
|
|
@@ -66,22 +79,6 @@ function createImageCommands(tool) {
|
|
|
66
79
|
return await tool.exportUserCroppedImage(options);
|
|
67
80
|
},
|
|
68
81
|
},
|
|
69
|
-
{
|
|
70
|
-
command: "fitImageToArea",
|
|
71
|
-
id: "fitImageToArea",
|
|
72
|
-
title: "Fit Image to Area",
|
|
73
|
-
handler: async (id, area) => {
|
|
74
|
-
await tool.fitImageToArea(id, area);
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
command: "fitImageToDefaultArea",
|
|
79
|
-
id: "fitImageToDefaultArea",
|
|
80
|
-
title: "Fit Image to Default Area",
|
|
81
|
-
handler: async (id) => {
|
|
82
|
-
await tool.fitImageToDefaultArea(id);
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
82
|
{
|
|
86
83
|
command: "focusImage",
|
|
87
84
|
id: "focusImage",
|
|
@@ -95,9 +92,10 @@ function createImageCommands(tool) {
|
|
|
95
92
|
id: "removeImage",
|
|
96
93
|
title: "Remove Image",
|
|
97
94
|
handler: (id) => {
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
|
|
95
|
+
const sourceItems = tool.isToolActive ? tool.workingItems : tool.items;
|
|
96
|
+
const removed = sourceItems.find((item) => item.id === id);
|
|
97
|
+
const next = sourceItems.filter((item) => item.id !== id);
|
|
98
|
+
if (next.length !== sourceItems.length) {
|
|
101
99
|
tool.purgeSourceSizeCacheForItem(removed);
|
|
102
100
|
if (tool.focusedImageId === id) {
|
|
103
101
|
tool.setImageFocus(null, {
|
|
@@ -105,6 +103,13 @@ function createImageCommands(tool) {
|
|
|
105
103
|
skipRender: true,
|
|
106
104
|
});
|
|
107
105
|
}
|
|
106
|
+
if (tool.isToolActive) {
|
|
107
|
+
tool.workingItems = tool.cloneItems(next);
|
|
108
|
+
tool.hasWorkingChanges = true;
|
|
109
|
+
tool.updateImages();
|
|
110
|
+
tool.emitWorkingChange(id);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
108
113
|
tool.updateConfig(next);
|
|
109
114
|
}
|
|
110
115
|
},
|
|
@@ -127,6 +132,13 @@ function createImageCommands(tool) {
|
|
|
127
132
|
syncCanvasSelection: true,
|
|
128
133
|
skipRender: true,
|
|
129
134
|
});
|
|
135
|
+
if (tool.isToolActive) {
|
|
136
|
+
tool.workingItems = [];
|
|
137
|
+
tool.hasWorkingChanges = true;
|
|
138
|
+
tool.updateImages();
|
|
139
|
+
tool.emitWorkingChange();
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
130
142
|
tool.updateConfig([]);
|
|
131
143
|
},
|
|
132
144
|
},
|
|
@@ -135,11 +147,19 @@ function createImageCommands(tool) {
|
|
|
135
147
|
id: "bringToFront",
|
|
136
148
|
title: "Bring Image to Front",
|
|
137
149
|
handler: (id) => {
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
150
|
+
const sourceItems = tool.isToolActive ? tool.workingItems : tool.items;
|
|
151
|
+
const index = sourceItems.findIndex((item) => item.id === id);
|
|
152
|
+
if (index !== -1 && index < sourceItems.length - 1) {
|
|
153
|
+
const next = [...sourceItems];
|
|
141
154
|
const [item] = next.splice(index, 1);
|
|
142
155
|
next.push(item);
|
|
156
|
+
if (tool.isToolActive) {
|
|
157
|
+
tool.workingItems = tool.cloneItems(next);
|
|
158
|
+
tool.hasWorkingChanges = true;
|
|
159
|
+
tool.updateImages();
|
|
160
|
+
tool.emitWorkingChange(id);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
143
163
|
tool.updateConfig(next);
|
|
144
164
|
}
|
|
145
165
|
},
|
|
@@ -149,11 +169,19 @@ function createImageCommands(tool) {
|
|
|
149
169
|
id: "sendToBack",
|
|
150
170
|
title: "Send Image to Back",
|
|
151
171
|
handler: (id) => {
|
|
152
|
-
const
|
|
172
|
+
const sourceItems = tool.isToolActive ? tool.workingItems : tool.items;
|
|
173
|
+
const index = sourceItems.findIndex((item) => item.id === id);
|
|
153
174
|
if (index > 0) {
|
|
154
|
-
const next = [...
|
|
175
|
+
const next = [...sourceItems];
|
|
155
176
|
const [item] = next.splice(index, 1);
|
|
156
177
|
next.unshift(item);
|
|
178
|
+
if (tool.isToolActive) {
|
|
179
|
+
tool.workingItems = tool.cloneItems(next);
|
|
180
|
+
tool.hasWorkingChanges = true;
|
|
181
|
+
tool.updateImages();
|
|
182
|
+
tool.emitWorkingChange(id);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
157
185
|
tool.updateConfig(next);
|
|
158
186
|
}
|
|
159
187
|
},
|
|
@@ -125,5 +125,12 @@ function createImageConfigurations() {
|
|
|
125
125
|
label: "Image Frame Outer Background",
|
|
126
126
|
default: "#f5f5f5",
|
|
127
127
|
},
|
|
128
|
+
{
|
|
129
|
+
id: "image.session.placementPolicy",
|
|
130
|
+
type: "select",
|
|
131
|
+
label: "Image Session Placement Policy",
|
|
132
|
+
options: ["free", "warn", "strict"],
|
|
133
|
+
default: "free",
|
|
134
|
+
},
|
|
128
135
|
];
|
|
129
136
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveImageOperationArea = resolveImageOperationArea;
|
|
4
|
+
exports.computeImageOperationUpdates = computeImageOperationUpdates;
|
|
5
|
+
const sourceSizeCache_1 = require("../../shared/imaging/sourceSizeCache");
|
|
6
|
+
function clampNormalizedAnchor(value) {
|
|
7
|
+
return Math.max(-1, Math.min(2, value));
|
|
8
|
+
}
|
|
9
|
+
function toNormalizedAnchor(center, start, size) {
|
|
10
|
+
return clampNormalizedAnchor((center - start) / Math.max(1, size));
|
|
11
|
+
}
|
|
12
|
+
function resolveAbsoluteScale(operation, area, source) {
|
|
13
|
+
const widthScale = Math.max(1, area.width) / Math.max(1, source.width);
|
|
14
|
+
const heightScale = Math.max(1, area.height) / Math.max(1, source.height);
|
|
15
|
+
switch (operation.type) {
|
|
16
|
+
case "cover":
|
|
17
|
+
return Math.max(widthScale, heightScale);
|
|
18
|
+
case "contain":
|
|
19
|
+
return Math.min(widthScale, heightScale);
|
|
20
|
+
case "maximizeWidth":
|
|
21
|
+
return widthScale;
|
|
22
|
+
case "maximizeHeight":
|
|
23
|
+
return heightScale;
|
|
24
|
+
default:
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function resolveImageOperationArea(args) {
|
|
29
|
+
const spec = args.area || { type: "frame" };
|
|
30
|
+
if (spec.type === "custom") {
|
|
31
|
+
return {
|
|
32
|
+
width: Math.max(1, spec.width),
|
|
33
|
+
height: Math.max(1, spec.height),
|
|
34
|
+
centerX: spec.centerX,
|
|
35
|
+
centerY: spec.centerY,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (spec.type === "viewport") {
|
|
39
|
+
return {
|
|
40
|
+
width: Math.max(1, args.viewport.width),
|
|
41
|
+
height: Math.max(1, args.viewport.height),
|
|
42
|
+
centerX: args.viewport.left + args.viewport.width / 2,
|
|
43
|
+
centerY: args.viewport.top + args.viewport.height / 2,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
width: Math.max(1, args.frame.width),
|
|
48
|
+
height: Math.max(1, args.frame.height),
|
|
49
|
+
centerX: args.frame.left + args.frame.width / 2,
|
|
50
|
+
centerY: args.frame.top + args.frame.height / 2,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function computeImageOperationUpdates(args) {
|
|
54
|
+
const { frame, source, operation, area } = args;
|
|
55
|
+
if (operation.type === "resetTransform") {
|
|
56
|
+
return {
|
|
57
|
+
scale: 1,
|
|
58
|
+
left: 0.5,
|
|
59
|
+
top: 0.5,
|
|
60
|
+
angle: 0,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const left = toNormalizedAnchor(area.centerX, frame.left, frame.width);
|
|
64
|
+
const top = toNormalizedAnchor(area.centerY, frame.top, frame.height);
|
|
65
|
+
if (operation.type === "center") {
|
|
66
|
+
return { left, top };
|
|
67
|
+
}
|
|
68
|
+
const absoluteScale = resolveAbsoluteScale(operation, area, source);
|
|
69
|
+
const coverScale = (0, sourceSizeCache_1.getCoverScale)(frame, source);
|
|
70
|
+
return {
|
|
71
|
+
scale: Math.max(0.05, (absoluteScale || coverScale) / coverScale),
|
|
72
|
+
left,
|
|
73
|
+
top,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateImagePlacement = validateImagePlacement;
|
|
4
|
+
const sourceSizeCache_1 = require("../../shared/imaging/sourceSizeCache");
|
|
5
|
+
function toRadians(angle) {
|
|
6
|
+
return (angle * Math.PI) / 180;
|
|
7
|
+
}
|
|
8
|
+
function validateImagePlacement(args) {
|
|
9
|
+
const { frame, source, placement } = args;
|
|
10
|
+
if (frame.width <= 0 ||
|
|
11
|
+
frame.height <= 0 ||
|
|
12
|
+
source.width <= 0 ||
|
|
13
|
+
source.height <= 0) {
|
|
14
|
+
return { ok: true };
|
|
15
|
+
}
|
|
16
|
+
const coverScale = (0, sourceSizeCache_1.getCoverScale)(frame, source);
|
|
17
|
+
const imageWidth = source.width * coverScale * Math.max(0.05, Number(placement.scale || 1));
|
|
18
|
+
const imageHeight = source.height * coverScale * Math.max(0.05, Number(placement.scale || 1));
|
|
19
|
+
if (imageWidth <= 0 || imageHeight <= 0) {
|
|
20
|
+
return { ok: true };
|
|
21
|
+
}
|
|
22
|
+
const centerX = frame.left + placement.left * frame.width;
|
|
23
|
+
const centerY = frame.top + placement.top * frame.height;
|
|
24
|
+
const halfWidth = imageWidth / 2;
|
|
25
|
+
const halfHeight = imageHeight / 2;
|
|
26
|
+
const radians = toRadians(placement.angle || 0);
|
|
27
|
+
const cos = Math.cos(radians);
|
|
28
|
+
const sin = Math.sin(radians);
|
|
29
|
+
const frameCorners = [
|
|
30
|
+
{ x: frame.left, y: frame.top },
|
|
31
|
+
{ x: frame.left + frame.width, y: frame.top },
|
|
32
|
+
{ x: frame.left + frame.width, y: frame.top + frame.height },
|
|
33
|
+
{ x: frame.left, y: frame.top + frame.height },
|
|
34
|
+
];
|
|
35
|
+
const coversFrame = frameCorners.every((corner) => {
|
|
36
|
+
const dx = corner.x - centerX;
|
|
37
|
+
const dy = corner.y - centerY;
|
|
38
|
+
const localX = dx * cos + dy * sin;
|
|
39
|
+
const localY = -dx * sin + dy * cos;
|
|
40
|
+
return (Math.abs(localX) <= halfWidth + 1e-6 &&
|
|
41
|
+
Math.abs(localY) <= halfHeight + 1e-6);
|
|
42
|
+
});
|
|
43
|
+
return { ok: coversFrame };
|
|
44
|
+
}
|
|
@@ -17,5 +17,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
__exportStar(require("./ImageTool"), exports);
|
|
18
18
|
__exportStar(require("./commands"), exports);
|
|
19
19
|
__exportStar(require("./config"), exports);
|
|
20
|
+
__exportStar(require("./imageOperations"), exports);
|
|
20
21
|
__exportStar(require("./model"), exports);
|
|
21
22
|
__exportStar(require("./renderer"), exports);
|
package/.test-dist/tests/run.js
CHANGED
|
@@ -12,6 +12,7 @@ const config_2 = require("../src/extensions/white-ink/config");
|
|
|
12
12
|
const commands_3 = require("../src/extensions/dieline/commands");
|
|
13
13
|
const config_3 = require("../src/extensions/dieline/config");
|
|
14
14
|
const featureCoordinates_1 = require("../src/extensions/featureCoordinates");
|
|
15
|
+
const model_1 = require("../src/extensions/image/model");
|
|
15
16
|
function assert(condition, message) {
|
|
16
17
|
if (!condition)
|
|
17
18
|
throw new Error(message);
|
|
@@ -66,10 +67,12 @@ function testMaskOps() {
|
|
|
66
67
|
assert(filled[4 * 9 + 4] === 1, "hole should be filled");
|
|
67
68
|
const imgW = 2;
|
|
68
69
|
const imgH = 1;
|
|
69
|
-
const rgba = new Uint8ClampedArray([
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
const rgba = new Uint8ClampedArray([255, 255, 255, 255, 10, 10, 10, 254]);
|
|
71
|
+
const imageData = {
|
|
72
|
+
width: imgW,
|
|
73
|
+
height: imgH,
|
|
74
|
+
data: rgba,
|
|
75
|
+
};
|
|
73
76
|
const paddedWidth = imgW + 4;
|
|
74
77
|
const paddedHeight = imgH + 4;
|
|
75
78
|
const created = (0, maskOps_1.createMask)(imageData, {
|
|
@@ -169,6 +172,43 @@ function testVisibilityDsl() {
|
|
|
169
172
|
],
|
|
170
173
|
}, context) === true, "any failed");
|
|
171
174
|
}
|
|
175
|
+
function testImageViewStateHelper() {
|
|
176
|
+
assert((0, model_1.hasAnyImageInViewState)(null) === false, "null image state should be empty");
|
|
177
|
+
assert((0, model_1.hasAnyImageInViewState)({
|
|
178
|
+
items: [],
|
|
179
|
+
hasAnyImage: false,
|
|
180
|
+
focusedId: null,
|
|
181
|
+
focusedItem: null,
|
|
182
|
+
isToolActive: false,
|
|
183
|
+
isImageSelectionActive: false,
|
|
184
|
+
hasWorkingChanges: false,
|
|
185
|
+
source: "committed",
|
|
186
|
+
placementPolicy: "free",
|
|
187
|
+
sessionNotice: null,
|
|
188
|
+
}) === false, "empty image state should report false");
|
|
189
|
+
assert((0, model_1.hasAnyImageInViewState)({
|
|
190
|
+
items: [
|
|
191
|
+
{
|
|
192
|
+
id: "img-1",
|
|
193
|
+
url: "blob:test",
|
|
194
|
+
opacity: 1,
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
hasAnyImage: true,
|
|
198
|
+
focusedId: "img-1",
|
|
199
|
+
focusedItem: {
|
|
200
|
+
id: "img-1",
|
|
201
|
+
url: "blob:test",
|
|
202
|
+
opacity: 1,
|
|
203
|
+
},
|
|
204
|
+
isToolActive: true,
|
|
205
|
+
isImageSelectionActive: true,
|
|
206
|
+
hasWorkingChanges: true,
|
|
207
|
+
source: "working",
|
|
208
|
+
placementPolicy: "free",
|
|
209
|
+
sessionNotice: null,
|
|
210
|
+
}) === true, "non-empty image state should report true");
|
|
211
|
+
}
|
|
172
212
|
function testContributionCompatibility() {
|
|
173
213
|
const imageCommandNames = (0, commands_1.createImageCommands)({}).map((entry) => entry.command);
|
|
174
214
|
const whiteInkCommandNames = (0, commands_2.createWhiteInkCommands)({}).map((entry) => entry.command);
|
|
@@ -179,13 +219,13 @@ function testContributionCompatibility() {
|
|
|
179
219
|
const expectedImageCommands = [
|
|
180
220
|
"addImage",
|
|
181
221
|
"upsertImage",
|
|
182
|
-
"
|
|
183
|
-
"
|
|
184
|
-
"
|
|
222
|
+
"applyImageOperation",
|
|
223
|
+
"getImageViewState",
|
|
224
|
+
"setImageTransform",
|
|
225
|
+
"imageSessionReset",
|
|
226
|
+
"validateImageSession",
|
|
185
227
|
"completeImages",
|
|
186
228
|
"exportUserCroppedImage",
|
|
187
|
-
"fitImageToArea",
|
|
188
|
-
"fitImageToDefaultArea",
|
|
189
229
|
"focusImage",
|
|
190
230
|
"removeImage",
|
|
191
231
|
"updateImage",
|
|
@@ -249,6 +289,7 @@ function testContributionCompatibility() {
|
|
|
249
289
|
"image.frame.dashLength",
|
|
250
290
|
"image.frame.innerBackground",
|
|
251
291
|
"image.frame.outerBackground",
|
|
292
|
+
"image.session.placementPolicy",
|
|
252
293
|
];
|
|
253
294
|
const expectedWhiteInkConfigKeys = [
|
|
254
295
|
"whiteInk.items",
|
|
@@ -285,6 +326,7 @@ function main() {
|
|
|
285
326
|
testEdgeScale();
|
|
286
327
|
testFeaturePlacementProjection();
|
|
287
328
|
testVisibilityDsl();
|
|
329
|
+
testImageViewStateHelper();
|
|
288
330
|
testContributionCompatibility();
|
|
289
331
|
console.log("ok");
|
|
290
332
|
}
|
package/CHANGELOG.md
CHANGED