From 3642d5b875ddb9b41f2422db0c4ba9b20002a76c Mon Sep 17 00:00:00 2001 From: Bhav Kushwaha <75977991+bhavkushwaha@users.noreply.github.com> Date: Sun, 26 Jan 2025 14:02:24 +0530 Subject: [PATCH] CropTool-fix --- dist/editor.html | 4 +- dist/popup.js | 121 +++++++++++++++++++++++++++++-------- dist/screenshot-editor.js | 121 +++++++++++++++++++++++++++++-------- editor.html | 4 +- js/screenshot-editor.js | 123 +++++++++++++++++++++++++++++--------- 5 files changed, 292 insertions(+), 81 deletions(-) diff --git a/dist/editor.html b/dist/editor.html index 52ecf38..b9dbb26 100644 --- a/dist/editor.html +++ b/dist/editor.html @@ -81,8 +81,8 @@
- - + diff --git a/dist/popup.js b/dist/popup.js index 18b98a0..24bd630 100644 --- a/dist/popup.js +++ b/dist/popup.js @@ -21,14 +21,13 @@ class ScreenshotEditor { this.lastY = 0; this.undoStack = []; this.redoStack = []; - this.shapes = []; - this.selectedShape = null; - this.isDragging = false; this.originalImage = null; this.currentState = null; this.scale = 1; this.paths = []; this.currentPath = []; + this.cropStart = null; + this.cropEnd = null; this.setupEventListeners(); this.setupTools(); console.log('ScreenshotEditor initialized'); @@ -115,7 +114,7 @@ class ScreenshotEditor { }); } setupTools() { - const tools = ['select', 'pen', 'rectangle', 'arrow', 'crop']; + const tools = ['pen', 'rectangle', 'arrow', 'crop']; tools.forEach(tool => { const button = document.getElementById(`${tool}-tool`); if (button) { @@ -160,16 +159,23 @@ class ScreenshotEditor { this.isDrawing = true; // Calculate coordinates taking into account scale and DPR - this.startX = (e.clientX - rect.left) / rect.width * this.canvas.width / dpr; - this.startY = (e.clientY - rect.top) / rect.height * this.canvas.height / dpr; - this.lastX = this.startX; - this.lastY = this.startY; - if (this.drawingMode === 'pen') { - // Start a new path array for the current drawing + const x = (e.clientX - rect.left) / rect.width * this.canvas.width / dpr; + const y = (e.clientY - rect.top) / rect.height * this.canvas.height / dpr; + this.startX = x; + this.startY = y; + this.lastX = x; + this.lastY = y; + if (this.drawingMode === 'crop') { + this.cropStart = { + x, + y + }; + this.cropEnd = null; + } else if (this.drawingMode === 'pen') { this.currentPath = []; this.currentPath.push({ - x: this.startX, - y: this.startY + x, + y }); this.paths.push(this.currentPath); } @@ -181,10 +187,6 @@ class ScreenshotEditor { const currentX = (e.clientX - rect.left) / rect.width * this.canvas.width / dpr; const currentY = (e.clientY - rect.top) / rect.height * this.canvas.height / dpr; - // Get the current state as an image - const baseImage = new Image(); - baseImage.src = this.currentState || this.canvas.toDataURL(); - // Clear the canvas this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); @@ -204,13 +206,10 @@ class ScreenshotEditor { this.ctx.lineJoin = 'round'; switch (this.drawingMode) { case 'pen': - // Add point to current path this.currentPath.push({ x: currentX, y: currentY }); - - // Draw the entire current path this.ctx.beginPath(); this.ctx.moveTo(this.currentPath[0].x, this.currentPath[0].y); for (let i = 1; i < this.currentPath.length; i++) { @@ -227,6 +226,29 @@ class ScreenshotEditor { case 'arrow': this.drawArrow(this.ctx, this.startX, this.startY, currentX, currentY); break; + case 'crop': + // Draw crop rectangle + this.ctx.save(); + this.ctx.strokeStyle = '#ffffff'; + this.ctx.lineWidth = 2; + this.ctx.setLineDash([5, 5]); + this.ctx.beginPath(); + this.ctx.rect(this.startX, this.startY, currentX - this.startX, currentY - this.startY); + this.ctx.stroke(); + + // Draw semi-transparent overlay + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.startY); // Top + this.ctx.fillRect(0, currentY, this.canvas.width, this.canvas.height - currentY); // Bottom + this.ctx.fillRect(0, this.startY, this.startX, currentY - this.startY); // Left + this.ctx.fillRect(currentX, this.startY, this.canvas.width - currentX, currentY - this.startY); // Right + + this.ctx.restore(); + this.cropEnd = { + x: currentX, + y: currentY + }; + break; } } drawArrow(ctx, fromX, fromY, toX, toY) { @@ -248,14 +270,65 @@ class ScreenshotEditor { ctx.stroke(); } stopDrawing() { - if (this.isDrawing) { - this.isDrawing = false; - // Save the current state with the completed drawing + if (!this.isDrawing) return; + this.isDrawing = false; + if (this.drawingMode === 'crop' && this.cropStart && this.cropEnd) { + // Ensure positive width and height + const x = Math.min(this.cropStart.x, this.cropEnd.x); + const y = Math.min(this.cropStart.y, this.cropEnd.y); + const width = Math.abs(this.cropEnd.x - this.cropStart.x); + const height = Math.abs(this.cropEnd.y - this.cropStart.y); + + // Create a temporary canvas for cropping + const tempCanvas = document.createElement('canvas'); + const tempCtx = tempCanvas.getContext('2d'); + tempCanvas.width = width; + tempCanvas.height = height; + + // Draw the cropped portion + if (this.currentState) { + const img = new Image(); + img.onload = () => { + tempCtx.drawImage(img, -x, -y); + + // Update canvas size + this.canvas.width = width; + this.canvas.height = height; + + // Draw cropped image + this.ctx.drawImage(tempCanvas, 0, 0); + + // Save the cropped state + this.currentState = this.canvas.toDataURL('image/png'); + this.saveState(); + }; + img.src = this.currentState; + } else if (this.originalImage) { + tempCtx.drawImage(this.originalImage, -x, -y); + + // Update canvas size + this.canvas.width = width; + this.canvas.height = height; + + // Draw cropped image + this.ctx.drawImage(tempCanvas, 0, 0); + + // Save the cropped state + this.currentState = this.canvas.toDataURL('image/png'); + this.saveState(); + } + + // Reset crop points + this.cropStart = null; + this.cropEnd = null; + } else { + // For other tools, save the current state this.currentState = this.canvas.toDataURL('image/png'); this.saveState(); - // Reset current path - this.currentPath = []; } + + // Reset current path + this.currentPath = []; } undo() { if (this.undoStack.length > 1) { diff --git a/dist/screenshot-editor.js b/dist/screenshot-editor.js index 9403800..d0bdd6b 100644 --- a/dist/screenshot-editor.js +++ b/dist/screenshot-editor.js @@ -16,14 +16,13 @@ class ScreenshotEditor { this.lastY = 0; this.undoStack = []; this.redoStack = []; - this.shapes = []; - this.selectedShape = null; - this.isDragging = false; this.originalImage = null; this.currentState = null; this.scale = 1; this.paths = []; this.currentPath = []; + this.cropStart = null; + this.cropEnd = null; this.setupEventListeners(); this.setupTools(); console.log('ScreenshotEditor initialized'); @@ -110,7 +109,7 @@ class ScreenshotEditor { }); } setupTools() { - const tools = ['select', 'pen', 'rectangle', 'arrow', 'crop']; + const tools = ['pen', 'rectangle', 'arrow', 'crop']; tools.forEach(tool => { const button = document.getElementById(`${tool}-tool`); if (button) { @@ -155,16 +154,23 @@ class ScreenshotEditor { this.isDrawing = true; // Calculate coordinates taking into account scale and DPR - this.startX = (e.clientX - rect.left) / rect.width * this.canvas.width / dpr; - this.startY = (e.clientY - rect.top) / rect.height * this.canvas.height / dpr; - this.lastX = this.startX; - this.lastY = this.startY; - if (this.drawingMode === 'pen') { - // Start a new path array for the current drawing + const x = (e.clientX - rect.left) / rect.width * this.canvas.width / dpr; + const y = (e.clientY - rect.top) / rect.height * this.canvas.height / dpr; + this.startX = x; + this.startY = y; + this.lastX = x; + this.lastY = y; + if (this.drawingMode === 'crop') { + this.cropStart = { + x, + y + }; + this.cropEnd = null; + } else if (this.drawingMode === 'pen') { this.currentPath = []; this.currentPath.push({ - x: this.startX, - y: this.startY + x, + y }); this.paths.push(this.currentPath); } @@ -176,10 +182,6 @@ class ScreenshotEditor { const currentX = (e.clientX - rect.left) / rect.width * this.canvas.width / dpr; const currentY = (e.clientY - rect.top) / rect.height * this.canvas.height / dpr; - // Get the current state as an image - const baseImage = new Image(); - baseImage.src = this.currentState || this.canvas.toDataURL(); - // Clear the canvas this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); @@ -199,13 +201,10 @@ class ScreenshotEditor { this.ctx.lineJoin = 'round'; switch (this.drawingMode) { case 'pen': - // Add point to current path this.currentPath.push({ x: currentX, y: currentY }); - - // Draw the entire current path this.ctx.beginPath(); this.ctx.moveTo(this.currentPath[0].x, this.currentPath[0].y); for (let i = 1; i < this.currentPath.length; i++) { @@ -222,6 +221,29 @@ class ScreenshotEditor { case 'arrow': this.drawArrow(this.ctx, this.startX, this.startY, currentX, currentY); break; + case 'crop': + // Draw crop rectangle + this.ctx.save(); + this.ctx.strokeStyle = '#ffffff'; + this.ctx.lineWidth = 2; + this.ctx.setLineDash([5, 5]); + this.ctx.beginPath(); + this.ctx.rect(this.startX, this.startY, currentX - this.startX, currentY - this.startY); + this.ctx.stroke(); + + // Draw semi-transparent overlay + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.startY); // Top + this.ctx.fillRect(0, currentY, this.canvas.width, this.canvas.height - currentY); // Bottom + this.ctx.fillRect(0, this.startY, this.startX, currentY - this.startY); // Left + this.ctx.fillRect(currentX, this.startY, this.canvas.width - currentX, currentY - this.startY); // Right + + this.ctx.restore(); + this.cropEnd = { + x: currentX, + y: currentY + }; + break; } } drawArrow(ctx, fromX, fromY, toX, toY) { @@ -243,14 +265,65 @@ class ScreenshotEditor { ctx.stroke(); } stopDrawing() { - if (this.isDrawing) { - this.isDrawing = false; - // Save the current state with the completed drawing + if (!this.isDrawing) return; + this.isDrawing = false; + if (this.drawingMode === 'crop' && this.cropStart && this.cropEnd) { + // Ensure positive width and height + const x = Math.min(this.cropStart.x, this.cropEnd.x); + const y = Math.min(this.cropStart.y, this.cropEnd.y); + const width = Math.abs(this.cropEnd.x - this.cropStart.x); + const height = Math.abs(this.cropEnd.y - this.cropStart.y); + + // Create a temporary canvas for cropping + const tempCanvas = document.createElement('canvas'); + const tempCtx = tempCanvas.getContext('2d'); + tempCanvas.width = width; + tempCanvas.height = height; + + // Draw the cropped portion + if (this.currentState) { + const img = new Image(); + img.onload = () => { + tempCtx.drawImage(img, -x, -y); + + // Update canvas size + this.canvas.width = width; + this.canvas.height = height; + + // Draw cropped image + this.ctx.drawImage(tempCanvas, 0, 0); + + // Save the cropped state + this.currentState = this.canvas.toDataURL('image/png'); + this.saveState(); + }; + img.src = this.currentState; + } else if (this.originalImage) { + tempCtx.drawImage(this.originalImage, -x, -y); + + // Update canvas size + this.canvas.width = width; + this.canvas.height = height; + + // Draw cropped image + this.ctx.drawImage(tempCanvas, 0, 0); + + // Save the cropped state + this.currentState = this.canvas.toDataURL('image/png'); + this.saveState(); + } + + // Reset crop points + this.cropStart = null; + this.cropEnd = null; + } else { + // For other tools, save the current state this.currentState = this.canvas.toDataURL('image/png'); this.saveState(); - // Reset current path - this.currentPath = []; } + + // Reset current path + this.currentPath = []; } undo() { if (this.undoStack.length > 1) { diff --git a/editor.html b/editor.html index 52ecf38..b9dbb26 100644 --- a/editor.html +++ b/editor.html @@ -81,8 +81,8 @@
- - + diff --git a/js/screenshot-editor.js b/js/screenshot-editor.js index dfa64f0..9f01f8c 100644 --- a/js/screenshot-editor.js +++ b/js/screenshot-editor.js @@ -13,14 +13,13 @@ class ScreenshotEditor { this.lastY = 0; this.undoStack = []; this.redoStack = []; - this.shapes = []; - this.selectedShape = null; - this.isDragging = false; this.originalImage = null; this.currentState = null; this.scale = 1; this.paths = []; this.currentPath = []; + this.cropStart = null; + this.cropEnd = null; this.setupEventListeners(); this.setupTools(); @@ -116,7 +115,7 @@ class ScreenshotEditor { } setupTools() { - const tools = ['select', 'pen', 'rectangle', 'arrow', 'crop']; + const tools = ['pen', 'rectangle', 'arrow', 'crop']; tools.forEach(tool => { const button = document.getElementById(`${tool}-tool`); if (button) { @@ -161,15 +160,20 @@ class ScreenshotEditor { this.isDrawing = true; // Calculate coordinates taking into account scale and DPR - this.startX = ((e.clientX - rect.left) / rect.width) * this.canvas.width / dpr; - this.startY = ((e.clientY - rect.top) / rect.height) * this.canvas.height / dpr; - this.lastX = this.startX; - this.lastY = this.startY; + const x = ((e.clientX - rect.left) / rect.width) * this.canvas.width / dpr; + const y = ((e.clientY - rect.top) / rect.height) * this.canvas.height / dpr; - if (this.drawingMode === 'pen') { - // Start a new path array for the current drawing + this.startX = x; + this.startY = y; + this.lastX = x; + this.lastY = y; + + if (this.drawingMode === 'crop') { + this.cropStart = { x, y }; + this.cropEnd = null; + } else if (this.drawingMode === 'pen') { this.currentPath = []; - this.currentPath.push({ x: this.startX, y: this.startY }); + this.currentPath.push({ x, y }); this.paths.push(this.currentPath); } } @@ -182,10 +186,6 @@ class ScreenshotEditor { const currentX = ((e.clientX - rect.left) / rect.width) * this.canvas.width / dpr; const currentY = ((e.clientY - rect.top) / rect.height) * this.canvas.height / dpr; - // Get the current state as an image - const baseImage = new Image(); - baseImage.src = this.currentState || this.canvas.toDataURL(); - // Clear the canvas this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); @@ -206,10 +206,7 @@ class ScreenshotEditor { switch (this.drawingMode) { case 'pen': - // Add point to current path this.currentPath.push({ x: currentX, y: currentY }); - - // Draw the entire current path this.ctx.beginPath(); this.ctx.moveTo(this.currentPath[0].x, this.currentPath[0].y); for (let i = 1; i < this.currentPath.length; i++) { @@ -221,18 +218,34 @@ class ScreenshotEditor { case 'rectangle': this.ctx.beginPath(); - this.ctx.rect( - this.startX, - this.startY, - currentX - this.startX, - currentY - this.startY - ); + this.ctx.rect(this.startX, this.startY, currentX - this.startX, currentY - this.startY); this.ctx.stroke(); break; case 'arrow': this.drawArrow(this.ctx, this.startX, this.startY, currentX, currentY); break; + + case 'crop': + // Draw crop rectangle + this.ctx.save(); + this.ctx.strokeStyle = '#ffffff'; + this.ctx.lineWidth = 2; + this.ctx.setLineDash([5, 5]); + this.ctx.beginPath(); + this.ctx.rect(this.startX, this.startY, currentX - this.startX, currentY - this.startY); + this.ctx.stroke(); + + // Draw semi-transparent overlay + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.startY); // Top + this.ctx.fillRect(0, currentY, this.canvas.width, this.canvas.height - currentY); // Bottom + this.ctx.fillRect(0, this.startY, this.startX, currentY - this.startY); // Left + this.ctx.fillRect(currentX, this.startY, this.canvas.width - currentX, currentY - this.startY); // Right + + this.ctx.restore(); + this.cropEnd = { x: currentX, y: currentY }; + break; } } @@ -262,14 +275,66 @@ class ScreenshotEditor { } stopDrawing() { - if (this.isDrawing) { - this.isDrawing = false; - // Save the current state with the completed drawing + if (!this.isDrawing) return; + this.isDrawing = false; + + if (this.drawingMode === 'crop' && this.cropStart && this.cropEnd) { + // Ensure positive width and height + const x = Math.min(this.cropStart.x, this.cropEnd.x); + const y = Math.min(this.cropStart.y, this.cropEnd.y); + const width = Math.abs(this.cropEnd.x - this.cropStart.x); + const height = Math.abs(this.cropEnd.y - this.cropStart.y); + + // Create a temporary canvas for cropping + const tempCanvas = document.createElement('canvas'); + const tempCtx = tempCanvas.getContext('2d'); + tempCanvas.width = width; + tempCanvas.height = height; + + // Draw the cropped portion + if (this.currentState) { + const img = new Image(); + img.onload = () => { + tempCtx.drawImage(img, -x, -y); + + // Update canvas size + this.canvas.width = width; + this.canvas.height = height; + + // Draw cropped image + this.ctx.drawImage(tempCanvas, 0, 0); + + // Save the cropped state + this.currentState = this.canvas.toDataURL('image/png'); + this.saveState(); + }; + img.src = this.currentState; + } else if (this.originalImage) { + tempCtx.drawImage(this.originalImage, -x, -y); + + // Update canvas size + this.canvas.width = width; + this.canvas.height = height; + + // Draw cropped image + this.ctx.drawImage(tempCanvas, 0, 0); + + // Save the cropped state + this.currentState = this.canvas.toDataURL('image/png'); + this.saveState(); + } + + // Reset crop points + this.cropStart = null; + this.cropEnd = null; + } else { + // For other tools, save the current state this.currentState = this.canvas.toDataURL('image/png'); this.saveState(); - // Reset current path - this.currentPath = []; } + + // Reset current path + this.currentPath = []; } undo() {