* Update generator to emit function pointers * Regenerate interop files * Enable USE_LIBRARY_IMPORT in HarfBuzzSharp * Enable USE_LIBRARY_IMPORT on SkiaSharp * Set DisableRuntimeMarshalling on HarfBuzzSharp * Replace remaining DllImports with LibraryImport on SkiaSharp * Set DisableRuntimeMarshalling on SkiaSharp as well * Fix missed proxy definition * Regenerate skia api with a correct submodule version * Collections literals are not supported on the CI .NET SDK * An attempt to fix Tizen build * Forgot about partial * Set UnmanagedType.LPStr on evas_gl_proc_address_get instead * Set USE_LIBRARY_IMPORT on remaining projects too * Update generator tool to generate DelegateProxy as well * Regenerate HarfBuzz and SkiaSharp with new DelegateProxy source gen * Regenerate other projects as well * Add `protected internal` to test classes too, since this project has InternalsVisibleTo configured * Disable DelegateTypesAreValid and DelegateTypesHaveAttributes tests on .NET 7+ build, see comments * Reduce warnings noise * Update binding/SkiaSharp/GRGlInterface.cs Co-authored-by: Filip Navara <filip.navara@gmail.com> * Add missing USE_LIBRARY_IMPORT defines * Update binding/SkiaSharp/GRGlInterface.cs * Also needs USE_LIBRARY_IMPORT --------- Co-authored-by: Matthew Leibowitz <mattleibow@live.com> Co-authored-by: Filip Navara <filip.navara@gmail.com>
787 lines
20 KiB
C#
787 lines
20 KiB
C#
#nullable disable
|
|
|
|
using System;
|
|
using System.ComponentModel;
|
|
using System.IO;
|
|
|
|
namespace SkiaSharp
|
|
{
|
|
// TODO: keep in mind SKBitmap may be going away (according to Google)
|
|
// TODO: `ComputeIsOpaque` may be useful
|
|
// TODO: `GenerationID` may be useful
|
|
// TODO: `GetAddr` and `GetPixel` are confusing
|
|
|
|
public unsafe class SKBitmap : SKObject, ISKSkipObjectRegistration
|
|
{
|
|
private const string UnsupportedColorTypeMessage = "Setting the ColorTable is only supported for bitmaps with ColorTypes of Index8.";
|
|
private const string UnableToAllocatePixelsMessage = "Unable to allocate pixels for the bitmap.";
|
|
|
|
internal SKBitmap (IntPtr handle, bool owns)
|
|
: base (handle, owns)
|
|
{
|
|
}
|
|
|
|
public SKBitmap ()
|
|
: this (SkiaApi.sk_bitmap_new (), true)
|
|
{
|
|
if (Handle == IntPtr.Zero) {
|
|
throw new InvalidOperationException ("Unable to create a new SKBitmap instance.");
|
|
}
|
|
}
|
|
|
|
public SKBitmap (int width, int height, bool isOpaque = false)
|
|
: this (width, height, SKImageInfo.PlatformColorType, isOpaque ? SKAlphaType.Opaque : SKAlphaType.Premul)
|
|
{
|
|
}
|
|
|
|
public SKBitmap (int width, int height, SKColorType colorType, SKAlphaType alphaType)
|
|
: this (new SKImageInfo (width, height, colorType, alphaType))
|
|
{
|
|
}
|
|
|
|
public SKBitmap (int width, int height, SKColorType colorType, SKAlphaType alphaType, SKColorSpace colorspace)
|
|
: this (new SKImageInfo (width, height, colorType, alphaType, colorspace))
|
|
{
|
|
}
|
|
|
|
public SKBitmap (SKImageInfo info)
|
|
: this (info, info.RowBytes)
|
|
{
|
|
}
|
|
|
|
public SKBitmap (SKImageInfo info, int rowBytes)
|
|
: this ()
|
|
{
|
|
if (!TryAllocPixels (info, rowBytes)) {
|
|
throw new Exception (UnableToAllocatePixelsMessage);
|
|
}
|
|
}
|
|
|
|
public SKBitmap (SKImageInfo info, SKBitmapAllocFlags flags)
|
|
: this ()
|
|
{
|
|
if (!TryAllocPixels (info, flags)) {
|
|
throw new Exception (UnableToAllocatePixelsMessage);
|
|
}
|
|
}
|
|
|
|
protected override void Dispose (bool disposing) =>
|
|
base.Dispose (disposing);
|
|
|
|
protected override void DisposeNative () =>
|
|
SkiaApi.sk_bitmap_destructor (Handle);
|
|
|
|
// TryAllocPixels
|
|
|
|
public bool TryAllocPixels (SKImageInfo info)
|
|
{
|
|
return TryAllocPixels (info, info.RowBytes);
|
|
}
|
|
|
|
public bool TryAllocPixels (SKImageInfo info, int rowBytes)
|
|
{
|
|
var cinfo = SKImageInfoNative.FromManaged (ref info);
|
|
return SkiaApi.sk_bitmap_try_alloc_pixels (Handle, &cinfo, (IntPtr)rowBytes);
|
|
}
|
|
|
|
public bool TryAllocPixels (SKImageInfo info, SKBitmapAllocFlags flags)
|
|
{
|
|
var cinfo = SKImageInfoNative.FromManaged (ref info);
|
|
return SkiaApi.sk_bitmap_try_alloc_pixels_with_flags (Handle, &cinfo, (uint)flags);
|
|
}
|
|
|
|
// Reset
|
|
|
|
public void Reset ()
|
|
{
|
|
SkiaApi.sk_bitmap_reset (Handle);
|
|
}
|
|
|
|
// SetImmutable
|
|
|
|
public void SetImmutable ()
|
|
{
|
|
SkiaApi.sk_bitmap_set_immutable (Handle);
|
|
}
|
|
|
|
// Erase
|
|
|
|
public void Erase (SKColor color)
|
|
{
|
|
SkiaApi.sk_bitmap_erase (Handle, (uint)color);
|
|
}
|
|
|
|
public void Erase (SKColor color, SKRectI rect)
|
|
{
|
|
SkiaApi.sk_bitmap_erase_rect (Handle, (uint)color, &rect);
|
|
}
|
|
|
|
// GetAddress
|
|
|
|
public IntPtr GetAddress (int x, int y) =>
|
|
(IntPtr)SkiaApi.sk_bitmap_get_addr (Handle, x, y);
|
|
|
|
// Pixels (color)
|
|
|
|
public SKColor GetPixel (int x, int y)
|
|
{
|
|
return SkiaApi.sk_bitmap_get_pixel_color (Handle, x, y);
|
|
}
|
|
|
|
public void SetPixel (int x, int y, SKColor color)
|
|
{
|
|
var info = Info;
|
|
if (x < 0 || x >= info.Width)
|
|
throw new ArgumentOutOfRangeException (nameof (x));
|
|
if (y < 0 || y >= info.Height)
|
|
throw new ArgumentOutOfRangeException (nameof (y));
|
|
|
|
using var canvas = new SKCanvas (this);
|
|
canvas.DrawPoint (x, y, color);
|
|
}
|
|
|
|
// Copy
|
|
|
|
public bool CanCopyTo (SKColorType colorType)
|
|
{
|
|
// TODO: optimize as this does more work that we really want
|
|
|
|
if (colorType == SKColorType.Unknown)
|
|
return false;
|
|
|
|
using var bmp = new SKBitmap ();
|
|
|
|
var info = Info
|
|
.WithColorType (colorType)
|
|
.WithSize (1, 1);
|
|
return bmp.TryAllocPixels (info);
|
|
}
|
|
|
|
public SKBitmap Copy ()
|
|
{
|
|
return Copy (ColorType);
|
|
}
|
|
|
|
public SKBitmap Copy (SKColorType colorType)
|
|
{
|
|
var destination = new SKBitmap ();
|
|
if (!CopyTo (destination, colorType)) {
|
|
destination.Dispose ();
|
|
destination = null;
|
|
}
|
|
return destination;
|
|
}
|
|
|
|
public bool CopyTo (SKBitmap destination)
|
|
{
|
|
if (destination == null) {
|
|
throw new ArgumentNullException (nameof (destination));
|
|
}
|
|
return CopyTo (destination, ColorType);
|
|
}
|
|
|
|
public bool CopyTo (SKBitmap destination, SKColorType colorType)
|
|
{
|
|
if (destination == null)
|
|
throw new ArgumentNullException (nameof (destination));
|
|
|
|
if (colorType == SKColorType.Unknown)
|
|
return false;
|
|
|
|
using var srcPixmap = PeekPixels ();
|
|
if (srcPixmap == null)
|
|
return false;
|
|
|
|
using var temp = new SKBitmap ();
|
|
|
|
var dstInfo = srcPixmap.Info.WithColorType (colorType);
|
|
if (!temp.TryAllocPixels (dstInfo))
|
|
return false;
|
|
|
|
using var canvas = new SKCanvas (temp);
|
|
|
|
using var paint = new SKPaint {
|
|
Shader = ToShader (),
|
|
BlendMode = SKBlendMode.Src
|
|
};
|
|
|
|
canvas.DrawPaint (paint);
|
|
|
|
destination.Swap (temp);
|
|
return true;
|
|
}
|
|
|
|
// ExtractSubset
|
|
|
|
public bool ExtractSubset (SKBitmap destination, SKRectI subset)
|
|
{
|
|
if (destination == null) {
|
|
throw new ArgumentNullException (nameof (destination));
|
|
}
|
|
return SkiaApi.sk_bitmap_extract_subset (Handle, destination.Handle, &subset);
|
|
}
|
|
|
|
// ExtractAlpha
|
|
|
|
public bool ExtractAlpha (SKBitmap destination)
|
|
{
|
|
return ExtractAlpha (destination, null, out var offset);
|
|
}
|
|
|
|
public bool ExtractAlpha (SKBitmap destination, out SKPointI offset)
|
|
{
|
|
return ExtractAlpha (destination, null, out offset);
|
|
}
|
|
|
|
public bool ExtractAlpha (SKBitmap destination, SKPaint paint)
|
|
{
|
|
return ExtractAlpha (destination, paint, out var offset);
|
|
}
|
|
|
|
public bool ExtractAlpha (SKBitmap destination, SKPaint paint, out SKPointI offset)
|
|
{
|
|
if (destination == null) {
|
|
throw new ArgumentNullException (nameof (destination));
|
|
}
|
|
fixed (SKPointI* o = &offset) {
|
|
return SkiaApi.sk_bitmap_extract_alpha (Handle, destination.Handle, paint == null ? IntPtr.Zero : paint.Handle, o);
|
|
}
|
|
}
|
|
|
|
// properties
|
|
|
|
public bool ReadyToDraw => SkiaApi.sk_bitmap_ready_to_draw (Handle);
|
|
|
|
public SKImageInfo Info {
|
|
get {
|
|
SKImageInfoNative cinfo;
|
|
SkiaApi.sk_bitmap_get_info (Handle, &cinfo);
|
|
return SKImageInfoNative.ToManaged (ref cinfo);
|
|
}
|
|
}
|
|
|
|
public int Width {
|
|
get { return Info.Width; }
|
|
}
|
|
|
|
public int Height {
|
|
get { return Info.Height; }
|
|
}
|
|
|
|
public SKColorType ColorType {
|
|
get { return Info.ColorType; }
|
|
}
|
|
|
|
public SKAlphaType AlphaType {
|
|
get { return Info.AlphaType; }
|
|
}
|
|
|
|
public SKColorSpace ColorSpace {
|
|
get { return Info.ColorSpace; }
|
|
}
|
|
|
|
public int BytesPerPixel {
|
|
get { return Info.BytesPerPixel; }
|
|
}
|
|
|
|
public int RowBytes {
|
|
get { return (int)SkiaApi.sk_bitmap_get_row_bytes (Handle); }
|
|
}
|
|
|
|
public int ByteCount {
|
|
get { return (int)SkiaApi.sk_bitmap_get_byte_count (Handle); }
|
|
}
|
|
|
|
// *Pixels*
|
|
|
|
public IntPtr GetPixels () =>
|
|
GetPixels (out _);
|
|
|
|
public Span<byte> GetPixelSpan () =>
|
|
new Span<byte> ((void*)GetPixels (out var length), (int)length);
|
|
|
|
public Span<byte> GetPixelSpan (int x, int y) =>
|
|
GetPixelSpan ().Slice (Info.GetPixelBytesOffset (x, y));
|
|
|
|
public IntPtr GetPixels (out IntPtr length)
|
|
{
|
|
fixed (IntPtr* l = &length) {
|
|
return (IntPtr)SkiaApi.sk_bitmap_get_pixels (Handle, l);
|
|
}
|
|
}
|
|
|
|
public void SetPixels (IntPtr pixels)
|
|
{
|
|
SkiaApi.sk_bitmap_set_pixels (Handle, (void*)pixels);
|
|
}
|
|
|
|
// more properties
|
|
|
|
public byte[] Bytes {
|
|
get {
|
|
var array = GetPixelSpan ().ToArray ();
|
|
GC.KeepAlive (this);
|
|
return array;
|
|
}
|
|
}
|
|
|
|
public SKColor[] Pixels {
|
|
get {
|
|
var info = Info;
|
|
var pixels = new SKColor[info.Width * info.Height];
|
|
fixed (SKColor* p = pixels) {
|
|
SkiaApi.sk_bitmap_get_pixel_colors (Handle, (uint*)p);
|
|
}
|
|
return pixels;
|
|
}
|
|
set {
|
|
if (value == null)
|
|
throw new ArgumentNullException (nameof (value));
|
|
|
|
var info = Info;
|
|
if (info.Width * info.Height != value.Length)
|
|
throw new ArgumentException ($"The number of pixels must equal Width x Height, or {info.Width * info.Height}.", nameof (value));
|
|
|
|
fixed (SKColor* v = value) {
|
|
var tempInfo = new SKImageInfo (info.Width, info.Height, SKColorType.Bgra8888, SKAlphaType.Unpremul);
|
|
using var temp = new SKBitmap ();
|
|
temp.InstallPixels (tempInfo, (IntPtr)v);
|
|
|
|
using var shader = temp.ToShader ();
|
|
|
|
using var canvas = new SKCanvas (this);
|
|
using var paint = new SKPaint {
|
|
Shader = shader,
|
|
BlendMode = SKBlendMode.Src
|
|
};
|
|
canvas.DrawPaint (paint);
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsEmpty {
|
|
get { return Info.IsEmpty; }
|
|
}
|
|
|
|
public bool IsNull {
|
|
get { return SkiaApi.sk_bitmap_is_null (Handle); }
|
|
}
|
|
|
|
public bool DrawsNothing {
|
|
get { return IsEmpty || IsNull; }
|
|
}
|
|
|
|
public bool IsImmutable {
|
|
get { return SkiaApi.sk_bitmap_is_immutable (Handle); }
|
|
}
|
|
|
|
// DecodeBounds
|
|
|
|
public static SKImageInfo DecodeBounds (Stream stream)
|
|
{
|
|
if (stream == null) {
|
|
throw new ArgumentNullException (nameof (stream));
|
|
}
|
|
using (var codec = SKCodec.Create (stream)) {
|
|
return codec?.Info ?? SKImageInfo.Empty;
|
|
}
|
|
}
|
|
|
|
public static SKImageInfo DecodeBounds (SKStream stream)
|
|
{
|
|
if (stream == null) {
|
|
throw new ArgumentNullException (nameof (stream));
|
|
}
|
|
using (var codec = SKCodec.Create (stream)) {
|
|
return codec?.Info ?? SKImageInfo.Empty;
|
|
}
|
|
}
|
|
|
|
public static SKImageInfo DecodeBounds (SKData data)
|
|
{
|
|
if (data == null) {
|
|
throw new ArgumentNullException (nameof (data));
|
|
}
|
|
using (var codec = SKCodec.Create (data)) {
|
|
return codec?.Info ?? SKImageInfo.Empty;
|
|
}
|
|
}
|
|
|
|
public static SKImageInfo DecodeBounds (string filename)
|
|
{
|
|
if (filename == null) {
|
|
throw new ArgumentNullException (nameof (filename));
|
|
}
|
|
using (var codec = SKCodec.Create (filename)) {
|
|
return codec?.Info ?? SKImageInfo.Empty;
|
|
}
|
|
}
|
|
|
|
public static SKImageInfo DecodeBounds (byte[] buffer) =>
|
|
DecodeBounds (buffer.AsSpan ());
|
|
|
|
public static SKImageInfo DecodeBounds (ReadOnlySpan<byte> buffer)
|
|
{
|
|
fixed (byte* b = buffer) {
|
|
using var skdata = SKData.Create ((IntPtr)b, buffer.Length);
|
|
using var codec = SKCodec.Create (skdata);
|
|
return codec?.Info ?? SKImageInfo.Empty;
|
|
}
|
|
}
|
|
|
|
// Decode
|
|
|
|
public static SKBitmap Decode (SKCodec codec)
|
|
{
|
|
if (codec == null) {
|
|
throw new ArgumentNullException (nameof (codec));
|
|
}
|
|
var info = codec.Info;
|
|
if (info.AlphaType == SKAlphaType.Unpremul) {
|
|
info.AlphaType = SKAlphaType.Premul;
|
|
}
|
|
return Decode (codec, info);
|
|
}
|
|
|
|
public static SKBitmap Decode (SKCodec codec, SKImageInfo bitmapInfo)
|
|
{
|
|
if (codec == null) {
|
|
throw new ArgumentNullException (nameof (codec));
|
|
}
|
|
|
|
var bitmap = new SKBitmap (bitmapInfo);
|
|
var result = codec.GetPixels (bitmapInfo, bitmap.GetPixels (out var length));
|
|
if (result != SKCodecResult.Success && result != SKCodecResult.IncompleteInput) {
|
|
bitmap.Dispose ();
|
|
bitmap = null;
|
|
}
|
|
return bitmap;
|
|
}
|
|
|
|
public static SKBitmap Decode (Stream stream)
|
|
{
|
|
if (stream == null) {
|
|
throw new ArgumentNullException (nameof (stream));
|
|
}
|
|
using (var codec = SKCodec.Create (stream)) {
|
|
if (codec == null) {
|
|
return null;
|
|
}
|
|
return Decode (codec);
|
|
}
|
|
}
|
|
|
|
public static SKBitmap Decode (Stream stream, SKImageInfo bitmapInfo)
|
|
{
|
|
if (stream == null) {
|
|
throw new ArgumentNullException (nameof (stream));
|
|
}
|
|
using (var codec = SKCodec.Create (stream)) {
|
|
if (codec == null) {
|
|
return null;
|
|
}
|
|
return Decode (codec, bitmapInfo);
|
|
}
|
|
}
|
|
|
|
public static SKBitmap Decode (SKStream stream)
|
|
{
|
|
if (stream == null) {
|
|
throw new ArgumentNullException (nameof (stream));
|
|
}
|
|
using (var codec = SKCodec.Create (stream)) {
|
|
if (codec == null) {
|
|
return null;
|
|
}
|
|
return Decode (codec);
|
|
}
|
|
}
|
|
|
|
public static SKBitmap Decode (SKStream stream, SKImageInfo bitmapInfo)
|
|
{
|
|
if (stream == null) {
|
|
throw new ArgumentNullException (nameof (stream));
|
|
}
|
|
using (var codec = SKCodec.Create (stream)) {
|
|
if (codec == null) {
|
|
return null;
|
|
}
|
|
return Decode (codec, bitmapInfo);
|
|
}
|
|
}
|
|
|
|
public static SKBitmap Decode (SKData data)
|
|
{
|
|
if (data == null) {
|
|
throw new ArgumentNullException (nameof (data));
|
|
}
|
|
using (var codec = SKCodec.Create (data)) {
|
|
if (codec == null) {
|
|
return null;
|
|
}
|
|
return Decode (codec);
|
|
}
|
|
}
|
|
|
|
public static SKBitmap Decode (SKData data, SKImageInfo bitmapInfo)
|
|
{
|
|
if (data == null) {
|
|
throw new ArgumentNullException (nameof (data));
|
|
}
|
|
using (var codec = SKCodec.Create (data)) {
|
|
if (codec == null) {
|
|
return null;
|
|
}
|
|
return Decode (codec, bitmapInfo);
|
|
}
|
|
}
|
|
|
|
public static SKBitmap Decode (string filename)
|
|
{
|
|
if (filename == null) {
|
|
throw new ArgumentNullException (nameof (filename));
|
|
}
|
|
using (var codec = SKCodec.Create (filename)) {
|
|
if (codec == null) {
|
|
return null;
|
|
}
|
|
return Decode (codec);
|
|
}
|
|
}
|
|
|
|
public static SKBitmap Decode (string filename, SKImageInfo bitmapInfo)
|
|
{
|
|
if (filename == null) {
|
|
throw new ArgumentNullException (nameof (filename));
|
|
}
|
|
using (var codec = SKCodec.Create (filename)) {
|
|
if (codec == null) {
|
|
return null;
|
|
}
|
|
return Decode (codec, bitmapInfo);
|
|
}
|
|
}
|
|
|
|
public static SKBitmap Decode (byte[] buffer) =>
|
|
Decode (buffer.AsSpan ());
|
|
|
|
public static SKBitmap Decode (byte[] buffer, SKImageInfo bitmapInfo) =>
|
|
Decode (buffer.AsSpan (), bitmapInfo);
|
|
|
|
public static SKBitmap Decode (ReadOnlySpan<byte> buffer)
|
|
{
|
|
fixed (byte* b = buffer) {
|
|
using var skdata = SKData.Create ((IntPtr)b, buffer.Length);
|
|
using var codec = SKCodec.Create (skdata);
|
|
return Decode (codec);
|
|
}
|
|
}
|
|
|
|
public static SKBitmap Decode (ReadOnlySpan<byte> buffer, SKImageInfo bitmapInfo)
|
|
{
|
|
fixed (byte* b = buffer) {
|
|
using var skdata = SKData.Create ((IntPtr)b, buffer.Length);
|
|
using var codec = SKCodec.Create (skdata);
|
|
return Decode (codec, bitmapInfo);
|
|
}
|
|
}
|
|
|
|
// InstallPixels
|
|
|
|
public bool InstallPixels (SKImageInfo info, IntPtr pixels)
|
|
{
|
|
return InstallPixels (info, pixels, info.RowBytes, null, null);
|
|
}
|
|
|
|
public bool InstallPixels (SKImageInfo info, IntPtr pixels, int rowBytes)
|
|
{
|
|
return InstallPixels (info, pixels, rowBytes, null, null);
|
|
}
|
|
|
|
public bool InstallPixels (SKImageInfo info, IntPtr pixels, int rowBytes, SKBitmapReleaseDelegate releaseProc)
|
|
{
|
|
return InstallPixels (info, pixels, rowBytes, releaseProc, null);
|
|
}
|
|
|
|
public bool InstallPixels (SKImageInfo info, IntPtr pixels, int rowBytes, SKBitmapReleaseDelegate releaseProc, object context)
|
|
{
|
|
var cinfo = SKImageInfoNative.FromManaged (ref info);
|
|
var del = releaseProc != null && context != null
|
|
? new SKBitmapReleaseDelegate ((addr, _) => releaseProc (addr, context))
|
|
: releaseProc;
|
|
DelegateProxies.Create (del, out _, out var ctx);
|
|
var proxy = del is not null ? DelegateProxies.SKBitmapReleaseProxy : null;
|
|
return SkiaApi.sk_bitmap_install_pixels (Handle, &cinfo, (void*)pixels, (IntPtr)rowBytes, proxy, (void*)ctx);
|
|
}
|
|
|
|
public bool InstallPixels (SKPixmap pixmap)
|
|
{
|
|
return SkiaApi.sk_bitmap_install_pixels_with_pixmap (Handle, pixmap.Handle);
|
|
}
|
|
|
|
// NotifyPixelsChanged
|
|
|
|
public void NotifyPixelsChanged ()
|
|
{
|
|
SkiaApi.sk_bitmap_notify_pixels_changed (Handle);
|
|
}
|
|
|
|
// PeekPixels
|
|
|
|
public SKPixmap PeekPixels ()
|
|
{
|
|
SKPixmap pixmap = new SKPixmap ();
|
|
var result = PeekPixels (pixmap);
|
|
if (result) {
|
|
return pixmap;
|
|
} else {
|
|
pixmap.Dispose ();
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public bool PeekPixels (SKPixmap pixmap)
|
|
{
|
|
if (pixmap == null) {
|
|
throw new ArgumentNullException (nameof (pixmap));
|
|
}
|
|
var result = SkiaApi.sk_bitmap_peek_pixels (Handle, pixmap.Handle);
|
|
if (result)
|
|
pixmap.pixelSource = this;
|
|
return result;
|
|
}
|
|
|
|
// Resize
|
|
|
|
[Obsolete ("Use Resize(SKImageInfo info, SKSamplingOptions sampling) instead.")]
|
|
public SKBitmap Resize (SKImageInfo info, SKFilterQuality quality) =>
|
|
Resize (info, quality.ToSamplingOptions ());
|
|
|
|
[Obsolete ("Use Resize(SKSizeI size, SKSamplingOptions sampling) instead.")]
|
|
public SKBitmap Resize (SKSizeI size, SKFilterQuality quality) =>
|
|
Resize (size, quality.ToSamplingOptions ());
|
|
|
|
public SKBitmap Resize (SKImageInfo info, SKSamplingOptions sampling)
|
|
{
|
|
if (info.IsEmpty)
|
|
return null;
|
|
|
|
var dst = new SKBitmap (info);
|
|
if (ScalePixels (dst, sampling)) {
|
|
return dst;
|
|
} else {
|
|
dst.Dispose ();
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public SKBitmap Resize (SKSizeI size, SKSamplingOptions sampling) =>
|
|
Resize (Info.WithSize (size), sampling);
|
|
|
|
// ScalePixels
|
|
|
|
[Obsolete ("Use ScalePixels(SKBitmap destination, SKSamplingOptions sampling) instead.")]
|
|
public bool ScalePixels (SKBitmap destination, SKFilterQuality quality) =>
|
|
ScalePixels (destination, quality.ToSamplingOptions ());
|
|
|
|
[Obsolete ("Use ScalePixels(SKPixmap destination, SKSamplingOptions sampling) instead.")]
|
|
public bool ScalePixels (SKPixmap destination, SKFilterQuality quality) =>
|
|
ScalePixels (destination, quality.ToSamplingOptions ());
|
|
|
|
public bool ScalePixels (SKBitmap destination, SKSamplingOptions sampling)
|
|
{
|
|
if (destination == null) {
|
|
throw new ArgumentNullException (nameof (destination));
|
|
}
|
|
|
|
using (var dstPix = destination.PeekPixels ()) {
|
|
return ScalePixels (dstPix, sampling);
|
|
}
|
|
}
|
|
|
|
public bool ScalePixels (SKPixmap destination, SKSamplingOptions sampling)
|
|
{
|
|
if (destination == null) {
|
|
throw new ArgumentNullException (nameof (destination));
|
|
}
|
|
|
|
using (var srcPix = PeekPixels ()) {
|
|
return srcPix.ScalePixels (destination, sampling);
|
|
}
|
|
}
|
|
|
|
// From/ToImage
|
|
|
|
public static SKBitmap FromImage (SKImage image)
|
|
{
|
|
if (image == null) {
|
|
throw new ArgumentNullException (nameof (image));
|
|
}
|
|
|
|
var info = new SKImageInfo (image.Width, image.Height, SKImageInfo.PlatformColorType, image.AlphaType);
|
|
var bmp = new SKBitmap (info);
|
|
if (!image.ReadPixels (info, bmp.GetPixels (), info.RowBytes, 0, 0)) {
|
|
bmp.Dispose ();
|
|
bmp = null;
|
|
}
|
|
return bmp;
|
|
}
|
|
|
|
// Encode
|
|
|
|
public SKData Encode (SKEncodedImageFormat format, int quality)
|
|
{
|
|
using var pixmap = PeekPixels ();
|
|
return pixmap?.Encode (format, quality);
|
|
}
|
|
|
|
public bool Encode (Stream dst, SKEncodedImageFormat format, int quality)
|
|
{
|
|
using var wrapped = new SKManagedWStream (dst);
|
|
return Encode (wrapped, format, quality);
|
|
}
|
|
|
|
public bool Encode (SKWStream dst, SKEncodedImageFormat format, int quality)
|
|
{
|
|
if (dst == null)
|
|
throw new ArgumentNullException (nameof (dst));
|
|
|
|
using var pixmap = PeekPixels ();
|
|
return pixmap?.Encode (dst, format, quality) ?? false;
|
|
}
|
|
|
|
// Swap
|
|
|
|
private void Swap (SKBitmap other)
|
|
{
|
|
SkiaApi.sk_bitmap_swap (Handle, other.Handle);
|
|
}
|
|
|
|
// ToShader
|
|
|
|
public SKShader ToShader () =>
|
|
ToShader (SKShaderTileMode.Clamp, SKShaderTileMode.Clamp, SKSamplingOptions.Default, null);
|
|
public SKShader ToShader (SKShaderTileMode tmx, SKShaderTileMode tmy) =>
|
|
ToShader (tmx, tmy, SKSamplingOptions.Default, null);
|
|
|
|
public SKShader ToShader (SKShaderTileMode tmx, SKShaderTileMode tmy, SKSamplingOptions sampling) =>
|
|
ToShader (tmx, tmy, sampling, null);
|
|
|
|
[Obsolete ("Use ToShader(SKShaderTileMode tmx, SKShaderTileMode tmy, SKSamplingOptions sampling) instead.")]
|
|
public SKShader ToShader (SKShaderTileMode tmx, SKShaderTileMode tmy, SKFilterQuality quality) =>
|
|
ToShader (tmx, tmy, quality.ToSamplingOptions(), null);
|
|
|
|
public SKShader ToShader (SKShaderTileMode tmx, SKShaderTileMode tmy, SKMatrix localMatrix) =>
|
|
ToShader (tmx, tmy, SKSamplingOptions.Default, &localMatrix);
|
|
|
|
public SKShader ToShader (SKShaderTileMode tmx, SKShaderTileMode tmy, SKSamplingOptions sampling, SKMatrix localMatrix) =>
|
|
ToShader (tmx, tmy, sampling, &localMatrix);
|
|
|
|
[Obsolete ("Use ToShader(SKShaderTileMode tmx, SKShaderTileMode tmy, SKSamplingOptions sampling, SKMatrix localMatrix) instead.")]
|
|
public SKShader ToShader (SKShaderTileMode tmx, SKShaderTileMode tmy, SKFilterQuality quality, SKMatrix localMatrix) =>
|
|
ToShader (tmx, tmy, quality.ToSamplingOptions(), &localMatrix);
|
|
|
|
private SKShader ToShader (SKShaderTileMode tmx, SKShaderTileMode tmy, SKSamplingOptions sampling, SKMatrix* localMatrix) =>
|
|
SKShader.GetObject (SkiaApi.sk_bitmap_make_shader (Handle, tmx, tmy, &sampling, localMatrix));
|
|
}
|
|
}
|