From 8e93fdb477bc3aaff5a69df0dbab4ffce1725c56 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Wed, 31 Oct 2018 14:11:00 +0200 Subject: [PATCH 1/4] Initial code for decoding app resource images. - tries to solve the issue with #618 --- .../ResourceExtensions.cs | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs diff --git a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs new file mode 100644 index 0000000000..c232a9a027 --- /dev/null +++ b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs @@ -0,0 +1,125 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Xamarin.Forms; + +#if __ANDROID__ +using Xamarin.Forms.Platform.Android; +using Application = global::Android.App.Application; +#elif __IOS__ || __MACOS__ +using Foundation; +#elif __TIZEN__ +using Xamarin.Forms.Platform.Tizen; +#elif WINDOWS_UWP +using Windows.ApplicationModel; +#endif + +namespace SkiaSharp.Views.Forms +{ + public static class ResourceExtensions + { + public static async Task CreateImageDataAsync(string resource) + { + if (string.IsNullOrEmpty(resource)) + throw new ArgumentNullException(nameof(resource)); + + if (File.Exists(resource)) + { + return SKData.Create(resource); + } + else + { +#if __ANDROID__ + var id = ResourceManager.GetDrawableByName(resource); + if (id == 0) + return null; + + using (var fd = Application.Context.Resources.OpenRawResourceFd(id)) + using (var stream = fd.CreateInputStream()) + { + return SKData.Create(stream, fd.Length); + } +#elif __IOS__ || __MACOS__ + resource = NSBundle.MainBundle.PathForResource(resource, null); + if (string.IsNullOrEmpty(resource)) + return null; + + return SKData.Create(resource); +#elif __TIZEN__ + resource = ResourcePath.GetPath(resource); + if (string.IsNullOrEmpty(resource)) + return null; + + return SKData.Create(resource); +#elif WINDOWS_UWP + resource = resource.Replace('/', Path.DirectorySeparatorChar); + using (var stream = await Package.Current.InstalledLocation.OpenStreamForReadAsync(resource)) + { + return SKData.Create(stream); + } +#elif NETSTANDARD + return null; +#else +#error Missing platform logic +#endif + } + } + + public static async Task CreateImageAsync(string resource) + { + using (var data = await CreateImageDataAsync(resource)) + { + if (data == null) + return null; + + return SKImage.FromEncodedData(data); + } + } + + public static async Task CreateBitmapAsync(string resource) + { + if (string.IsNullOrEmpty(resource)) + throw new ArgumentNullException(nameof(resource)); + + if (File.Exists(resource)) + { + return SKBitmap.Decode(resource); + } + else + { +#if __ANDROID__ + var id = ResourceManager.GetDrawableByName(resource); + if (id == 0) + return null; + + using (var stream = Application.Context.Resources.OpenRawResource(id)) + { + return SKBitmap.Decode(stream); + } +#elif __IOS__ || __MACOS__ + resource = NSBundle.MainBundle.PathForResource(resource, null); + if (string.IsNullOrEmpty(resource)) + return null; + + return SKBitmap.Decode(resource); +#elif __TIZEN__ + resource = ResourcePath.GetPath(resource); + if (string.IsNullOrEmpty(resource)) + return null; + + return SKBitmap.Decode(resource); +#elif WINDOWS_UWP + resource = resource.Replace('/', Path.DirectorySeparatorChar); + using (var stream = await Package.Current.InstalledLocation.OpenStreamForReadAsync(resource)) + { + return SKBitmap.Decode(stream); + } +#elif NETSTANDARD + return null; +#else +#error Missing platform logic +#endif + } + } + } +} From 59b03f3c828c801818ef74ba3f34954a76dce59d Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Wed, 31 Oct 2018 14:22:04 +0200 Subject: [PATCH 2/4] Renamed the type to be more descriptive and accurate --- .../SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs index c232a9a027..a2192eb823 100644 --- a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs +++ b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs @@ -18,7 +18,7 @@ namespace SkiaSharp.Views.Forms { public static class ResourceExtensions { - public static async Task CreateImageDataAsync(string resource) + public static async Task LoadImageDataAsync(string resource) { if (string.IsNullOrEmpty(resource)) throw new ArgumentNullException(nameof(resource)); @@ -65,9 +65,9 @@ public static async Task CreateImageDataAsync(string resource) } } - public static async Task CreateImageAsync(string resource) + public static async Task DecodeImageAsync(string resource) { - using (var data = await CreateImageDataAsync(resource)) + using (var data = await LoadImageDataAsync(resource)) { if (data == null) return null; @@ -76,7 +76,7 @@ public static async Task CreateImageAsync(string resource) } } - public static async Task CreateBitmapAsync(string resource) + public static async Task DecodeBitmapAsync(string resource) { if (string.IsNullOrEmpty(resource)) throw new ArgumentNullException(nameof(resource)); From c20d0b383bcb876d9889f49f0559f042c3485271 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Thu, 1 Nov 2018 15:05:20 +0200 Subject: [PATCH 3/4] Check the android assets and then the resources --- .../ResourceExtensions.cs | 70 +++++++++++++++---- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs index a2192eb823..92ccc1e22b 100644 --- a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs +++ b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs @@ -23,6 +23,8 @@ public static async Task LoadImageDataAsync(string resource) if (string.IsNullOrEmpty(resource)) throw new ArgumentNullException(nameof(resource)); + resource = NormalizePath(resource); + if (File.Exists(resource)) { return SKData.Create(resource); @@ -30,14 +32,33 @@ public static async Task LoadImageDataAsync(string resource) else { #if __ANDROID__ - var id = ResourceManager.GetDrawableByName(resource); - if (id == 0) - return null; + if ((await Application.Context.Assets.ListAsync(resource)).Length > 0) + { + using (var fd = Application.Context.Assets.OpenFd(resource)) + { + if (fd != null) + { + using (var stream = fd.CreateInputStream()) + { + return SKData.Create(stream, fd.Length); + } + } + } + } - using (var fd = Application.Context.Resources.OpenRawResourceFd(id)) - using (var stream = fd.CreateInputStream()) + var id = ResourceManager.GetDrawableByName(resource); + if (id != 0) { - return SKData.Create(stream, fd.Length); + using (var fd = Application.Context.Resources.OpenRawResourceFd(id)) + { + if (fd != null) + { + using (var stream = fd.CreateInputStream()) + { + return SKData.Create(stream, fd.Length); + } + } + } } #elif __IOS__ || __MACOS__ resource = NSBundle.MainBundle.PathForResource(resource, null); @@ -52,16 +73,16 @@ public static async Task LoadImageDataAsync(string resource) return SKData.Create(resource); #elif WINDOWS_UWP - resource = resource.Replace('/', Path.DirectorySeparatorChar); using (var stream = await Package.Current.InstalledLocation.OpenStreamForReadAsync(resource)) { return SKData.Create(stream); } #elif NETSTANDARD - return null; #else #error Missing platform logic #endif + + return null; } } @@ -81,6 +102,8 @@ public static async Task DecodeBitmapAsync(string resource) if (string.IsNullOrEmpty(resource)) throw new ArgumentNullException(nameof(resource)); + resource = NormalizePath(resource); + if (File.Exists(resource)) { return SKBitmap.Decode(resource); @@ -88,13 +111,24 @@ public static async Task DecodeBitmapAsync(string resource) else { #if __ANDROID__ - var id = ResourceManager.GetDrawableByName(resource); - if (id == 0) - return null; + if ((await Application.Context.Assets.ListAsync(resource)).Length > 0) + { + using (var stream = Application.Context.Assets.Open(resource)) + { + if (stream != null) + { + return SKBitmap.Decode(stream); + } + } + } - using (var stream = Application.Context.Resources.OpenRawResource(id)) + var id = ResourceManager.GetDrawableByName(resource); + if (id != 0) { - return SKBitmap.Decode(stream); + using (var stream = Application.Context.Resources.OpenRawResource(id)) + { + return SKBitmap.Decode(stream); + } } #elif __IOS__ || __MACOS__ resource = NSBundle.MainBundle.PathForResource(resource, null); @@ -115,11 +149,19 @@ public static async Task DecodeBitmapAsync(string resource) return SKBitmap.Decode(stream); } #elif NETSTANDARD - return null; #else #error Missing platform logic #endif + + return null; } } + + private static string NormalizePath(string path) => +#if WINDOWS_UWP + path.Replace('/', Path.DirectorySeparatorChar); +#else + path.Replace('\\', Path.DirectorySeparatorChar); +#endif } } From 015ca8fdf4f456e873edde86731296e426f86a67 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Sat, 22 Jun 2019 21:12:14 +0200 Subject: [PATCH 4/4] Fix resource loading logic --- .../ResourceExtensions.cs | 134 +++++------------- 1 file changed, 37 insertions(+), 97 deletions(-) diff --git a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs index 92ccc1e22b..cb5974709e 100644 --- a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs +++ b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/ResourceExtensions.cs @@ -26,135 +26,75 @@ public static async Task LoadImageDataAsync(string resource) resource = NormalizePath(resource); if (File.Exists(resource)) - { return SKData.Create(resource); - } - else - { + #if __ANDROID__ - if ((await Application.Context.Assets.ListAsync(resource)).Length > 0) + try + { + using (var fd = Application.Context.Assets.OpenFd(resource)) + using (var stream = fd?.CreateInputStream()) { - using (var fd = Application.Context.Assets.OpenFd(resource)) - { - if (fd != null) - { - using (var stream = fd.CreateInputStream()) - { - return SKData.Create(stream, fd.Length); - } - } - } + if (stream != null) + return SKData.Create(stream, fd.Length); } + } + catch (Java.IO.FileNotFoundException) + { + // fall through + } - var id = ResourceManager.GetDrawableByName(resource); - if (id != 0) + var id = ResourceManager.GetDrawableByName(resource); + if (id != 0) + { + using (var fd = Application.Context.Resources.OpenRawResourceFd(id)) + using (var stream = fd?.CreateInputStream()) { - using (var fd = Application.Context.Resources.OpenRawResourceFd(id)) - { - if (fd != null) - { - using (var stream = fd.CreateInputStream()) - { - return SKData.Create(stream, fd.Length); - } - } - } + if (stream != null) + return SKData.Create(stream, fd.Length); } + } #elif __IOS__ || __MACOS__ - resource = NSBundle.MainBundle.PathForResource(resource, null); - if (string.IsNullOrEmpty(resource)) - return null; - + resource = NSBundle.MainBundle.PathForResource(resource, null); + if (!string.IsNullOrEmpty(resource)) return SKData.Create(resource); #elif __TIZEN__ - resource = ResourcePath.GetPath(resource); - if (string.IsNullOrEmpty(resource)) - return null; - + resource = ResourcePath.GetPath(resource); + if (!string.IsNullOrEmpty(resource)) return SKData.Create(resource); #elif WINDOWS_UWP - using (var stream = await Package.Current.InstalledLocation.OpenStreamForReadAsync(resource)) - { + using (var stream = await Package.Current.InstalledLocation.OpenStreamForReadAsync(resource)) + { + if (stream != null) return SKData.Create(stream); - } + } #elif NETSTANDARD #else #error Missing platform logic #endif - return null; - } + return null; } public static async Task DecodeImageAsync(string resource) { using (var data = await LoadImageDataAsync(resource)) { - if (data == null) - return null; - - return SKImage.FromEncodedData(data); + if (data != null) + return SKImage.FromEncodedData(data); } + + return null; } public static async Task DecodeBitmapAsync(string resource) { - if (string.IsNullOrEmpty(resource)) - throw new ArgumentNullException(nameof(resource)); - - resource = NormalizePath(resource); - - if (File.Exists(resource)) + using (var data = await LoadImageDataAsync(resource)) { - return SKBitmap.Decode(resource); + if (data != null) + return SKBitmap.Decode(data); } - else - { -#if __ANDROID__ - if ((await Application.Context.Assets.ListAsync(resource)).Length > 0) - { - using (var stream = Application.Context.Assets.Open(resource)) - { - if (stream != null) - { - return SKBitmap.Decode(stream); - } - } - } - - var id = ResourceManager.GetDrawableByName(resource); - if (id != 0) - { - using (var stream = Application.Context.Resources.OpenRawResource(id)) - { - return SKBitmap.Decode(stream); - } - } -#elif __IOS__ || __MACOS__ - resource = NSBundle.MainBundle.PathForResource(resource, null); - if (string.IsNullOrEmpty(resource)) - return null; - return SKBitmap.Decode(resource); -#elif __TIZEN__ - resource = ResourcePath.GetPath(resource); - if (string.IsNullOrEmpty(resource)) - return null; - - return SKBitmap.Decode(resource); -#elif WINDOWS_UWP - resource = resource.Replace('/', Path.DirectorySeparatorChar); - using (var stream = await Package.Current.InstalledLocation.OpenStreamForReadAsync(resource)) - { - return SKBitmap.Decode(stream); - } -#elif NETSTANDARD -#else -#error Missing platform logic -#endif - - return null; - } + return null; } private static string NormalizePath(string path) =>