diff --git a/App.xaml b/App.xaml
new file mode 100644
index 0000000..fe3cec2
--- /dev/null
+++ b/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/App.xaml.cs b/App.xaml.cs
new file mode 100644
index 0000000..723039d
--- /dev/null
+++ b/App.xaml.cs
@@ -0,0 +1,14 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace ROIEditor
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ }
+
+}
diff --git a/AssemblyInfo.cs b/AssemblyInfo.cs
new file mode 100644
index 0000000..b0ec827
--- /dev/null
+++ b/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/DatabaseManager.cs b/DatabaseManager.cs
new file mode 100644
index 0000000..c0a5989
--- /dev/null
+++ b/DatabaseManager.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Text.Json;
+using Microsoft.Data.Sqlite;
+using System.ComponentModel;
+
+namespace ROIEditor
+{
+
+ public class DatabaseManager
+ {
+ private readonly string connectionString;
+ private readonly string tableName;
+ private List data = new List();
+
+ public void Add(T item)
+ {
+ data.Add(item);
+ }
+
+ public void Clear()
+ {
+ data.Clear();
+ }
+
+ public List GetList()
+ {
+ return data;
+ }
+
+ public int Count => data.Count;
+
+ public DatabaseManager(string dbPath, string tableName)
+ {
+ connectionString = $"Data Source={dbPath}";
+ this.tableName = tableName;
+ InitializeDatabase();
+ }
+
+ private void InitializeDatabase()
+ {
+ using (var connection = new SqliteConnection(connectionString))
+ {
+ connection.Open();
+
+ var command = connection.CreateCommand();
+ command.CommandText = $@"
+ CREATE TABLE IF NOT EXISTS {tableName} (
+ Id INTEGER PRIMARY KEY AUTOINCREMENT,
+ Clave TEXT,
+ SerializeData TEXT
+ )";
+ command.ExecuteNonQuery();
+ }
+ }
+
+ public void SaveData(string clave)
+ {
+
+ using (var connection = new SqliteConnection(connectionString))
+ {
+ connection.Open();
+
+ var deleteCommand = connection.CreateCommand();
+ deleteCommand.CommandText = @"DELETE FROM Roi WHERE Clave = $Clave";
+ deleteCommand.Parameters.AddWithValue("$Clave", clave);
+ deleteCommand.ExecuteNonQuery();
+
+ foreach (var elemento in data)
+ {
+ string serializedData = JsonSerializer.Serialize(elemento);
+
+ var command = connection.CreateCommand();
+ command.CommandText = $"INSERT INTO {tableName} (Clave, SerializeData) VALUES ($Clave, $SerializedData)";
+ command.Parameters.AddWithValue("$Clave", clave);
+ command.Parameters.AddWithValue("$SerializedData", serializedData);
+ command.ExecuteNonQuery();
+ }
+ }
+ }
+
+ public List LoadData(string clave)
+ {
+ var dataList = new List();
+
+ using (var connection = new SqliteConnection(connectionString))
+ {
+ connection.Open();
+
+ var command = connection.CreateCommand();
+ command.CommandText = $"SELECT SerializeData FROM {tableName} WHERE Clave = $Clave";
+ command.Parameters.AddWithValue("$Clave", clave);
+
+ using (var reader = command.ExecuteReader())
+ {
+ while (reader.Read())
+ {
+ string serializedData = reader.GetString(0);
+ List data = JsonSerializer.Deserialize>(serializedData);
+ dataList.AddRange(data);
+ }
+ }
+ }
+
+ return dataList;
+ }
+ }
+
+}
diff --git a/ImagenEstado.cs b/ImagenEstado.cs
new file mode 100644
index 0000000..ba19995
--- /dev/null
+++ b/ImagenEstado.cs
@@ -0,0 +1,81 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Media;
+
+namespace ROIEditor
+{
+ public class ImagenEstado
+ {
+ public double ZoomScaleX { get; set; }
+ public double ZoomScaleY { get; set; }
+ public double HorizontalOffset { get; set; }
+ public double VerticalOffset { get; set; }
+ public string NombreImagen;
+
+
+ // Constructor sin parámetros
+ public ImagenEstado()
+ {
+
+ }
+ public ImagenEstado(string imageNameActual)
+ {
+ NombreImagen = imageNameActual;
+
+ }
+
+ public string PathPlantillasJson()
+ {
+ string jsonPath = Path.ChangeExtension(NombreImagen, ".json");
+ var imagePath = Path.Combine(Directory.GetCurrentDirectory(), "Plantillas", jsonPath);
+ return imagePath;
+ }
+ public string PathPlantillasPNG()
+ {
+ string jsonPath = Path.ChangeExtension(NombreImagen, ".png");
+ var imagePath = Path.Combine(Directory.GetCurrentDirectory(), "Plantillas", jsonPath);
+ return imagePath;
+ }
+
+ public void SalvarEstadoJSON()
+ {
+ // Cambia la extensión del archivo de imagen a .json
+ string jsonPath = PathPlantillasJson();
+
+ // Serializa el estado de la imagen a JSON
+ string json = JsonConvert.SerializeObject(NombreImagen, Formatting.Indented);
+
+ // Escribe el JSON en un archivo
+ File.WriteAllText(jsonPath, json);
+ }
+
+ public void CargarEstadoJSON()
+ {
+ string jsonPath = PathPlantillasJson();
+
+ if (File.Exists(jsonPath))
+ {
+ string json = File.ReadAllText(jsonPath);
+ ImagenEstado estadoCargado = JsonConvert.DeserializeObject(json);
+
+ // Usar reflexión para copiar todas las propiedades
+ foreach (PropertyInfo prop in typeof(ImagenEstado).GetProperties())
+ {
+ if (prop.CanRead && prop.CanWrite)
+ {
+ prop.SetValue(this, prop.GetValue(estadoCargado, null), null);
+ }
+ }
+ }
+ }
+
+
+ }
+
+}
diff --git a/MainWindow.xaml b/MainWindow.xaml
new file mode 100644
index 0000000..130232b
--- /dev/null
+++ b/MainWindow.xaml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
new file mode 100644
index 0000000..0ee07de
--- /dev/null
+++ b/MainWindow.xaml.cs
@@ -0,0 +1,490 @@
+using Newtonsoft.Json;
+using System.Diagnostics.Eventing.Reader;
+using System.IO;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using Path = System.IO.Path;
+
+
+
+namespace ROIEditor
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public partial class MainWindow : Window
+ {
+
+ private ImagenEstado EstadoImagenActual = new ImagenEstado();
+
+ private Point? clickPosition = null;
+ private bool _isDrawing = false;
+ private Point _startPosition;
+ private Rectangle _currentRect = null;
+ private Image imagenDeFondo;
+ private bool _isDragging = false;
+ private Point _lastMousePosition;
+ public dbROIs ListaDeROIs = new dbROIs();
+
+
+ // Constructor de MainWindow
+ public MainWindow()
+ {
+ InitializeComponent();
+ CargarImagenes();
+ ListaImagenes.SelectionChanged += ListaImagenes_SelectionChanged;
+
+ ImagenEnTrabajoCanvas.MouseLeftButtonDown += ImagenEnTrabajoCanvas_MouseLeftButtonDown;
+ ImagenEnTrabajoCanvas.MouseRightButtonDown += ImagenEnTrabajoCanvas_MouseRightButtonDown;
+
+ ImagenEnTrabajoCanvas.MouseDown += Canvas_MouseDown;
+ ImagenEnTrabajoCanvas.MouseMove += Canvas_MouseMove;
+ ImagenEnTrabajoScrollViewer.PreviewMouseWheel += ImagenEnTrabajoCanvas_MouseWheel;
+
+ // En el constructor de MainWindow o un método de inicialización
+ ImagenEnTrabajoCanvas.MouseDown += Canvas_MouseDown_Panning;
+ ImagenEnTrabajoCanvas.MouseMove += Canvas_MouseMove_Panning;
+ ImagenEnTrabajoCanvas.MouseUp += Canvas_MouseUp_Panning;
+
+ // Agrega este manejador en el inicializador de tu ventana o control
+ ListaROIs.SelectionChanged += ListaROIs_SelectionChanged;
+
+ // Agrega este manejador en el inicializador de tu ventana o control
+ Guardar_ROI.Click += Guardar_ROI_Click;
+
+ // Suscripción a los eventos LostFocus
+ ROI_xy.LostFocus += GuardarCambiosRoi;
+ ROI_dxdy.LostFocus += GuardarCambiosRoi;
+ ROI_nombre.LostFocus += GuardarCambiosRoi;
+ ROI_num.LostFocus += GuardarCambiosRoi;
+ ROI_descripcion.LostFocus += GuardarCambiosRoi;
+ ROI_text1.LostFocus += GuardarCambiosRoi;
+ ROI_text2.LostFocus += GuardarCambiosRoi;
+ ROI_text3.LostFocus += GuardarCambiosRoi;
+
+ }
+
+ private void ListaROIs_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ if (ListaROIs.SelectedItem is Roi selectedRoi)
+ {
+ CargarDatosROI(selectedRoi);
+ }
+ }
+
+ private void Guardar_ROI_Click(object sender, RoutedEventArgs e)
+ {
+ if (ListaROIs.SelectedItem is Roi selectedRoi)
+ {
+ ActualizarDatosROI(selectedRoi);
+ }
+ }
+
+ private void CargarDatosROI(Roi selectedRoi)
+ {
+ ROI_xy.Text = $"{selectedRoi.X}, {selectedRoi.Y}";
+ ROI_dxdy.Text = $"{selectedRoi.Width}, {selectedRoi.Height}";
+ ROI_nombre.Text = selectedRoi.Nombre;
+ ROI_num.Text = selectedRoi.CodigoNumerico.ToString();
+ ROI_descripcion.Text = selectedRoi.Descripcion;
+ ROI_text1.Text = selectedRoi.CampoTexto1;
+ ROI_text2.Text = selectedRoi.CampoTexto2;
+ ROI_text3.Text = selectedRoi.CampoTexto3;
+ }
+
+ private void ActualizarDatosROI(Roi selectedRoi)
+ {
+ try
+ {
+ // Suponiendo que se validen y parseen adecuadamente los valores
+ var xy = ROI_xy.Text.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+ var dxdy = ROI_dxdy.Text.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+
+ selectedRoi.X = int.Parse(xy[0].Trim());
+ selectedRoi.Y = int.Parse(xy[1].Trim());
+ selectedRoi.Width = int.Parse(dxdy[0].Trim());
+ selectedRoi.Height = int.Parse(dxdy[1].Trim());
+ selectedRoi.Nombre = ROI_nombre.Text;
+ selectedRoi.CodigoNumerico = int.TryParse(ROI_num.Text, out int codigo) ? codigo : 0;
+ selectedRoi.Descripcion = ROI_descripcion.Text;
+ selectedRoi.CampoTexto1 = ROI_text1.Text;
+ selectedRoi.CampoTexto2 = ROI_text2.Text;
+ selectedRoi.CampoTexto3 = ROI_text3.Text;
+
+ // Aquí podrías llamar a un método que realice el guardado específico, si es necesario
+ // Por ejemplo, actualizar la visualización del ROI o guardar en un archivo JSON
+ }
+ catch (Exception ex)
+ {
+ // Manejar posibles errores de parseo o validación
+ MessageBox.Show($"Error al actualizar los datos del ROI: {ex.Message}");
+ }
+
+ }
+
+ private void GuardarCambiosRoi(object sender, RoutedEventArgs e)
+ {
+ if (ListaROIs.SelectedItem is Roi selectedRoi)
+ {
+ ActualizarDatosROI(selectedRoi);
+ }
+ }
+
+
+ private void CargarImagenes()
+ {
+ // Asumiendo que las imágenes están en una carpeta "Imagenes" dentro del directorio de salida de tu aplicación
+ string folderPath = Path.Combine(Directory.GetCurrentDirectory(), "Plantillas");
+
+ if (Directory.Exists(folderPath))
+ {
+ var archivosImagen = Directory.GetFiles(folderPath, "*.png"); // Asumiendo que buscas archivos .png
+ foreach (var archivo in archivosImagen)
+ {
+ // Aquí simplemente añadimos el nombre del archivo a la lista, pero podrías querer añadir un objeto más complejo
+ ListaImagenes.Items.Add(Path.GetFileName(archivo));
+ }
+ }
+ else
+ {
+ MessageBox.Show("No se encontró la carpeta de imágenes.");
+ }
+ }
+
+
+ private void Canvas_MouseDown_Panning(object sender, MouseButtonEventArgs e)
+ {
+ if (e.LeftButton == MouseButtonState.Pressed && !_isDrawing)
+ {
+ // Indica que se inicia el panning
+ _isDragging = true;
+ // Guarda la posición actual del ratón
+ _lastMousePosition = e.GetPosition(ImagenEnTrabajoScrollViewer);
+ //ImagenEnTrabajoScrollViewer.CaptureMouse(); // Importante para capturar el movimiento
+ }
+ }
+
+ private void Canvas_MouseMove_Panning(object sender, MouseEventArgs e)
+ {
+ if (_isDragging && !_isDrawing)
+ {
+ // Calcula el nuevo desplazamiento basado en el movimiento del ratón
+ var currentPosition = e.GetPosition(ImagenEnTrabajoScrollViewer);
+ var dx = currentPosition.X - _lastMousePosition.X;
+ var dy = currentPosition.Y - _lastMousePosition.Y;
+
+ // Ajusta el desplazamiento del ScrollViewer
+ ImagenEnTrabajoScrollViewer.ScrollToHorizontalOffset(ImagenEnTrabajoScrollViewer.HorizontalOffset - dx);
+ ImagenEnTrabajoScrollViewer.ScrollToVerticalOffset(ImagenEnTrabajoScrollViewer.VerticalOffset - dy);
+
+ // Actualiza la posición del ratón para el próximo movimiento
+ _lastMousePosition = currentPosition;
+ }
+ }
+
+ private void Canvas_MouseUp_Panning(object sender, MouseButtonEventArgs e)
+ {
+ if (_isDragging)
+ {
+ _isDragging = false;
+ ImagenEnTrabajoScrollViewer.ReleaseMouseCapture(); // Finaliza la captura del ratón
+ }
+ }
+
+
+ private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
+ {
+ // Verifica si el botón derecho del ratón fue el que se presionó
+ if (e.ChangedButton == MouseButton.Right)
+ {
+ if (!_isDrawing)
+ {
+ _startPosition = e.GetPosition(ImagenEnTrabajoCanvas);
+ _isDrawing = true;
+
+ // Inicializar un nuevo rectángulo
+ _currentRect = new Rectangle
+ {
+ Stroke = Brushes.Red,
+ StrokeThickness = 2,
+ Fill = Brushes.Transparent
+ };
+
+ Canvas.SetLeft(_currentRect, _startPosition.X);
+ Canvas.SetTop(_currentRect, _startPosition.Y);
+ ImagenEnTrabajoCanvas.Children.Add(_currentRect);
+ }
+ else
+ {
+ // Finaliza el dibujo del rectángulo
+ _isDrawing = false;
+
+ // Calcula las dimensiones finales y posición del ROI
+ var endPosition = e.GetPosition(ImagenEnTrabajoCanvas);
+ var x = Math.Min(_startPosition.X, endPosition.X);
+ var y = Math.Min(_startPosition.Y, endPosition.Y);
+ var width = Math.Abs(endPosition.X - _startPosition.X);
+ var height = Math.Abs(endPosition.Y - _startPosition.Y);
+
+ // Crea el nuevo objeto Roi con la información recopilada
+ Roi newRoi = new Roi(EstadoImagenActual.NombreImagen, (int)x, (int)y, (int)width, (int)height);
+
+ // Agrega el nuevo Roi a la lista de ROIs
+ ListaDeROIs.Add(newRoi);
+
+ // Elimina el rectángulo temporal del Canvas
+ ImagenEnTrabajoCanvas.Children.Remove(_currentRect);
+ _currentRect = null;
+
+ // Actualiza la interfaz de usuario con el nuevo ROI
+ ActualizarUIConROIs();
+ }
+ }
+ }
+
+
+ private void ActualizarUIConROIs()
+ {
+ // Aquí actualizas los controles de la interfaz de usuario que muestran los ROIs
+ // Por ejemplo, si tienes una ListBox para los ROIs, actualízala así:
+ ListaROIs.ItemsSource = null;
+ if (ListaDeROIs.Count() > 0)
+ {
+ ListaROIs.ItemsSource = ListaDeROIs.rois;
+ }
+ DibujarROIsEnCanvas();
+ }
+
+ private void Canvas_MouseMove(object sender, MouseEventArgs e)
+ {
+ if (_isDrawing)
+ {
+ var currentPosition = e.GetPosition(ImagenEnTrabajoCanvas);
+ var width = Math.Abs(currentPosition.X - _startPosition.X);
+ var height = Math.Abs(currentPosition.Y - _startPosition.Y);
+ _currentRect.Width = width;
+ _currentRect.Height = height;
+
+ // Ajusta la posición si el dibujo se hace hacia arriba o hacia la izquierda
+ if (currentPosition.X < _startPosition.X)
+ {
+ Canvas.SetLeft(_currentRect, currentPosition.X);
+ }
+
+ if (currentPosition.Y < _startPosition.Y)
+ {
+ Canvas.SetTop(_currentRect, currentPosition.Y);
+ }
+ }
+ }
+
+ private void ImagenEnTrabajoCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
+ {
+ var st = (ScaleTransform)ImagenEnTrabajoCanvas.LayoutTransform;
+ double zoomFactor = e.Delta > 0 ? 1.1 : 0.9;
+ Point cursorPosition = e.GetPosition(ImagenEnTrabajoScrollViewer);
+
+ // Calcular el punto focal del zoom relativo al contenido del ScrollViewer
+ var absoluteX = ImagenEnTrabajoScrollViewer.HorizontalOffset + cursorPosition.X;
+ var absoluteY = ImagenEnTrabajoScrollViewer.VerticalOffset + cursorPosition.Y;
+
+ // Aplicar el zoom
+ st.ScaleX *= zoomFactor;
+ st.ScaleY *= zoomFactor;
+
+ // Calcular el nuevo desplazamiento para que el zoom se centre en la posición del cursor
+ ImagenEnTrabajoScrollViewer.UpdateLayout(); // Asegurarse de que el layout del ScrollViewer esté actualizado
+ var newHorizontalOffset = absoluteX * zoomFactor - cursorPosition.X;
+ var newVerticalOffset = absoluteY * zoomFactor - cursorPosition.Y;
+
+ // Aplicar el nuevo desplazamiento
+ ImagenEnTrabajoScrollViewer.ScrollToHorizontalOffset(newHorizontalOffset);
+ ImagenEnTrabajoScrollViewer.ScrollToVerticalOffset(newVerticalOffset);
+
+ e.Handled = true; // Evita el procesamiento adicional del evento
+ }
+
+ private void ImagenEnTrabajoCanvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
+ {
+ var mousePos = e.GetPosition(ImagenEnTrabajoCanvas);
+ // Verificar si mousePos está dentro de algún ROI y mostrar el formulario de comentario si es así
+ }
+
+ private void ImagenEnTrabajoCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+ {
+ var mousePos = e.GetPosition(ImagenEnTrabajoCanvas);
+ // Aquí puedes inicializar la creación de un nuevo ROI basándote en mousePos
+ }
+
+
+ private void CargarImagenEnTrabajo(string imagePath)
+ {
+ BitmapImage bitmap = new BitmapImage(new Uri(imagePath, UriKind.Absolute));
+
+ if (imagenDeFondo == null)
+ {
+ imagenDeFondo = new Image();
+ ImagenEnTrabajoCanvas.Children.Add(imagenDeFondo);
+ }
+ imagenDeFondo.Source = bitmap;
+ RenderOptions.SetBitmapScalingMode(imagenDeFondo, BitmapScalingMode.HighQuality);
+
+
+ // Elimina solo los ROIs, no la imagen de fondo
+ for (int i = ImagenEnTrabajoCanvas.Children.Count - 1; i >= 0; i--)
+ {
+ if (ImagenEnTrabajoCanvas.Children[i] is Rectangle)
+ {
+ ImagenEnTrabajoCanvas.Children.RemoveAt(i);
+ }
+ }
+
+ // Ajusta el tamaño del Canvas a la imagen, si es necesario
+ ImagenEnTrabajoCanvas.Width = bitmap.Width;
+ ImagenEnTrabajoCanvas.Height = bitmap.Height;
+
+ // Posiciona la imagen correctamente dentro del Canvas
+ Canvas.SetLeft(imagenDeFondo, 0);
+ Canvas.SetTop(imagenDeFondo, 0);
+
+ }
+
+ private void ListaImagenes_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ if (ListaImagenes.SelectedItem != null)
+ {
+ if (EstadoImagenActual.NombreImagen != null)
+ {
+ SalvarEstadoImagen();
+ }
+ if (ListaDeROIs.Count()>0)
+ {
+ ListaDeROIs.GuardarRois();
+ }
+ EstadoImagenActual = new ImagenEstado();
+ EstadoImagenActual.NombreImagen = ListaImagenes.SelectedItem.ToString();
+ ListaDeROIs = new dbROIs(EstadoImagenActual.NombreImagen);
+
+
+ var imagePath = EstadoImagenActual.PathPlantillasPNG();
+ CargarImagenEnTrabajo(imagePath);
+
+ CargarEstadoImagen();
+ }
+ }
+
+ private void CargarEstadoImagen()
+ {
+ string jsonPath = EstadoImagenActual.PathPlantillasJson();
+
+ if (File.Exists(jsonPath))
+ {
+ string json = File.ReadAllText(jsonPath);
+ EstadoImagenActual = JsonConvert.DeserializeObject(json);
+ var st = (ScaleTransform)ImagenEnTrabajoCanvas.LayoutTransform;
+
+ st.ScaleX= EstadoImagenActual.ZoomScaleX ;
+ st.ScaleY = EstadoImagenActual.ZoomScaleY;
+
+ // Aplicar el nuevo desplazamiento
+ ImagenEnTrabajoScrollViewer.ScrollToHorizontalOffset(EstadoImagenActual.HorizontalOffset);
+ ImagenEnTrabajoScrollViewer.ScrollToVerticalOffset(EstadoImagenActual.VerticalOffset);
+
+ DibujarROIsEnCanvas();
+ } else
+ {
+ var st = (ScaleTransform)ImagenEnTrabajoCanvas.LayoutTransform;
+ EstadoImagenActual.ZoomScaleX = st.ScaleX;
+ EstadoImagenActual.ZoomScaleY = st.ScaleY;
+ EstadoImagenActual.HorizontalOffset = EstadoImagenActual.HorizontalOffset;
+ EstadoImagenActual.VerticalOffset = EstadoImagenActual.VerticalOffset;
+ }
+ }
+
+ private void SalvarEstadoImagen()
+ {
+
+ // Cambia la extensión del archivo de imagen a .json
+ string jsonPath = EstadoImagenActual.PathPlantillasJson();
+
+ var st = (ScaleTransform)ImagenEnTrabajoCanvas.LayoutTransform;
+ EstadoImagenActual.ZoomScaleX = st.ScaleX;
+ EstadoImagenActual.ZoomScaleY = st.ScaleY;
+ EstadoImagenActual.HorizontalOffset = ImagenEnTrabajoScrollViewer.HorizontalOffset;
+ EstadoImagenActual.VerticalOffset = ImagenEnTrabajoScrollViewer.VerticalOffset;
+
+ // Serializa el estado de la imagen a JSON
+ string json = JsonConvert.SerializeObject(EstadoImagenActual, Formatting.Indented);
+
+ // Escribe el JSON en un archivo
+ File.WriteAllText(jsonPath, json);
+
+ }
+
+
+ private void DibujarROIsEnCanvas()
+ {
+ // Elimina solo los ROIs, no la imagen de fondo
+ for (int i = ImagenEnTrabajoCanvas.Children.Count - 1; i >= 0; i--)
+ {
+ if (ImagenEnTrabajoCanvas.Children[i] is Rectangle)
+ {
+ ImagenEnTrabajoCanvas.Children.RemoveAt(i);
+ }
+ }
+
+ // Dibuja los ROIs
+ foreach (var roi in ListaDeROIs.rois)
+ {
+ Rectangle rect = roi.DibujarRoiEnCanvas(ImagenEnTrabajoCanvas);
+ // Eventos
+ rect.MouseEnter += Rect_MouseEnter;
+ rect.MouseLeave += Rect_MouseLeave;
+ rect.MouseDown += Rect_MouseDown;
+ }
+
+ }
+
+ private void Rect_MouseEnter(object sender, MouseEventArgs e)
+ {
+ if (sender is Rectangle rect)
+ {
+ rect.StrokeThickness = 4; // Aumenta el grosor
+ }
+ }
+
+ private void Rect_MouseLeave(object sender, MouseEventArgs e)
+ {
+ if (sender is Rectangle rect)
+ {
+ rect.StrokeThickness = 2; // Restaura el grosor
+ }
+ }
+
+ private void Rect_MouseDown(object sender, MouseButtonEventArgs e)
+ {
+ if (sender is Rectangle rect && rect.Tag is Roi roi)
+ {
+ int index = ListaDeROIs.rois.IndexOf(roi);
+ if (index != -1)
+ {
+ ListaROIs.SelectedIndex = index; // Selecciona el ROI en la lista
+ e.Handled = true; // Evita la propagación del evento
+ }
+ }
+ }
+
+
+
+
+ }
+
+}
\ No newline at end of file
diff --git a/ROI.cs b/ROI.cs
new file mode 100644
index 0000000..8f0acd0
--- /dev/null
+++ b/ROI.cs
@@ -0,0 +1,229 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Controls;
+using System.Windows.Media;
+using System.Windows.Shapes;
+using Microsoft.Data.Sqlite;
+using System;
+using System.Collections.Generic;
+using static System.Runtime.InteropServices.JavaScript.JSType;
+
+namespace ROIEditor
+{
+
+ public class dbROIs
+ {
+ public List rois { get; set; }
+ const string dbPath = "Data Source=roiseditor.db";
+ public string NombreImagen;
+
+ public void Add(Roi r)
+ {
+ rois.Add(r);
+ }
+ public int Count() { return rois.Count; }
+
+ public dbROIs()
+ {
+ rois = new List();
+ }
+
+ public dbROIs(string nombreImagen)
+ {
+ NombreImagen = nombreImagen;
+ rois = new List();
+ CrearBaseDeDatosSiNoExiste();
+ CargarROIs();
+ }
+
+ private void CrearBaseDeDatosSiNoExiste()
+ {
+ using (var connection = new SqliteConnection(dbPath))
+ {
+ connection.Open();
+
+ var command = connection.CreateCommand();
+ command.CommandText =
+ @"
+ CREATE TABLE IF NOT EXISTS Roi (
+ Id INTEGER PRIMARY KEY AUTOINCREMENT,
+ X INTEGER NOT NULL,
+ Y INTEGER NOT NULL,
+ Width INTEGER NOT NULL,
+ Height INTEGER NOT NULL,
+ Nombre TEXT,
+ NombreImagen TEXT,
+ CodigoNumerico INTEGER,
+ Descripcion TEXT,
+ CampoTexto1 TEXT,
+ CampoTexto2 TEXT,
+ CampoTexto3 TEXT
+ );
+ ";
+ command.ExecuteNonQuery();
+ }
+ }
+ public void CargarROIs()
+ {
+ rois.Clear();
+ using (var connection = new SqliteConnection(dbPath))
+ {
+ connection.Open();
+
+ var command = connection.CreateCommand();
+ command.CommandText = @"SELECT * FROM Roi WHERE NombreImagen = $NombreImagen";
+ command.Parameters.AddWithValue("$NombreImagen", NombreImagen);
+
+ using (var reader = command.ExecuteReader())
+ {
+ while (reader.Read())
+ {
+ rois.Add(new Roi
+ {
+ X = reader.GetInt32(reader.GetOrdinal("X")),
+ Y = reader.GetInt32(reader.GetOrdinal("Y")),
+ Width = reader.GetInt32(reader.GetOrdinal("Width")),
+ Height = reader.GetInt32(reader.GetOrdinal("Height")),
+ Nombre = reader.IsDBNull(reader.GetOrdinal("Nombre")) ? null : reader.GetString(reader.GetOrdinal("Nombre")),
+ NombreImagen = reader.GetString(reader.GetOrdinal("NombreImagen")),
+ CodigoNumerico = reader.GetInt32(reader.GetOrdinal("CodigoNumerico")),
+ Descripcion = reader.IsDBNull(reader.GetOrdinal("Descripcion")) ? null : reader.GetString(reader.GetOrdinal("Descripcion")),
+ CampoTexto1 = reader.IsDBNull(reader.GetOrdinal("CampoTexto1")) ? null : reader.GetString(reader.GetOrdinal("CampoTexto1")),
+ CampoTexto2 = reader.IsDBNull(reader.GetOrdinal("CampoTexto2")) ? null : reader.GetString(reader.GetOrdinal("CampoTexto2")),
+ CampoTexto3 = reader.IsDBNull(reader.GetOrdinal("CampoTexto3")) ? null : reader.GetString(reader.GetOrdinal("CampoTexto3")),
+ });
+ }
+ }
+ }
+ }
+
+ public void GuardarRois()
+ {
+ using (var connection = new SqliteConnection(dbPath))
+ {
+ connection.Open();
+
+ var deleteCommand = connection.CreateCommand();
+ deleteCommand.CommandText = @"DELETE FROM Roi WHERE NombreImagen = $NombreImagen";
+ deleteCommand.Parameters.AddWithValue("$NombreImagen", NombreImagen);
+ deleteCommand.ExecuteNonQuery();
+ }
+
+ using (var connection = new SqliteConnection(dbPath))
+ {
+ connection.Open();
+
+ foreach (var roi in rois)
+ {
+ var insertCommand = connection.CreateCommand();
+ insertCommand.CommandText =
+ @"INSERT INTO Roi (X, Y, Width, Height, Nombre, NombreImagen, CodigoNumerico, Descripcion, CampoTexto1, CampoTexto2, CampoTexto3)
+ VALUES ($X, $Y, $Width, $Height, $Nombre, $NombreImagen, $CodigoNumerico, $Descripcion, $CampoTexto1, $CampoTexto2, $CampoTexto3)";
+
+ insertCommand.Parameters.AddWithValue("$X", roi.X);
+ insertCommand.Parameters.AddWithValue("$Y", roi.Y);
+ insertCommand.Parameters.AddWithValue("$Width", roi.Width);
+ insertCommand.Parameters.AddWithValue("$Height", roi.Height);
+ insertCommand.Parameters.AddWithValue("$Nombre", roi.Nombre ?? (object)DBNull.Value);
+ insertCommand.Parameters.AddWithValue("$NombreImagen", roi.NombreImagen);
+ insertCommand.Parameters.AddWithValue("$CodigoNumerico", roi.CodigoNumerico);
+ insertCommand.Parameters.AddWithValue("$Descripcion", roi.Descripcion ?? (object)DBNull.Value);
+ insertCommand.Parameters.AddWithValue("$CampoTexto1", roi.CampoTexto1 ?? (object)DBNull.Value);
+ insertCommand.Parameters.AddWithValue("$CampoTexto2", roi.CampoTexto2 ?? (object)DBNull.Value);
+ insertCommand.Parameters.AddWithValue("$CampoTexto3", roi.CampoTexto3 ?? (object)DBNull.Value);
+
+ insertCommand.ExecuteNonQuery();
+ }
+ }
+ }
+
+
+ public void EliminarRoi( string nombre)
+ {
+ using (var connection = new SqliteConnection(dbPath))
+ {
+ connection.Open();
+
+ var command = connection.CreateCommand();
+ command.CommandText = @"DELETE FROM Roi WHERE NombreImagen = $NombreImagen AND Nombre = $Nombre";
+ command.Parameters.AddWithValue("$NombreImagen", NombreImagen);
+ command.Parameters.AddWithValue("$Nombre", nombre);
+
+ command.ExecuteNonQuery();
+ }
+ }
+
+
+
+ }
+
+
+
+ public class Roi
+ {
+ public int X { get; set; }
+ public int Y { get; set; }
+ public int Width { get; set; }
+ public int Height { get; set; }
+ public string Nombre { get; set; }
+ public string NombreImagen { get; set; }
+ public int CodigoNumerico { get; set; }
+ public string Descripcion { get; set; }
+ public string CampoTexto1 { get; set; }
+ public string CampoTexto2 { get; set; }
+ public string CampoTexto3 { get; set; }
+
+ // Constructor sin parámetros para facilitar la deserialización
+ public Roi() { }
+
+ // Puedes agregar un constructor con parámetros si lo necesitas,
+ // para facilitar la creación de instancias de Roi con información específica.
+ public Roi(string nombreImagen, int x, int y, int width, int height, string nombre, int codigoNumerico, string descripcion, string campoTexto1, string campoTexto2, string campoTexto3)
+ {
+ X = x;
+ Y = y;
+ Width = width;
+ Height = height;
+ Nombre = nombre;
+ NombreImagen = nombreImagen;
+ CodigoNumerico = codigoNumerico;
+ Descripcion = descripcion;
+ CampoTexto1 = campoTexto1;
+ CampoTexto2 = campoTexto2;
+ CampoTexto3 = campoTexto3;
+ }
+ public Roi(string nombreImagen, int x, int y, int width, int height)
+ {
+ X = x;
+ Y = y;
+ Width = width;
+ Height = height;
+ NombreImagen = nombreImagen;
+ }
+
+
+ public Rectangle DibujarRoiEnCanvas(System.Windows.Controls.Canvas ImagenEnTrabajoCanvas)
+ {
+ Rectangle rect = new Rectangle
+ {
+ Stroke = Brushes.Red,
+ StrokeThickness = 2, // Grosor normal
+ Width = Width, // No ajustar aquí por el zoom; ajustar al aplicar el zoom si es necesario
+ Height = Height, // No ajustar aquí por el zoom; ajustar al aplicar el zoom si es necesario
+ Fill = Brushes.Transparent, // Permite la detección de eventos MouseEnter en todo el rectángulo
+ Tag = this // Almacena el Roi en el Tag para identificarlo después
+ };
+
+ Canvas.SetLeft(rect, X);
+ Canvas.SetTop(rect, Y);
+ ImagenEnTrabajoCanvas.Children.Add(rect); // Asegúrate de que esto se refiere al Canvas, no al ScrollViewer
+
+ return rect;
+ }
+ }
+
+}
diff --git a/ROIEditor.csproj b/ROIEditor.csproj
new file mode 100644
index 0000000..022abf3
--- /dev/null
+++ b/ROIEditor.csproj
@@ -0,0 +1,16 @@
+
+
+
+ WinExe
+ net8.0-windows
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
diff --git a/ROIEditor.sln b/ROIEditor.sln
new file mode 100644
index 0000000..3ba0330
--- /dev/null
+++ b/ROIEditor.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.9.34714.143
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ROIEditor", "ROIEditor.csproj", "{C65863DA-ED9E-4603-BEE3-BED19A267C0C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C65863DA-ED9E-4603-BEE3-BED19A267C0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C65863DA-ED9E-4603-BEE3-BED19A267C0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C65863DA-ED9E-4603-BEE3-BED19A267C0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C65863DA-ED9E-4603-BEE3-BED19A267C0C}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {F5432400-54BE-443D-B3B3-2AA32382F2BF}
+ EndGlobalSection
+EndGlobal
diff --git a/roiseditor.db b/roiseditor.db
new file mode 100644
index 0000000..7060eab
Binary files /dev/null and b/roiseditor.db differ
diff --git a/roiseditor.sqbpro b/roiseditor.sqbpro
new file mode 100644
index 0000000..7bded7f
--- /dev/null
+++ b/roiseditor.sqbpro
@@ -0,0 +1,14 @@
+
CREATE TABLE IF NOT EXISTS Roi (
+ Id INTEGER PRIMARY KEY AUTOINCREMENT,
+ X INTEGER NOT NULL,
+ Y INTEGER NOT NULL,
+ Width INTEGER NOT NULL,
+ Height INTEGER NOT NULL,
+ Nombre TEXT,
+ CodigoNumerico INTEGER,
+ Descripcion TEXT,
+ CampoTexto1 TEXT,
+ CampoTexto2 TEXT,
+ CampoTexto3 TEXT
+);
+