using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using CtrEditor.ObjetosSim;
using System.Diagnostics;
namespace CtrEditor.Services
{
///
/// Gestor centralizado de capturas de pantalla del canvas.
/// Proporciona funcionalidades para capturar:
/// 1. Objetos específicos por ID
/// 2. Áreas específicas en coordenadas de metros
/// 3. Todo el canvas
///
/// Utiliza la misma lógica que ObjectManipulationManager para calcular
/// las dimensiones reales de los objetos en el canvas.
///
public class ScreenshotManager
{
private readonly MainViewModel _mainViewModel;
private readonly Canvas _canvas;
private readonly string _defaultScreenshotsDirectory;
public ScreenshotManager(MainViewModel mainViewModel, Canvas canvas)
{
_mainViewModel = mainViewModel ?? throw new ArgumentNullException(nameof(mainViewModel));
_canvas = canvas ?? throw new ArgumentNullException(nameof(canvas));
_defaultScreenshotsDirectory = System.IO.Path.Combine(EstadoPersistente.Instance.directorio, "screenshots");
}
#region Public Methods
///
/// Captura screenshot de objetos específicos por sus IDs
///
/// Array de IDs de objetos a capturar
/// Padding adicional alrededor de los objetos en metros
/// Nombre del archivo (opcional)
/// Si incluir imagen de fondo
/// Si guardar el archivo
/// Si retornar la imagen como base64
/// Resultado de la captura
public ScreenshotResult CaptureObjects(
string[] objectIds,
float paddingMeters = 0.5f,
string filename = null,
bool includeBackground = false,
bool saveToFile = true,
bool returnBase64 = true)
{
try
{
if (objectIds == null || objectIds.Length == 0)
throw new ArgumentException("objectIds no puede estar vacío");
// Buscar objetos por ID
var targetObjects = FindObjectsByIds(objectIds);
if (!targetObjects.Any())
throw new ArgumentException($"No se encontraron objetos visibles con los IDs: {string.Join(", ", objectIds)}");
// SOLUCIÓN 2: Usar bounding box mejorado para objetos con dimensiones 0.0
var boundingBox = CalculateObjectsBoundingBoxImproved(targetObjects);
// Aplicar padding
var captureArea = new ScreenshotArea
{
Left = boundingBox.Left - paddingMeters,
Top = boundingBox.Top - paddingMeters,
Width = boundingBox.Width + (paddingMeters * 2),
Height = boundingBox.Height + (paddingMeters * 2)
};
// Asegurar dimensiones mínimas
captureArea.Width = Math.Max(captureArea.Width, 0.1f);
captureArea.Height = Math.Max(captureArea.Height, 0.1f);
// Capturar la imagen
var bitmap = CaptureCanvasArea(captureArea, includeBackground);
// Preparar resultado
var result = new ScreenshotResult
{
Success = true,
Bitmap = bitmap,
CaptureType = ScreenshotType.Objects,
CapturedObjects = targetObjects.Select(obj => new CapturedObjectInfo
{
Id = obj.Id.Value.ToString(),
Name = obj.Nombre,
Type = obj.GetType().Name,
Left = obj.Left,
Top = obj.Top,
Width = obj.Ancho,
Height = obj.Alto,
CenterX = obj.Left + obj.Ancho / 2,
CenterY = obj.Top + obj.Alto / 2
}).ToList(),
BoundingBox = new AreaInfo
{
Left = boundingBox.Left,
Top = boundingBox.Top,
Width = boundingBox.Width,
Height = boundingBox.Height,
CenterX = boundingBox.Left + boundingBox.Width / 2,
CenterY = boundingBox.Top + boundingBox.Height / 2
},
CaptureArea = new AreaInfo
{
Left = captureArea.Left,
Top = captureArea.Top,
Width = captureArea.Width,
Height = captureArea.Height,
CenterX = captureArea.Left + captureArea.Width / 2,
CenterY = captureArea.Top + captureArea.Height / 2
},
PaddingMeters = paddingMeters,
IncludeBackground = includeBackground
};
// Guardar archivo y/o generar base64
return ProcessScreenshotOutput(result, filename, saveToFile, returnBase64);
}
catch (Exception ex)
{
return new ScreenshotResult
{
Success = false,
ErrorMessage = ex.Message,
ErrorType = ex.GetType().Name
};
}
}
///
/// Captura screenshot de un área específica en coordenadas de metros
///
/// Coordenada X izquierda en metros
/// Coordenada Y superior en metros
/// Ancho en metros
/// Alto en metros
/// Nombre del archivo (opcional)
/// Si incluir imagen de fondo
/// Si guardar el archivo
/// Si retornar la imagen como base64
/// Resultado de la captura
public ScreenshotResult CaptureArea(
float left,
float top,
float width,
float height,
string filename = null,
bool includeBackground = false,
bool saveToFile = true,
bool returnBase64 = true)
{
try
{
if (width <= 0 || height <= 0)
throw new ArgumentException("Width y height deben ser mayores que 0");
var captureArea = new ScreenshotArea
{
Left = left,
Top = top,
Width = width,
Height = height
};
var bitmap = CaptureCanvasArea(captureArea, includeBackground);
var result = new ScreenshotResult
{
Success = true,
Bitmap = bitmap,
CaptureType = ScreenshotType.Area,
CaptureArea = new AreaInfo
{
Left = left,
Top = top,
Width = width,
Height = height,
CenterX = left + width / 2,
CenterY = top + height / 2
},
IncludeBackground = includeBackground
};
return ProcessScreenshotOutput(result, filename, saveToFile, returnBase64);
}
catch (Exception ex)
{
return new ScreenshotResult
{
Success = false,
ErrorMessage = ex.Message,
ErrorType = ex.GetType().Name
};
}
}
///
/// Captura screenshot de un área centrada en coordenadas específicas
///
/// Coordenada X del centro en metros
/// Coordenada Y del centro en metros
/// Ancho en metros
/// Alto en metros
/// Nombre del archivo (opcional)
/// Si incluir imagen de fondo
/// Si guardar el archivo
/// Si retornar la imagen como base64
/// Resultado de la captura
public ScreenshotResult CaptureCenteredArea(
float centerX,
float centerY,
float width,
float height,
string filename = null,
bool includeBackground = false,
bool saveToFile = true,
bool returnBase64 = true)
{
var left = centerX - width / 2;
var top = centerY - height / 2;
return CaptureArea(left, top, width, height, filename, includeBackground, saveToFile, returnBase64);
}
///
/// Captura screenshot de todo el canvas con auto-zoom inteligente
///
/// Nombre del archivo (opcional)
/// Si incluir imagen de fondo
/// Si guardar el archivo
/// Si retornar la imagen como base64
/// Si usar auto-zoom a área con objetos (por defecto true)
/// Resultado de la captura
public ScreenshotResult CaptureFullCanvas(
string filename = null,
bool includeBackground = true,
bool saveToFile = true,
bool returnBase64 = true,
bool autoZoom = true)
{
try
{
// SOLUCIÓN 1: Auto-zoom inteligente
if (autoZoom)
{
var visibleObjects = _mainViewModel.ObjetosSimulables
.Where(o => o.Show_On_This_Page).ToList();
if (visibleObjects.Any())
{
try
{
var bounds = CalculateObjectsBoundingBoxImproved(visibleObjects);
var padding = Math.Max(2.0f, Math.Max(bounds.Width, bounds.Height) * 0.2f);
Trace.WriteLine($"[ScreenshotManager] Auto-zoom detectado: área {bounds.Width:F1}×{bounds.Height:F1}m, padding {padding:F1}m");
return CaptureArea(
bounds.Left - padding,
bounds.Top - padding,
bounds.Width + (padding * 2),
bounds.Height + (padding * 2),
filename, includeBackground, saveToFile, returnBase64);
}
catch (Exception ex)
{
Trace.WriteLine($"[ScreenshotManager] Auto-zoom falló: {ex.Message}, usando canvas completo");
}
}
}
// Fallback a canvas completo
var bitmap = CaptureEntireCanvas(includeBackground);
var canvasWidthMeters = PixelToMeter.Instance.calc.PixelsToMeters((float)_canvas.ActualWidth);
var canvasHeightMeters = PixelToMeter.Instance.calc.PixelsToMeters((float)_canvas.ActualHeight);
var result = new ScreenshotResult
{
Success = true,
Bitmap = bitmap,
CaptureType = ScreenshotType.FullCanvas,
CaptureArea = new AreaInfo
{
Left = 0,
Top = 0,
Width = canvasWidthMeters,
Height = canvasHeightMeters,
CenterX = canvasWidthMeters / 2,
CenterY = canvasHeightMeters / 2
},
IncludeBackground = includeBackground
};
return ProcessScreenshotOutput(result, filename, saveToFile, returnBase64);
}
catch (Exception ex)
{
return new ScreenshotResult
{
Success = false,
ErrorMessage = ex.Message,
ErrorType = ex.GetType().Name
};
}
}
#endregion
#region Private Helper Methods
///
/// Busca objetos por sus IDs
///
private List FindObjectsByIds(string[] objectIds)
{
var allObjects = _mainViewModel.ObjetosSimulables.ToList();
var result = new List();
foreach (var objectId in objectIds)
{
var obj = allObjects.FirstOrDefault(o => o.Id.Value.ToString() == objectId);
if (obj != null && obj.Show_On_This_Page)
{
result.Add(obj);
Console.WriteLine($"DEBUG: Object {objectId} ADDED - Type: {obj.GetType().Name}, Left: {obj.Left}, Top: {obj.Top}");
}
else
{
Console.WriteLine($"DEBUG: Object {objectId} REJECTED - Found: {obj != null}, Show_On_This_Page: {obj?.Show_On_This_Page}");
}
}
Console.WriteLine($"DEBUG: Total objects found: {result.Count}");
return result;
}
///
/// Calcula el bounding box de un conjunto de objetos usando coordenadas directas
///
private ScreenshotArea CalculateObjectsBoundingBox(List objects)
{
if (!objects.Any())
throw new ArgumentException("La lista de objetos no puede estar vacía");
float left = float.MaxValue;
float top = float.MaxValue;
float right = float.MinValue;
float bottom = float.MinValue;
foreach (var obj in objects)
{
// Usar coordenadas directas del objeto (ya están en metros)
float objLeft = obj.Left;
float objTop = obj.Top;
float objRight = obj.Left + obj.Ancho;
float objBottom = obj.Top + obj.Alto;
left = Math.Min(left, objLeft);
top = Math.Min(top, objTop);
right = Math.Max(right, objRight);
bottom = Math.Max(bottom, objBottom);
Console.WriteLine($"DEBUG: Object {obj.Id.Value} bounds - L:{objLeft} T:{objTop} R:{objRight} B:{objBottom}");
}
if (left == float.MaxValue) // No se encontraron objetos válidos
throw new InvalidOperationException("No se encontraron objetos válidos para calcular el bounding box");
Console.WriteLine($"DEBUG: Final bounding box - L:{left} T:{top} W:{right - left} H:{bottom - top}");
return new ScreenshotArea
{
Left = left,
Top = top,
Width = right - left,
Height = bottom - top
};
}
///
/// SOLUCIÓN 2: Calcula el bounding box mejorado que maneja objetos con dimensiones 0.0
///
private ScreenshotArea CalculateObjectsBoundingBoxImproved(List objects)
{
if (!objects.Any())
throw new ArgumentException("La lista de objetos no puede estar vacía");
float left = float.MaxValue;
float top = float.MaxValue;
float right = float.MinValue;
float bottom = float.MinValue;
foreach (var obj in objects)
{
// Obtener dimensiones reales del objeto
float objWidth = obj.Ancho;
float objHeight = obj.Alto;
// SOLUCIÓN 2: Manejar objetos con dimensiones 0.0 (como botellas)
if (objWidth <= 0.0f || objHeight <= 0.0f)
{
// Usar dimensiones por defecto basadas en el tipo de objeto
if (obj.GetType().Name == "osBotella")
{
objWidth = 0.2f; // 20cm por defecto para botellas
objHeight = 0.2f;
}
else
{
objWidth = Math.Max(objWidth, 0.1f); // Mínimo 10cm
objHeight = Math.Max(objHeight, 0.1f);
}
}
float objLeft = obj.Left - objWidth / 2; // Centrar el objeto
float objTop = obj.Top - objHeight / 2;
float objRight = obj.Left + objWidth / 2;
float objBottom = obj.Top + objHeight / 2;
left = Math.Min(left, objLeft);
top = Math.Min(top, objTop);
right = Math.Max(right, objRight);
bottom = Math.Max(bottom, objBottom);
Trace.WriteLine($"[ScreenshotManager] Object {obj.Id.Value} ({obj.GetType().Name}) - Original: {obj.Ancho}×{obj.Alto}, Used: {objWidth}×{objHeight}");
}
if (left == float.MaxValue)
throw new InvalidOperationException("No se encontraron objetos válidos para calcular el bounding box");
var finalWidth = right - left;
var finalHeight = bottom - top;
// Asegurar dimensiones mínimas
if (finalWidth < 0.5f)
{
var center = (left + right) / 2;
left = center - 0.25f;
right = center + 0.25f;
finalWidth = 0.5f;
}
if (finalHeight < 0.5f)
{
var center = (top + bottom) / 2;
top = center - 0.25f;
bottom = center + 0.25f;
finalHeight = 0.5f;
}
Trace.WriteLine($"[ScreenshotManager] Bounding box mejorado - L:{left:F2} T:{top:F2} W:{finalWidth:F2} H:{finalHeight:F2}");
return new ScreenshotArea
{
Left = left,
Top = top,
Width = finalWidth,
Height = finalHeight
};
}
///
/// Captura un área específica del canvas
///
private RenderTargetBitmap CaptureCanvasArea(ScreenshotArea area, bool includeBackground)
{
// Asegurar que el canvas esté actualizado
_canvas.UpdateLayout();
// Convertir área de metros a píxeles
var pixelLeft = PixelToMeter.Instance.calc.MetersToPixels(area.Left);
var pixelTop = PixelToMeter.Instance.calc.MetersToPixels(area.Top);
var pixelWidth = PixelToMeter.Instance.calc.MetersToPixels(area.Width);
var pixelHeight = PixelToMeter.Instance.calc.MetersToPixels(area.Height);
var captureRect = new Rect(pixelLeft, pixelTop, pixelWidth, pixelHeight);
// Validar que el área esté dentro del canvas
var canvasRect = new Rect(0, 0, _canvas.ActualWidth, _canvas.ActualHeight);
if (!canvasRect.IntersectsWith(captureRect))
throw new ArgumentException("El área especificada está fuera del canvas");
// Intersectar con el canvas para evitar áreas fuera de límites
captureRect.Intersect(canvasRect);
return CaptureCanvasRect(captureRect, includeBackground);
}
///
/// Captura todo el canvas
///
private RenderTargetBitmap CaptureEntireCanvas(bool includeBackground)
{
_canvas.UpdateLayout();
var canvasRect = new Rect(0, 0, _canvas.ActualWidth, _canvas.ActualHeight);
return CaptureCanvasRect(canvasRect, includeBackground);
}
///
/// SOLUCIÓN 3: Captura un rectángulo específico del canvas usando DrawingVisual (sin VisualBrush)
///
private RenderTargetBitmap CaptureCanvasRect(Rect captureRect, bool includeBackground)
{
if (captureRect.Width <= 0 || captureRect.Height <= 0)
throw new ArgumentException("Las dimensiones de captura deben ser mayores que 0");
// SOLUCIÓN 3: Reducir scaleFactor de 2.0 a 1.0 para evitar problemas de memoria
var scaleFactor = 1.0; // Reducido para mayor estabilidad
var renderWidth = Math.Max(1, (int)(captureRect.Width * scaleFactor));
var renderHeight = Math.Max(1, (int)(captureRect.Height * scaleFactor));
var dpi = 96 * scaleFactor;
Trace.WriteLine($"[ScreenshotManager] Capturando {renderWidth}×{renderHeight} px (scaleFactor: {scaleFactor})");
var renderBitmap = new RenderTargetBitmap(
renderWidth,
renderHeight,
dpi,
dpi,
PixelFormats.Pbgra32);
// SOLUCIÓN 3 CORREGIDA: Enfoque híbrido - Canvas temporal con VisualBrush mejorado
var tempCanvas = new Canvas()
{
Width = captureRect.Width * scaleFactor,
Height = captureRect.Height * scaleFactor,
Background = includeBackground ? _canvas.Background : Brushes.White
};
tempCanvas.RenderTransform = new ScaleTransform(scaleFactor, scaleFactor);
// Forzar actualización de layout del canvas principal antes de capturar
_canvas.UpdateLayout();
_canvas.InvalidateVisual();
// Renderizar elementos con VisualBrush mejorado
int elementCount = 0;
foreach (UIElement child in _canvas.Children)
{
if (ValidateElementForCapture(child, captureRect))
{
try
{
var left = Canvas.GetLeft(child);
var top = Canvas.GetTop(child);
// SOLUCIÓN 3: Validación mejorada de coordenadas
if (double.IsNaN(left)) left = 0;
if (double.IsNaN(top)) top = 0;
if (double.IsInfinity(left) || double.IsInfinity(top)) continue;
var elementRect = new Rect(left, top, child.RenderSize.Width, child.RenderSize.Height);
if (captureRect.IntersectsWith(elementRect))
{
// Forzar actualización del UserControl
child.UpdateLayout();
child.InvalidateVisual();
// Usar VisualBrush mejorado con manejo robusto de errores
try
{
var visualBrush = new VisualBrush(child)
{
Stretch = Stretch.None,
AlignmentX = AlignmentX.Left,
AlignmentY = AlignmentY.Top,
ViewboxUnits = BrushMappingMode.Absolute,
Viewbox = new Rect(0, 0, child.RenderSize.Width, child.RenderSize.Height)
};
var rect = new Rectangle()
{
Width = child.RenderSize.Width * scaleFactor,
Height = child.RenderSize.Height * scaleFactor,
Fill = visualBrush
};
Canvas.SetLeft(rect, (elementRect.X - captureRect.X) * scaleFactor);
Canvas.SetTop(rect, (elementRect.Y - captureRect.Y) * scaleFactor);
tempCanvas.Children.Add(rect);
elementCount++;
Trace.WriteLine($"[ScreenshotManager] Capturado UserControl: {child.GetType().Name} en ({elementRect.X:F1}, {elementRect.Y:F1})");
}
catch (Exception brushEx)
{
Trace.WriteLine($"[ScreenshotManager] Error con VisualBrush para {child.GetType().Name}: {brushEx.Message}");
// Fallback: Rectángulo de placeholder
var placeholder = new Rectangle()
{
Width = child.RenderSize.Width * scaleFactor,
Height = child.RenderSize.Height * scaleFactor,
Fill = Brushes.LightGray,
Stroke = Brushes.Red,
StrokeThickness = 2
};
Canvas.SetLeft(placeholder, (elementRect.X - captureRect.X) * scaleFactor);
Canvas.SetTop(placeholder, (elementRect.Y - captureRect.Y) * scaleFactor);
tempCanvas.Children.Add(placeholder);
}
}
}
catch (Exception ex)
{
Trace.WriteLine($"[ScreenshotManager] Error procesando elemento {child.GetType().Name}: {ex.Message}");
}
}
}
Trace.WriteLine($"[ScreenshotManager] Renderizados {elementCount} elementos UserControl");
// Renderizar canvas temporal mejorado
var scaledSize = new Size(captureRect.Width * scaleFactor, captureRect.Height * scaleFactor);
tempCanvas.Measure(scaledSize);
tempCanvas.Arrange(new Rect(0, 0, scaledSize.Width, scaledSize.Height));
tempCanvas.UpdateLayout();
renderBitmap.Render(tempCanvas);
return renderBitmap;
}
///
/// SOLUCIÓN 3: Valida si un elemento debe ser incluido en la captura
///
private bool ValidateElementForCapture(UIElement element, Rect captureRect)
{
if (element.Visibility != Visibility.Visible)
return false;
if (element.RenderSize.Width <= 0 || element.RenderSize.Height <= 0)
return false;
var left = Canvas.GetLeft(element);
var top = Canvas.GetTop(element);
// Validación mejorada de posiciones
if (double.IsNaN(left) || double.IsNaN(top) ||
double.IsInfinity(left) || double.IsInfinity(top))
return false;
var elementRect = new Rect(left, top, element.RenderSize.Width, element.RenderSize.Height);
return captureRect.IntersectsWith(elementRect);
}
///
/// Procesa la salida del screenshot (guardar archivo y/o generar base64)
///
private ScreenshotResult ProcessScreenshotOutput(ScreenshotResult result, string filename, bool saveToFile, bool returnBase64)
{
try
{
// Generar nombre de archivo si no se proporcionó
if (string.IsNullOrEmpty(filename))
{
var typePrefix = result.CaptureType.ToString().ToLower();
filename = $"{typePrefix}_screenshot_{DateTime.Now:yyyyMMdd_HHmmss}.png";
}
// Asegurar extensión .png
if (!filename.ToLower().EndsWith(".png"))
filename += ".png";
// Guardar archivo si se solicita
if (saveToFile)
{
Directory.CreateDirectory(_defaultScreenshotsDirectory);
var fullPath = System.IO.Path.IsPathRooted(filename) ? filename : System.IO.Path.Combine(_defaultScreenshotsDirectory, filename);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(result.Bitmap));
using (var fileStream = new FileStream(fullPath, FileMode.Create))
{
encoder.Save(fileStream);
}
var fileInfo = new FileInfo(fullPath);
result.FilePath = fullPath;
result.FileName = System.IO.Path.GetFileName(fullPath);
result.Directory = System.IO.Path.GetDirectoryName(fullPath);
result.FileSizeBytes = fileInfo.Length;
}
// Generar base64 solo si se cumplen las condiciones restrictivas
if (returnBase64 && ShouldGenerateBase64(result))
{
using (var memoryStream = new MemoryStream())
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(result.Bitmap));
encoder.Save(memoryStream);
result.Base64Data = Convert.ToBase64String(memoryStream.ToArray());
}
}
else if (returnBase64)
{
// Informar por qué no se generó el base64
result.Base64SkipReason = GetBase64SkipReason(result);
}
result.Timestamp = DateTime.Now;
return result;
}
catch (Exception ex)
{
result.Success = false;
result.ErrorMessage = $"Error procesando salida: {ex.Message}";
result.ErrorType = ex.GetType().Name;
return result;
}
}
///
/// Determina si se debe generar base64 basado en las restricciones de tamaño y cantidad de objetos
///
private bool ShouldGenerateBase64(ScreenshotResult result)
{
const int MAX_DIMENSION = 1024;
// Solo permitir base64 para objetos únicos
if (result.CaptureType == ScreenshotType.Objects && (result.CapturedObjects?.Count != 1))
{
return false;
}
// Verificar dimensiones de la imagen
if (result.Bitmap != null)
{
if (result.Bitmap.PixelWidth > MAX_DIMENSION || result.Bitmap.PixelHeight > MAX_DIMENSION)
{
return false;
}
}
// No generar base64 para canvas completo o áreas grandes
if (result.CaptureType == ScreenshotType.FullCanvas)
{
return false;
}
return true;
}
///
/// Obtiene la razón por la cual no se generó el base64
///
private string GetBase64SkipReason(ScreenshotResult result)
{
const int MAX_DIMENSION = 1024;
if (result.CaptureType == ScreenshotType.FullCanvas)
{
return "Base64 no generado: Canvas completo excede límites de tokens";
}
if (result.CaptureType == ScreenshotType.Objects && (result.CapturedObjects?.Count != 1))
{
return $"Base64 no generado: Solo se permite para objetos únicos (encontrados: {result.CapturedObjects?.Count ?? 0})";
}
if (result.Bitmap != null && (result.Bitmap.PixelWidth > MAX_DIMENSION || result.Bitmap.PixelHeight > MAX_DIMENSION))
{
return $"Base64 no generado: Imagen excede {MAX_DIMENSION}x{MAX_DIMENSION} píxeles (actual: {result.Bitmap.PixelWidth}x{result.Bitmap.PixelHeight})";
}
return "Base64 no generado: Condiciones no cumplidas";
}
#endregion
}
#region Data Classes
///
/// Resultado de una operación de screenshot
///
public class ScreenshotResult
{
public bool Success { get; set; }
public string ErrorMessage { get; set; }
public string ErrorType { get; set; }
public RenderTargetBitmap Bitmap { get; set; }
public ScreenshotType CaptureType { get; set; }
public string FilePath { get; set; }
public string FileName { get; set; }
public string Directory { get; set; }
public long FileSizeBytes { get; set; }
public string Base64Data { get; set; }
public string Base64SkipReason { get; set; }
public DateTime Timestamp { get; set; }
public bool IncludeBackground { get; set; }
public List CapturedObjects { get; set; } = new List();
public AreaInfo BoundingBox { get; set; }
public AreaInfo CaptureArea { get; set; }
public float PaddingMeters { get; set; }
}
///
/// Información de un objeto capturado
///
public class CapturedObjectInfo
{
public string Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public float Left { get; set; }
public float Top { get; set; }
public float Width { get; set; }
public float Height { get; set; }
public float CenterX { get; set; }
public float CenterY { get; set; }
}
///
/// Información de un área
///
public class AreaInfo
{
public float Left { get; set; }
public float Top { get; set; }
public float Width { get; set; }
public float Height { get; set; }
public float CenterX { get; set; }
public float CenterY { get; set; }
}
///
/// Área de screenshot en coordenadas de metros
///
internal class ScreenshotArea
{
public float Left { get; set; }
public float Top { get; set; }
public float Width { get; set; }
public float Height { get; set; }
}
///
/// Tipos de captura de screenshot
///
public enum ScreenshotType
{
Objects,
Area,
FullCanvas
}
#endregion
}