Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
<PackageVersion Include="Serilog.Exceptions" Version="8.4.0" />
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.31.0.145097" />
<PackageVersion Include="SimpleInjector" Version="5.6.0" />
<PackageVersion Include="SkiaSharp" Version="4.151.0" />
<!-- SkiaSharp brings only the macOS and Win32 native assets on the plain .NET target frameworks. -->
<PackageVersion Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="4.151.0" />
<!-- StyleSharp.Analyzers, PerformanceSharp.Analyzers and SecuritySharp.Analyzers ship from the
same release pipeline and always share a version. -->
<PackageVersion Include="StyleSharp.Analyzers" Version="3.40.1" />
Expand Down
40 changes: 40 additions & 0 deletions src/Splat.SkiaSharp/BitmapMixins.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved.
// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using SkiaSharp;

namespace Splat.SkiaSharp;

/// <summary>Converts between <see cref="IBitmap"/> and the Skia bitmap behind it.</summary>
/// <remarks>
/// Skia is not the host's imaging stack, and these conversions do not pretend otherwise: what comes
/// back is an <see cref="SKBitmap"/>, not a platform bitmap type.
/// </remarks>
public static class BitmapMixins
{
/// <summary>Extension members for <see cref="IBitmap"/>.</summary>
/// <param name="value">The value the extension members operate on.</param>
extension(IBitmap value)
{
/// <summary>Gets the Skia bitmap behind an <see cref="IBitmap"/> this package produced.</summary>
/// <returns>The Skia bitmap, which the <see cref="IBitmap"/> still owns.</returns>
/// <exception cref="InvalidOperationException">The bitmap has been disposed.</exception>
/// <exception cref="InvalidCastException">The bitmap came from a different loader.</exception>
public SKBitmap ToNative()
{
ArgumentExceptionHelper.ThrowIfNull(value);

return ((SkiaBitmap)value).Inner ?? throw new InvalidOperationException("The bitmap has been disposed");
}
}

/// <summary>Extension members for <see cref="SKBitmap"/>.</summary>
/// <param name="value">The value the extension members operate on.</param>
extension(SKBitmap value)
{
/// <summary>Wraps a Skia bitmap as an <see cref="IBitmap"/>, taking ownership of it.</summary>
/// <returns>The wrapped bitmap.</returns>
public IBitmap FromNative() => new SkiaBitmap(value);
}
}
38 changes: 38 additions & 0 deletions src/Splat.SkiaSharp/Builder/SkiaSharpSplatModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved.
// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using SkiaSharp;

using Splat.SkiaSharp;

namespace Splat.Builder;

/// <summary>Registers Skia as the bitmap loader when the application is built.</summary>
/// <remarks>
/// Registration is a plain method call rather than assembly scanning, so it survives trimming and
/// ahead-of-time compilation.
/// </remarks>
/// <param name="sampling">The sampling to resize with, or <see langword="null"/> for the loader's default.</param>
public sealed class SkiaSharpSplatModule(SKSamplingOptions? sampling) : IModule
{
/// <summary>Initializes a new instance of the <see cref="SkiaSharpSplatModule"/> class.</summary>
public SkiaSharpSplatModule()
: this(null)
{
}

/// <inheritdoc />
public void Configure(IMutableDependencyResolver resolver)
{
ArgumentExceptionHelper.ThrowIfNull(resolver);

if (sampling is null)
{
resolver.UseSkiaSharpBitmapLoader();
return;
}

resolver.UseSkiaSharpBitmapLoader(sampling.Value);
}
}
43 changes: 43 additions & 0 deletions src/Splat.SkiaSharp/MutableDependencyResolverExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved.
// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using SkiaSharp;

namespace Splat.SkiaSharp;

/// <summary>Registers Skia as the bitmap loader Splat resolves.</summary>
/// <remarks>
/// The plain .NET target frameworks register no bitmap loader of their own, so <see cref="BitmapLoader.Current"/>
/// throws until something is registered. Registration is explicit: nothing scans assemblies for it.
/// </remarks>
public static class MutableDependencyResolverExtensions
{
/// <summary>Extension members for <see cref="IMutableDependencyResolver"/>.</summary>
/// <param name="instance">An instance of Mutable Dependency Resolver.</param>
extension(IMutableDependencyResolver instance)
{
/// <summary>Registers <see cref="SkiaBitmapLoader"/> as the <see cref="IBitmapLoader"/>.</summary>
/// <example>
/// <c>AppLocator.CurrentMutable.UseSkiaSharpBitmapLoader();</c>
/// </example>
public void UseSkiaSharpBitmapLoader()
{
ArgumentExceptionHelper.ThrowIfNull(instance);

instance.RegisterLazySingleton(static () => new SkiaBitmapLoader(), typeof(IBitmapLoader));
}

/// <summary>Registers <see cref="SkiaBitmapLoader"/> as the <see cref="IBitmapLoader"/>, resizing with the given sampling.</summary>
/// <param name="sampling">The sampling to resize with.</param>
/// <example>
/// <c>AppLocator.CurrentMutable.UseSkiaSharpBitmapLoader(new SKSamplingOptions(SKFilterMode.Nearest));</c>
/// </example>
public void UseSkiaSharpBitmapLoader(SKSamplingOptions sampling)
{
ArgumentExceptionHelper.ThrowIfNull(instance);

instance.RegisterLazySingleton(() => new SkiaBitmapLoader(sampling), typeof(IBitmapLoader));
}
}
}
53 changes: 53 additions & 0 deletions src/Splat.SkiaSharp/PublicAPI/net10.0/PublicAPI.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Splat.SkiaSharp.Tests")]
namespace Splat.Builder
{
public sealed class SkiaSharpSplatModule : Splat.Builder.IModule
{
public SkiaSharpSplatModule() { }
public SkiaSharpSplatModule(SkiaSharp.SKSamplingOptions? sampling) { }
public void Configure(Splat.IMutableDependencyResolver resolver) { }
}
}
namespace Splat.SkiaSharp
{
public static class BitmapMixins
{
extension(SkiaSharp.SKBitmap value)
{
public Splat.IBitmap FromNative() { }
}
extension(Splat.IBitmap value)
{
public SkiaSharp.SKBitmap ToNative() { }
}
}
public static class MutableDependencyResolverExtensions
{
extension(Splat.IMutableDependencyResolver instance)
{
public void UseSkiaSharpBitmapLoader() { }
public void UseSkiaSharpBitmapLoader(SkiaSharp.SKSamplingOptions sampling) { }
}
}
public sealed class SkiaBitmap : Splat.IBitmap
{
public SkiaBitmap(SkiaSharp.SKBitmap bitmap) { }
public SkiaBitmap(SkiaSharp.SKBitmap bitmap, SkiaSharp.SKEncodedOrigin encodedOrigin) { }
public SkiaSharp.SKEncodedOrigin EncodedOrigin { get; }
public float Height { get; }
public SkiaSharp.SKBitmap? Inner { get; }
public float Width { get; }
public void Dispose() { }
public System.Threading.Tasks.Task Save(SkiaSharp.SKEncodedImageFormat format, float quality, System.IO.Stream target) { }
public System.Threading.Tasks.Task Save(Splat.CompressedBitmapFormat format, float quality, System.IO.Stream target) { }
}
public sealed class SkiaBitmapLoader : Splat.IBitmapLoader
{
public SkiaBitmapLoader() { }
public SkiaBitmapLoader(SkiaSharp.SKSamplingOptions sampling) { }
public SkiaSharp.SKSamplingOptions Sampling { get; }
public Splat.IBitmap Create(float width, float height) { }
public System.Threading.Tasks.Task<Splat.IBitmap?> Load(System.IO.Stream sourceStream, float? desiredWidth, float? desiredHeight) { }
public System.Threading.Tasks.Task<Splat.IBitmap?> LoadFromResource(string source, float? desiredWidth, float? desiredHeight) { }
}
}
53 changes: 53 additions & 0 deletions src/Splat.SkiaSharp/PublicAPI/net11.0/PublicAPI.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Splat.SkiaSharp.Tests")]
namespace Splat.Builder
{
public sealed class SkiaSharpSplatModule : Splat.Builder.IModule
{
public SkiaSharpSplatModule() { }
public SkiaSharpSplatModule(SkiaSharp.SKSamplingOptions? sampling) { }
public void Configure(Splat.IMutableDependencyResolver resolver) { }
}
}
namespace Splat.SkiaSharp
{
public static class BitmapMixins
{
extension(SkiaSharp.SKBitmap value)
{
public Splat.IBitmap FromNative() { }
}
extension(Splat.IBitmap value)
{
public SkiaSharp.SKBitmap ToNative() { }
}
}
public static class MutableDependencyResolverExtensions
{
extension(Splat.IMutableDependencyResolver instance)
{
public void UseSkiaSharpBitmapLoader() { }
public void UseSkiaSharpBitmapLoader(SkiaSharp.SKSamplingOptions sampling) { }
}
}
public sealed class SkiaBitmap : Splat.IBitmap
{
public SkiaBitmap(SkiaSharp.SKBitmap bitmap) { }
public SkiaBitmap(SkiaSharp.SKBitmap bitmap, SkiaSharp.SKEncodedOrigin encodedOrigin) { }
public SkiaSharp.SKEncodedOrigin EncodedOrigin { get; }
public float Height { get; }
public SkiaSharp.SKBitmap? Inner { get; }
public float Width { get; }
public void Dispose() { }
public System.Threading.Tasks.Task Save(SkiaSharp.SKEncodedImageFormat format, float quality, System.IO.Stream target) { }
public System.Threading.Tasks.Task Save(Splat.CompressedBitmapFormat format, float quality, System.IO.Stream target) { }
}
public sealed class SkiaBitmapLoader : Splat.IBitmapLoader
{
public SkiaBitmapLoader() { }
public SkiaBitmapLoader(SkiaSharp.SKSamplingOptions sampling) { }
public SkiaSharp.SKSamplingOptions Sampling { get; }
public Splat.IBitmap Create(float width, float height) { }
public System.Threading.Tasks.Task<Splat.IBitmap?> Load(System.IO.Stream sourceStream, float? desiredWidth, float? desiredHeight) { }
public System.Threading.Tasks.Task<Splat.IBitmap?> LoadFromResource(string source, float? desiredWidth, float? desiredHeight) { }
}
}
53 changes: 53 additions & 0 deletions src/Splat.SkiaSharp/PublicAPI/net8.0/PublicAPI.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Splat.SkiaSharp.Tests")]
namespace Splat.Builder
{
public sealed class SkiaSharpSplatModule : Splat.Builder.IModule
{
public SkiaSharpSplatModule() { }
public SkiaSharpSplatModule(SkiaSharp.SKSamplingOptions? sampling) { }
public void Configure(Splat.IMutableDependencyResolver resolver) { }
}
}
namespace Splat.SkiaSharp
{
public static class BitmapMixins
{
extension(SkiaSharp.SKBitmap value)
{
public Splat.IBitmap FromNative() { }
}
extension(Splat.IBitmap value)
{
public SkiaSharp.SKBitmap ToNative() { }
}
}
public static class MutableDependencyResolverExtensions
{
extension(Splat.IMutableDependencyResolver instance)
{
public void UseSkiaSharpBitmapLoader() { }
public void UseSkiaSharpBitmapLoader(SkiaSharp.SKSamplingOptions sampling) { }
}
}
public sealed class SkiaBitmap : Splat.IBitmap
{
public SkiaBitmap(SkiaSharp.SKBitmap bitmap) { }
public SkiaBitmap(SkiaSharp.SKBitmap bitmap, SkiaSharp.SKEncodedOrigin encodedOrigin) { }
public SkiaSharp.SKEncodedOrigin EncodedOrigin { get; }
public float Height { get; }
public SkiaSharp.SKBitmap? Inner { get; }
public float Width { get; }
public void Dispose() { }
public System.Threading.Tasks.Task Save(SkiaSharp.SKEncodedImageFormat format, float quality, System.IO.Stream target) { }
public System.Threading.Tasks.Task Save(Splat.CompressedBitmapFormat format, float quality, System.IO.Stream target) { }
}
public sealed class SkiaBitmapLoader : Splat.IBitmapLoader
{
public SkiaBitmapLoader() { }
public SkiaBitmapLoader(SkiaSharp.SKSamplingOptions sampling) { }
public SkiaSharp.SKSamplingOptions Sampling { get; }
public Splat.IBitmap Create(float width, float height) { }
public System.Threading.Tasks.Task<Splat.IBitmap?> Load(System.IO.Stream sourceStream, float? desiredWidth, float? desiredHeight) { }
public System.Threading.Tasks.Task<Splat.IBitmap?> LoadFromResource(string source, float? desiredWidth, float? desiredHeight) { }
}
}
53 changes: 53 additions & 0 deletions src/Splat.SkiaSharp/PublicAPI/net9.0/PublicAPI.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Splat.SkiaSharp.Tests")]
namespace Splat.Builder
{
public sealed class SkiaSharpSplatModule : Splat.Builder.IModule
{
public SkiaSharpSplatModule() { }
public SkiaSharpSplatModule(SkiaSharp.SKSamplingOptions? sampling) { }
public void Configure(Splat.IMutableDependencyResolver resolver) { }
}
}
namespace Splat.SkiaSharp
{
public static class BitmapMixins
{
extension(SkiaSharp.SKBitmap value)
{
public Splat.IBitmap FromNative() { }
}
extension(Splat.IBitmap value)
{
public SkiaSharp.SKBitmap ToNative() { }
}
}
public static class MutableDependencyResolverExtensions
{
extension(Splat.IMutableDependencyResolver instance)
{
public void UseSkiaSharpBitmapLoader() { }
public void UseSkiaSharpBitmapLoader(SkiaSharp.SKSamplingOptions sampling) { }
}
}
public sealed class SkiaBitmap : Splat.IBitmap
{
public SkiaBitmap(SkiaSharp.SKBitmap bitmap) { }
public SkiaBitmap(SkiaSharp.SKBitmap bitmap, SkiaSharp.SKEncodedOrigin encodedOrigin) { }
public SkiaSharp.SKEncodedOrigin EncodedOrigin { get; }
public float Height { get; }
public SkiaSharp.SKBitmap? Inner { get; }
public float Width { get; }
public void Dispose() { }
public System.Threading.Tasks.Task Save(SkiaSharp.SKEncodedImageFormat format, float quality, System.IO.Stream target) { }
public System.Threading.Tasks.Task Save(Splat.CompressedBitmapFormat format, float quality, System.IO.Stream target) { }
}
public sealed class SkiaBitmapLoader : Splat.IBitmapLoader
{
public SkiaBitmapLoader() { }
public SkiaBitmapLoader(SkiaSharp.SKSamplingOptions sampling) { }
public SkiaSharp.SKSamplingOptions Sampling { get; }
public Splat.IBitmap Create(float width, float height) { }
public System.Threading.Tasks.Task<Splat.IBitmap?> Load(System.IO.Stream sourceStream, float? desiredWidth, float? desiredHeight) { }
public System.Threading.Tasks.Task<Splat.IBitmap?> LoadFromResource(string source, float? desiredWidth, float? desiredHeight) { }
}
}
Loading
Loading