@nextcloud/image-editor 1.0.0-beta.1 → 1.0.0-beta.2
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/README.md +30 -3
- package/dist/assets/index.css +61 -43
- package/dist/index.cjs +420 -104
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.mjs +421 -105
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -76,14 +76,21 @@ function createInitialState() {
|
|
|
76
76
|
flipX: false,
|
|
77
77
|
flipY: false,
|
|
78
78
|
crop: null,
|
|
79
|
-
adjustments: {
|
|
79
|
+
adjustments: {
|
|
80
|
+
exposure: 0,
|
|
81
|
+
brightness: 0,
|
|
82
|
+
contrast: 0,
|
|
83
|
+
saturation: 0,
|
|
84
|
+
temperature: 0,
|
|
85
|
+
tint: 0,
|
|
86
|
+
sharpen: 0
|
|
87
|
+
},
|
|
80
88
|
preset: "none",
|
|
81
89
|
annotations: []
|
|
82
90
|
};
|
|
83
91
|
}
|
|
84
92
|
function isPristine(state) {
|
|
85
|
-
|
|
86
|
-
return state.rotation === 0 && state.fineRotation === 0 && state.zoom === 1 && !state.flipX && !state.flipY && state.crop === null && adjustments.brightness === 0 && adjustments.contrast === 0 && adjustments.saturation === 0 && state.preset === "none" && state.annotations.length === 0;
|
|
93
|
+
return state.rotation === 0 && state.fineRotation === 0 && state.zoom === 1 && !state.flipX && !state.flipY && state.crop === null && Object.values(state.adjustments).every((value) => value === 0) && state.preset === "none" && state.annotations.length === 0;
|
|
87
94
|
}
|
|
88
95
|
function orientedSize(natural, rotation) {
|
|
89
96
|
return rotation % 180 === 0 ? { width: natural.width, height: natural.height } : { width: natural.height, height: natural.width };
|
|
@@ -118,6 +125,7 @@ function mapAnnotationCW(annotation, height) {
|
|
|
118
125
|
case "draw":
|
|
119
126
|
return { ...annotation, points: mapPointsCW(annotation.points, height) };
|
|
120
127
|
case "arrow":
|
|
128
|
+
case "line":
|
|
121
129
|
return { ...annotation, points: mapPointsCW(annotation.points, height) };
|
|
122
130
|
case "rectangle":
|
|
123
131
|
case "ellipse":
|
|
@@ -149,7 +157,8 @@ function rotateCW(state, oriented) {
|
|
|
149
157
|
function mapAnnotationFlipX(annotation, width) {
|
|
150
158
|
switch (annotation.type) {
|
|
151
159
|
case "draw":
|
|
152
|
-
case "arrow":
|
|
160
|
+
case "arrow":
|
|
161
|
+
case "line": {
|
|
153
162
|
const points = annotation.points.map((value, i) => i % 2 === 0 ? width - value : value);
|
|
154
163
|
return { ...annotation, points };
|
|
155
164
|
}
|
|
@@ -194,7 +203,8 @@ function flipHorizontal(state, oriented) {
|
|
|
194
203
|
function mapAnnotationFlipY(annotation, height) {
|
|
195
204
|
switch (annotation.type) {
|
|
196
205
|
case "draw":
|
|
197
|
-
case "arrow":
|
|
206
|
+
case "arrow":
|
|
207
|
+
case "line": {
|
|
198
208
|
const points = annotation.points.map((value, i) => i % 2 === 1 ? height - value : value);
|
|
199
209
|
return { ...annotation, points };
|
|
200
210
|
}
|
|
@@ -239,7 +249,8 @@ function flipVertical(state, oriented) {
|
|
|
239
249
|
function translateAnnotation(annotation, dx, dy) {
|
|
240
250
|
switch (annotation.type) {
|
|
241
251
|
case "draw":
|
|
242
|
-
case "arrow":
|
|
252
|
+
case "arrow":
|
|
253
|
+
case "line": {
|
|
243
254
|
const points = annotation.points.map((value, i) => value + (i % 2 === 0 ? dx : dy));
|
|
244
255
|
return { ...annotation, points };
|
|
245
256
|
}
|
|
@@ -258,7 +269,7 @@ function translateAnnotation(annotation, dx, dy) {
|
|
|
258
269
|
function duplicateAnnotation(annotation, offset = 16) {
|
|
259
270
|
return { ...translateAnnotation(annotation, offset, offset), id: newId() };
|
|
260
271
|
}
|
|
261
|
-
const _sfc_main$
|
|
272
|
+
const _sfc_main$N = /* @__PURE__ */ vue.defineComponent({
|
|
262
273
|
__name: "GlassSurface",
|
|
263
274
|
props: {
|
|
264
275
|
variant: {}
|
|
@@ -280,8 +291,51 @@ const _export_sfc = (sfc, props) => {
|
|
|
280
291
|
}
|
|
281
292
|
return target;
|
|
282
293
|
};
|
|
283
|
-
const GlassSurface = /* @__PURE__ */ _export_sfc(_sfc_main$
|
|
284
|
-
const _sfc_main$
|
|
294
|
+
const GlassSurface = /* @__PURE__ */ _export_sfc(_sfc_main$N, [["__scopeId", "data-v-b60e81d9"]]);
|
|
295
|
+
const _sfc_main$M = {
|
|
296
|
+
name: "CameraIrisIcon",
|
|
297
|
+
emits: ["click"],
|
|
298
|
+
props: {
|
|
299
|
+
title: {
|
|
300
|
+
type: String
|
|
301
|
+
},
|
|
302
|
+
fillColor: {
|
|
303
|
+
type: String,
|
|
304
|
+
default: "currentColor"
|
|
305
|
+
},
|
|
306
|
+
size: {
|
|
307
|
+
type: Number,
|
|
308
|
+
default: 24
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
const _hoisted_1$J = ["aria-hidden", "aria-label"];
|
|
313
|
+
const _hoisted_2$E = ["fill", "width", "height"];
|
|
314
|
+
const _hoisted_3$B = { d: "M13.73,15L9.83,21.76C10.53,21.91 11.25,22 12,22C14.4,22 16.6,21.15 18.32,19.75L14.66,13.4M2.46,15C3.38,17.92 5.61,20.26 8.45,21.34L12.12,15M8.54,12L4.64,5.25C3,7 2,9.39 2,12C2,12.68 2.07,13.35 2.2,14H9.69M21.8,10H14.31L14.6,10.5L19.36,18.75C21,16.97 22,14.6 22,12C22,11.31 21.93,10.64 21.8,10M21.54,9C20.62,6.07 18.39,3.74 15.55,2.66L11.88,9M9.4,10.5L14.17,2.24C13.47,2.09 12.75,2 12,2C9.6,2 7.4,2.84 5.68,4.25L9.34,10.6L9.4,10.5Z" };
|
|
315
|
+
const _hoisted_4$A = { key: 0 };
|
|
316
|
+
function _sfc_render$w(_ctx, _cache, $props, $setup, $data, $options) {
|
|
317
|
+
return vue.openBlock(), vue.createElementBlock("span", vue.mergeProps(_ctx.$attrs, {
|
|
318
|
+
"aria-hidden": $props.title ? null : "true",
|
|
319
|
+
"aria-label": $props.title,
|
|
320
|
+
class: "material-design-icon camera-iris-icon",
|
|
321
|
+
role: "img",
|
|
322
|
+
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("click", $event))
|
|
323
|
+
}), [
|
|
324
|
+
(vue.openBlock(), vue.createElementBlock("svg", {
|
|
325
|
+
fill: $props.fillColor,
|
|
326
|
+
class: "material-design-icon__svg",
|
|
327
|
+
width: $props.size,
|
|
328
|
+
height: $props.size,
|
|
329
|
+
viewBox: "0 0 24 24"
|
|
330
|
+
}, [
|
|
331
|
+
vue.createElementVNode("path", _hoisted_3$B, [
|
|
332
|
+
$props.title ? (vue.openBlock(), vue.createElementBlock("title", _hoisted_4$A, vue.toDisplayString($props.title), 1)) : vue.createCommentVNode("", true)
|
|
333
|
+
])
|
|
334
|
+
], 8, _hoisted_2$E))
|
|
335
|
+
], 16, _hoisted_1$J);
|
|
336
|
+
}
|
|
337
|
+
const CameraIris = /* @__PURE__ */ _export_sfc(_sfc_main$M, [["render", _sfc_render$w]]);
|
|
338
|
+
const _sfc_main$L = {
|
|
285
339
|
name: "ContrastCircleIcon",
|
|
286
340
|
emits: ["click"],
|
|
287
341
|
props: {
|
|
@@ -298,11 +352,11 @@ const _sfc_main$H = {
|
|
|
298
352
|
}
|
|
299
353
|
}
|
|
300
354
|
};
|
|
301
|
-
const _hoisted_1$
|
|
302
|
-
const _hoisted_2$
|
|
303
|
-
const _hoisted_3$
|
|
304
|
-
const _hoisted_4$
|
|
305
|
-
function _sfc_render$
|
|
355
|
+
const _hoisted_1$I = ["aria-hidden", "aria-label"];
|
|
356
|
+
const _hoisted_2$D = ["fill", "width", "height"];
|
|
357
|
+
const _hoisted_3$A = { d: "M12,20C9.79,20 7.79,19.1 6.34,17.66L17.66,6.34C19.1,7.79 20,9.79 20,12A8,8 0 0,1 12,20M6,8H8V6H9.5V8H11.5V9.5H9.5V11.5H8V9.5H6M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,16H17V14.5H12V16Z" };
|
|
358
|
+
const _hoisted_4$z = { key: 0 };
|
|
359
|
+
function _sfc_render$v(_ctx, _cache, $props, $setup, $data, $options) {
|
|
306
360
|
return vue.openBlock(), vue.createElementBlock("span", vue.mergeProps(_ctx.$attrs, {
|
|
307
361
|
"aria-hidden": $props.title ? null : "true",
|
|
308
362
|
"aria-label": $props.title,
|
|
@@ -317,14 +371,57 @@ function _sfc_render$r(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
317
371
|
height: $props.size,
|
|
318
372
|
viewBox: "0 0 24 24"
|
|
319
373
|
}, [
|
|
320
|
-
vue.createElementVNode("path", _hoisted_3$
|
|
321
|
-
$props.title ? (vue.openBlock(), vue.createElementBlock("title", _hoisted_4$
|
|
374
|
+
vue.createElementVNode("path", _hoisted_3$A, [
|
|
375
|
+
$props.title ? (vue.openBlock(), vue.createElementBlock("title", _hoisted_4$z, vue.toDisplayString($props.title), 1)) : vue.createCommentVNode("", true)
|
|
322
376
|
])
|
|
323
|
-
], 8, _hoisted_2$
|
|
324
|
-
], 16, _hoisted_1$
|
|
377
|
+
], 8, _hoisted_2$D))
|
|
378
|
+
], 16, _hoisted_1$I);
|
|
325
379
|
}
|
|
326
|
-
const ContrastCircle = /* @__PURE__ */ _export_sfc(_sfc_main$
|
|
327
|
-
const _sfc_main$
|
|
380
|
+
const ContrastCircle = /* @__PURE__ */ _export_sfc(_sfc_main$L, [["render", _sfc_render$v]]);
|
|
381
|
+
const _sfc_main$K = {
|
|
382
|
+
name: "ImageFilterCenterFocusIcon",
|
|
383
|
+
emits: ["click"],
|
|
384
|
+
props: {
|
|
385
|
+
title: {
|
|
386
|
+
type: String
|
|
387
|
+
},
|
|
388
|
+
fillColor: {
|
|
389
|
+
type: String,
|
|
390
|
+
default: "currentColor"
|
|
391
|
+
},
|
|
392
|
+
size: {
|
|
393
|
+
type: Number,
|
|
394
|
+
default: 24
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
const _hoisted_1$H = ["aria-hidden", "aria-label"];
|
|
399
|
+
const _hoisted_2$C = ["fill", "width", "height"];
|
|
400
|
+
const _hoisted_3$z = { d: "M12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9M19,19H15V21H19A2,2 0 0,0 21,19V15H19M19,3H15V5H19V9H21V5A2,2 0 0,0 19,3M5,5H9V3H5A2,2 0 0,0 3,5V9H5M5,15H3V19A2,2 0 0,0 5,21H9V19H5V15Z" };
|
|
401
|
+
const _hoisted_4$y = { key: 0 };
|
|
402
|
+
function _sfc_render$u(_ctx, _cache, $props, $setup, $data, $options) {
|
|
403
|
+
return vue.openBlock(), vue.createElementBlock("span", vue.mergeProps(_ctx.$attrs, {
|
|
404
|
+
"aria-hidden": $props.title ? null : "true",
|
|
405
|
+
"aria-label": $props.title,
|
|
406
|
+
class: "material-design-icon image-filter-center-focus-icon",
|
|
407
|
+
role: "img",
|
|
408
|
+
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("click", $event))
|
|
409
|
+
}), [
|
|
410
|
+
(vue.openBlock(), vue.createElementBlock("svg", {
|
|
411
|
+
fill: $props.fillColor,
|
|
412
|
+
class: "material-design-icon__svg",
|
|
413
|
+
width: $props.size,
|
|
414
|
+
height: $props.size,
|
|
415
|
+
viewBox: "0 0 24 24"
|
|
416
|
+
}, [
|
|
417
|
+
vue.createElementVNode("path", _hoisted_3$z, [
|
|
418
|
+
$props.title ? (vue.openBlock(), vue.createElementBlock("title", _hoisted_4$y, vue.toDisplayString($props.title), 1)) : vue.createCommentVNode("", true)
|
|
419
|
+
])
|
|
420
|
+
], 8, _hoisted_2$C))
|
|
421
|
+
], 16, _hoisted_1$H);
|
|
422
|
+
}
|
|
423
|
+
const ImageFilterCenterFocus = /* @__PURE__ */ _export_sfc(_sfc_main$K, [["render", _sfc_render$u]]);
|
|
424
|
+
const _sfc_main$J = {
|
|
328
425
|
name: "InvertColorsIcon",
|
|
329
426
|
emits: ["click"],
|
|
330
427
|
props: {
|
|
@@ -341,11 +438,11 @@ const _sfc_main$G = {
|
|
|
341
438
|
}
|
|
342
439
|
}
|
|
343
440
|
};
|
|
344
|
-
const _hoisted_1$
|
|
345
|
-
const _hoisted_2$
|
|
346
|
-
const _hoisted_3$
|
|
347
|
-
const _hoisted_4$
|
|
348
|
-
function _sfc_render$
|
|
441
|
+
const _hoisted_1$G = ["aria-hidden", "aria-label"];
|
|
442
|
+
const _hoisted_2$B = ["fill", "width", "height"];
|
|
443
|
+
const _hoisted_3$y = { d: "M12,19.58V19.58C10.4,19.58 8.89,18.96 7.76,17.83C6.62,16.69 6,15.19 6,13.58C6,12 6.62,10.47 7.76,9.34L12,5.1M17.66,7.93L12,2.27V2.27L6.34,7.93C3.22,11.05 3.22,16.12 6.34,19.24C7.9,20.8 9.95,21.58 12,21.58C14.05,21.58 16.1,20.8 17.66,19.24C20.78,16.12 20.78,11.05 17.66,7.93Z" };
|
|
444
|
+
const _hoisted_4$x = { key: 0 };
|
|
445
|
+
function _sfc_render$t(_ctx, _cache, $props, $setup, $data, $options) {
|
|
349
446
|
return vue.openBlock(), vue.createElementBlock("span", vue.mergeProps(_ctx.$attrs, {
|
|
350
447
|
"aria-hidden": $props.title ? null : "true",
|
|
351
448
|
"aria-label": $props.title,
|
|
@@ -360,14 +457,100 @@ function _sfc_render$q(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
360
457
|
height: $props.size,
|
|
361
458
|
viewBox: "0 0 24 24"
|
|
362
459
|
}, [
|
|
363
|
-
vue.createElementVNode("path", _hoisted_3$
|
|
364
|
-
$props.title ? (vue.openBlock(), vue.createElementBlock("title", _hoisted_4$
|
|
460
|
+
vue.createElementVNode("path", _hoisted_3$y, [
|
|
461
|
+
$props.title ? (vue.openBlock(), vue.createElementBlock("title", _hoisted_4$x, vue.toDisplayString($props.title), 1)) : vue.createCommentVNode("", true)
|
|
365
462
|
])
|
|
366
|
-
], 8, _hoisted_2$
|
|
367
|
-
], 16, _hoisted_1$
|
|
463
|
+
], 8, _hoisted_2$B))
|
|
464
|
+
], 16, _hoisted_1$G);
|
|
465
|
+
}
|
|
466
|
+
const InvertColors = /* @__PURE__ */ _export_sfc(_sfc_main$J, [["render", _sfc_render$t]]);
|
|
467
|
+
const _sfc_main$I = {
|
|
468
|
+
name: "ThermometerIcon",
|
|
469
|
+
emits: ["click"],
|
|
470
|
+
props: {
|
|
471
|
+
title: {
|
|
472
|
+
type: String
|
|
473
|
+
},
|
|
474
|
+
fillColor: {
|
|
475
|
+
type: String,
|
|
476
|
+
default: "currentColor"
|
|
477
|
+
},
|
|
478
|
+
size: {
|
|
479
|
+
type: Number,
|
|
480
|
+
default: 24
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
const _hoisted_1$F = ["aria-hidden", "aria-label"];
|
|
485
|
+
const _hoisted_2$A = ["fill", "width", "height"];
|
|
486
|
+
const _hoisted_3$x = { d: "M15 13V5A3 3 0 0 0 9 5V13A5 5 0 1 0 15 13M12 4A1 1 0 0 1 13 5V8H11V5A1 1 0 0 1 12 4Z" };
|
|
487
|
+
const _hoisted_4$w = { key: 0 };
|
|
488
|
+
function _sfc_render$s(_ctx, _cache, $props, $setup, $data, $options) {
|
|
489
|
+
return vue.openBlock(), vue.createElementBlock("span", vue.mergeProps(_ctx.$attrs, {
|
|
490
|
+
"aria-hidden": $props.title ? null : "true",
|
|
491
|
+
"aria-label": $props.title,
|
|
492
|
+
class: "material-design-icon thermometer-icon",
|
|
493
|
+
role: "img",
|
|
494
|
+
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("click", $event))
|
|
495
|
+
}), [
|
|
496
|
+
(vue.openBlock(), vue.createElementBlock("svg", {
|
|
497
|
+
fill: $props.fillColor,
|
|
498
|
+
class: "material-design-icon__svg",
|
|
499
|
+
width: $props.size,
|
|
500
|
+
height: $props.size,
|
|
501
|
+
viewBox: "0 0 24 24"
|
|
502
|
+
}, [
|
|
503
|
+
vue.createElementVNode("path", _hoisted_3$x, [
|
|
504
|
+
$props.title ? (vue.openBlock(), vue.createElementBlock("title", _hoisted_4$w, vue.toDisplayString($props.title), 1)) : vue.createCommentVNode("", true)
|
|
505
|
+
])
|
|
506
|
+
], 8, _hoisted_2$A))
|
|
507
|
+
], 16, _hoisted_1$F);
|
|
368
508
|
}
|
|
369
|
-
const
|
|
370
|
-
const _sfc_main$
|
|
509
|
+
const Thermometer = /* @__PURE__ */ _export_sfc(_sfc_main$I, [["render", _sfc_render$s]]);
|
|
510
|
+
const _sfc_main$H = {
|
|
511
|
+
name: "WhiteBalanceIridescentIcon",
|
|
512
|
+
emits: ["click"],
|
|
513
|
+
props: {
|
|
514
|
+
title: {
|
|
515
|
+
type: String
|
|
516
|
+
},
|
|
517
|
+
fillColor: {
|
|
518
|
+
type: String,
|
|
519
|
+
default: "currentColor"
|
|
520
|
+
},
|
|
521
|
+
size: {
|
|
522
|
+
type: Number,
|
|
523
|
+
default: 24
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
const _hoisted_1$E = ["aria-hidden", "aria-label"];
|
|
528
|
+
const _hoisted_2$z = ["fill", "width", "height"];
|
|
529
|
+
const _hoisted_3$w = { d: "M4.96,19.95L6.76,18.15L5.34,16.74L3.55,18.53M3.55,4.46L5.34,6.26L6.76,4.84L4.96,3.05M20.45,18.53L18.66,16.74L17.24,18.15L19.04,19.95M13,22.45V19.5H11V22.45C11.32,22.45 13,22.45 13,22.45M19.04,3.05L17.24,4.84L18.66,6.26L20.45,4.46M11,3.5H13V0.55H11M5,14.5H19V8.5H5V14.5Z" };
|
|
530
|
+
const _hoisted_4$v = { key: 0 };
|
|
531
|
+
function _sfc_render$r(_ctx, _cache, $props, $setup, $data, $options) {
|
|
532
|
+
return vue.openBlock(), vue.createElementBlock("span", vue.mergeProps(_ctx.$attrs, {
|
|
533
|
+
"aria-hidden": $props.title ? null : "true",
|
|
534
|
+
"aria-label": $props.title,
|
|
535
|
+
class: "material-design-icon white-balance-iridescent-icon",
|
|
536
|
+
role: "img",
|
|
537
|
+
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("click", $event))
|
|
538
|
+
}), [
|
|
539
|
+
(vue.openBlock(), vue.createElementBlock("svg", {
|
|
540
|
+
fill: $props.fillColor,
|
|
541
|
+
class: "material-design-icon__svg",
|
|
542
|
+
width: $props.size,
|
|
543
|
+
height: $props.size,
|
|
544
|
+
viewBox: "0 0 24 24"
|
|
545
|
+
}, [
|
|
546
|
+
vue.createElementVNode("path", _hoisted_3$w, [
|
|
547
|
+
$props.title ? (vue.openBlock(), vue.createElementBlock("title", _hoisted_4$v, vue.toDisplayString($props.title), 1)) : vue.createCommentVNode("", true)
|
|
548
|
+
])
|
|
549
|
+
], 8, _hoisted_2$z))
|
|
550
|
+
], 16, _hoisted_1$E);
|
|
551
|
+
}
|
|
552
|
+
const WhiteBalanceIridescent = /* @__PURE__ */ _export_sfc(_sfc_main$H, [["render", _sfc_render$r]]);
|
|
553
|
+
const _sfc_main$G = {
|
|
371
554
|
name: "WhiteBalanceSunnyIcon",
|
|
372
555
|
emits: ["click"],
|
|
373
556
|
props: {
|
|
@@ -384,11 +567,11 @@ const _sfc_main$F = {
|
|
|
384
567
|
}
|
|
385
568
|
}
|
|
386
569
|
};
|
|
387
|
-
const _hoisted_1$
|
|
388
|
-
const _hoisted_2$
|
|
389
|
-
const _hoisted_3$
|
|
390
|
-
const _hoisted_4$
|
|
391
|
-
function _sfc_render$
|
|
570
|
+
const _hoisted_1$D = ["aria-hidden", "aria-label"];
|
|
571
|
+
const _hoisted_2$y = ["fill", "width", "height"];
|
|
572
|
+
const _hoisted_3$v = { d: "M3.55 19.09L4.96 20.5L6.76 18.71L5.34 17.29M12 6C8.69 6 6 8.69 6 12S8.69 18 12 18 18 15.31 18 12C18 8.68 15.31 6 12 6M20 13H23V11H20M17.24 18.71L19.04 20.5L20.45 19.09L18.66 17.29M20.45 5L19.04 3.6L17.24 5.39L18.66 6.81M13 1H11V4H13M6.76 5.39L4.96 3.6L3.55 5L5.34 6.81L6.76 5.39M1 13H4V11H1M13 20H11V23H13" };
|
|
573
|
+
const _hoisted_4$u = { key: 0 };
|
|
574
|
+
function _sfc_render$q(_ctx, _cache, $props, $setup, $data, $options) {
|
|
392
575
|
return vue.openBlock(), vue.createElementBlock("span", vue.mergeProps(_ctx.$attrs, {
|
|
393
576
|
"aria-hidden": $props.title ? null : "true",
|
|
394
577
|
"aria-label": $props.title,
|
|
@@ -403,16 +586,16 @@ function _sfc_render$p(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
403
586
|
height: $props.size,
|
|
404
587
|
viewBox: "0 0 24 24"
|
|
405
588
|
}, [
|
|
406
|
-
vue.createElementVNode("path", _hoisted_3$
|
|
407
|
-
$props.title ? (vue.openBlock(), vue.createElementBlock("title", _hoisted_4$
|
|
589
|
+
vue.createElementVNode("path", _hoisted_3$v, [
|
|
590
|
+
$props.title ? (vue.openBlock(), vue.createElementBlock("title", _hoisted_4$u, vue.toDisplayString($props.title), 1)) : vue.createCommentVNode("", true)
|
|
408
591
|
])
|
|
409
|
-
], 8, _hoisted_2$
|
|
410
|
-
], 16, _hoisted_1$
|
|
592
|
+
], 8, _hoisted_2$y))
|
|
593
|
+
], 16, _hoisted_1$D);
|
|
411
594
|
}
|
|
412
|
-
const WhiteBalanceSunny = /* @__PURE__ */ _export_sfc(_sfc_main$
|
|
413
|
-
const _hoisted_1$
|
|
414
|
-
const _hoisted_2$
|
|
415
|
-
const _sfc_main$
|
|
595
|
+
const WhiteBalanceSunny = /* @__PURE__ */ _export_sfc(_sfc_main$G, [["render", _sfc_render$q]]);
|
|
596
|
+
const _hoisted_1$C = { class: "editor-slider" };
|
|
597
|
+
const _hoisted_2$x = ["value", "data-test", "disabled", "aria-label", "min", "max", "step"];
|
|
598
|
+
const _sfc_main$F = /* @__PURE__ */ vue.defineComponent({
|
|
416
599
|
__name: "EditorSlider",
|
|
417
600
|
props: {
|
|
418
601
|
value: {},
|
|
@@ -432,7 +615,7 @@ const _sfc_main$E = /* @__PURE__ */ vue.defineComponent({
|
|
|
432
615
|
emit("input", Number(event.target.value));
|
|
433
616
|
}
|
|
434
617
|
return (_ctx, _cache) => {
|
|
435
|
-
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$
|
|
618
|
+
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$C, [
|
|
436
619
|
vue.createElementVNode("input", {
|
|
437
620
|
value: props.value,
|
|
438
621
|
"data-test": __props.dataTest,
|
|
@@ -444,7 +627,7 @@ const _sfc_main$E = /* @__PURE__ */ vue.defineComponent({
|
|
|
444
627
|
step: __props.step,
|
|
445
628
|
onInput,
|
|
446
629
|
onChange: _cache[0] || (_cache[0] = ($event) => emit("commit"))
|
|
447
|
-
}, null, 40, _hoisted_2$
|
|
630
|
+
}, null, 40, _hoisted_2$x),
|
|
448
631
|
vue.createElementVNode("output", null, [
|
|
449
632
|
vue.renderSlot(_ctx.$slots, "preview", {}, () => [
|
|
450
633
|
vue.createTextVNode(vue.toDisplayString(__props.display ?? props.value), 1)
|
|
@@ -454,9 +637,9 @@ const _sfc_main$E = /* @__PURE__ */ vue.defineComponent({
|
|
|
454
637
|
};
|
|
455
638
|
}
|
|
456
639
|
});
|
|
457
|
-
const EditorSlider = /* @__PURE__ */ _export_sfc(_sfc_main$
|
|
458
|
-
const _hoisted_1$
|
|
459
|
-
const _sfc_main$
|
|
640
|
+
const EditorSlider = /* @__PURE__ */ _export_sfc(_sfc_main$F, [["__scopeId", "data-v-6562ea60"]]);
|
|
641
|
+
const _hoisted_1$B = ["disabled", "data-test", "aria-pressed"];
|
|
642
|
+
const _sfc_main$E = /* @__PURE__ */ vue.defineComponent({
|
|
460
643
|
__name: "IconTab",
|
|
461
644
|
props: {
|
|
462
645
|
label: {},
|
|
@@ -478,11 +661,11 @@ const _sfc_main$D = /* @__PURE__ */ vue.defineComponent({
|
|
|
478
661
|
}, [
|
|
479
662
|
vue.renderSlot(_ctx.$slots, "default", {}, void 0, true),
|
|
480
663
|
vue.createElementVNode("span", null, vue.toDisplayString(__props.label), 1)
|
|
481
|
-
], 10, _hoisted_1$
|
|
664
|
+
], 10, _hoisted_1$B);
|
|
482
665
|
};
|
|
483
666
|
}
|
|
484
667
|
});
|
|
485
|
-
const IconTab = /* @__PURE__ */ _export_sfc(_sfc_main$
|
|
668
|
+
const IconTab = /* @__PURE__ */ _export_sfc(_sfc_main$E, [["__scopeId", "data-v-95889662"]]);
|
|
486
669
|
const gtBuilder = gettext.getGettextBuilder().detectLocale();
|
|
487
670
|
[].map((data) => gtBuilder.addTranslation(data.locale, data.json));
|
|
488
671
|
const gt = gtBuilder.build();
|
|
@@ -638,9 +821,9 @@ function useEditorContext() {
|
|
|
638
821
|
}
|
|
639
822
|
return context;
|
|
640
823
|
}
|
|
641
|
-
const _hoisted_1$
|
|
642
|
-
const _hoisted_2$
|
|
643
|
-
const _sfc_main$
|
|
824
|
+
const _hoisted_1$A = { class: "adjust-panel" };
|
|
825
|
+
const _hoisted_2$w = { class: "adjust-panel__tabs" };
|
|
826
|
+
const _sfc_main$D = /* @__PURE__ */ vue.defineComponent({
|
|
644
827
|
__name: "AdjustPanel",
|
|
645
828
|
props: {
|
|
646
829
|
loaded: { type: Boolean }
|
|
@@ -648,11 +831,15 @@ const _sfc_main$C = /* @__PURE__ */ vue.defineComponent({
|
|
|
648
831
|
setup(__props) {
|
|
649
832
|
const context = useEditorContext();
|
|
650
833
|
const adjustments = [
|
|
834
|
+
{ id: "exposure", label: t("Exposure"), icon: CameraIris },
|
|
651
835
|
{ id: "brightness", label: t("Brightness"), icon: WhiteBalanceSunny },
|
|
652
836
|
{ id: "contrast", label: t("Contrast"), icon: ContrastCircle },
|
|
653
|
-
{ id: "saturation", label: t("Saturation"), icon: InvertColors }
|
|
837
|
+
{ id: "saturation", label: t("Saturation"), icon: InvertColors },
|
|
838
|
+
{ id: "temperature", label: t("Temperature"), icon: Thermometer },
|
|
839
|
+
{ id: "tint", label: t("Tint"), icon: WhiteBalanceIridescent },
|
|
840
|
+
{ id: "sharpen", label: t("Sharpen"), icon: ImageFilterCenterFocus }
|
|
654
841
|
];
|
|
655
|
-
const activeAdjustment = vue.shallowRef("
|
|
842
|
+
const activeAdjustment = vue.shallowRef("exposure");
|
|
656
843
|
const display = vue.computed(() => {
|
|
657
844
|
const value = context.state.value.adjustments[activeAdjustment.value];
|
|
658
845
|
return value > 0 ? `+${value}` : `${value}`;
|
|
@@ -668,8 +855,8 @@ const _sfc_main$C = /* @__PURE__ */ vue.defineComponent({
|
|
|
668
855
|
context.commit(context.state.value, adjustments.find((entry) => entry.id === activeAdjustment.value).label);
|
|
669
856
|
}
|
|
670
857
|
return (_ctx, _cache) => {
|
|
671
|
-
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$
|
|
672
|
-
vue.createElementVNode("div", _hoisted_2$
|
|
858
|
+
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$A, [
|
|
859
|
+
vue.createElementVNode("div", _hoisted_2$w, [
|
|
673
860
|
(vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(adjustments, (adjustment) => {
|
|
674
861
|
return vue.createVNode(IconTab, {
|
|
675
862
|
key: adjustment.id,
|
|
@@ -702,8 +889,8 @@ const _sfc_main$C = /* @__PURE__ */ vue.defineComponent({
|
|
|
702
889
|
};
|
|
703
890
|
}
|
|
704
891
|
});
|
|
705
|
-
const AdjustPanel = /* @__PURE__ */ _export_sfc(_sfc_main$
|
|
706
|
-
const _sfc_main$
|
|
892
|
+
const AdjustPanel = /* @__PURE__ */ _export_sfc(_sfc_main$D, [["__scopeId", "data-v-3ad63bd8"]]);
|
|
893
|
+
const _sfc_main$C = {
|
|
707
894
|
name: "ArrowTopRightIcon",
|
|
708
895
|
emits: ["click"],
|
|
709
896
|
props: {
|
|
@@ -720,15 +907,58 @@ const _sfc_main$B = {
|
|
|
720
907
|
}
|
|
721
908
|
}
|
|
722
909
|
};
|
|
910
|
+
const _hoisted_1$z = ["aria-hidden", "aria-label"];
|
|
911
|
+
const _hoisted_2$v = ["fill", "width", "height"];
|
|
912
|
+
const _hoisted_3$u = { d: "M5,17.59L15.59,7H9V5H19V15H17V8.41L6.41,19L5,17.59Z" };
|
|
913
|
+
const _hoisted_4$t = { key: 0 };
|
|
914
|
+
function _sfc_render$p(_ctx, _cache, $props, $setup, $data, $options) {
|
|
915
|
+
return vue.openBlock(), vue.createElementBlock("span", vue.mergeProps(_ctx.$attrs, {
|
|
916
|
+
"aria-hidden": $props.title ? null : "true",
|
|
917
|
+
"aria-label": $props.title,
|
|
918
|
+
class: "material-design-icon arrow-top-right-icon",
|
|
919
|
+
role: "img",
|
|
920
|
+
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("click", $event))
|
|
921
|
+
}), [
|
|
922
|
+
(vue.openBlock(), vue.createElementBlock("svg", {
|
|
923
|
+
fill: $props.fillColor,
|
|
924
|
+
class: "material-design-icon__svg",
|
|
925
|
+
width: $props.size,
|
|
926
|
+
height: $props.size,
|
|
927
|
+
viewBox: "0 0 24 24"
|
|
928
|
+
}, [
|
|
929
|
+
vue.createElementVNode("path", _hoisted_3$u, [
|
|
930
|
+
$props.title ? (vue.openBlock(), vue.createElementBlock("title", _hoisted_4$t, vue.toDisplayString($props.title), 1)) : vue.createCommentVNode("", true)
|
|
931
|
+
])
|
|
932
|
+
], 8, _hoisted_2$v))
|
|
933
|
+
], 16, _hoisted_1$z);
|
|
934
|
+
}
|
|
935
|
+
const ArrowTopRight = /* @__PURE__ */ _export_sfc(_sfc_main$C, [["render", _sfc_render$p]]);
|
|
936
|
+
const _sfc_main$B = {
|
|
937
|
+
name: "EllipseOutlineIcon",
|
|
938
|
+
emits: ["click"],
|
|
939
|
+
props: {
|
|
940
|
+
title: {
|
|
941
|
+
type: String
|
|
942
|
+
},
|
|
943
|
+
fillColor: {
|
|
944
|
+
type: String,
|
|
945
|
+
default: "currentColor"
|
|
946
|
+
},
|
|
947
|
+
size: {
|
|
948
|
+
type: Number,
|
|
949
|
+
default: 24
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
};
|
|
723
953
|
const _hoisted_1$y = ["aria-hidden", "aria-label"];
|
|
724
954
|
const _hoisted_2$u = ["fill", "width", "height"];
|
|
725
|
-
const _hoisted_3$t = { d: "
|
|
955
|
+
const _hoisted_3$t = { d: "M12,6C16.41,6 20,8.69 20,12C20,15.31 16.41,18 12,18C7.59,18 4,15.31 4,12C4,8.69 7.59,6 12,6M12,4C6.5,4 2,7.58 2,12C2,16.42 6.5,20 12,20C17.5,20 22,16.42 22,12C22,7.58 17.5,4 12,4Z" };
|
|
726
956
|
const _hoisted_4$s = { key: 0 };
|
|
727
957
|
function _sfc_render$o(_ctx, _cache, $props, $setup, $data, $options) {
|
|
728
958
|
return vue.openBlock(), vue.createElementBlock("span", vue.mergeProps(_ctx.$attrs, {
|
|
729
959
|
"aria-hidden": $props.title ? null : "true",
|
|
730
960
|
"aria-label": $props.title,
|
|
731
|
-
class: "material-design-icon
|
|
961
|
+
class: "material-design-icon ellipse-outline-icon",
|
|
732
962
|
role: "img",
|
|
733
963
|
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("click", $event))
|
|
734
964
|
}), [
|
|
@@ -745,9 +975,9 @@ function _sfc_render$o(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
745
975
|
], 8, _hoisted_2$u))
|
|
746
976
|
], 16, _hoisted_1$y);
|
|
747
977
|
}
|
|
748
|
-
const
|
|
978
|
+
const EllipseOutline = /* @__PURE__ */ _export_sfc(_sfc_main$B, [["render", _sfc_render$o]]);
|
|
749
979
|
const _sfc_main$A = {
|
|
750
|
-
name: "
|
|
980
|
+
name: "FormatTextIcon",
|
|
751
981
|
emits: ["click"],
|
|
752
982
|
props: {
|
|
753
983
|
title: {
|
|
@@ -765,13 +995,13 @@ const _sfc_main$A = {
|
|
|
765
995
|
};
|
|
766
996
|
const _hoisted_1$x = ["aria-hidden", "aria-label"];
|
|
767
997
|
const _hoisted_2$t = ["fill", "width", "height"];
|
|
768
|
-
const _hoisted_3$s = { d: "
|
|
998
|
+
const _hoisted_3$s = { d: "M18.5,4L19.66,8.35L18.7,8.61C18.25,7.74 17.79,6.87 17.26,6.43C16.73,6 16.11,6 15.5,6H13V16.5C13,17 13,17.5 13.33,17.75C13.67,18 14.33,18 15,18V19H9V18C9.67,18 10.33,18 10.67,17.75C11,17.5 11,17 11,16.5V6H8.5C7.89,6 7.27,6 6.74,6.43C6.21,6.87 5.75,7.74 5.3,8.61L4.34,8.35L5.5,4H18.5Z" };
|
|
769
999
|
const _hoisted_4$r = { key: 0 };
|
|
770
1000
|
function _sfc_render$n(_ctx, _cache, $props, $setup, $data, $options) {
|
|
771
1001
|
return vue.openBlock(), vue.createElementBlock("span", vue.mergeProps(_ctx.$attrs, {
|
|
772
1002
|
"aria-hidden": $props.title ? null : "true",
|
|
773
1003
|
"aria-label": $props.title,
|
|
774
|
-
class: "material-design-icon
|
|
1004
|
+
class: "material-design-icon format-text-icon",
|
|
775
1005
|
role: "img",
|
|
776
1006
|
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("click", $event))
|
|
777
1007
|
}), [
|
|
@@ -788,9 +1018,9 @@ function _sfc_render$n(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
788
1018
|
], 8, _hoisted_2$t))
|
|
789
1019
|
], 16, _hoisted_1$x);
|
|
790
1020
|
}
|
|
791
|
-
const
|
|
1021
|
+
const FormatText = /* @__PURE__ */ _export_sfc(_sfc_main$A, [["render", _sfc_render$n]]);
|
|
792
1022
|
const _sfc_main$z = {
|
|
793
|
-
name: "
|
|
1023
|
+
name: "PencilIcon",
|
|
794
1024
|
emits: ["click"],
|
|
795
1025
|
props: {
|
|
796
1026
|
title: {
|
|
@@ -808,13 +1038,13 @@ const _sfc_main$z = {
|
|
|
808
1038
|
};
|
|
809
1039
|
const _hoisted_1$w = ["aria-hidden", "aria-label"];
|
|
810
1040
|
const _hoisted_2$s = ["fill", "width", "height"];
|
|
811
|
-
const _hoisted_3$r = { d: "
|
|
1041
|
+
const _hoisted_3$r = { d: "M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z" };
|
|
812
1042
|
const _hoisted_4$q = { key: 0 };
|
|
813
1043
|
function _sfc_render$m(_ctx, _cache, $props, $setup, $data, $options) {
|
|
814
1044
|
return vue.openBlock(), vue.createElementBlock("span", vue.mergeProps(_ctx.$attrs, {
|
|
815
1045
|
"aria-hidden": $props.title ? null : "true",
|
|
816
1046
|
"aria-label": $props.title,
|
|
817
|
-
class: "material-design-icon
|
|
1047
|
+
class: "material-design-icon pencil-icon",
|
|
818
1048
|
role: "img",
|
|
819
1049
|
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("click", $event))
|
|
820
1050
|
}), [
|
|
@@ -831,9 +1061,9 @@ function _sfc_render$m(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
831
1061
|
], 8, _hoisted_2$s))
|
|
832
1062
|
], 16, _hoisted_1$w);
|
|
833
1063
|
}
|
|
834
|
-
const
|
|
1064
|
+
const Pencil = /* @__PURE__ */ _export_sfc(_sfc_main$z, [["render", _sfc_render$m]]);
|
|
835
1065
|
const _sfc_main$y = {
|
|
836
|
-
name: "
|
|
1066
|
+
name: "RectangleOutlineIcon",
|
|
837
1067
|
emits: ["click"],
|
|
838
1068
|
props: {
|
|
839
1069
|
title: {
|
|
@@ -851,13 +1081,13 @@ const _sfc_main$y = {
|
|
|
851
1081
|
};
|
|
852
1082
|
const _hoisted_1$v = ["aria-hidden", "aria-label"];
|
|
853
1083
|
const _hoisted_2$r = ["fill", "width", "height"];
|
|
854
|
-
const _hoisted_3$q = { d: "
|
|
1084
|
+
const _hoisted_3$q = { d: "M4,6V19H20V6H4M18,17H6V8H18V17Z" };
|
|
855
1085
|
const _hoisted_4$p = { key: 0 };
|
|
856
1086
|
function _sfc_render$l(_ctx, _cache, $props, $setup, $data, $options) {
|
|
857
1087
|
return vue.openBlock(), vue.createElementBlock("span", vue.mergeProps(_ctx.$attrs, {
|
|
858
1088
|
"aria-hidden": $props.title ? null : "true",
|
|
859
1089
|
"aria-label": $props.title,
|
|
860
|
-
class: "material-design-icon
|
|
1090
|
+
class: "material-design-icon rectangle-outline-icon",
|
|
861
1091
|
role: "img",
|
|
862
1092
|
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("click", $event))
|
|
863
1093
|
}), [
|
|
@@ -874,9 +1104,9 @@ function _sfc_render$l(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
874
1104
|
], 8, _hoisted_2$r))
|
|
875
1105
|
], 16, _hoisted_1$v);
|
|
876
1106
|
}
|
|
877
|
-
const
|
|
1107
|
+
const RectangleOutline = /* @__PURE__ */ _export_sfc(_sfc_main$y, [["render", _sfc_render$l]]);
|
|
878
1108
|
const _sfc_main$x = {
|
|
879
|
-
name: "
|
|
1109
|
+
name: "VectorLineIcon",
|
|
880
1110
|
emits: ["click"],
|
|
881
1111
|
props: {
|
|
882
1112
|
title: {
|
|
@@ -894,13 +1124,13 @@ const _sfc_main$x = {
|
|
|
894
1124
|
};
|
|
895
1125
|
const _hoisted_1$u = ["aria-hidden", "aria-label"];
|
|
896
1126
|
const _hoisted_2$q = ["fill", "width", "height"];
|
|
897
|
-
const _hoisted_3$p = { d: "
|
|
1127
|
+
const _hoisted_3$p = { d: "M15,3V7.59L7.59,15H3V21H9V16.42L16.42,9H21V3M17,5H19V7H17M5,17H7V19H5" };
|
|
898
1128
|
const _hoisted_4$o = { key: 0 };
|
|
899
1129
|
function _sfc_render$k(_ctx, _cache, $props, $setup, $data, $options) {
|
|
900
1130
|
return vue.openBlock(), vue.createElementBlock("span", vue.mergeProps(_ctx.$attrs, {
|
|
901
1131
|
"aria-hidden": $props.title ? null : "true",
|
|
902
1132
|
"aria-label": $props.title,
|
|
903
|
-
class: "material-design-icon
|
|
1133
|
+
class: "material-design-icon vector-line-icon",
|
|
904
1134
|
role: "img",
|
|
905
1135
|
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("click", $event))
|
|
906
1136
|
}), [
|
|
@@ -917,7 +1147,7 @@ function _sfc_render$k(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
917
1147
|
], 8, _hoisted_2$q))
|
|
918
1148
|
], 16, _hoisted_1$u);
|
|
919
1149
|
}
|
|
920
|
-
const
|
|
1150
|
+
const VectorLine = /* @__PURE__ */ _export_sfc(_sfc_main$x, [["render", _sfc_render$k]]);
|
|
921
1151
|
function useAnnotationColor(context) {
|
|
922
1152
|
function recolorable() {
|
|
923
1153
|
const annotation = context.state.value.annotations.find((entry) => entry.id === context.selectedId.value);
|
|
@@ -972,9 +1202,10 @@ const _sfc_main$w = /* @__PURE__ */ vue.defineComponent({
|
|
|
972
1202
|
{ id: "rectangle", label: t("Rectangle"), icon: RectangleOutline },
|
|
973
1203
|
{ id: "ellipse", label: t("Ellipse"), icon: EllipseOutline },
|
|
974
1204
|
{ id: "arrow", label: t("Arrow"), icon: ArrowTopRight },
|
|
1205
|
+
{ id: "line", label: t("Line"), icon: VectorLine },
|
|
975
1206
|
{ id: "text", label: t("Text"), icon: FormatText }
|
|
976
1207
|
];
|
|
977
|
-
const showStrokeOptions = vue.computed(() => ["draw", "rectangle", "ellipse", "arrow"].includes(context.activeTool.value));
|
|
1208
|
+
const showStrokeOptions = vue.computed(() => ["draw", "rectangle", "ellipse", "arrow", "line"].includes(context.activeTool.value));
|
|
978
1209
|
const viewScale = vue.computed(() => (context.viewFit.value?.scale ?? 1) * context.viewZoom.value);
|
|
979
1210
|
const strokePreview = vue.computed(() => Math.min(PREVIEW_CAP, Math.max(2, context.strokeWidth.value * viewScale.value)));
|
|
980
1211
|
const fontPreview = vue.computed(() => Math.min(PREVIEW_CAP, Math.max(8, context.fontSize.value * viewScale.value)));
|
|
@@ -1059,7 +1290,7 @@ const _sfc_main$w = /* @__PURE__ */ vue.defineComponent({
|
|
|
1059
1290
|
};
|
|
1060
1291
|
}
|
|
1061
1292
|
});
|
|
1062
|
-
const AnnotatePanel = /* @__PURE__ */ _export_sfc(_sfc_main$w, [["__scopeId", "data-v-
|
|
1293
|
+
const AnnotatePanel = /* @__PURE__ */ _export_sfc(_sfc_main$w, [["__scopeId", "data-v-f7e8a194"]]);
|
|
1063
1294
|
const _sfc_main$v = {
|
|
1064
1295
|
name: "FlipHorizontalIcon",
|
|
1065
1296
|
emits: ["click"],
|
|
@@ -1459,6 +1690,43 @@ const PresetChip = /* @__PURE__ */ _export_sfc(_sfc_main$q, [["__scopeId", "data
|
|
|
1459
1690
|
function luma(r, g, b) {
|
|
1460
1691
|
return 0.299 * r + 0.587 * g + 0.114 * b;
|
|
1461
1692
|
}
|
|
1693
|
+
const EXPOSURE_RANGE = 2;
|
|
1694
|
+
const TEMPERATURE_RANGE = 0.25;
|
|
1695
|
+
const TINT_RANGE = 0.25;
|
|
1696
|
+
function tone(imageData) {
|
|
1697
|
+
const { data } = imageData;
|
|
1698
|
+
const exposure = 2 ** ((this.getAttr("exposure") ?? 0) * EXPOSURE_RANGE);
|
|
1699
|
+
const temperature = (this.getAttr("temperature") ?? 0) * TEMPERATURE_RANGE;
|
|
1700
|
+
const tint = (this.getAttr("tint") ?? 0) * TINT_RANGE;
|
|
1701
|
+
const red = exposure * (1 + temperature) * (1 + tint / 2);
|
|
1702
|
+
const green = exposure * (1 - tint);
|
|
1703
|
+
const blue = exposure * (1 - temperature) * (1 + tint / 2);
|
|
1704
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
1705
|
+
data[i] = data[i] * red;
|
|
1706
|
+
data[i + 1] = data[i + 1] * green;
|
|
1707
|
+
data[i + 2] = data[i + 2] * blue;
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
const SHARPEN_RANGE = 1.2;
|
|
1711
|
+
function sharpen(imageData) {
|
|
1712
|
+
const amount = (this.getAttr("sharpen") ?? 0) * SHARPEN_RANGE;
|
|
1713
|
+
if (amount === 0) {
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
const { data, width, height } = imageData;
|
|
1717
|
+
const source = new Uint8ClampedArray(data);
|
|
1718
|
+
const stride = width * 4;
|
|
1719
|
+
for (let y = 1; y < height - 1; y++) {
|
|
1720
|
+
for (let x = 1; x < width - 1; x++) {
|
|
1721
|
+
const centre = y * stride + x * 4;
|
|
1722
|
+
for (let channel = 0; channel < 3; channel++) {
|
|
1723
|
+
const i = centre + channel;
|
|
1724
|
+
const neighbours = source[i - 4] + source[i + 4] + source[i - stride] + source[i + stride];
|
|
1725
|
+
data[i] = source[i] * (1 + 4 * amount) - amount * neighbours;
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1462
1730
|
function saturate(imageData) {
|
|
1463
1731
|
const { data } = imageData;
|
|
1464
1732
|
const factor = this.saturation() + 1;
|
|
@@ -1621,6 +1889,14 @@ function buildAnnotationNode(annotation, oriented) {
|
|
|
1621
1889
|
lineCap: "round",
|
|
1622
1890
|
lineJoin: "round"
|
|
1623
1891
|
});
|
|
1892
|
+
case "line":
|
|
1893
|
+
return new Konva__default.default.Line({
|
|
1894
|
+
...base,
|
|
1895
|
+
points: [...annotation.points],
|
|
1896
|
+
stroke: annotation.color,
|
|
1897
|
+
strokeWidth: annotation.strokeWidth,
|
|
1898
|
+
lineCap: "round"
|
|
1899
|
+
});
|
|
1624
1900
|
case "arrow":
|
|
1625
1901
|
return new Konva__default.default.Arrow({
|
|
1626
1902
|
...base,
|
|
@@ -1679,8 +1955,11 @@ function buildAnnotationNode(annotation, oriented) {
|
|
|
1679
1955
|
}
|
|
1680
1956
|
}
|
|
1681
1957
|
function applyFilters(node, state, pixelRatio = 1) {
|
|
1682
|
-
const { brightness, contrast, saturation } = state.adjustments;
|
|
1958
|
+
const { exposure, brightness, contrast, saturation, temperature, tint } = state.adjustments;
|
|
1683
1959
|
const filters = [];
|
|
1960
|
+
if (exposure !== 0 || temperature !== 0 || tint !== 0) {
|
|
1961
|
+
filters.push(tone);
|
|
1962
|
+
}
|
|
1684
1963
|
if (brightness !== 0) {
|
|
1685
1964
|
filters.push(Konva__default.default.Filters.Brighten);
|
|
1686
1965
|
}
|
|
@@ -1712,6 +1991,9 @@ function applyFilters(node, state, pixelRatio = 1) {
|
|
|
1712
1991
|
if (presetFilters !== null) {
|
|
1713
1992
|
filters.push(presetFilters);
|
|
1714
1993
|
}
|
|
1994
|
+
if (state.adjustments.sharpen !== 0) {
|
|
1995
|
+
filters.push(sharpen);
|
|
1996
|
+
}
|
|
1715
1997
|
if (filters.length === 0) {
|
|
1716
1998
|
node.filters([]);
|
|
1717
1999
|
node.clearCache();
|
|
@@ -1721,6 +2003,10 @@ function applyFilters(node, state, pixelRatio = 1) {
|
|
|
1721
2003
|
node.brightness(brightness / 100);
|
|
1722
2004
|
node.contrast(contrast);
|
|
1723
2005
|
node.saturation(saturation / 100);
|
|
2006
|
+
node.setAttr("exposure", exposure / 100);
|
|
2007
|
+
node.setAttr("temperature", temperature / 100);
|
|
2008
|
+
node.setAttr("tint", tint / 100);
|
|
2009
|
+
node.setAttr("sharpen", state.adjustments.sharpen / 100);
|
|
1724
2010
|
if (state.preset === "posterize") {
|
|
1725
2011
|
node.levels(0.02);
|
|
1726
2012
|
}
|
|
@@ -1736,9 +2022,7 @@ function thumbnailKey(state) {
|
|
|
1736
2022
|
crop?.y,
|
|
1737
2023
|
crop?.width,
|
|
1738
2024
|
crop?.height,
|
|
1739
|
-
adjustments
|
|
1740
|
-
adjustments.contrast,
|
|
1741
|
-
adjustments.saturation
|
|
2025
|
+
...Object.values(adjustments)
|
|
1742
2026
|
].join("|");
|
|
1743
2027
|
}
|
|
1744
2028
|
function presetThumbnail(oriented, state, preset, size = 96) {
|
|
@@ -1793,8 +2077,7 @@ function createScene(stage) {
|
|
|
1793
2077
|
viewGroup.clipHeight(void 0);
|
|
1794
2078
|
}
|
|
1795
2079
|
const pixelRatio = options.fastFilters ? Math.min(1, options.scale * (globalThis.devicePixelRatio || 1)) : 1;
|
|
1796
|
-
const
|
|
1797
|
-
const nextFilterKey = `${brightness}|${contrast}|${saturation}|${state.preset}|${pixelRatio}`;
|
|
2080
|
+
const nextFilterKey = `${Object.values(state.adjustments).join("|")}|${state.preset}|${pixelRatio}`;
|
|
1798
2081
|
if (orientedChanged || nextFilterKey !== filterKey) {
|
|
1799
2082
|
applyFilters(imageNode, state, pixelRatio);
|
|
1800
2083
|
filterKey = nextFilterKey;
|
|
@@ -2768,7 +3051,8 @@ const _hoisted_4$3 = { class: "editor-topbar__actions" };
|
|
|
2768
3051
|
const _sfc_main$5 = /* @__PURE__ */ vue.defineComponent({
|
|
2769
3052
|
__name: "EditorTopBar",
|
|
2770
3053
|
props: {
|
|
2771
|
-
loaded: { type: Boolean }
|
|
3054
|
+
loaded: { type: Boolean },
|
|
3055
|
+
saving: { type: Boolean }
|
|
2772
3056
|
},
|
|
2773
3057
|
emits: ["save", "cancel"],
|
|
2774
3058
|
setup(__props, { emit: __emit }) {
|
|
@@ -2951,20 +3235,31 @@ const _sfc_main$5 = /* @__PURE__ */ vue.defineComponent({
|
|
|
2951
3235
|
vue.createVNode(vue.unref(NcButton__default.default), {
|
|
2952
3236
|
"data-test": "save",
|
|
2953
3237
|
variant: "primary",
|
|
2954
|
-
disabled: !__props.loaded,
|
|
3238
|
+
disabled: !__props.loaded || __props.saving,
|
|
2955
3239
|
onClick: _cache[6] || (_cache[6] = ($event) => emit("save"))
|
|
2956
|
-
}, {
|
|
3240
|
+
}, vue.createSlots({
|
|
2957
3241
|
default: vue.withCtx(() => [
|
|
2958
|
-
vue.createTextVNode(vue.toDisplayString(labels.save), 1)
|
|
3242
|
+
vue.createTextVNode(" " + vue.toDisplayString(labels.save), 1)
|
|
2959
3243
|
]),
|
|
2960
|
-
_:
|
|
2961
|
-
},
|
|
3244
|
+
_: 2
|
|
3245
|
+
}, [
|
|
3246
|
+
__props.saving ? {
|
|
3247
|
+
name: "icon",
|
|
3248
|
+
fn: vue.withCtx(() => [
|
|
3249
|
+
vue.createVNode(vue.unref(NcLoadingIcon__default.default), {
|
|
3250
|
+
size: 20,
|
|
3251
|
+
"data-test": "saving"
|
|
3252
|
+
})
|
|
3253
|
+
]),
|
|
3254
|
+
key: "0"
|
|
3255
|
+
} : void 0
|
|
3256
|
+
]), 1032, ["disabled"])
|
|
2962
3257
|
])
|
|
2963
3258
|
]);
|
|
2964
3259
|
};
|
|
2965
3260
|
}
|
|
2966
3261
|
});
|
|
2967
|
-
const EditorTopBar = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-
|
|
3262
|
+
const EditorTopBar = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-50392429"]]);
|
|
2968
3263
|
const _sfc_main$4 = {
|
|
2969
3264
|
name: "ContentCopyIcon",
|
|
2970
3265
|
emits: ["click"],
|
|
@@ -3385,7 +3680,13 @@ async function canvasToBlob(canvas, type = "image/png", quality) {
|
|
|
3385
3680
|
}, type, quality);
|
|
3386
3681
|
});
|
|
3387
3682
|
}
|
|
3683
|
+
async function painted() {
|
|
3684
|
+
await new Promise((resolve) => {
|
|
3685
|
+
requestAnimationFrame(() => requestAnimationFrame(() => resolve(null)));
|
|
3686
|
+
});
|
|
3687
|
+
}
|
|
3388
3688
|
function useExportImage(deps) {
|
|
3689
|
+
const exporting = vue.ref(false);
|
|
3389
3690
|
async function exportImage(options = {}) {
|
|
3390
3691
|
const oriented = deps.oriented();
|
|
3391
3692
|
if (oriented === null) {
|
|
@@ -3395,6 +3696,15 @@ function useExportImage(deps) {
|
|
|
3395
3696
|
if (source !== null && source.type !== "" && isPristine(deps.getState()) && options.maxSize === void 0 && (options.format === void 0 || options.format === source.type)) {
|
|
3396
3697
|
return { blob: source, width: oriented.width, height: oriented.height, mimeType: source.type };
|
|
3397
3698
|
}
|
|
3699
|
+
exporting.value = true;
|
|
3700
|
+
await painted();
|
|
3701
|
+
try {
|
|
3702
|
+
return await encode(oriented, options);
|
|
3703
|
+
} finally {
|
|
3704
|
+
exporting.value = false;
|
|
3705
|
+
}
|
|
3706
|
+
}
|
|
3707
|
+
async function encode(oriented, options) {
|
|
3398
3708
|
const canvas = renderToCanvas(oriented, deps.getState(), options.maxSize);
|
|
3399
3709
|
const mimeType = options.format ?? "image/png";
|
|
3400
3710
|
try {
|
|
@@ -3417,7 +3727,7 @@ function useExportImage(deps) {
|
|
|
3417
3727
|
deps.onError(error instanceof Error ? error : new Error(String(error)));
|
|
3418
3728
|
}
|
|
3419
3729
|
}
|
|
3420
|
-
return { exportImage, save };
|
|
3730
|
+
return { exporting, exportImage, save };
|
|
3421
3731
|
}
|
|
3422
3732
|
function useTextEditing(deps) {
|
|
3423
3733
|
const { context } = deps;
|
|
@@ -3905,7 +4215,8 @@ function transformPoints(points, node) {
|
|
|
3905
4215
|
function applyNodeTransform(annotation, node) {
|
|
3906
4216
|
switch (annotation.type) {
|
|
3907
4217
|
case "draw":
|
|
3908
|
-
case "arrow":
|
|
4218
|
+
case "arrow":
|
|
4219
|
+
case "line": {
|
|
3909
4220
|
const points = transformPoints(annotation.points, node);
|
|
3910
4221
|
const scale = (Math.abs(node.scaleX()) + Math.abs(node.scaleY())) / 2;
|
|
3911
4222
|
const strokeWidth = Math.max(1, annotation.strokeWidth * scale);
|
|
@@ -4034,11 +4345,12 @@ const TOOL_LABELS = {
|
|
|
4034
4345
|
rectangle: t("Rectangle"),
|
|
4035
4346
|
ellipse: t("Ellipse"),
|
|
4036
4347
|
arrow: t("Arrow"),
|
|
4348
|
+
line: t("Line"),
|
|
4037
4349
|
sticker: t("Sticker"),
|
|
4038
4350
|
redact: t("Redact")
|
|
4039
4351
|
};
|
|
4040
4352
|
function attachPointerTools(tool, deps) {
|
|
4041
|
-
if (!["draw", "rectangle", "ellipse", "arrow", "text", "sticker", "redact"].includes(tool)) {
|
|
4353
|
+
if (!["draw", "rectangle", "ellipse", "arrow", "line", "text", "sticker", "redact"].includes(tool)) {
|
|
4042
4354
|
return () => {
|
|
4043
4355
|
};
|
|
4044
4356
|
}
|
|
@@ -4056,7 +4368,7 @@ function attachPointerTools(tool, deps) {
|
|
|
4056
4368
|
previewNode = null;
|
|
4057
4369
|
return;
|
|
4058
4370
|
}
|
|
4059
|
-
if (previewNode !== null && (active.type === "draw" || active.type === "arrow")) {
|
|
4371
|
+
if (previewNode !== null && (active.type === "draw" || active.type === "arrow" || active.type === "line")) {
|
|
4060
4372
|
previewNode.points(active.points);
|
|
4061
4373
|
return;
|
|
4062
4374
|
}
|
|
@@ -4087,7 +4399,8 @@ function attachPointerTools(tool, deps) {
|
|
|
4087
4399
|
active = { id: newId(), type: "draw", points: [point.x, point.y], color: options.color, strokeWidth: options.strokeWidth };
|
|
4088
4400
|
break;
|
|
4089
4401
|
case "arrow":
|
|
4090
|
-
|
|
4402
|
+
case "line":
|
|
4403
|
+
active = { id: newId(), type: tool, points: [point.x, point.y, point.x, point.y], color: options.color, strokeWidth: options.strokeWidth };
|
|
4091
4404
|
break;
|
|
4092
4405
|
case "rectangle":
|
|
4093
4406
|
case "ellipse":
|
|
@@ -4134,6 +4447,7 @@ function attachPointerTools(tool, deps) {
|
|
|
4134
4447
|
active.points.push(point.x, point.y);
|
|
4135
4448
|
break;
|
|
4136
4449
|
case "arrow":
|
|
4450
|
+
case "line":
|
|
4137
4451
|
active.points = [start.x, start.y, point.x, point.y];
|
|
4138
4452
|
break;
|
|
4139
4453
|
case "rectangle":
|
|
@@ -4197,7 +4511,8 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
4197
4511
|
src: {},
|
|
4198
4512
|
label: {},
|
|
4199
4513
|
exportOptions: {},
|
|
4200
|
-
initialState: {}
|
|
4514
|
+
initialState: {},
|
|
4515
|
+
saving: { type: Boolean }
|
|
4201
4516
|
},
|
|
4202
4517
|
emits: ["save", "cancel", "error", "change"],
|
|
4203
4518
|
setup(__props, { expose: __expose, emit: __emit }) {
|
|
@@ -4237,7 +4552,7 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
4237
4552
|
return "grab";
|
|
4238
4553
|
}
|
|
4239
4554
|
const tool = context.activeTool.value;
|
|
4240
|
-
if (["draw", "rectangle", "ellipse", "arrow", "text", "sticker", "redact"].includes(tool)) {
|
|
4555
|
+
if (["draw", "rectangle", "ellipse", "arrow", "line", "text", "sticker", "redact"].includes(tool)) {
|
|
4241
4556
|
return "crosshair";
|
|
4242
4557
|
}
|
|
4243
4558
|
return "default";
|
|
@@ -4281,7 +4596,7 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
4281
4596
|
viewOptions: () => viewOptions.value,
|
|
4282
4597
|
oriented: () => orientedCanvas.value
|
|
4283
4598
|
});
|
|
4284
|
-
const { exportImage, save: onSave } = useExportImage({
|
|
4599
|
+
const { exporting, exportImage, save: onSave } = useExportImage({
|
|
4285
4600
|
oriented: () => orientedCanvas.value,
|
|
4286
4601
|
getState: () => context.state.value,
|
|
4287
4602
|
source: () => props.src instanceof Blob ? props.src : null,
|
|
@@ -4663,9 +4978,10 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
4663
4978
|
vue.createVNode(EditorTopBar, {
|
|
4664
4979
|
class: "image-editor__topbar",
|
|
4665
4980
|
loaded: loaded.value,
|
|
4981
|
+
saving: vue.unref(exporting) || __props.saving === true,
|
|
4666
4982
|
onSave: vue.unref(onSave),
|
|
4667
4983
|
onCancel: _cache[2] || (_cache[2] = ($event) => emit("cancel"))
|
|
4668
|
-
}, null, 8, ["loaded", "onSave"]),
|
|
4984
|
+
}, null, 8, ["loaded", "saving", "onSave"]),
|
|
4669
4985
|
vue.createVNode(EditorPanel, {
|
|
4670
4986
|
class: vue.normalizeClass(vue.unref(context).activeMode.value === "filter" ? "image-editor__strip" : "image-editor__controls"),
|
|
4671
4987
|
loaded: loaded.value,
|
|
@@ -4682,7 +4998,7 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
4682
4998
|
};
|
|
4683
4999
|
}
|
|
4684
5000
|
});
|
|
4685
|
-
const ImageEditor = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
5001
|
+
const ImageEditor = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-5225c517"]]);
|
|
4686
5002
|
exports.ImageEditor = ImageEditor;
|
|
4687
5003
|
exports.createInitialState = createInitialState;
|
|
4688
5004
|
exports.isPristine = isPristine;
|