Skip to main content
Glama

Peekaboo MCP

by steipete
PixelAnalyzer.swiftβ€’7.14 kB
// // PixelAnalyzer.swift // PeekabooCore // import AppKit import Foundation /// Analyzes pixel regions to find uniform (boring) areas for optimal label placement struct PixelAnalyzer { private let image: NSImage private let bitmapRep: NSBitmapImageRep? private let textDetector: AcceleratedTextDetector init?(image: NSImage) { self.image = image self.textDetector = AcceleratedTextDetector() // Get bitmap representation for fallback pixel access if let tiffData = image.tiffRepresentation, let bitmap = NSBitmapImageRep(data: tiffData) { self.bitmapRep = bitmap } else { self.bitmapRep = nil } } /// Scores a region based on absence of text/edges (higher score = better for labels) func scoreRegion(_ rect: NSRect) -> Float { // Clamp rect to image bounds let imageRect = NSRect(origin: .zero, size: image.size) let clampedRect = rect.intersection(imageRect) // If rect is outside image, return low score guard !clampedRect.isEmpty else { return 0 } // Use Accelerated Sobel edge detection to find text return textDetector.scoreRegionForLabelPlacement(clampedRect, in: image) } /// Scores a region using simple variance (fallback method) func scoreRegionSimple(_ rect: NSRect) -> Float { guard bitmapRep != nil else { return 0 } // Clamp rect to image bounds let imageRect = NSRect(origin: .zero, size: image.size) let clampedRect = rect.intersection(imageRect) // If rect is outside image, return low score guard !clampedRect.isEmpty else { return 0 } // Sample pixels in a 7x7 grid for better coverage let samples = samplePixels(in: clampedRect, gridSize: 7) // Calculate contrast instead of variance let contrast = calculateContrast(samples) // Convert to score: lower contrast = higher score (more uniform) // Add small epsilon to avoid division by zero return 1.0 / (contrast + 0.001) } /// Finds the best position from candidates based on background uniformity func findBestPosition(from candidates: [NSRect]) -> (rect: NSRect, score: Float)? { var bestPosition: (rect: NSRect, score: Float)? for candidate in candidates { let score = scoreRegion(candidate) if bestPosition == nil || score > bestPosition!.score { bestPosition = (rect: candidate, score: score) } } return bestPosition } // MARK: - Private Methods private func samplePixels(in rect: NSRect, gridSize: Int) -> [NSColor] { var colors: [NSColor] = [] let stepX = rect.width / CGFloat(gridSize - 1) let stepY = rect.height / CGFloat(gridSize - 1) for row in 0..<gridSize { for col in 0..<gridSize { let x = rect.minX + CGFloat(col) * stepX let y = rect.minY + CGFloat(row) * stepY if let color = getPixelColor(at: CGPoint(x: x, y: y)) { colors.append(color) } } } return colors } private func getPixelColor(at point: CGPoint) -> NSColor? { guard let bitmap = bitmapRep else { return nil } // Convert to bitmap coordinates (flip Y if needed) let x = Int(point.x) let y = Int(image.size.height - point.y - 1) // Flip Y coordinate // Check bounds guard x >= 0, x < bitmap.pixelsWide, y >= 0, y < bitmap.pixelsHigh else { return nil } return bitmap.colorAt(x: x, y: y) } private func calculateBrightnessVariance(_ colors: [NSColor]) -> Float { guard !colors.isEmpty else { return 0 } // Calculate brightness for each color let brightnesses = colors.map { color -> Float in // Convert to RGB color space if needed guard let rgbColor = color.usingColorSpace(.deviceRGB) else { return 0.5 // Default middle brightness } // Calculate luminance using standard formula return Float(rgbColor.redComponent) * 0.299 + Float(rgbColor.greenComponent) * 0.587 + Float(rgbColor.blueComponent) * 0.114 } // Calculate mean brightness let mean = brightnesses.reduce(0, +) / Float(brightnesses.count) // Calculate variance let squaredDiffs = brightnesses.map { pow($0 - mean, 2) } let variance = squaredDiffs.reduce(0, +) / Float(brightnesses.count) return variance } private func calculateContrast(_ colors: [NSColor]) -> Float { guard !colors.isEmpty else { return 0 } // Calculate brightness for each color let brightnesses = colors.map { color -> Float in guard let rgbColor = color.usingColorSpace(.deviceRGB) else { return 0.5 } return Float(rgbColor.redComponent) * 0.299 + Float(rgbColor.greenComponent) * 0.587 + Float(rgbColor.blueComponent) * 0.114 } // Calculate contrast as difference between min and max brightness let minBrightness = brightnesses.min() ?? 0 let maxBrightness = brightnesses.max() ?? 0 return maxBrightness - minBrightness } } // Extension for checking if a region has high contrast (text, edges) extension PixelAnalyzer { /// Quick check if region likely contains text or edges func hasHighContrast(in rect: NSRect) -> Bool { // Sample just 5 pixels in a cross pattern let center = CGPoint(x: rect.midX, y: rect.midY) let points = [ center, CGPoint(x: rect.minX + rect.width * 0.25, y: rect.midY), CGPoint(x: rect.maxX - rect.width * 0.25, y: rect.midY), CGPoint(x: rect.midX, y: rect.minY + rect.height * 0.25), CGPoint(x: rect.midX, y: rect.maxY - rect.height * 0.25) ] let colors = points.compactMap { getPixelColor(at: $0) } guard colors.count >= 2 else { return false } // Check if colors vary significantly let brightnesses = colors.map { color -> Float in guard let rgbColor = color.usingColorSpace(.deviceRGB) else { return 0.5 } return Float(rgbColor.redComponent) * 0.299 + Float(rgbColor.greenComponent) * 0.587 + Float(rgbColor.blueComponent) * 0.114 } let minBrightness = brightnesses.min() ?? 0 let maxBrightness = brightnesses.max() ?? 0 // If brightness range > 0.3, we likely have text or edges return (maxBrightness - minBrightness) > 0.3 } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/steipete/Peekaboo'

If you have feedback or need assistance with the MCP directory API, please join our Discord server