GTPCorrgir/ScreenCaptureWindow.cs

368 lines
14 KiB
C#

using System;
using System.IO;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Controls;
using System.Windows.Shapes;
using Tesseract;
using System.Threading.Tasks;
using Point = System.Windows.Point;
using Rect = System.Windows.Rect;
using Size = System.Windows.Size;
using Brushes = System.Windows.Media.Brushes;
using Cursors = System.Windows.Input.Cursors;
using Cursor = System.Windows.Input.Cursor;
using Color = System.Windows.Media.Color;
using Path = System.IO.Path;
using MessageBox = System.Windows.MessageBox;
using MouseEventArgs = System.Windows.Input.MouseEventArgs;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
using Rectangle = System.Windows.Shapes.Rectangle;
namespace GTPCorrgir
{
public class ScreenCaptureWindow : Window
{
private Point startPoint;
private Point currentPoint;
private bool hasFirstPoint;
private System.Windows.Shapes.Rectangle selectionRectangle;
private Canvas overlayCanvas;
private readonly Cursor crosshairCursor = Cursors.Cross;
private Window overlayWindow;
private System.Windows.Forms.Screen targetScreen; // Añadimos esta referencia
public ScreenCaptureWindow()
{
InitializeInitialWindow();
}
private void InitializeInitialWindow()
{
// Calcular el rectángulo virtual que engloba todas las pantallas
var allScreens = System.Windows.Forms.Screen.AllScreens;
int minX = allScreens.Min(s => s.Bounds.Left);
int minY = allScreens.Min(s => s.Bounds.Top);
int maxX = allScreens.Max(s => s.Bounds.Right);
int maxY = allScreens.Max(s => s.Bounds.Bottom);
// Configurar la ventana inicial para cubrir todas las pantallas
this.WindowStyle = WindowStyle.None;
this.ResizeMode = ResizeMode.NoResize;
this.Width = maxX - minX;
this.Height = maxY - minY;
this.Left = minX;
this.Top = minY;
this.AllowsTransparency = true;
this.Background = new SolidColorBrush(Color.FromArgb(0, 0, 0, 0));
this.ShowInTaskbar = false;
this.Topmost = true;
this.Cursor = crosshairCursor;
// Añadir un panel transparente que cubra toda la ventana
var panel = new Grid
{
Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0))
};
this.Content = panel;
// Agregar el evento del primer clic
this.MouseLeftButtonDown += InitialWindow_MouseLeftButtonDown;
}
private void InitialWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// Obtener la pantalla donde se hizo clic
var clickPoint = PointToScreen(e.GetPosition(this));
Console.WriteLine($"Click point screen coords: X={clickPoint.X}, Y={clickPoint.Y}");
targetScreen = System.Windows.Forms.Screen.FromPoint(
new System.Drawing.Point((int)clickPoint.X, (int)clickPoint.Y));
Console.WriteLine($"Target screen bounds: Left={targetScreen.Bounds.Left}, Top={targetScreen.Bounds.Top}, Right={targetScreen.Bounds.Right}, Bottom={targetScreen.Bounds.Bottom}");
// Remover este evento ya que solo lo necesitamos una vez
this.MouseLeftButtonDown -= InitialWindow_MouseLeftButtonDown;
// Calcular el punto relativo a la pantalla objetivo
startPoint = new Point(
clickPoint.X - targetScreen.Bounds.Left,
clickPoint.Y - targetScreen.Bounds.Top
);
Console.WriteLine($"Start point relative coords: X={startPoint.X}, Y={startPoint.Y}");
// Inicializar la ventana de overlay ANTES de posicionar el rectángulo
InitializeOverlayWindow(targetScreen);
// Asegurarse que el overlay esté completamente inicializado
overlayWindow.Dispatcher.Invoke(() =>
{
selectionRectangle.Visibility = Visibility.Visible;
Canvas.SetLeft(selectionRectangle, startPoint.X);
Canvas.SetTop(selectionRectangle, startPoint.Y);
selectionRectangle.Width = 0;
selectionRectangle.Height = 0;
hasFirstPoint = true;
});
}
private void InitializeOverlayWindow(System.Windows.Forms.Screen screen)
{
overlayWindow = new Window
{
WindowStyle = WindowStyle.None,
ResizeMode = ResizeMode.NoResize,
AllowsTransparency = true,
Background = new SolidColorBrush(Color.FromArgb(128, 0, 0, 0)),
Topmost = true,
ShowInTaskbar = false,
Width = screen.Bounds.Width,
Height = screen.Bounds.Height,
WindowStartupLocation = WindowStartupLocation.Manual,
Left = screen.Bounds.Left,
Top = screen.Bounds.Top
};
InitializeComponents(overlayWindow);
SetupEventHandlers();
overlayWindow.Show();
overlayWindow.Activate(); // Asegurar que la ventana tiene el foco
this.Hide();
}
private void InitializeComponents(Window window)
{
overlayCanvas = new Canvas
{
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
VerticalAlignment = System.Windows.VerticalAlignment.Stretch
};
var grid = new Grid();
grid.Children.Add(overlayCanvas);
window.Content = grid;
selectionRectangle = new System.Windows.Shapes.Rectangle
{
Stroke = new SolidColorBrush(Colors.Red),
StrokeThickness = 2,
Fill = new SolidColorBrush(Color.FromArgb(50, 255, 255, 255)),
Visibility = Visibility.Collapsed
};
overlayCanvas.Children.Add(selectionRectangle);
}
private void SetupEventHandlers()
{
overlayWindow.MouseLeftButtonDown += OverlaySecondPoint_MouseLeftButtonDown;
overlayWindow.MouseMove += OverlayCanvas_MouseMove;
overlayWindow.KeyDown += MainWindow_KeyDown;
}
private void OverlayCanvas_MouseMove(object sender, MouseEventArgs e)
{
if (!hasFirstPoint) return;
currentPoint = e.GetPosition(overlayCanvas);
UpdateSelectionRectangle(startPoint, currentPoint);
}
private void OverlaySecondPoint_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!hasFirstPoint) return;
// Capturar el segundo punto
var endPoint = e.GetPosition(overlayCanvas);
// Validar el tamaño del rectángulo
double width = Math.Abs(endPoint.X - startPoint.X);
double height = Math.Abs(endPoint.Y - startPoint.Y);
// Validar tamaño mínimo (5x5 pixels)
const double MIN_SIZE = 5.0;
if (width < MIN_SIZE || height < MIN_SIZE)
{
selectionRectangle.Visibility = Visibility.Collapsed;
var notification = new notificacion();
notification.UpdateNotification("Selección muy pequeña",
"Por favor, seleccione un área más grande (mínimo 5x5 píxeles)");
notification.Show();
hasFirstPoint = false;
return;
}
// Ocultar el rectángulo inmediatamente
selectionRectangle.Visibility = Visibility.Collapsed;
// Mostrar notificación de procesamiento
var processingNotification = new notificacion();
processingNotification.UpdateNotification("Procesando", "Analizando imagen seleccionada...");
processingNotification.Show();
// Si las validaciones pasan, proceder con la captura
CaptureAndProcessArea();
}
private void UpdateSelectionRectangle(Point start, Point current)
{
double x = Math.Min(start.X, current.X);
double y = Math.Min(start.Y, current.Y);
double width = Math.Abs(current.X - start.X);
double height = Math.Abs(current.Y - start.Y);
Canvas.SetLeft(selectionRectangle, x);
Canvas.SetTop(selectionRectangle, y);
selectionRectangle.Width = width;
selectionRectangle.Height = height;
}
private void MainWindow_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
overlayWindow?.Close();
this.Close();
}
}
private string GetTesseractExecutablePath()
{
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
string tessDataDir = Path.Combine(baseDir, "tessdata");
if (!Directory.Exists(tessDataDir))
{
throw new DirectoryNotFoundException(
$"No se encontró el directorio tessdata en {tessDataDir}. " +
"Asegúrate de que la carpeta tessdata existe y contiene los archivos de entrenamiento.");
}
return tessDataDir;
}
private BitmapSource CaptureScreen(double x, double y, double width, double height)
{
try
{
// Usar la referencia guardada del screen objetivo
var screenPoint = new System.Drawing.Point(
(int)(targetScreen.Bounds.Left + x),
(int)(targetScreen.Bounds.Top + y)
);
Console.WriteLine($"Capture coordinates: X={screenPoint.X}, Y={screenPoint.Y}, Width={width}, Height={height}");
using (var screenBmp = new System.Drawing.Bitmap(
(int)width,
(int)height,
System.Drawing.Imaging.PixelFormat.Format32bppArgb))
{
using (var bmpGraphics = System.Drawing.Graphics.FromImage(screenBmp))
{
bmpGraphics.CopyFromScreen(
screenPoint.X,
screenPoint.Y,
0,
0,
new System.Drawing.Size((int)width, (int)height)
);
}
using (var memory = new MemoryStream())
{
screenBmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
memory.Position = 0;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
}
}
catch (Exception ex)
{
MessageBox.Show($"Error al capturar pantalla: {ex.Message}");
return null;
}
}
private async void CaptureAndProcessArea()
{
try
{
this.Hide();
await Task.Delay(100);
double x = Canvas.GetLeft(selectionRectangle);
double y = Canvas.GetTop(selectionRectangle);
double width = selectionRectangle.Width;
double height = selectionRectangle.Height;
var screenCapture = CaptureScreen(x, y, width, height);
if (screenCapture == null) return;
var screenBitmap = new RenderTargetBitmap(
(int)width,
(int)height,
96, 96,
PixelFormats.Pbgra32);
var visual = new DrawingVisual();
using (var context = visual.RenderOpen())
{
context.DrawImage(screenCapture, new Rect(0, 0, width, height));
}
screenBitmap.Render(visual);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(screenBitmap));
using (var memoryStream = new MemoryStream())
{
encoder.Save(memoryStream);
memoryStream.Position = 0;
string tesseractPath = GetTesseractExecutablePath();
using (var engine = new TesseractEngine(tesseractPath, "eng", EngineMode.Default))
{
engine.SetVariable("tessedit_char_whitelist", " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.");
using (var img = Pix.LoadFromMemory(memoryStream.ToArray()))
{
var result = engine.Process(img);
string ocrText = result.GetText();
using (var textProcessor = new OcrTextProcessor())
{
string processedText = await textProcessor.ProcessOcrText(ocrText);
var notificationWindow = new notificacion();
notificationWindow.UpdateNotification("OCR Completado", "Texto copiado al portapapeles");
notificationWindow.Show();
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show($"Error processing capture: {ex.Message}",
"Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
overlayWindow?.Close();
this.Close();
}
}
}
}