1
0
Fork 0

fix(gui): draw single clicks and avoid blending mask with itself

This commit is contained in:
Sean Sube 2023-01-19 17:18:59 -06:00
parent df7bba47dd
commit 5e23f84e5a
1 changed files with 56 additions and 48 deletions

View File

@ -48,19 +48,6 @@ export function MaskCanvas(props: MaskCanvasProps) {
const { source, mask } = props;
const { params } = mustExist(useContext(ConfigContext));
function saveMask(): void {
if (doesExist(bufferRef.current)) {
if (maskState.current === MASK_STATE.clean) {
return;
}
bufferRef.current.toBlob((blob) => {
maskState.current = MASK_STATE.clean;
props.onSave(mustExist(blob));
});
}
}
function drawBuffer() {
if (doesExist(brushRef.current) && doesExist(bufferRef.current) && doesExist(canvasRef.current)) {
const { ctx } = getClearContext(canvasRef);
@ -73,10 +60,38 @@ export function MaskCanvas(props: MaskCanvasProps) {
}
}
function drawBrush(point: Point): void {
const { ctx } = getClearContext(brushRef);
ctx.fillStyle = grayToRGB(brush.color, brush.strength);
drawCircle(ctx, {
x: point.x,
y: point.y,
}, brush.size);
drawBuffer();
}
function drawClicks(): void {
if (clicks.length > 0) {
const { ctx } = getContext(bufferRef);
ctx.fillStyle = grayToRGB(brush.color, brush.strength);
for (const click of clicks) {
drawCircle(ctx, click, brush.size);
}
clicks.length = 0;
drawBuffer();
}
}
function drawSource(file: Blob): void {
const image = new Image();
image.onload = () => {
const { ctx } = getContext(bufferRef);
const { ctx } = getClearContext(bufferRef);
ctx.globalAlpha = 1.0;
ctx.drawImage(image, 0, 0);
URL.revokeObjectURL(src);
@ -90,12 +105,25 @@ export function MaskCanvas(props: MaskCanvasProps) {
function finishPainting() {
if (doesExist(brushRef.current)) {
getClearContext(brushRef);
drawBuffer();
}
drawClicks();
if (maskState.current === MASK_STATE.painting) {
maskState.current = MASK_STATE.dirty;
save();
}
}
function saveMask(): void {
if (doesExist(bufferRef.current)) {
if (maskState.current === MASK_STATE.clean) {
return;
}
bufferRef.current.toBlob((blob) => {
maskState.current = MASK_STATE.clean;
props.onSave(mustExist(blob));
});
}
}
@ -118,21 +146,6 @@ export function MaskCanvas(props: MaskCanvasProps) {
// eslint-disable-next-line @typescript-eslint/unbound-method
const setBrush = useStore(state, (s) => s.setBrush);
useEffect(() => {
// including clicks.length prevents the initial render from saving a blank canvas
if (doesExist(bufferRef.current) && maskState.current === MASK_STATE.painting && clicks.length > 0) {
const { ctx } = getContext(bufferRef);
ctx.fillStyle = grayToRGB(brush.color, brush.strength);
for (const click of clicks) {
drawCircle(ctx, click, brush.size);
}
clicks.length = 0;
drawBuffer();
}
}, [clicks.length]);
useEffect(() => {
if (maskState.current === MASK_STATE.dirty) {
save();
@ -155,6 +168,9 @@ export function MaskCanvas(props: MaskCanvasProps) {
}
}, [source]);
// last resort to draw lost clicks
drawClicks();
const styles: React.CSSProperties = {
border: '1px solid black',
maxHeight: params.height.default,
@ -191,16 +207,13 @@ export function MaskCanvas(props: MaskCanvasProps) {
const canvas = mustExist(canvasRef.current);
const bounds = canvas.getBoundingClientRect();
const { ctx } = getContext(bufferRef);
ctx.fillStyle = grayToRGB(brush.color, brush.strength);
drawCircle(ctx, {
setClicks([...clicks, {
x: event.clientX - bounds.left,
y: event.clientY - bounds.top,
}, brush.size);
}]);
drawClicks();
maskState.current = MASK_STATE.dirty;
save();
}}
onMouseDown={() => {
maskState.current = MASK_STATE.painting;
@ -218,15 +231,10 @@ export function MaskCanvas(props: MaskCanvasProps) {
y: event.clientY - bounds.top,
}]);
} else {
const { ctx } = getClearContext(brushRef);
ctx.fillStyle = grayToRGB(brush.color, brush.strength);
drawCircle(ctx, {
drawBrush({
x: event.clientX - bounds.left,
y: event.clientY - bounds.top,
}, brush.size);
drawBuffer();
});
}
}}
/>
@ -272,7 +280,7 @@ export function MaskCanvas(props: MaskCanvasProps) {
onClick={() => {
floodCanvas(bufferRef, floodBelow);
drawBuffer();
save();
maskState.current = MASK_STATE.dirty;
}}>
Gray to black
</Button>
@ -282,7 +290,7 @@ export function MaskCanvas(props: MaskCanvasProps) {
onClick={() => {
floodCanvas(bufferRef, floodBlack);
drawBuffer();
save();
maskState.current = MASK_STATE.dirty;
}}>
Fill with black
</Button>
@ -292,7 +300,7 @@ export function MaskCanvas(props: MaskCanvasProps) {
onClick={() => {
floodCanvas(bufferRef, floodWhite);
drawBuffer();
save();
maskState.current = MASK_STATE.dirty;
}}>
Fill with white
</Button>
@ -302,7 +310,7 @@ export function MaskCanvas(props: MaskCanvasProps) {
onClick={() => {
floodCanvas(bufferRef, floodAbove);
drawBuffer();
save();
maskState.current = MASK_STATE.dirty;
}}>
Gray to white
</Button>