2025-11-19
C#
00

目录

Nuget 安装包
图像加载基础
从文件加载图像
从内存流加载图像
图像保存技巧
保存为不同格式
性能与内存管理
使用 using 语句
结语
注意事项

SkiaSharp 是一个强大的跨平台 2D 图形库,提供了丰富的图像处理能力。本文将深入探讨 SkiaSharp 中图像的加载、保存和基本操作。

Nuget 安装包

C#
SkiaSharp SkiaSharp.Views.WindowsForms

图像加载基础

从文件加载图像

C#
using System.Drawing; using System.Windows.Forms; using SkiaSharp; using SkiaSharp.Views.Desktop; namespace AppLoadSave { public partial class Form1 : Form { private SKBitmap loadedBitmap; public Form1() { InitializeComponent(); } // 从文件加载图像的方法 private SKBitmap LoadImageFromFile(string filePath) { try { // 使用 SKBitmap.Decode 方法加载图像 using (var stream = System.IO.File.OpenRead(filePath)) { return SKBitmap.Decode(stream); } } catch (Exception ex) { MessageBox.Show($"图像加载错误: {ex.Message}", "错误" , MessageBoxButtons.OK, MessageBoxIcon.Error); return null; } } private Bitmap SKBitmapToSystemBitmap(SKBitmap skBitmap) { // 创建一个新的 Bitmap,使用 SKBitmap 的宽度和高度 Bitmap bitmap = new Bitmap(skBitmap.Width, skBitmap.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb); // 锁定位图的位图数据 System.Drawing.Imaging.BitmapData bmpData = bitmap.LockBits( new Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, bitmap.PixelFormat); // 复制像素数据 IntPtr ptr = bmpData.Scan0; int bytes = Math.Abs(bmpData.Stride) * bitmap.Height; byte[] rgbValues = new byte[bytes]; // 从 SKBitmap 获取像素数据 byte[] skPixels = skBitmap.Bytes; // 转换颜色通道(BGRA to ARGB) for (int i = 0; i < skPixels.Length; i += 4) { rgbValues[i] = skPixels[i + 2]; // B rgbValues[i + 1] = skPixels[i + 1]; // G rgbValues[i + 2] = skPixels[i]; // R rgbValues[i + 3] = skPixels[i + 3]; // A } // 将像素数据复制到位图 System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes); bitmap.UnlockBits(bmpData); return bitmap; } private void btnLoad_Click(object sender, EventArgs e) { using (OpenFileDialog openFileDialog = new OpenFileDialog()) { openFileDialog.Filter = "图像文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif"; openFileDialog.Title = "选择图像文件"; if (openFileDialog.ShowDialog() == DialogResult.OK) { // 加载图像 loadedBitmap = LoadImageFromFile(openFileDialog.FileName); if (loadedBitmap != null) { // 直接从 SKBitmap 创建 Bitmap Bitmap bitmap = SKBitmapToSystemBitmap(loadedBitmap); pic.Image = bitmap; } } } } } }

image.png

从内存流加载图像

C#
SKBitmap LoadImageFromMemory(byte[] imageData) { try { // 从字节数组创建内存流 using (var stream = new MemoryStream(imageData)) { return SKBitmap.Decode(stream); } } catch (Exception ex) { Console.WriteLine($"内存流图像加载错误: {ex.Message}"); return null; } }

图像保存技巧

保存为不同格式

C#
private void btnSave_Click(object sender, EventArgs e) { // 检查 PictureBox 中是否有图像 if (pic.Image == null) { MessageBox.Show("没有可保存的图像", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } using (SaveFileDialog saveFileDialog = new SaveFileDialog()) { // 设置文件过滤器和标题 saveFileDialog.Filter = "JPEG 图像|*.jpg|PNG 图像|*.png|BMP 图像|*.bmp|GIF 图像|*.gif"; saveFileDialog.Title = "保存图像文件"; // 设置默认文件扩展名 saveFileDialog.DefaultExt = "jpg"; if (saveFileDialog.ShowDialog() == DialogResult.OK) { try { // 从 PictureBox 获取图像 Bitmap bitmapToSave = (Bitmap)pic.Image; // 将 System.Drawing.Bitmap 转换为 SKBitmap SKBitmap skBitmapToSave = SystemBitmapToSKBitmap(bitmapToSave); // 根据选择的文件类型确定编码格式 SKEncodedImageFormat imageFormat; switch (Path.GetExtension(saveFileDialog.FileName).ToLower()) { case ".png": imageFormat = SKEncodedImageFormat.Png; break; case ".bmp": imageFormat = SKEncodedImageFormat.Bmp; break; case ".gif": imageFormat = SKEncodedImageFormat.Gif; break; default: imageFormat = SKEncodedImageFormat.Jpeg; break; } // 保存图像 using (var stream = File.OpenWrite(saveFileDialog.FileName)) { // 压缩质量,对于 JPEG 可以调整(0-100) int quality = imageFormat == SKEncodedImageFormat.Jpeg ? 90 : 100; skBitmapToSave.Encode(imageFormat, quality) .SaveTo(stream); } MessageBox.Show("图像保存成功", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (Exception ex) { MessageBox.Show($"保存图像时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } } // 新增方法:将 System.Drawing.Bitmap 转换为 SKBitmap private SKBitmap SystemBitmapToSKBitmap(Bitmap systemBitmap) { // 使用 SkiaSharp 直接从 Bitmap 创建 SKBitmap using (var skImage = SKImage.FromEncodedData(BitmapToBytes(systemBitmap))) { return SKBitmap.FromImage(skImage); } } // 辅助方法:将 Bitmap 转换为字节数组 private byte[] BitmapToBytes(Bitmap bitmap) { using (var stream = new MemoryStream()) { // 将 Bitmap 保存到内存流 bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png); return stream.ToArray(); } }

性能与内存管理

使用 using 语句

  • 始终使用 using 语句管理 SKBitmapSKImage 等资源
  • 及时 Dispose() 不再使用的对象
  • 避免长时间持有大型图像对象

结语

SkiaSharp 提供了强大且灵活的图像处理能力。通过合理使用其 API,您可以轻松实现复杂的图像加载、保存和转换操作。

注意事项

  • 确保安装 SkiaSharp NuGet 包
  • 处理大型图像时注意内存消耗
  • 对于高性能场景,考虑使用流式处理

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!