368 lines
14 KiB
C#
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();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|