246 lines
7.1 KiB
JavaScript
246 lines
7.1 KiB
JavaScript
/**
|
|
* Screen Capture Tool
|
|
* Captures a screenshot from the user's screen using the Screen Capture API
|
|
*
|
|
* @module ScreenCapture
|
|
*/
|
|
|
|
(function() {
|
|
console.log('Starting Screen Capture Tool initialization...');
|
|
|
|
window.captureScreenshot = async function() {
|
|
console.log('captureScreenshot called');
|
|
try {
|
|
// Request screen capture from user
|
|
const mediaStream = await navigator.mediaDevices.getDisplayMedia({
|
|
video: { mediaSource: 'screen' }
|
|
});
|
|
|
|
// Create video element to capture frame
|
|
const video = document.createElement('video');
|
|
video.srcObject = mediaStream;
|
|
|
|
return new Promise((resolve) => {
|
|
video.onloadedmetadata = () => {
|
|
// Create canvas and draw video frame
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = video.videoWidth;
|
|
canvas.height = video.videoHeight;
|
|
|
|
const ctx = canvas.getContext('2d');
|
|
ctx.drawImage(video, 0, 0);
|
|
|
|
// Stop all media tracks
|
|
mediaStream.getTracks().forEach(track => track.stop());
|
|
|
|
// Return canvas for further processing
|
|
resolve(canvas);
|
|
};
|
|
|
|
video.play();
|
|
});
|
|
} catch (error) {
|
|
console.error('Screenshot capture failed:', error);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
window.captureSnip = async function() {
|
|
console.log('captureSnip called');
|
|
try {
|
|
// First, get the full screen capture
|
|
const mediaStream = await navigator.mediaDevices.getDisplayMedia({
|
|
video: { mediaSource: 'screen' }
|
|
});
|
|
|
|
// Create video element to capture frame
|
|
const video = document.createElement('video');
|
|
video.srcObject = mediaStream;
|
|
|
|
return new Promise((resolve) => {
|
|
video.onloadedmetadata = () => {
|
|
// Capture full screen to canvas
|
|
const fullCanvas = document.createElement('canvas');
|
|
fullCanvas.width = video.videoWidth;
|
|
fullCanvas.height = video.videoHeight;
|
|
const fullCtx = fullCanvas.getContext('2d');
|
|
fullCtx.drawImage(video, 0, 0);
|
|
|
|
// Stop video tracks
|
|
mediaStream.getTracks().forEach(track => track.stop());
|
|
|
|
// Show selection overlay
|
|
createSelectionOverlay(fullCanvas, resolve);
|
|
};
|
|
|
|
video.play();
|
|
});
|
|
} catch (error) {
|
|
console.error('Snip capture failed:', error);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
function createSelectionOverlay(fullCanvas, resolve) {
|
|
console.log('createSelectionOverlay called');
|
|
// Create overlay container
|
|
const overlay = document.createElement('div');
|
|
overlay.style.cssText = `
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100vw;
|
|
height: 100vh;
|
|
background: rgba(0, 0, 0, 0.3);
|
|
cursor: crosshair;
|
|
z-index: 99999;
|
|
user-select: none;
|
|
`;
|
|
|
|
// Create canvas for drawing selection box
|
|
const selectionCanvas = document.createElement('canvas');
|
|
selectionCanvas.style.cssText = `
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
cursor: crosshair;
|
|
z-index: 100000;
|
|
`;
|
|
selectionCanvas.width = window.innerWidth;
|
|
selectionCanvas.height = window.innerHeight;
|
|
|
|
// Scale factor for mapping screen pixels to window pixels
|
|
const scaleX = fullCanvas.width / window.innerWidth;
|
|
const scaleY = fullCanvas.height / window.innerHeight;
|
|
|
|
let isDrawing = false;
|
|
let startX = 0;
|
|
let startY = 0;
|
|
let endX = 0;
|
|
let endY = 0;
|
|
|
|
const ctx = selectionCanvas.getContext('2d');
|
|
|
|
function drawSelection() {
|
|
ctx.clearRect(0, 0, selectionCanvas.width, selectionCanvas.height);
|
|
|
|
if (!isDrawing && (startX === endX && startY === endY)) {
|
|
return;
|
|
}
|
|
|
|
const x = Math.min(startX, endX);
|
|
const y = Math.min(startY, endY);
|
|
const width = Math.abs(endX - startX);
|
|
const height = Math.abs(endY - startY);
|
|
|
|
// Draw selection rectangle
|
|
ctx.strokeStyle = '#0EA5E9';
|
|
ctx.lineWidth = 2;
|
|
ctx.strokeRect(x, y, width, height);
|
|
|
|
// Fill with semi-transparent color
|
|
ctx.fillStyle = 'rgba(14, 165, 233, 0.1)';
|
|
ctx.fillRect(x, y, width, height);
|
|
|
|
// Draw corner handles
|
|
const handleSize = 8;
|
|
ctx.fillStyle = '#0EA5E9';
|
|
ctx.fillRect(x - handleSize / 2, y - handleSize / 2, handleSize, handleSize);
|
|
ctx.fillRect(x + width - handleSize / 2, y - handleSize / 2, handleSize, handleSize);
|
|
ctx.fillRect(x - handleSize / 2, y + height - handleSize / 2, handleSize, handleSize);
|
|
ctx.fillRect(x + width - handleSize / 2, y + height - handleSize / 2, handleSize, handleSize);
|
|
}
|
|
|
|
selectionCanvas.addEventListener('mousedown', (e) => {
|
|
isDrawing = true;
|
|
startX = e.clientX;
|
|
startY = e.clientY;
|
|
endX = startX;
|
|
endY = startY;
|
|
});
|
|
|
|
selectionCanvas.addEventListener('mousemove', (e) => {
|
|
if (isDrawing) {
|
|
endX = e.clientX;
|
|
endY = e.clientY;
|
|
drawSelection();
|
|
}
|
|
});
|
|
|
|
selectionCanvas.addEventListener('mouseup', () => {
|
|
if (isDrawing) {
|
|
isDrawing = false;
|
|
|
|
const x = Math.min(startX, endX);
|
|
const y = Math.min(startY, endY);
|
|
const width = Math.abs(endX - startX);
|
|
const height = Math.abs(endY - startY);
|
|
|
|
// Validate selection
|
|
if (width < 10 || height < 10) {
|
|
console.warn('Selection too small');
|
|
cleanup();
|
|
resolve(null);
|
|
return;
|
|
}
|
|
|
|
// Create cropped canvas from full screenshot
|
|
const croppedCanvas = document.createElement('canvas');
|
|
croppedCanvas.width = width * scaleX;
|
|
croppedCanvas.height = height * scaleY;
|
|
const croppedCtx = croppedCanvas.getContext('2d');
|
|
|
|
// Draw cropped section from full canvas
|
|
croppedCtx.drawImage(
|
|
fullCanvas,
|
|
x * scaleX,
|
|
y * scaleY,
|
|
width * scaleX,
|
|
height * scaleY,
|
|
0,
|
|
0,
|
|
width * scaleX,
|
|
height * scaleY
|
|
);
|
|
|
|
cleanup();
|
|
resolve(croppedCanvas);
|
|
}
|
|
});
|
|
|
|
// Handle escape key
|
|
const handleKeydown = (e) => {
|
|
if (e.key === 'Escape') {
|
|
cleanup();
|
|
resolve(null);
|
|
}
|
|
};
|
|
|
|
function cleanup() {
|
|
document.removeEventListener('keydown', handleKeydown);
|
|
overlay.remove();
|
|
selectionCanvas.remove();
|
|
}
|
|
|
|
document.addEventListener('keydown', handleKeydown);
|
|
document.body.appendChild(overlay);
|
|
document.body.appendChild(selectionCanvas);
|
|
|
|
console.log('Snipping tool active: Draw a rectangle to select area. Press ESC to cancel.');
|
|
}
|
|
|
|
window.canvasToFile = async function(canvas, filename = null) {
|
|
console.log('canvasToFile called');
|
|
return new Promise((resolve) => {
|
|
const name = filename || `screenshot-${Date.now()}.png`;
|
|
canvas.toBlob((blob) => {
|
|
const file = new File([blob], name, { type: 'image/png' });
|
|
resolve(file);
|
|
});
|
|
});
|
|
};
|
|
|
|
console.log('✓ Screen Capture Tool loaded successfully');
|
|
console.log('Functions available: window.captureScreenshot, window.captureSnip, window.canvasToFile');
|
|
})();
|