diff --git a/js/CanvasState.js b/js/CanvasState.js index 0b7745b..2fca6eb 100644 --- a/js/CanvasState.js +++ b/js/CanvasState.js @@ -404,12 +404,10 @@ If you see dark images or masks in the output, make sure node_id is set to ${cor } if (this.maskUndoStack.length > 0) { const prevState = this.maskUndoStack[this.maskUndoStack.length - 1]; - const maskCanvas = this.canvas.maskTool.getMask(); - const maskCtx = maskCanvas.getContext('2d', { willReadFrequently: true }); - if (maskCtx) { - maskCtx.clearRect(0, 0, maskCanvas.width, maskCanvas.height); - maskCtx.drawImage(prevState, 0, 0); - } + // Use the new restoreMaskFromSavedState method that properly clears chunks first + this.canvas.maskTool.restoreMaskFromSavedState(prevState); + // Clear stroke overlay to prevent old drawing previews from persisting + this.canvas.canvasRenderer.clearMaskStrokeOverlay(); this.canvas.render(); } this.canvas.updateHistoryButtons(); @@ -420,12 +418,10 @@ If you see dark images or masks in the output, make sure node_id is set to ${cor const nextState = this.maskRedoStack.pop(); if (nextState) { this.maskUndoStack.push(nextState); - const maskCanvas = this.canvas.maskTool.getMask(); - const maskCtx = maskCanvas.getContext('2d', { willReadFrequently: true }); - if (maskCtx) { - maskCtx.clearRect(0, 0, maskCanvas.width, maskCanvas.height); - maskCtx.drawImage(nextState, 0, 0); - } + // Use the new restoreMaskFromSavedState method that properly clears chunks first + this.canvas.maskTool.restoreMaskFromSavedState(nextState); + // Clear stroke overlay to prevent old drawing previews from persisting + this.canvas.canvasRenderer.clearMaskStrokeOverlay(); this.canvas.render(); } this.canvas.updateHistoryButtons(); diff --git a/js/MaskTool.js b/js/MaskTool.js index 86ee686..80f3f13 100644 --- a/js/MaskTool.js +++ b/js/MaskTool.js @@ -1352,6 +1352,23 @@ export class MaskTool { this.canvasInstance.render(); log.info("Cleared all mask data from all chunks"); } + /** + * Clears all chunks and restores mask from saved state + * This is used during undo/redo operations to ensure clean state restoration + */ + restoreMaskFromSavedState(savedMaskCanvas) { + // First, clear ALL chunks to ensure no leftover data + this.clearAllMaskChunks(); + // Now apply the saved mask state to chunks + if (savedMaskCanvas.width > 0 && savedMaskCanvas.height > 0) { + // Apply the saved mask to the chunk system at the correct position + const bounds = this.canvasInstance.outputAreaBounds; + this.applyMaskCanvasToChunks(savedMaskCanvas, this.x, this.y); + } + // Update the active mask canvas to show the restored state + this.updateActiveMaskCanvas(true); + log.debug("Restored mask from saved state with clean chunk system"); + } getMask() { // Return the current active mask canvas which shows all chunks // Only update if there are pending changes to avoid unnecessary redraws diff --git a/src/CanvasState.ts b/src/CanvasState.ts index 0aa89e0..b219faf 100644 --- a/src/CanvasState.ts +++ b/src/CanvasState.ts @@ -456,12 +456,13 @@ If you see dark images or masks in the output, make sure node_id is set to ${cor if (this.maskUndoStack.length > 0) { const prevState = this.maskUndoStack[this.maskUndoStack.length - 1]; - const maskCanvas = this.canvas.maskTool.getMask(); - const maskCtx = maskCanvas.getContext('2d', { willReadFrequently: true }); - if (maskCtx) { - maskCtx.clearRect(0, 0, maskCanvas.width, maskCanvas.height); - maskCtx.drawImage(prevState, 0, 0); - } + + // Use the new restoreMaskFromSavedState method that properly clears chunks first + this.canvas.maskTool.restoreMaskFromSavedState(prevState); + + // Clear stroke overlay to prevent old drawing previews from persisting + this.canvas.canvasRenderer.clearMaskStrokeOverlay(); + this.canvas.render(); } @@ -474,12 +475,13 @@ If you see dark images or masks in the output, make sure node_id is set to ${cor const nextState = this.maskRedoStack.pop(); if (nextState) { this.maskUndoStack.push(nextState); - const maskCanvas = this.canvas.maskTool.getMask(); - const maskCtx = maskCanvas.getContext('2d', { willReadFrequently: true }); - if (maskCtx) { - maskCtx.clearRect(0, 0, maskCanvas.width, maskCanvas.height); - maskCtx.drawImage(nextState, 0, 0); - } + + // Use the new restoreMaskFromSavedState method that properly clears chunks first + this.canvas.maskTool.restoreMaskFromSavedState(nextState); + + // Clear stroke overlay to prevent old drawing previews from persisting + this.canvas.canvasRenderer.clearMaskStrokeOverlay(); + this.canvas.render(); } this.canvas.updateHistoryButtons(); diff --git a/src/MaskTool.ts b/src/MaskTool.ts index 7e8eea4..c8eb1a2 100644 --- a/src/MaskTool.ts +++ b/src/MaskTool.ts @@ -1674,6 +1674,27 @@ export class MaskTool { log.info("Cleared all mask data from all chunks"); } + /** + * Clears all chunks and restores mask from saved state + * This is used during undo/redo operations to ensure clean state restoration + */ + restoreMaskFromSavedState(savedMaskCanvas: HTMLCanvasElement): void { + // First, clear ALL chunks to ensure no leftover data + this.clearAllMaskChunks(); + + // Now apply the saved mask state to chunks + if (savedMaskCanvas.width > 0 && savedMaskCanvas.height > 0) { + // Apply the saved mask to the chunk system at the correct position + const bounds = this.canvasInstance.outputAreaBounds; + this.applyMaskCanvasToChunks(savedMaskCanvas, this.x, this.y); + } + + // Update the active mask canvas to show the restored state + this.updateActiveMaskCanvas(true); + + log.debug("Restored mask from saved state with clean chunk system"); + } + getMask(): HTMLCanvasElement { // Return the current active mask canvas which shows all chunks // Only update if there are pending changes to avoid unnecessary redraws