UNPKG

ai-debug-local-mcp

Version:

🎯 ENHANCED AI GUIDANCE v4.1.2: Dramatically improved tool descriptions help AI users choose the right tools instead of 'close enough' options. Ultra-fast keyboard automation (10x speed), universal recording, multi-ecosystem debugging support, and compreh

127 lines • 5.15 kB
export class ScreenshotOptimizer { static MAX_SIZE_BYTES = 1.5 * 1024 * 1024; // 1.5MB max for Claude static MAX_DIMENSION = 2048; // Max width or height static TARGET_SIZE_BYTES = 1 * 1024 * 1024; // Target 1MB static async optimizeScreenshot(buffer, fullPage) { const originalSize = buffer.length; // Check if optimization is needed if (originalSize <= this.TARGET_SIZE_BYTES) { return { buffer, mimeType: 'image/png', wasOptimized: false, originalSize, optimizedSize: originalSize }; } // Dynamic import sharp to handle potential loading issues let sharp; try { sharp = (await import('sharp')).default; } catch (error) { console.error('Failed to load sharp:', error); // Fallback to original buffer if sharp fails return { buffer, mimeType: 'image/png', wasOptimized: false, originalSize, optimizedSize: originalSize }; } try { // Get image metadata const metadata = await sharp(buffer).metadata(); const { width = 0, height = 0 } = metadata; // Calculate resize if dimensions are too large let resizeOptions; if (width > this.MAX_DIMENSION || height > this.MAX_DIMENSION) { const scaleFactor = Math.min(this.MAX_DIMENSION / width, this.MAX_DIMENSION / height); resizeOptions = { width: Math.round(width * scaleFactor), height: Math.round(height * scaleFactor) }; } // Start with high quality and reduce if needed let quality = 90; let format = 'jpeg'; // JPEG is generally smaller let optimizedBuffer = buffer; // Try optimization with current settings while (quality >= 50) { let sharpInstance = sharp(buffer); // Apply resize if needed if (resizeOptions) { sharpInstance = sharpInstance.resize(resizeOptions); } // Try JPEG first (usually smaller) if (format === 'jpeg') { optimizedBuffer = await sharpInstance .jpeg({ quality, progressive: true, mozjpeg: true // Use mozjpeg encoder for better compression }) .toBuffer(); } else { optimizedBuffer = await sharpInstance .png({ quality, compressionLevel: 9, palette: true // Use palette mode for smaller file size }) .toBuffer(); } // Check if we're under the limit if (optimizedBuffer.length <= this.MAX_SIZE_BYTES) { break; } // Try more aggressive optimization quality -= 10; // If still too large and we haven't resized yet, resize more aggressively if (!resizeOptions && quality < 70) { const newDimension = Math.round(this.MAX_DIMENSION * 0.75); const scaleFactor = Math.min(newDimension / width, newDimension / height); resizeOptions = { width: Math.round(width * scaleFactor), height: Math.round(height * scaleFactor) }; } } // Last resort: aggressive resize and compression if (optimizedBuffer.length > this.MAX_SIZE_BYTES) { const aggressiveSize = Math.round(this.MAX_DIMENSION * 0.5); optimizedBuffer = await sharp(buffer) .resize({ width: aggressiveSize, height: aggressiveSize, fit: 'inside', withoutEnlargement: true }) .jpeg({ quality: 60, mozjpeg: true }) .toBuffer(); format = 'jpeg'; } return { buffer: optimizedBuffer, mimeType: format === 'jpeg' ? 'image/jpeg' : 'image/png', wasOptimized: true, originalSize, optimizedSize: optimizedBuffer.length }; } catch (error) { console.error('Error optimizing screenshot:', error); // Return original on error return { buffer, mimeType: 'image/png', wasOptimized: false, originalSize, optimizedSize: originalSize }; } } } //# sourceMappingURL=screenshot-optimizer.js.map