BackgroundBuilder/Services/ImageService.cs
Giuliano Paschoalino 2636848f6d Adiciona funcionalidade de upload de imagens PNG
Foi adicionada a funcionalidade de upload de imagens PNG para um
local de rede específico. No backend, a interface `IImageService`
e o serviço `ImageService` foram atualizados com o método
assíncrono `MoveFile`, que move arquivos para o destino desejado,
criando diretórios se necessário e exibindo mensagens de erro em
caso de falha.

No frontend, foi adicionado um botão "Upload" à interface gráfica
(`MainWindow.xaml`), vinculado ao comando `UploadImageCommand` no
`MainWindowViewModel`. Este comando utiliza o método privado
`UploadImageAsync` para abrir uma caixa de diálogo, permitir a
seleção de um arquivo PNG e mover o arquivo utilizando o serviço
de imagens. Feedback ao usuário é exibido para sucesso ou erro.
2025-08-28 15:24:44 -03:00

203 lines
7.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace BackgroundBuilder.Services
{
public class ImageService : IImageService
{
// no longer injected — use a private constant
private static readonly Thickness OverlayOffset = new(10, 53, 10, 53);
public async Task<BitmapImage> LoadAsync(string path)
{
// Load image from disk into BitmapImage
var bmp = new BitmapImage();
using var stream = File.OpenRead(path);
bmp.BeginInit();
bmp.UriSource = new Uri(path, UriKind.Absolute);
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.EndInit();
// no real async work—return completed task
return await Task.FromResult(bmp);
}
public async Task SaveAsync(
FrameworkElement overlay,
BitmapImage background,
string primaryPath,
string? overlayPath = null)
{
string? savedOverlayPath = null;
if (!string.IsNullOrWhiteSpace(overlayPath))
{
var overlayBmp = RenderComposite(overlay, null, new Thickness(0));
SaveBitmap(overlayBmp, overlayPath!);
savedOverlayPath = overlayPath;
}
var compositeBmp = RenderComposite(overlay, background, OverlayOffset);
SaveBitmap(compositeBmp, primaryPath);
await Task.FromResult((primaryPath, savedOverlayPath));
}
public async Task MoveFile(string sourcePath)
{
string destinationPath = "\\\\SRV-DADOS\\Wallpaper$\\Wallpaper.png";
try
{
var directory = Path.GetDirectoryName(destinationPath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory!);
}
File.Copy(sourcePath, destinationPath, true);
}
catch (Exception ex)
{
MessageBox.Show($"Erro ao mover a imagem:\n{ex.Message}\n\nCaminho: {sourcePath} para {destinationPath}");
}
await Task.CompletedTask;
}
/// <summary>
/// Renders a <paramref name="background"/> plus the <paramref name="mainGrid"/>
/// at bottomright offset by <paramref name="offset"/>. If background is null,
/// only the mainGrid is rendered at (0,0).
/// </summary>
private static RenderTargetBitmap RenderComposite(
FrameworkElement mainGrid,
BitmapImage? background,
Thickness offset,
int taskbarHeight = 0)
{
double width = background?.PixelWidth ?? mainGrid.ActualWidth;
double height = background?.PixelHeight ?? mainGrid.ActualHeight;
// Measure & arrange the mainGrid so ActualWidth/Height are valid
mainGrid.Measure(new Size(width, height));
mainGrid.Arrange(new Rect(0, 0, mainGrid.DesiredSize.Width, mainGrid.DesiredSize.Height));
double gridWidth = mainGrid.ActualWidth > 0 ? mainGrid.ActualWidth : mainGrid.DesiredSize.Width;
double gridHeight = mainGrid.ActualHeight > 0 ? mainGrid.ActualHeight : mainGrid.DesiredSize.Height;
double x;
double y;
double scale;
if (background != null)
{
// Calculate max allowed size (half background, minus taskbar for height)
double maxWidth = width;
double maxHeight = (height - taskbarHeight);
// Compute scale factor to fit within maxWidth/maxHeight, preserving aspect ratio
scale = Math.Min(1.0, Math.Min(maxWidth / gridWidth, maxHeight / gridHeight));
double scaledWidth = gridWidth * scale;
double scaledHeight = gridHeight * scale;
// Place at lower right, offset
x = width - scaledWidth - offset.Right;
y = height - scaledHeight - offset.Bottom;
gridWidth = scaledWidth;
gridHeight = scaledHeight;
}
else
{
// When rendering without background, use the mainGrid's own size and render at (0,0)
// --- Fix: Ensure full layout and hide scrollbars before rendering ---
mainGrid.UpdateLayout();
// If mainGrid is a ScrollViewer or contains one, hide scrollbars
if (mainGrid is System.Windows.Controls.ScrollViewer sv)
{
sv.HorizontalScrollBarVisibility = System.Windows.Controls.ScrollBarVisibility.Hidden;
sv.VerticalScrollBarVisibility = System.Windows.Controls.ScrollBarVisibility.Hidden;
}
// If mainGrid contains a DataGrid or similar, try to hide scrollbars
if (mainGrid is System.Windows.Controls.Panel panel)
{
foreach (var child in panel.Children)
{
if (child is System.Windows.Controls.DataGrid dg)
{
dg.HorizontalScrollBarVisibility = System.Windows.Controls.ScrollBarVisibility.Hidden;
dg.VerticalScrollBarVisibility = System.Windows.Controls.ScrollBarVisibility.Hidden;
}
}
}
// Re-measure after hiding scrollbars
mainGrid.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
mainGrid.Arrange(new Rect(0, 0, mainGrid.DesiredSize.Width, mainGrid.DesiredSize.Height));
mainGrid.UpdateLayout();
gridWidth = mainGrid.ActualWidth > 0 ? mainGrid.ActualWidth : mainGrid.DesiredSize.Width;
gridHeight = mainGrid.ActualHeight > 0 ? mainGrid.ActualHeight : mainGrid.DesiredSize.Height;
width = (int)Math.Ceiling(gridWidth);
height = (int)Math.Ceiling(gridHeight);
x = 0;
y = 0;
}
var dv = new DrawingVisual();
using (var ctx = dv.RenderOpen())
{
// Draw background if provided
if (background != null)
{
ctx.DrawImage(background, new Rect(0, 0, width, height));
}
// Draw mainGrid at calculated position, with scaling if needed
var brush = new VisualBrush(mainGrid)
{
Stretch = Stretch.Uniform,
};
ctx.DrawRectangle(brush, null, new Rect(x, y, gridWidth, gridHeight));
}
var rtb = new RenderTargetBitmap(
(int)width,
(int)height,
96,
96,
PixelFormats.Pbgra32);
rtb.Render(dv);
return rtb;
}
/// <summary>
/// Encodes the given bitmap as PNG and writes it to disk.
/// </summary>
private static void SaveBitmap(RenderTargetBitmap bitmap, string path)
{
try
{
var directory = Path.GetDirectoryName(path);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory!);
}
using var fs = new FileStream(path, FileMode.Create, FileAccess.Write);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
encoder.Save(fs);
}
catch (Exception ex)
{
MessageBox.Show($"Erro ao salvar a imagem:\n{ex.Message}\n\nCaminho: {path}");
}
}
}
}