【SkiaSharp绘图10】SKBitmap方法详解

SKBitMap方法

CanCopyTo 是否可复制为指定颜色类型

public bool CanCopyTo (SkiaSharp.SKColorType colorType);

判断是否可以将当前颜色类型转换为指定颜色类型。

Copy 深拷贝

public SkiaSharp.SKBitmap Copy ();

复制并返回一个SKBitmap对象。

Copy(SKColorType) 深拷贝为指定颜色类型

public SkiaSharp.SKBitmap Copy (SkiaSharp.SKColorType colorType);

复制为指定颜色类型的SKBitmap对象。

CopyTo(SKBitmap) 深拷贝

public bool CopyTo (SkiaSharp.SKBitmap destination);

复制到指定SKBitmap对象,并返回是否成功。

CopyTo(SKBitmap, SKColorType) 深拷贝

public bool CopyTo (SkiaSharp.SKBitmap destination, SkiaSharp.SKColorType colorType);

复制为指定颜色类型到指定SKBitmap对象,并返回是否成功。

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);

using (var paint = new SKPaint())
{
    paint.TextSize = 18;
    paint.Typeface = SKTypeface.FromFamilyName("黑体");
    paint.Color = SKColors.Green;
    using(var bgraBtmp=new SKBitmap(100,100, SKColorType.Bgra8888, SKAlphaType.Premul))               
    {
        using (var bCanvas = new SKCanvas(bgraBtmp))
        {
            bCanvas.DrawRect(new SKRect(10, 20, 90, 80), paint);
            canvas.DrawBitmap(bgraBtmp, 20, 20, paint);
            canvas.DrawText($"原图,矩形无圆形", 20, 20, paint);

            using (var copyBmp = bgraBtmp.Copy())
            {
                paint.Color = SKColors.Blue;
                bCanvas.DrawCircle(bgraBtmp.Width / 2, bgraBtmp.Height / 2, bgraBtmp.Width / 4, paint);

                canvas.DrawBitmap(copyBmp, 450, 20, paint);
                canvas.DrawText($"复制原图,后在原图上画圆", 450, 20, paint);
            }
        }                    

        using (var rgbaBmp = new SKBitmap())
        {
            if (bgraBtmp.CanCopyTo(SKColorType.Rgba8888))
            {//可以复制
                bgraBtmp.CopyTo(rgbaBmp, SKColorType.Rgba8888);
                canvas.DrawBitmap(rgbaBmp, 20, 120, paint);
                canvas.DrawText($"复制带圆的原图转RGBA", 20, 120, paint);
            }
            if(rgbaBmp.CanCopyTo(SKColorType.Gray8))
            {//可以复制
                using (var grayBmp = new SKBitmap(100, 100, SKColorType.Gray8, SKAlphaType.Premul))
                {
                    rgbaBmp.CopyTo(grayBmp, SKColorType.Gray8);
                    canvas.DrawBitmap(grayBmp, 20, 240, paint);
                    canvas.DrawText($"复制带圆的原图转Gray", 20, 240, paint);
                }
            }
        }                    
    }                
}

Copy
图像为深拷贝,修改原图,不影响复制后的图像。

Decode 解码内容

Decode(string)

public static SkiaSharp.SKBitmap Decode (string filename);

可使用相对或绝对路径

//支持中文,直接读取图像文件,正常,返回SKBitmap对象
var skBmp = SKBitmap.Decode(@"Images\中文路径\AIWomanBig.png");
//支持中文,直接读取图像文件,正常,返回SKBitmap对象
var skBmp = SKBitmap.Decode(@"D:\Images\中文路径\AIWomanBig.png");

注意,加载解码图像文件时:

  1. 解码不成功时,返回null,不报错。
  2. 图像文件不存在时,返回null,不报错。

Decode(Byte[])

public static SkiaSharp.SKBitmap Decode (byte[] buffer);
public static SkiaSharp.SKBitmap Decode (ReadOnlySpan<byte> buffer);

解码图像字节数组。

//先获取文件字节,再解码字节数组。正常,返回SKBitmap对象
byte[] fileBytes = File.ReadAllBytes(@"Images\中文路径\AIWomanBig.png");
skBmp = SKBitmap.Decode(fileBytes);
skBmp.Dispose()
;
//异常,fileBytes不可以为null
fileBytes = null;
if (fileBytes != null)
{
    skBmp = SKBitmap.Decode(fileBytes);
}

try
{
    fileBytes = new byte[] { 0x01, 0x02 };
    skBmp = SKBitmap.Decode(fileBytes);
}
catch (Exception ex)
{
    ;//报“值不能为null”
}

注意:

  1. 传入的字节数组为空或解码失败时,报异常。

Decode(Stream)

public static SkiaSharp.SKBitmap Decode (System.IO.Stream stream);
using (var stream = new FileStream(@"Images\中文路径\AIWomanBig.png", FileMode.Open))
{
    skBmp = SKBitmap.Decode(stream);
    skBmp.Dispose();
}

using (var stream = File.OpenRead(@"Images\中文路径\AIWomanBig.png"))
{
    skBmp = SKBitmap.Decode(stream);
    skBmp.Dispose();
}

using (var stream = File.OpenRead(@"Images\notImg.png"))
{//文件读取成功,但非图像
    //返回null,不报错
    skBmp = SKBitmap.Decode(stream);
}
  1. 解码成功时,返回SKBitmap对象
  2. 解码失败时,返回null,不报错。

Decode(SKStream)

public static SkiaSharp.SKBitmap Decode (SkiaSharp.SKStream stream);

使用SKStream解码图像

// 打开文件并创建流
using (FileStream fileStream = new FileStream(@"Images\AIWomanBig.png", FileMode.Open, FileAccess.Read))
{
    // 将 FileStream 转换为 SKManagedStream
    using (SKManagedStream skStream = new SKManagedStream(fileStream))
    {
        // 使用 SkiaSharp 解码图像
        skBmp = SKBitmap.Decode(skStream);
        skBmp.Dispose();
    }
}

// 打开文件并创建流
using (FileStream fileStream = new FileStream(@"Images\notImg.png", FileMode.Open, FileAccess.Read))
{
    // 将 FileStream 转换为 SKManagedStream
    using (SKManagedStream skStream = new SKManagedStream(fileStream))
    {
        // 非图像,解码失败,返回null,不报错
        skBmp = SKBitmap.Decode(skStream);
        ;
    }
}
  1. 解码成功时,返回SKBitmap对象
  2. 解码失败时,返回null,不报错。

Decode(SKData)

public static SkiaSharp.SKBitmap Decode (SkiaSharp.SKData data);
// 打开文件并创建流
using (FileStream fileStream = new FileStream(@"Images\AIWomanBig.png", FileMode.Open, FileAccess.Read))
{
    // 将 FileStream 转换为 SKManagedStream
    using (var skData = SKData.Create(fileStream))
    {
        // 使用 SkiaSharp 解码图像
        skBmp = SKBitmap.Decode(skData);
        skBmp.Dispose();
    }
}

// 打开文件并创建流
using (FileStream fileStream = new FileStream(@"Images\notImg.png", FileMode.Open, FileAccess.Read))
{
    // 将 FileStream 转换为 SKManagedStream
    using (var skData = SKData.Create(fileStream))
    {
        // 非图像,解码失败,返回null,不报错
        skBmp = SKBitmap.Decode(skData);
        ;
    }
}
  1. 解码成功时,返回SKBitmap对象
  2. 解码失败时,返回null,不报错。

Decdoe(SKCodec)

public static SkiaSharp.SKBitmap Decode (SkiaSharp.SKCodec codec);
// 打开文件并创建流
using (FileStream fileStream = new FileStream(@"Images\AIWomanBig.png", FileMode.Open, FileAccess.Read))
{
    // 将 FileStream 转换为 SKManagedStream
    using (var skCodec = SKCodec.Create(fileStream))
    {
        // 使用 SkiaSharp 解码图像
        skBmp = SKBitmap.Decode(skCodec);
        skBmp.Dispose();
    }
}

// 打开文件并创建流
using (FileStream fileStream = new FileStream(@"Images\notImg.png", FileMode.Open, FileAccess.Read))
{
    // 将 FileStream 转换为 SKManagedStream
    using (var skCodec = SKCodec.Create(fileStream))
    {
        try
        {
            // 非图像,解码失败,异常,报错
            skBmp = SKBitmap.Decode(skCodec);
            ;
        }
        catch (Exception ex)
        {
        }                            
    }
}

  1. 解码成功时,返回SKBitmap对象
  2. 解码失败时,异常、报错。

Decode(X,SKImageInfo)

按官网的解析应该是,可以通过SKImageInfo来控制图像的缩放和颜色类型的转换,可我在实际测试过程中,只要SKImageInfo与原图像的SKImageInfo对象不一样,都是返回null。不知是Bug,还是调用方法不正确!?

DecodeBounds 解码图像信息

public static SkiaSharp.SKImageInfo DecodeBounds (string filename);
public static SkiaSharp.SKImageInfo DecodeBounds (System.IO.Stream stream);
public static SkiaSharp.SKImageInfo DecodeBounds (ReadOnlySpan<byte> buffer);
public static SkiaSharp.SKImageInfo DecodeBounds (SkiaSharp.SKStream stream);
public static SkiaSharp.SKImageInfo DecodeBounds (SkiaSharp.SKData data);
public static SkiaSharp.SKImageInfo DecodeBounds (byte[] buffer);

调整获取图像信息,不解码具体内容

 SKImageInfo imgInfo = SKImageInfo.Empty;
 var sw = Stopwatch.StartNew();
 var times = 10;

 for (int i = 0; i < times; i++)
 {
     imgInfo = SKBitmap.DecodeBounds(@"Images\AIWoman.png");
 }
 sw.Stop();

 if (imgInfo != SKImageInfo.Empty)
 {
     canvas.DrawText($"DecodeBounds {times}times:{sw.ElapsedMilliseconds}ms,Img Width:{imgInfo.Width},Height:{imgInfo.Height}", 20, 30, paint);
 }

 sw.Restart();

 for (int i = 0; i < times; i++)
 {
     skBmp = SKBitmap.Decode(@"Images\AIWoman.png");
 }
 sw.Stop();

 if (imgInfo != SKImageInfo.Empty)
 {
     canvas.DrawText($"Decode {times}times:{sw.ElapsedMilliseconds}ms,Img Width:{skBmp.Width},Height:{skBmp.Height},", 20, 60, paint);
 }

对比Decode与DecodeBounds的速度。
DecoudeBounds

Encode 编码

public SkiaSharp.SKData Encode (SkiaSharp.SKEncodedImageFormat format, int quality);
public bool Encode (SkiaSharp.SKWStream dst, SkiaSharp.SKEncodedImageFormat format, int quality);
public bool Encode (System.IO.Stream dst, SkiaSharp.SKEncodedImageFormat format, int quality);

SKBitmap可以Encode为Jpeg、Png格式,不能直接保存为Gif,Bmp格式?

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);

using (var paint = new SKPaint())
{
    paint.TextSize = 18;
    paint.Typeface = SKTypeface.FromFamilyName("黑体");
    int width = 200;
    int height = 200;
    using (var bmp = new SKBitmap(width, height))
    {
        using (var sCanvas = new SKCanvas(bmp))
        {
            sCanvas.Clear(SKColors.White);
            using (var sPaint = new SKPaint())
            {
                sPaint.Color = SKColors.Green;
                sPaint.IsAntialias = true;
                sCanvas.DrawCircle(bmp.Width / 2, bmp.Height / 2, bmp.Width / 4, sPaint);
            }
        }


        //Encode(SKEncodedImageFormat, Int32)
        using (var skData=bmp.Encode(SKEncodedImageFormat.Jpeg,80))
        {
            using (var stream = File.OpenWrite(@"Images\circle.jpg"))
            {
                skData.SaveTo(stream);
            }
        }

        //Encode(SKWStream, SKEncodedImageFormat, Int32)
        using (var fileStream=File.OpenWrite(@"Images\circle.png"))
        {
            using (var managedStream = new SKManagedWStream(fileStream))
            {
                var success = bmp.Encode(managedStream, SKEncodedImageFormat.Png, 100);
                if(!success)
                {
                    Console.WriteLine("Encode SKBitmap fail!");
                }
            }
        }

        //不支持直接,保存为bmp?SKBitmap转Bitmap

        // 将 SKBitmap 转换为 Bitmap
        using (var image = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
        {
            var data = bmp.Bytes;
            var bitmapData = image.LockBits(new System.Drawing.Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, image.PixelFormat);
            IntPtr pointer = bitmapData.Scan0;
            System.Runtime.InteropServices.Marshal.Copy(data, 0, pointer, data.Length); // 
            image.UnlockBits(bitmapData);

            // 将 Bitmap 保存为 BMP 文件
            image.Save("Images/circle.bmp", ImageFormat.Bmp);
        }
    }
}

Erase 清除图像

public void Erase (SkiaSharp.SKColor color);
public void Erase (SkiaSharp.SKColor color, SkiaSharp.SKRectI rect);

填充整个图像或指定矩形区域为指定颜色。

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);

using (var paint = new SKPaint())
{
    paint.TextSize = 18;
    paint.Typeface = SKTypeface.FromFamilyName("黑体");
    int width = 200;
    int height = 200;
    using (var bmp = new SKBitmap(width, height))
    {
        //将图像填充为LightGreen
        bmp.Erase(SKColors.LightGreen);
        canvas.DrawBitmap(bmp,20,20, paint);

        //将指定矩形区域填充为Red
        bmp.Erase(SKColors.Red, new SKRectI(40, 40, 140, 140));
        canvas.DrawBitmap(bmp, 320, 20, paint);    
    }
}

Erase

ExtractAlpha 提取透明通道

public bool ExtractAlpha (SkiaSharp.SKBitmap destination);

单独提取Alpha通道作为新的SkBitmap对象。

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);

using (var paint = new SKPaint())
{
    paint.TextSize = 18;
    paint.Typeface = SKTypeface.FromFamilyName("宋体");
    paint.FilterQuality = SKFilterQuality.High;
    if (skBmp == null) skBmp = SKBitmap.Decode(@"Images\Transparent.png");
    // 创建一个 SKPaint 对象,用于模糊处理
    paint.ImageFilter = SKImageFilter.CreateBlur(5, 5);
    // 提取 alpha 通道并应用模糊滤镜
    SKBitmap alphaBitmap = new SKBitmap();

    var width = 500;
    var height = width * skBmp.Height / skBmp.Width;
    if (skBmp.ExtractAlpha(alphaBitmap, paint))
    {
        // 绘制阴影
        canvas.DrawBitmap(alphaBitmap, new SKRect(25, 25, 25 + width, 25 + height), paint);  // 阴影位置偏移
    }
    alphaBitmap.Dispose();
    paint.ImageFilter = null;
    // 绘制原图像
    canvas.DrawBitmap(skBmp, new SKRect(20, 20, 20 + width, 20 + height), paint);
    canvas.DrawText($"原图+阴影", 20, 20 + height + 20, paint);

    canvas.DrawBitmap(skBmp, new SKRect(20, 40 + height, 20 + width, 40 + height * 2), paint);
    canvas.DrawText($"原图", 20, 20 + height*2 + 20, paint);
}

提取原图的Alpha通道,进行模糊后做为原图的阴影。
ExtractAlpha

ExtractSubset提取子图像

public bool ExtractSubset (SkiaSharp.SKBitmap destination, SkiaSharp.SKRectI subset);

从原像中获取指定区域的子图像。一般情况,该子图像与原图像是共享内存的,除非ColorType不支持。

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);

using (var paint = new SKPaint())
{
    paint.TextSize = 18;
    paint.Typeface = SKTypeface.FromFamilyName("宋体");
    paint.FilterQuality = SKFilterQuality.High;
    if (skBmp == null) skBmp = SKBitmap.Decode(@"Images\AIWoman.png");

    SKBitmap subBmp = new SKBitmap();
    //提取子图像
    if(skBmp.ExtractSubset(subBmp,new SKRectI(1400, 0, 2400,1100)))
    {
        canvas.DrawBitmap(subBmp, new SKRect(20, 20,320,320), paint);
    }
    subBmp.Dispose();

    canvas.DrawBitmap(skBmp, new SKRect(350,20,750,420), paint);
}

提取子图像并绘制。
ExtractSubset

GetAddress 获取指定像素的内存地址

public IntPtr GetAddress (int x, int y);

获取指定像素的内存地址。

GetPixel 获取指定像素的颜色

public SkiaSharp.SKColor GetPixel (int x, int y);

获取指定像素的颜色。(注意,大量访问时,效率不高,请改用指针方式)

GetPixels 获取像素内存地址

public IntPtr GetPixels ();
public IntPtr GetPixels (out IntPtr length);

获取图像的像素地址和大小。(如果图像没有任何像素,返回IntPtr.Zero)
大量像素时,使用指针操作,性能更优。

GetPixelSpan 获取像素字节数组

public ReadOnlySpan<byte> GetPixelSpan ();

获取图像的字节数组。

InstallMaskPixels 像素转Alpha位图(蒙版)

public bool InstallMaskPixels (SkiaSharp.SKMask mask);

将指定蒙版的像素安装(赋值)到位图中。(得到的位图只有Alpha通道)

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);

using (var paint = new SKPaint())
{
    paint.TextSize = 18;
    paint.Typeface = SKTypeface.FromFamilyName("宋体");
    paint.FilterQuality = SKFilterQuality.High;

    if (skBmp == null) skBmp = SKBitmap.Decode(@"Images\AIWoman.png");

    // 创建一个掩码图像的数据
    int width = 800;
    int height = 800;
    // 分配掩码数据的非托管内存
    IntPtr maskPtr = Marshal.AllocHGlobal(width * height);

    try
    {
        //绘制原图
        canvas.DrawBitmap(skBmp, new SKRect(0, 0, width, height), paint);
        //渐变透明
        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                Marshal.WriteByte(maskPtr, y * width + x, (byte)(255F * (x + y) / (height + width)));
            }
        }

        var mask = new SKMask
        {
            Image = maskPtr,
            Format = SKMaskFormat.A8,
            Bounds = new SKRectI(0, 0, width, height),
            RowBytes = (uint)width
        };
        
        using (var bmp = new SKBitmap(width, height))
        {
            if (bmp.InstallMaskPixels(mask))
            {
                paint.BlendMode = SKBlendMode.DstIn;
                //绘制半透层
                canvas.DrawBitmap(bmp, 0, 0,paint);
            }
        }           
    }
    finally
    {
        Marshal.FreeHGlobal(maskPtr);
    }
}

定义一个SKMask,赋值为从左上角到右下角的半透掩膜。先绘制原图,再在原图上绘制半透明掩膜。
InstallMaskPixels

InstallPixels 像素转位图

public bool InstallPixels (SkiaSharp.SKPixmap pixmap);
public bool InstallPixels (SkiaSharp.SKImageInfo info, IntPtr pixels);
public bool InstallPixels (SkiaSharp.SKImageInfo info, IntPtr pixels, int rowBytes);
public bool InstallPixels (SkiaSharp.SKImageInfo info, IntPtr pixels, int rowBytes, SkiaSharp.SKBitmapReleaseDelegate releaseProc);

用于将现有的像素数据安装到一个 SKBitmap 对象中。

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);

// 假设我们有一个已存在的像素数组
int width = 300;
int height = 300;
int bytesPerPixel = 4;
byte[] pixelData = new byte[width * height * bytesPerPixel];

// 填充像素数据
for (int i = 0; i < pixelData.Length; i++)
{
    if ((i + 1) % 4 == 0)
    {
        pixelData[i] = 255;
    }
    else
    {
        pixelData[i] = (byte)(i % 256);
    }
}

// 创建 SKBitmap 并安装像素数据
SKBitmap bitmap = new SKBitmap();
IntPtr pixelPtr = Marshal.UnsafeAddrOfPinnedArrayElement(pixelData, 0);

// 定义解构函数,当 bitmap 释放时释放内存
SkiaSharp.SKBitmapReleaseDelegate releaseFunction = (addr, context) => { };

// 安装像素数据
bitmap.InstallPixels(new SKImageInfo(width, height), pixelPtr, width * bytesPerPixel, releaseFunction, IntPtr.Zero);

using(var paint=new SKPaint())
{
    paint.FilterQuality = SKFilterQuality.High;
    paint.BlendMode = SKBlendMode.SrcOver;
    canvas.DrawBitmap(bitmap, new SKRect(0,0,width,height),paint);
}           

// 不再需要 bitmap 时,释放资源
bitmap.Dispose();

定义并赋值一个字节数组,获取到去指针后通过InstallPixels赋值给SKBitmap对象,并绘制出结果。
InstallPixels

NotifyPixelsChanged 修改通知

public void NotifyPixelsChanged ();

向位图的使用者指示像素数据已更改。
使用指针直接修改像素时,调用NotifyPixelsChanged()方法,确保输出SKBitmap对象与实际内容一致。

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);

int width = 100;
int height = 100;
int bytesPerPixel = 4;

// 创建一个空的 SKBitmap
SKBitmap bitmap = new SKBitmap(width, height, SKColorType.Rgba8888, SKAlphaType.Premul);

// 获取像素数据指针
IntPtr pixelPtr = bitmap.GetPixels();

// 直接操作像素数据
unsafe
{
    byte* pixels = (byte*)pixelPtr.ToPointer();
    for (int i = 0; i < width * height * bytesPerPixel; i++)
    {
        if ((i + 1) % 4 == 0)
        {
            pixels[i] = 255;
        }
        else
        {
            pixels[i] = (byte)(i % 256);
        }                    
    }
}
// 通知 SKBitmap 像素数据已经改变
bitmap.NotifyPixelsChanged();
canvas.DrawBitmap(bitmap, 0, 0);
bitmap.Dispose();

PeekPixels 获取图像信息

public SkiaSharp.SKPixmap PeekPixels ();
public bool PeekPixels (SkiaSharp.SKPixmap pixmap);

提供对 SKBitmap 内部像素数据的直接访问,而不需要复制数据。这在需要高效地读取或修改像素数据时非常有用
意义

  1. 性能优化:通过避免数据复制,PeekPixels 可以提高性能,尤其是在处理大位图或频繁访问像素数据的情况下。
  2. 直接操作像素:允许开发者直接读取和操作位图的像素数据,从而实现一些低级别的图像处理操作,比如图像滤镜、特效等。
  3. 内存效率:减少内存占用,因为无需创建像素数据的副本。
var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);

if (skBmp == null) skBmp = SKBitmap.Decode(@"Images\AIWoman.png");

var sw=Stopwatch.StartNew();
var pixmap = new SKPixmap();
if (skBmp.PeekPixels(pixmap))
{
    int width = pixmap.Width;
    int height = pixmap.Height;
    IntPtr pixels = pixmap.GetPixels();

    // Example: Invert colors
    unsafe
    {
        byte* ptr = (byte*)pixels;
        for (int i = 0; i < height; i++)
        {
            for (int j = 0; j < width; j++)
            {
                int index = (i * width + j) * 4;
                ptr[index] = (byte)(255 - ptr[index]);       // R
                ptr[index + 1] = (byte)(255 - ptr[index + 1]); // G
                ptr[index + 2] = (byte)(255 - ptr[index + 2]); // B
            }
        }
    }
}
sw.Stop();
using (var paint = new SKPaint())
{
    paint.FilterQuality = SKFilterQuality.High;
    canvas.DrawBitmap(skBmp, new SKRect(20, 20, 420, 420), paint);
    paint.TextSize = 24;
    canvas.DrawText($"Invert {pixmap.Width}x{pixmap.Height} elapsed time:{sw.ElapsedMilliseconds}ms", 20, 450, paint);
}

使用PeekPixels使用图像信息,并反转每个像素。

PeekPixels

Reset 重置

public void Reset ();

将位图置为宽高都为0。释放资源、清空内容。

Resize 缩放

public SkiaSharp.SKBitmap Resize (SkiaSharp.SKImageInfo info, SkiaSharp.SKFilterQuality quality);
public SkiaSharp.SKBitmap Resize (SkiaSharp.SKSizeI size, SkiaSharp.SKFilterQuality quality);

缩放为指定尺寸和质量的图像。

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);

if (skBmp == null) skBmp = SKBitmap.Decode(@"Images\AIWoman.png");

var resizeBmp = skBmp.Resize(new SKSizeI(400, 400), SKFilterQuality.High);

var sw = Stopwatch.StartNew();
if (resizeBmp != null)
{
    using (var paint = new SKPaint())
    {
        paint.FilterQuality = SKFilterQuality.High;
        canvas.DrawBitmap(resizeBmp, 20, 20, paint);
        paint.TextSize = 24;
        sw.Stop();
        canvas.DrawText($"Size: {resizeBmp.Width}x{resizeBmp.Height} Elapsed time:{sw.ElapsedMilliseconds}ms", 20, 450, paint);
    }
    resizeBmp.Dispose();
}
sw.Restart();

using (var paint = new SKPaint())
{
    paint.FilterQuality = SKFilterQuality.High;
    canvas.DrawBitmap(skBmp, new SKRect(440, 20, 840, 420), paint);
    paint.TextSize = 24;
    sw.Stop();
    sw.Stop();
    canvas.DrawText($"Elapsed time:{sw.ElapsedMilliseconds}ms", 420, 450, paint);
}

缩放后绘制,与直接绘制为指定尺寸的图像,其性能不一样。
Resize

ScalePixels 缩放

public bool ScalePixels (SkiaSharp.SKPixmap destination, SkiaSharp.SKFilterQuality quality);
public bool ScalePixels (SkiaSharp.SKBitmap destination, SkiaSharp.SKFilterQuality quality);

将图像缩放结果保存到已创建的SKBitmap对象。

SetPixel/SetPixels 设置像素

public void SetPixel (int x, int y, SkiaSharp.SKColor color);
public void SetPixels (IntPtr pixels);

设置指定像素的颜色。
设置图像指定的像素内存地址。

ToShader 转为着色器

public SkiaSharp.SKShader ToShader ();
public SkiaSharp.SKShader ToShader (SkiaSharp.SKShaderTileMode tmx, SkiaSharp.SKShaderTileMode tmy);
public SkiaSharp.SKShader ToShader (SkiaSharp.SKShaderTileMode tmx, SkiaSharp.SKShaderTileMode tmy, SkiaSharp.SKMatrix localMatrix);

将位图 (SKBitmap) 转换为一个着色器 (SKShader),从而可以在绘制操作中使用该位图作为填充图案或纹理。通过这种方式,可以实现复杂的图形效果,例如图像填充、纹理映射等。

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);

if (skBmp == null) skBmp = SKBitmap.Decode(@"Images\wall.png");

// 定义TileMode和Transform
var tileMode = SKShaderTileMode.Repeat;
var transform = SKMatrix.CreateScale(0.5f, 0.5f);

// 将SKBitmap转换为SKShader
using (SKShader shader = skBmp.ToShader(tileMode, tileMode, transform))
{
    // 创建一个画笔,并设置其着色器为bitmap的着色器
    using (SKPaint paint = new SKPaint())
    {
        paint.Shader = shader;

        // 使用这个画笔来绘制一个矩形
        SKRect rect = new SKRect(0, 0, info.Width,info.Height);
        canvas.DrawRect(rect, paint);
    }
}      

SKBitmap转着色器,填充画布。
ToShader

TryAllocPixels 尝试分配内存

public bool TryAllocPixels (SkiaSharp.SKImageInfo info);
public bool TryAllocPixels (SkiaSharp.SKImageInfo info, SkiaSharp.SKBitmapAllocFlags flags);
public bool TryAllocPixels (SkiaSharp.SKImageInfo info, int rowBytes);

尝试为 SKBitmap 对象分配像素数据的存储空间。成功调用后,SKBitmap 对象将有足够的内存来存储像素数据,可以用于绘制和图像处理操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图南科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值