So there was a small subtle issue with the notifications on Windows toast where the image wouldn't render correctly I changed it to the hero style which shows the album art way better

This commit is contained in:
minster586
2026-09-10 17:02:26 -04:00
parent e74fa6246a
commit 3b9437b4cb
2 changed files with 134 additions and 11 deletions
+132 -9
View File
@@ -40,6 +40,7 @@ namespace RadioDJViewer
private string currentSongImagePath = string.Empty; // Path to the current song image private string currentSongImagePath = string.Empty; // Path to the current song image
private string defaultImagePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "default.jpg"); private string defaultImagePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "default.jpg");
private string mainImagesFolderPath = string.Empty; // New field for main images folder path private string mainImagesFolderPath = string.Empty; // New field for main images folder path
private string _lastToastImagePath = string.Empty;
private Profile loadedProfile = null; // Field to store the loaded profile private Profile loadedProfile = null; // Field to store the loaded profile
private WidgetServer widgetServer = null; // Local widget HTTP server private WidgetServer widgetServer = null; // Local widget HTTP server
private bool widgetRunning = false; private bool widgetRunning = false;
@@ -283,18 +284,16 @@ namespace RadioDJViewer
} }
if (useFallback) if (useFallback)
{ {
// Use fallback PNG from resources
var fallbackImg = Properties.Resources.fallback; var fallbackImg = Properties.Resources.fallback;
if (fallbackImg != null) if (fallbackImg != null)
{ {
var resized = new Bitmap(fallbackImg, pictureBox1.Size); var resized = new Bitmap(fallbackImg, pictureBox1.Size);
pictureBox1.Image = resized; pictureBox1.Image = resized;
currentSongImagePath = defaultImagePath; currentSongImagePath = defaultImagePath;
// Save fallback image to output folder as PNG
if (!string.IsNullOrEmpty(outputFolderPath) && !string.IsNullOrEmpty(outputImageName)) if (!string.IsNullOrEmpty(outputFolderPath) && !string.IsNullOrEmpty(outputImageName))
{ {
string destPath = Path.Combine(outputFolderPath, Path.ChangeExtension(outputImageName, ".png")); string destPath = Path.Combine(outputFolderPath, Path.ChangeExtension(outputImageName, ".png"));
resized.Save(destPath, System.Drawing.Imaging.ImageFormat.Png); SaveImageAsPng(resized, destPath);
} }
} }
else else
@@ -311,17 +310,15 @@ namespace RadioDJViewer
var resized = new Bitmap(img, pictureBox1.Size); var resized = new Bitmap(img, pictureBox1.Size);
pictureBox1.Image = resized; pictureBox1.Image = resized;
currentSongImagePath = imagePath; currentSongImagePath = imagePath;
// Save to output folder as PNG
if (!string.IsNullOrEmpty(outputFolderPath) && !string.IsNullOrEmpty(outputImageName)) if (!string.IsNullOrEmpty(outputFolderPath) && !string.IsNullOrEmpty(outputImageName))
{ {
string destPath = Path.Combine(outputFolderPath, Path.ChangeExtension(outputImageName, ".png")); string destPath = Path.Combine(outputFolderPath, Path.ChangeExtension(outputImageName, ".png"));
resized.Save(destPath, System.Drawing.Imaging.ImageFormat.Png); SaveImageAsPng(resized, destPath);
} }
} }
} }
catch catch
{ {
// If loading image fails, fallback
var fallbackImg = Properties.Resources.fallback; var fallbackImg = Properties.Resources.fallback;
if (fallbackImg != null) if (fallbackImg != null)
{ {
@@ -331,7 +328,7 @@ namespace RadioDJViewer
if (!string.IsNullOrEmpty(outputFolderPath) && !string.IsNullOrEmpty(outputImageName)) if (!string.IsNullOrEmpty(outputFolderPath) && !string.IsNullOrEmpty(outputImageName))
{ {
string destPath = Path.Combine(outputFolderPath, Path.ChangeExtension(outputImageName, ".png")); string destPath = Path.Combine(outputFolderPath, Path.ChangeExtension(outputImageName, ".png"));
resized.Save(destPath, System.Drawing.Imaging.ImageFormat.Png); SaveImageAsPng(resized, destPath);
} }
} }
else else
@@ -342,6 +339,131 @@ namespace RadioDJViewer
} }
} }
private void SaveImageAsPng(Image image, string destinationPath)
{
if (image == null || string.IsNullOrWhiteSpace(destinationPath))
return;
string directory = Path.GetDirectoryName(destinationPath);
if (!string.IsNullOrWhiteSpace(directory))
Directory.CreateDirectory(directory);
string tempPath = destinationPath + ".tmp";
using (var fileStream = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.Read))
{
image.Save(fileStream, System.Drawing.Imaging.ImageFormat.Png);
fileStream.Flush(true);
}
if (File.Exists(destinationPath))
File.Delete(destinationPath);
File.Move(tempPath, destinationPath);
}
private string BuildToastImagePath()
{
try
{
string sourcePath = currentSongImagePath;
if (string.IsNullOrWhiteSpace(sourcePath) || !File.Exists(sourcePath))
sourcePath = GetProfileOutputImagePath();
if (string.IsNullOrWhiteSpace(sourcePath) || !File.Exists(sourcePath))
return string.Empty;
string toastDirectory = Path.Combine(Path.GetTempPath(), "RadioDJViewer", "ToastImages");
Directory.CreateDirectory(toastDirectory);
string toastPath = Path.Combine(toastDirectory, $"Album-Art-Hero-{DateTime.UtcNow.Ticks}.png");
using (var sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var memoryStream = new MemoryStream())
{
sourceStream.CopyTo(memoryStream);
memoryStream.Position = 0;
using (var sourceImage = Image.FromStream(memoryStream))
using (var heroImage = CreateToastHeroCanvas(sourceImage))
using (var fileStream = new FileStream(toastPath, FileMode.Create, FileAccess.Write, FileShare.Read))
{
heroImage.Save(fileStream, System.Drawing.Imaging.ImageFormat.Png);
fileStream.Flush(true);
}
}
if (!string.IsNullOrWhiteSpace(_lastToastImagePath) && !string.Equals(_lastToastImagePath, toastPath, StringComparison.OrdinalIgnoreCase))
{
try
{
if (File.Exists(_lastToastImagePath))
File.Delete(_lastToastImagePath);
}
catch { }
}
_lastToastImagePath = toastPath;
#if DEBUG
System.Diagnostics.Debug.WriteLine($"[Toast] Prepared 16:9 hero image '{toastPath}' from '{sourcePath}'");
#endif
return toastPath;
}
catch (Exception ex)
{
#if DEBUG
System.Diagnostics.Debug.WriteLine($"[Toast] Failed to prepare toast image: {ex}");
#endif
return string.Empty;
}
}
private Bitmap CreateToastHeroCanvas(Image sourceImage)
{
const double targetAspectRatio = 16d / 9d;
int sourceWidth = Math.Max(sourceImage.Width, 1);
int sourceHeight = Math.Max(sourceImage.Height, 1);
double sourceAspectRatio = (double)sourceWidth / sourceHeight;
if (sourceWidth >= sourceHeight && Math.Abs(sourceAspectRatio - targetAspectRatio) < 0.01d)
return new Bitmap(sourceImage);
int canvasWidth;
int canvasHeight;
if (sourceAspectRatio < targetAspectRatio)
{
canvasHeight = sourceHeight;
canvasWidth = (int)Math.Ceiling(canvasHeight * targetAspectRatio);
}
else
{
canvasWidth = sourceWidth;
canvasHeight = (int)Math.Ceiling(canvasWidth / targetAspectRatio);
}
canvasWidth = Math.Max(canvasWidth, sourceWidth);
canvasHeight = Math.Max(canvasHeight, sourceHeight);
var heroCanvas = new Bitmap(canvasWidth, canvasHeight, PixelFormat.Format32bppArgb);
using (var graphics = Graphics.FromImage(heroCanvas))
{
graphics.Clear(Color.Black);
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.SmoothingMode = SmoothingMode.HighQuality;
int x = (canvasWidth - sourceWidth) / 2;
int y = (canvasHeight - sourceHeight) / 2;
graphics.DrawImage(sourceImage, new Rectangle(x, y, sourceWidth, sourceHeight));
}
#if DEBUG
System.Diagnostics.Debug.WriteLine($"[Toast] Hero canvas created: source={sourceWidth}x{sourceHeight}, canvas={canvasWidth}x{canvasHeight}");
#endif
return heroCanvas;
}
private void PlaybackTimer_Tick(object sender, EventArgs e) private void PlaybackTimer_Tick(object sender, EventArgs e)
{ {
UpdatePlaybackDisplay(); UpdatePlaybackDisplay();
@@ -838,7 +960,8 @@ namespace RadioDJViewer
string safeArtist = string.IsNullOrWhiteSpace(artist) ? "No artist" : artist; string safeArtist = string.IsNullOrWhiteSpace(artist) ? "No artist" : artist;
DateTime now = DateTime.Now; DateTime now = DateTime.Now;
string attribution = $"Date: {now:MM/dd/yyyy} | Time: {now:hh:mm tt}"; string attribution = $"Date: {now:MM/dd/yyyy} | Time: {now:hh:mm tt}";
ToastNotificationService.ShowTrackChangeToast(safeTitle, safeArtist, attribution, outputImagePath); string toastImagePath = BuildToastImagePath();
ToastNotificationService.ShowTrackChangeToast(safeTitle, safeArtist, attribution, string.IsNullOrWhiteSpace(toastImagePath) ? outputImagePath : toastImagePath);
} }
private void HandleToastForTrackChange(string title, string artist) private void HandleToastForTrackChange(string title, string artist)
@@ -1014,7 +1137,7 @@ namespace RadioDJViewer
string safeImage = SecurityElement.Escape(imageUri); string safeImage = SecurityElement.Escape(imageUri);
string imageNode = string.IsNullOrWhiteSpace(safeImage) string imageNode = string.IsNullOrWhiteSpace(safeImage)
? string.Empty ? string.Empty
: $"<image placement='appLogoOverride' hint-crop='none' src='{safeImage}'/>"; : $"<image placement='hero' src='{safeImage}' hint-crop='none'/>";
#if DEBUG #if DEBUG
System.Diagnostics.Debug.WriteLine($"[Toast] Image URI used: '{imageUri}'"); System.Diagnostics.Debug.WriteLine($"[Toast] Image URI used: '{imageUri}'");
+2 -2
View File
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("1.14.3")] [assembly: AssemblyVersion("1.14.5")]
[assembly: AssemblyFileVersion("1.14.3")] [assembly: AssemblyFileVersion("1.14.5")]