diff --git a/Source/LibationAvalonia/AvaloniaUtils.cs b/Source/LibationAvalonia/AvaloniaUtils.cs index 9a9d669d..9a1090be 100644 --- a/Source/LibationAvalonia/AvaloniaUtils.cs +++ b/Source/LibationAvalonia/AvaloniaUtils.cs @@ -1,6 +1,8 @@ using Avalonia.Controls; using Avalonia.Media; +using Avalonia.Media.Imaging; using LibationAvalonia.Dialogs; +using LibationFileManager; using System.Threading.Tasks; namespace LibationAvalonia @@ -20,5 +22,21 @@ namespace LibationAvalonia => dialogWindow.ShowDialog(owner ?? App.MainWindow); public static Window GetParentWindow(this IControl control) => control.VisualRoot as Window; + + + private static Bitmap defaultImage; + public static Bitmap TryLoadImageOrDefault(byte[] picture, PictureSize defaultSize = PictureSize.Native) + { + try + { + using var ms = new System.IO.MemoryStream(picture); + return new Bitmap(ms); + } + catch + { + using var ms = new System.IO.MemoryStream(PictureStorage.GetDefaultImage(defaultSize)); + return defaultImage ??= new Bitmap(ms); + } + } } } diff --git a/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs index 21b1527c..2896c08b 100644 --- a/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs @@ -1,5 +1,4 @@ using ApplicationServices; -using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; using Avalonia.Media.Imaging; @@ -10,7 +9,6 @@ using LibationAvalonia.ViewModels; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using System; namespace LibationAvalonia.Dialogs { @@ -112,8 +110,7 @@ namespace LibationAvalonia.Dialogs //init cover image var picture = PictureStorage.GetPictureSynchronously(new PictureDefinition(libraryBook.Book.PictureId, PictureSize._80x80)); - using var ms = new System.IO.MemoryStream(picture); - Cover = new Bitmap(ms); + Cover = AvaloniaUtils.TryLoadImageOrDefault(picture, PictureSize._80x80); //init book details DetailsText = @$" diff --git a/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs index 837ef7ab..048b2416 100644 --- a/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs @@ -2,7 +2,6 @@ using Avalonia.Markup.Xaml; using Avalonia.Media.Imaging; using System; using System.ComponentModel; -using System.IO; using ReactiveUI; using Avalonia.Platform.Storage; @@ -29,17 +28,7 @@ namespace LibationAvalonia.Dialogs public void SetCoverBytes(byte[] cover) { - try - { - var ms = new MemoryStream(cover); - _bitmapHolder.CoverImage = new Bitmap(ms); - } - catch (Exception ex) - { - Serilog.Log.Logger.Error(ex, "Error loading cover art for {file}", PictureFileName); - using var ms = App.OpenAsset("img-coverart-prod-unavailable_500x500.jpg"); - _bitmapHolder.CoverImage = new Bitmap(ms); - } + _bitmapHolder.CoverImage = AvaloniaUtils.TryLoadImageOrDefault(cover); } public async void SaveImage_Clicked(object sender, Avalonia.Interactivity.RoutedEventArgs e) diff --git a/Source/LibationAvalonia/ViewModels/AvaloniaEntryStatus.cs b/Source/LibationAvalonia/ViewModels/AvaloniaEntryStatus.cs index e484206c..2664489f 100644 --- a/Source/LibationAvalonia/ViewModels/AvaloniaEntryStatus.cs +++ b/Source/LibationAvalonia/ViewModels/AvaloniaEntryStatus.cs @@ -8,28 +8,17 @@ namespace LibationAvalonia.ViewModels { public class AvaloniaEntryStatus : EntryStatus, IEntryStatus, IComparable { - private static Bitmap _defaultImage; public override IBrush BackgroundBrush => IsEpisode ? App.SeriesEntryGridBackgroundBrush : Brushes.Transparent; private AvaloniaEntryStatus(LibraryBook libraryBook) : base(libraryBook) { } public static EntryStatus Create(LibraryBook libraryBook) => new AvaloniaEntryStatus(libraryBook); protected override Bitmap LoadImage(byte[] picture) - { - try - { - using var ms = new System.IO.MemoryStream(picture); - return new Bitmap(ms); - } - catch (Exception ex) - { - Serilog.Log.Logger.Error(ex, "Error loading cover art for {Book}", Book); - return _defaultImage ??= new Bitmap(App.OpenAsset("img-coverart-prod-unavailable_80x80.jpg")); - } - } + => AvaloniaUtils.TryLoadImageOrDefault(picture, LibationFileManager.PictureSize._80x80); protected override Bitmap GetResourceImage(string rescName) { + //These images are assest, so assume they will never corrupt. using var stream = App.OpenAsset(rescName + ".png"); return new Bitmap(stream); } diff --git a/Source/LibationAvalonia/ViewModels/ProcessBookViewModel.cs b/Source/LibationAvalonia/ViewModels/ProcessBookViewModel.cs index ef7fe809..58dfe144 100644 --- a/Source/LibationAvalonia/ViewModels/ProcessBookViewModel.cs +++ b/Source/LibationAvalonia/ViewModels/ProcessBookViewModel.cs @@ -115,16 +115,14 @@ namespace LibationAvalonia.ViewModels PictureStorage.PictureCached += PictureStorage_PictureCached; // Mutable property. Set the field so PropertyChanged isn't fired. - using var ms = new System.IO.MemoryStream(picture); - _cover = new Bitmap(ms); + _cover = AvaloniaUtils.TryLoadImageOrDefault(picture, PictureSize._80x80); } private void PictureStorage_PictureCached(object sender, PictureCachedEventArgs e) { if (e.Definition.PictureId == LibraryBook.Book.PictureId) { - using var ms = new System.IO.MemoryStream(e.Picture); - Cover = new Bitmap(ms); + Cover = AvaloniaUtils.TryLoadImageOrDefault(e.Picture, PictureSize._80x80); PictureStorage.PictureCached -= PictureStorage_PictureCached; } } diff --git a/Source/LibationFileManager/PictureStorage.cs b/Source/LibationFileManager/PictureStorage.cs index 5360501a..e3081038 100644 --- a/Source/LibationFileManager/PictureStorage.cs +++ b/Source/LibationFileManager/PictureStorage.cs @@ -67,7 +67,7 @@ namespace LibationFileManager } DownloadQueue.Add(def); - return (true, getDefaultImage(def.Size)); + return (true, GetDefaultImage(def.Size)); } } @@ -96,7 +96,7 @@ namespace LibationFileManager public static void SetDefaultImage(PictureSize pictureSize, byte[] bytes) => defaultImages[pictureSize] = bytes; - private static byte[] getDefaultImage(PictureSize size) + public static byte[] GetDefaultImage(PictureSize size) => defaultImages.ContainsKey(size) ? defaultImages[size] : new byte[0]; @@ -120,7 +120,7 @@ namespace LibationFileManager private static byte[] downloadBytes(PictureDefinition def) { if (def.PictureId is null) - return getDefaultImage(def.Size); + return GetDefaultImage(def.Size); try { @@ -135,7 +135,7 @@ namespace LibationFileManager } catch { - return getDefaultImage(def.Size); + return GetDefaultImage(def.Size); } } } diff --git a/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs b/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs index ccb04746..be111a04 100644 --- a/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs +++ b/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using DataLayer; @@ -42,7 +41,7 @@ namespace LibationWinForms.Dialogs this.Text = Book.Title; (_, var picture) = PictureStorage.GetPicture(new PictureDefinition(Book.PictureId, PictureSize._80x80)); - this.coverPb.Image = Dinah.Core.WindowsDesktop.Drawing.ImageReader.ToImage(picture); + this.coverPb.Image = WinFormsUtil.TryLoadImageOrDefault(picture, PictureSize._80x80); var t = @$" Title: {Book.Title} diff --git a/Source/LibationWinForms/GridView/ImageDisplay.cs b/Source/LibationWinForms/GridView/ImageDisplay.cs index 36419f3b..0f04bb2e 100644 --- a/Source/LibationWinForms/GridView/ImageDisplay.cs +++ b/Source/LibationWinForms/GridView/ImageDisplay.cs @@ -19,15 +19,7 @@ namespace LibationWinForms.GridView public void SetCoverArt(byte[] cover) { - try - { - pictureBox1.Image = Dinah.Core.WindowsDesktop.Drawing.ImageReader.ToImage(cover); - } - catch (Exception ex) - { - Serilog.Log.Logger.Error(ex, "Error loading cover art for {file}", PictureFileName); - pictureBox1.Image = Properties.Resources.default_cover_500x500; - } + pictureBox1.Image = WinFormsUtil.TryLoadImageOrDefault(cover); } #region Make the form's aspect ratio always match the picture's aspect ratio. diff --git a/Source/LibationWinForms/GridView/WinFormsEntryStatus.cs b/Source/LibationWinForms/GridView/WinFormsEntryStatus.cs index e9c679d9..0a24361a 100644 --- a/Source/LibationWinForms/GridView/WinFormsEntryStatus.cs +++ b/Source/LibationWinForms/GridView/WinFormsEntryStatus.cs @@ -1,7 +1,5 @@ using DataLayer; -using Dinah.Core.WindowsDesktop.Drawing; using LibationUiBase.GridView; -using System; using System.Drawing; namespace LibationWinForms.GridView @@ -14,23 +12,12 @@ namespace LibationWinForms.GridView private WinFormsEntryStatus(LibraryBook libraryBook) : base(libraryBook) { } public static EntryStatus Create(LibraryBook libraryBook) => new WinFormsEntryStatus(libraryBook); - protected override object LoadImage(byte[] picture) - { - try - { - return ImageReader.ToImage(picture); - } - catch (Exception ex) - { - Serilog.Log.Logger.Error(ex, "Error loading cover art for {Book}", Book); - return Properties.Resources.default_cover_80x80; - } - } + protected override Image LoadImage(byte[] picture) + => WinFormsUtil.TryLoadImageOrDefault(picture, LibationFileManager.PictureSize._80x80); protected override Image GetResourceImage(string rescName) { var image = Properties.Resources.ResourceManager.GetObject(rescName); - return image as Bitmap; } } diff --git a/Source/LibationWinForms/ProcessQueue/ProcessBook.cs b/Source/LibationWinForms/ProcessQueue/ProcessBook.cs index d06c0da4..1159b24b 100644 --- a/Source/LibationWinForms/ProcessQueue/ProcessBook.cs +++ b/Source/LibationWinForms/ProcessQueue/ProcessBook.cs @@ -12,7 +12,6 @@ using AudibleApi; using DataLayer; using Dinah.Core; using Dinah.Core.ErrorHandling; -using Dinah.Core.WindowsDesktop.Drawing; using FileLiberator; using LibationFileManager; using LibationUiBase; @@ -87,7 +86,7 @@ namespace LibationWinForms.ProcessQueue if (isDefault) PictureStorage.PictureCached += PictureStorage_PictureCached; - _cover = ImageReader.ToImage(picture); + _cover = WinFormsUtil.TryLoadImageOrDefault(picture, PictureSize._80x80); ; } @@ -95,7 +94,7 @@ namespace LibationWinForms.ProcessQueue { if (e.Definition.PictureId == LibraryBook.Book.PictureId) { - Cover = ImageReader.ToImage(e.Picture); + Cover = WinFormsUtil.TryLoadImageOrDefault(e.Picture, PictureSize._80x80); PictureStorage.PictureCached -= PictureStorage_PictureCached; } } @@ -260,7 +259,7 @@ namespace LibationWinForms.ProcessQueue private void AudioDecodable_CoverImageDiscovered(object sender, byte[] coverArt) { - Cover = ImageReader.ToImage(coverArt); + Cover = WinFormsUtil.TryLoadImageOrDefault(coverArt, PictureSize._80x80); } #endregion diff --git a/Source/LibationWinForms/WinFormsUtil.cs b/Source/LibationWinForms/WinFormsUtil.cs new file mode 100644 index 00000000..bf97bf97 --- /dev/null +++ b/Source/LibationWinForms/WinFormsUtil.cs @@ -0,0 +1,23 @@ +using Dinah.Core.WindowsDesktop.Drawing; +using LibationFileManager; +using System.Drawing; + +namespace LibationWinForms +{ + internal static class WinFormsUtil + { + private static Bitmap defaultImage; + public static Image TryLoadImageOrDefault(byte[] picture, PictureSize defaultSize = PictureSize.Native) + { + try + { + return ImageReader.ToImage(picture); + } + catch + { + using var ms = new System.IO.MemoryStream(PictureStorage.GetDefaultImage(defaultSize)); + return defaultImage ??= new Bitmap(ms); + } + } + } +}