BackgroundBuilder/Services/ImageService.cs

116 lines
4.1 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, 58, 10, 58);
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<(string primaryPath, string? overlayPath)> SaveAsync(
FrameworkElement overlay,
BitmapImage background,
string primaryPath,
string? overlayPath = null)
{
var compositeBmp = RenderComposite(overlay, background, OverlayOffset);
SaveBitmap(compositeBmp, primaryPath);
string? savedOverlayPath = null;
if (!string.IsNullOrWhiteSpace(overlayPath))
{
var overlayBmp = RenderComposite(overlay, null, new Thickness(0));
SaveBitmap(overlayBmp, overlayPath!);
savedOverlayPath = overlayPath;
}
return await Task.FromResult((primaryPath, savedOverlayPath));
}
/// <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)
{
// Determine canvas size
int width = background?.PixelWidth ?? (int)mainGrid.ActualWidth;
int height = background?.PixelHeight ?? (int)mainGrid.ActualHeight;
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));
}
// 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 ow = mainGrid.ActualWidth > 0 ? mainGrid.ActualWidth : mainGrid.DesiredSize.Width;
double oh = mainGrid.ActualHeight > 0 ? mainGrid.ActualHeight : mainGrid.DesiredSize.Height;
double x = width - ow - offset.Left;
double y = height - oh - offset.Right;
// Draw mainGrid at either origin or bottom-right with offset
var brush = new VisualBrush(mainGrid);
ctx.DrawRectangle(brush, null, new Rect(x, y, ow, oh));
}
var rtb = new RenderTargetBitmap(
width,
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)
{
// Ensure directory exists
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
using var fs = new FileStream(path, FileMode.Create, FileAccess.Write);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
encoder.Save(fs);
}
}
}