SkiaSharp 提供了多种强大的图像缩放方法,可以满足不同场景下的图像处理需求。本文将详细探讨 SkiaSharp 中图像缩放的各种技术和最佳实践。
Nuget 安装包
SkiaSharp
SkiaSharp.Views.WindowsForms
基本缩放方法
等比例缩放
using System.Windows.Forms;
using SkiaSharp;
namespace AppImageScaling
{
    public partial class Form1 : Form
    {
        private SKBitmap originalImage;
        public Form1()
        {
            InitializeComponent();
        }
        private void btnLoad_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog openFileDialog = new OpenFileDialog())
            {
                openFileDialog.Filter = "Image Files|*.bmp;*.jpg;*.jpeg;*.png;*.gif";
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    originalImage = SKBitmap.Decode(openFileDialog.FileName);
                    SKBitmap scaledImage = ScaleImageProportionally(originalImage, 400);
                    pic.Image = BitmapFromSKBitmap(scaledImage);
                }
            }
        }
        public SKBitmap ScaleImageProportionally(SKBitmap originalImage, int targetWidth)
        {
            // 计算等比例缩放的高度  
            float aspectRatio = (float)originalImage.Height / originalImage.Width;
            int targetHeight = (int)(targetWidth * aspectRatio);
            // 创建缩放后的位图  
            SKBitmap scaledBitmap = new SKBitmap(targetWidth, targetHeight);
            // 使用高质量缩放  
            using (SKCanvas canvas = new SKCanvas(scaledBitmap))
            {
                canvas.SetMatrix(SKMatrix.CreateScale(
                    (float)targetWidth / originalImage.Width,
                    (float)targetHeight / originalImage.Height
                ));
                // 绘制原始图像  
                canvas.DrawBitmap(originalImage, 0, 0);
            }
            return scaledBitmap;
        }
        private Bitmap BitmapFromSKBitmap(SKBitmap skBitmap)
        {
            using (var image = SKImage.FromBitmap(skBitmap))
            using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
            using (var stream = new System.IO.MemoryStream(data.ToArray()))
            {
                returnnew Bitmap(stream);
            }
        }
    }
}

指定缩放质量
SkiaSharp 提供多种缩放滤波器,可以根据不同需求选择:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SkiaSharp;
namespace AppImageScaling
{
    public partial class Form2 : Form
    {
        private SKBitmap originalImage;
        public Form2()
        {
            InitializeComponent();
        }
        private void btnLoad_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog openFileDialog = new OpenFileDialog())
            {
                openFileDialog.Filter = "Image Files|*.bmp;*.jpg;*.jpeg;*.png;*.gif";
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    originalImage = SKBitmap.Decode(openFileDialog.FileName);
                    int targetWidth = 400;
                    int targetHeight = (int)((float)originalImage.Height / originalImage.Width * targetWidth);
                    SKFilterQuality filterQuality = GetFilterQuality(cboQuality.SelectedItem.ToString());
                    SKBitmap scaledImage = ScaleImageWithFilter(originalImage, targetWidth, targetHeight, filterQuality);
                    pic.Image = BitmapFromSKBitmap(scaledImage);
                }
            }
        }
        public SKBitmap ScaleImageWithFilter(SKBitmap originalImage, int targetWidth
            , int targetHeight, SKFilterQuality filterQuality)
        {
            // 创建目标位图  
            SKBitmap scaledBitmap = new SKBitmap(targetWidth, targetHeight);
            using (SKCanvas canvas = new SKCanvas(scaledBitmap))
            {
                // 创建绘制对象并设置过滤质量  
                using (var paint = new SKPaint())
                {
                    paint.FilterQuality = filterQuality;
                    // 通过指定目标点和目标尺寸来绘制原始图像到目标位图  
                    canvas.DrawBitmap(originalImage, new SKRect(0, 0, targetWidth, targetHeight),
                                           new SKRect(0, 0, originalImage.Width, originalImage.Height), paint);
                }
            }
            return scaledBitmap;
        }
        private SKFilterQuality GetFilterQuality(string quality)
        {
            return quality switch
            {
                "Low" => SKFilterQuality.Low,
                "Medium" => SKFilterQuality.Medium,
                "High" => SKFilterQuality.High,
                _ => SKFilterQuality.None,
            };
        }
        private Bitmap BitmapFromSKBitmap(SKBitmap skBitmap)
        {
            using (var image = SKImage.FromBitmap(skBitmap))
            using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
            using (var stream = new System.IO.MemoryStream(data.ToArray()))
            {
                returnnew Bitmap(stream);
            }
        }
    }
}

高级缩放技术
保持图像清晰度的缩放
public SKBitmap ScaleImageWithSharpness(SKBitmap originalImage, float scaleFactor)
{
    // 计算目标尺寸
    int targetWidth = (int)(originalImage.Width * scaleFactor);
    int targetHeight = (int)(originalImage.Height * scaleFactor);
    // 创建高清缩放位图
    SKBitmap scaledBitmap = new SKBitmap(targetWidth, targetHeight);
    using (SKCanvas canvas = new SKCanvas(scaledBitmap))
    {
        // 使用高质量插值
        canvas.DrawBitmap(originalImage, 
            new SKRect(0, 0, originalImage.Width, originalImage.Height),
            new SKRect(0, 0, targetWidth, targetHeight), 
            new SKPaint 
            { 
                FilterQuality = SKFilterQuality.High 
            }
        );
    }
    return scaledBitmap;
}
缩放实践建议
性能与质量平衡
- 对于缩略图,使用 SKFilterQuality.Low
- 对于高质量展示,使用 SKFilterQuality.High
- 大幅缩放时,考虑分步缩放以保持图像质量
异常处理
public SKBitmap SafeScaleImage(SKBitmap originalImage, int targetWidth, int targetHeight)
{
    // 检查输入有效性
    if (originalImage == null)
        thrownew ArgumentNullException(nameof(originalImage));
    if (targetWidth <= 0 || targetHeight <= 0)
        thrownew ArgumentException("目标尺寸必须为正数");
    try
    {
        return ScaleImageWithFilter(
            originalImage, 
            targetWidth, 
            targetHeight, 
            SKFilterQuality.Medium
        );
    }
    catch (Exception ex)
    {
        // 记录错误或返回原图
        Console.WriteLine($"图像缩放失败:{ex.Message}");
        return originalImage;
    }
}
总结
SkiaSharp 提供了灵活且强大的图像缩放功能,能够通过选择合适的缩放方法和质量滤波器,在性能与图像质量之间实现良好平衡。在使用过程中,需要注意几个关键技巧:保持图像的纵横比以避免变形,根据需求选择适当的缩放质量以优化视觉效果,妥善处理边界情况以确保输出的准确性,同时权衡性能开销以满足实际应用的需求。这些策略有助于高效地实现高质量的图像缩放。
阅读原文:原文链接
该文章在 2025/9/4 14:39:27 编辑过