-
-
+
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() {