From 6584c866332bf6d01df9a5f263b447160db9d044 Mon Sep 17 00:00:00 2001 From: Igor Zinken <730069+igorski@users.noreply.github.com> Date: Sun, 26 Apr 2026 11:46:29 +0200 Subject: [PATCH] Add feather and threshold control to smart fill tool --- .../tool-options-fill/messages.json | 4 +- .../tool-options-fill/tool-options-fill.vue | 58 ++++++++++++++++--- src/definitions/editor.ts | 2 + src/rendering/actors/layer-renderer.ts | 5 +- src/rendering/operations/fill.ts | 10 ++-- src/store/modules/editor-module.ts | 2 +- .../unit/store/modules/editor-module.spec.ts | 2 +- 7 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/components/tool-options-panel/tool-options-fill/messages.json b/src/components/tool-options-panel/tool-options-fill/messages.json index 2fe7598..d2a99d7 100644 --- a/src/components/tool-options-panel/tool-options-fill/messages.json +++ b/src/components/tool-options-panel/tool-options-fill/messages.json @@ -2,6 +2,8 @@ "en-US": { "fill": "Fill", "smartFill": "Use smart fill", - "smartFillExpl": "When using smart fill, the area surrounding the fill origin will be filled until a boundary has been recognized." + "smartFillExpl": "When using smart fill, the area surrounding the fill origin will be filled until a boundary has been recognized.", + "feather": "Feather", + "threshold": "Threshold" } } diff --git a/src/components/tool-options-panel/tool-options-fill/tool-options-fill.vue b/src/components/tool-options-panel/tool-options-fill/tool-options-fill.vue index 0af68d1..c556cb5 100644 --- a/src/components/tool-options-panel/tool-options-fill/tool-options-fill.vue +++ b/src/components/tool-options-panel/tool-options-fill/tool-options-fill.vue @@ -1,7 +1,7 @@ /** * The MIT License (MIT) * - * Igor Zinken 2022 - https://www.igorski.nl + * Igor Zinken 2022-2026 - https://www.igorski.nl * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in @@ -32,18 +32,41 @@ />
+ + diff --git a/src/definitions/editor.ts b/src/definitions/editor.ts index b923cc4..800d6e9 100644 --- a/src/definitions/editor.ts +++ b/src/definitions/editor.ts @@ -136,6 +136,8 @@ export type SelectionToolOptions = { export type FillToolOptions = { smartFill: boolean; + feather: number; + threshold: number; }; export type WandToolOptions = { diff --git a/src/rendering/actors/layer-renderer.ts b/src/rendering/actors/layer-renderer.ts index 7c80337..46232b2 100644 --- a/src/rendering/actors/layer-renderer.ts +++ b/src/rendering/actors/layer-renderer.ts @@ -355,9 +355,10 @@ export default class LayerRenderer extends ZoomableSprite { if ( this.toolOptions.smartFill ) { // we need to translate pointer offset to match the relative, untransformed source layer content const point = rotatePointer( this._pointer, this.layer, width, height ); - floodFill( ctx, point.x, point.y, color ); + const { fillOptions } = this.getStore().getters; + floodFill( ctx, point.x, point.y, color, fillOptions.feather, fillOptions.threshold ); } else { - ctx.fillStyle = this.getStore().getters.activeColor; + ctx.fillStyle = color; if ( selection ) { ctx.fill(); } else { diff --git a/src/rendering/operations/fill.ts b/src/rendering/operations/fill.ts index 7838561..17833f1 100644 --- a/src/rendering/operations/fill.ts +++ b/src/rendering/operations/fill.ts @@ -1,7 +1,7 @@ /** * The MIT License (MIT) * - * Igor Zinken 2022-2023 - https://www.igorski.nl + * Igor Zinken 2022-2026 - https://www.igorski.nl * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in @@ -35,10 +35,12 @@ const TWO_PI = Math.PI * 2; * @param {Number} sourceY y-coordinate of the fill origin * @param {String} fillColor RGBA String value for the fill color * @param {Number=} feather optional amount of pixels at edges to fill (less aliased result) + * @param {Number=} threshold optional threshold to apply to the color selection */ -export const floodFill = ( ctx: CanvasRenderingContext2D, sourceX: number, sourceY: number, - fillColor: string, feather = 5 ): void => { - const path = selectByColor( ctx.canvas, sourceX, sourceY ); +export const floodFill = ( + ctx: CanvasRenderingContext2D, sourceX: number, sourceY: number, fillColor: string, feather = 5, threshold = 0, +): void => { + const path = selectByColor( ctx.canvas, sourceX, sourceY, threshold ); ctx.strokeStyle = fillColor; ctx.fillStyle = fillColor; diff --git a/src/store/modules/editor-module.ts b/src/store/modules/editor-module.ts index f4f21a4..2fe90cf 100644 --- a/src/store/modules/editor-module.ts +++ b/src/store/modules/editor-module.ts @@ -63,7 +63,7 @@ export const createEditorState = ( props?: Partial