688 lines
27 KiB
C#
688 lines
27 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
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
|
|
|
|
/// <summary>
|
|
/// Captura screenshot de objetos específicos por sus IDs
|
|
/// </summary>
|
|
/// <param name="objectIds">Array de IDs de objetos a capturar</param>
|
|
/// <param name="paddingMeters">Padding adicional alrededor de los objetos en metros</param>
|
|
/// <param name="filename">Nombre del archivo (opcional)</param>
|
|
/// <param name="includeBackground">Si incluir imagen de fondo</param>
|
|
/// <param name="saveToFile">Si guardar el archivo</param>
|
|
/// <param name="returnBase64">Si retornar la imagen como base64</param>
|
|
/// <returns>Resultado de la captura</returns>
|
|
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)}");
|
|
|
|
// Calcular bounding box usando la misma lógica que ObjectManipulationManager
|
|
var boundingBox = CalculateObjectsBoundingBox(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
|
|
};
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Captura screenshot de un área específica en coordenadas de metros
|
|
/// </summary>
|
|
/// <param name="left">Coordenada X izquierda en metros</param>
|
|
/// <param name="top">Coordenada Y superior en metros</param>
|
|
/// <param name="width">Ancho en metros</param>
|
|
/// <param name="height">Alto en metros</param>
|
|
/// <param name="filename">Nombre del archivo (opcional)</param>
|
|
/// <param name="includeBackground">Si incluir imagen de fondo</param>
|
|
/// <param name="saveToFile">Si guardar el archivo</param>
|
|
/// <param name="returnBase64">Si retornar la imagen como base64</param>
|
|
/// <returns>Resultado de la captura</returns>
|
|
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
|
|
};
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Captura screenshot de un área centrada en coordenadas específicas
|
|
/// </summary>
|
|
/// <param name="centerX">Coordenada X del centro en metros</param>
|
|
/// <param name="centerY">Coordenada Y del centro en metros</param>
|
|
/// <param name="width">Ancho en metros</param>
|
|
/// <param name="height">Alto en metros</param>
|
|
/// <param name="filename">Nombre del archivo (opcional)</param>
|
|
/// <param name="includeBackground">Si incluir imagen de fondo</param>
|
|
/// <param name="saveToFile">Si guardar el archivo</param>
|
|
/// <param name="returnBase64">Si retornar la imagen como base64</param>
|
|
/// <returns>Resultado de la captura</returns>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Captura screenshot de todo el canvas
|
|
/// </summary>
|
|
/// <param name="filename">Nombre del archivo (opcional)</param>
|
|
/// <param name="includeBackground">Si incluir imagen de fondo</param>
|
|
/// <param name="saveToFile">Si guardar el archivo</param>
|
|
/// <param name="returnBase64">Si retornar la imagen como base64</param>
|
|
/// <returns>Resultado de la captura</returns>
|
|
public ScreenshotResult CaptureFullCanvas(
|
|
string filename = null,
|
|
bool includeBackground = true,
|
|
bool saveToFile = true,
|
|
bool returnBase64 = true)
|
|
{
|
|
try
|
|
{
|
|
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
|
|
|
|
/// <summary>
|
|
/// Busca objetos por sus IDs
|
|
/// </summary>
|
|
private List<osBase> FindObjectsByIds(string[] objectIds)
|
|
{
|
|
var allObjects = _mainViewModel.ObjetosSimulables.ToList();
|
|
var result = new List<osBase>();
|
|
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calcula el bounding box de un conjunto de objetos usando coordenadas directas
|
|
/// </summary>
|
|
private ScreenshotArea CalculateObjectsBoundingBox(List<osBase> 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
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Captura un área específica del canvas
|
|
/// </summary>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Captura todo el canvas
|
|
/// </summary>
|
|
private RenderTargetBitmap CaptureEntireCanvas(bool includeBackground)
|
|
{
|
|
_canvas.UpdateLayout();
|
|
var canvasRect = new Rect(0, 0, _canvas.ActualWidth, _canvas.ActualHeight);
|
|
return CaptureCanvasRect(canvasRect, includeBackground);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Captura un rectángulo específico del canvas en coordenadas de píxeles
|
|
/// </summary>
|
|
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");
|
|
|
|
// Configurar escala para alta calidad
|
|
var scaleFactor = 2.0; // Factor de escala para mejor calidad
|
|
var renderWidth = Math.Max(1, (int)(captureRect.Width * scaleFactor));
|
|
var renderHeight = Math.Max(1, (int)(captureRect.Height * scaleFactor));
|
|
var dpi = 96 * scaleFactor;
|
|
|
|
var renderBitmap = new RenderTargetBitmap(
|
|
renderWidth,
|
|
renderHeight,
|
|
dpi,
|
|
dpi,
|
|
PixelFormats.Pbgra32);
|
|
|
|
// Crear canvas temporal para renderizado
|
|
var tempCanvas = new Canvas()
|
|
{
|
|
Width = captureRect.Width * scaleFactor,
|
|
Height = captureRect.Height * scaleFactor,
|
|
Background = includeBackground ? _canvas.Background : Brushes.White
|
|
};
|
|
|
|
tempCanvas.RenderTransform = new ScaleTransform(scaleFactor, scaleFactor);
|
|
|
|
// Clonar elementos visibles que intersectan con el área de captura
|
|
foreach (UIElement child in _canvas.Children)
|
|
{
|
|
if (child.Visibility == Visibility.Visible)
|
|
{
|
|
try
|
|
{
|
|
var left = Canvas.GetLeft(child);
|
|
var top = Canvas.GetTop(child);
|
|
|
|
var elementRect = new Rect(
|
|
double.IsNaN(left) ? 0 : left,
|
|
double.IsNaN(top) ? 0 : top,
|
|
child.RenderSize.Width,
|
|
child.RenderSize.Height);
|
|
|
|
if (captureRect.IntersectsWith(elementRect))
|
|
{
|
|
var visualBrush = new VisualBrush(child)
|
|
{
|
|
Stretch = Stretch.None,
|
|
AlignmentX = AlignmentX.Left,
|
|
AlignmentY = AlignmentY.Top
|
|
};
|
|
|
|
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);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine($"[ScreenshotManager] Error procesando elemento: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Renderizar canvas temporal
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Procesa la salida del screenshot (guardar archivo y/o generar base64)
|
|
/// </summary>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determina si se debe generar base64 basado en las restricciones de tamaño y cantidad de objetos
|
|
/// </summary>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Obtiene la razón por la cual no se generó el base64
|
|
/// </summary>
|
|
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
|
|
|
|
/// <summary>
|
|
/// Resultado de una operación de screenshot
|
|
/// </summary>
|
|
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<CapturedObjectInfo> CapturedObjects { get; set; } = new List<CapturedObjectInfo>();
|
|
public AreaInfo BoundingBox { get; set; }
|
|
public AreaInfo CaptureArea { get; set; }
|
|
public float PaddingMeters { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Información de un objeto capturado
|
|
/// </summary>
|
|
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; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Información de un área
|
|
/// </summary>
|
|
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; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Área de screenshot en coordenadas de metros
|
|
/// </summary>
|
|
internal class ScreenshotArea
|
|
{
|
|
public float Left { get; set; }
|
|
public float Top { get; set; }
|
|
public float Width { get; set; }
|
|
public float Height { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tipos de captura de screenshot
|
|
/// </summary>
|
|
public enum ScreenshotType
|
|
{
|
|
Objects,
|
|
Area,
|
|
FullCanvas
|
|
}
|
|
|
|
#endregion
|
|
}
|