C#图像处理:使用imagemagick实现像素放大水印转换等多种功能

C#图像处理:使用imagemagick实现像素放大水印转换等多种功能

C#图像处理:使用imagemagick实现像素放大水印转换等多种功能

上一篇文章写了最近邻和双线性插值的C#实现,代码量不小,而且只支持灰度图。彩色图要拆三个通道分别处理,代码翻三倍。

后来项目里需要同时处理缩放、格式转换、水印、合成,自己写显然不现实。换了ImageMagick的.NET封装------Magick.NET,几行代码全搞定。

这篇文章把Magick.NET常用的几个功能贴出来,包括上一篇文章的核心"像素放大",以及格式转换、水印、合成这些日常高频操作。

一、Magick.NET是什么?

ImageMagick本身是C写的,跨平台命令行工具,功能极其强大------支持100多种图像格式,缩放、旋转、裁剪、滤镜、合成、PDF转换全都能干。

Magick.NET是它的.NET封装,NuGet装上就能用,不需要在服务器上额外安装ImageMagick。

安装

复制代码
Install-Package Magick.NET-Q16-AnyCPU

Q16表示每个通道16位(颜色精度更高),AnyCPU表示跨平台。如果只需要8位精度,可以用Magick.NET-Q8-AnyCPU

二、像素放大:一行代码的事

上一篇文章用几十行代码实现了最近邻和双线性插值。Magick.NET里,缩放就一行:

csharp 复制代码
using ImageMagick;

public void ResizeImage(string inputPath, string outputPath, int width, int height)
{
    using (var image = new MagickImage(inputPath))
    {
        // 缩放到指定尺寸,自动保持宽高比
        image.Resize(width, height);
        image.Write(outputPath);
    }
}

如果高度传0,Magick.NET会自动根据宽高比计算。

强制拉伸(忽略宽高比)

csharp 复制代码
var size = new MagickGeometry(width, height);
size.IgnoreAspectRatio = true;
image.Resize(size);

插值算法怎么选:Magick.NET默认用Lanczos滤波算法,质量很高。如果追求速度、不介意画质,可以改成最近邻:

csharp 复制代码
image.Resize(width, height, FilterType.Point);  // Point = 最近邻

其他可选:FilterType.Box(邻域平均)、FilterType.Mitchell(双三次)、FilterType.Lanczos(高质量默认)。

批量处理 :循环读文件,逐个Resize,没什么特别的。但注意用完及时Dispose,using包好就行。

三、格式转换:100多种格式随便转

工业相机出来的可能是RAW、Bayer、TIFF,但最终存图常用JPEG或PNG。Magick.NET支持100多种格式互转。

csharp 复制代码
public void ConvertFormat(string inputPath, string outputPath)
{
    using (var image = new MagickImage(inputPath))
    {
        // 根据输出文件扩展名自动判断格式
        image.Write(outputPath);
    }
}

想指定格式也行:

csharp 复制代码
image.Format = MagickFormat.Png;
image.Write(outputPath);

JPEG质量控制

csharp 复制代码
image.Quality = 90;  // 0-100,越高文件越大质量越好
image.Write("output.jpg");

质量值越高保留细节越多,文件也越大。工业存档一般用95,预览用80就够了。

四、添加水印:文字和图片都能加

文字水印

csharp 复制代码
public void AddTextWatermark(string inputPath, string outputPath, string text)
{
    using (var image = new MagickImage(inputPath))
    {
        // 创建一个绘图对象
        using (var drawing = new Drawables())
        {
            // 设置字体、大小、颜色、位置
            drawing.FontPointSize(48);
            drawing.FillColor(MagickColors.White);
            drawing.TextAlignment(TextAlignment.Center);
            // 在图片中央偏下位置写字
            drawing.Text(image.Width / 2, image.Height - 50, text);
            drawing.Draw(image);
        }
        image.Write(outputPath);
    }
}

图片水印(Logo叠加)

csharp 复制代码
public void AddImageWatermark(string backgroundPath, string watermarkPath, string outputPath)
{
    using (var background = new MagickImage(backgroundPath))
    using (var watermark = new MagickImage(watermarkPath))
    {
        // 把水印缩放到合适大小(比如原图的1/4)
        watermark.Resize(background.Width / 4, 0);
        
        // 合成:把水印放在右下角
        int x = background.Width - watermark.Width - 20;
        int y = background.Height - watermark.Height - 20;
        background.Composite(watermark, x, y, CompositeOperator.Over);
        
        background.Write(outputPath);
    }
}

CompositeOperator.Over表示水印盖在背景图上面。还可以用Multiply(变暗)、Screen(变亮)等不同的合成模式。

五、图像合成:两张拼一张

左右拼接

csharp 复制代码
public void MergeHorizontal(string leftPath, string rightPath, string outputPath)
{
    using (var left = new MagickImage(leftPath))
    using (var right = new MagickImage(rightPath))
    {
        // 先创建一个空白画布,宽度=两张宽度之和,高度取最大值
        int totalWidth = left.Width + right.Width;
        int maxHeight = Math.Max(left.Height, right.Height);
        
        using (var result = new MagickImage(MagickColors.White, totalWidth, maxHeight))
        {
            // 把左图贴上去
            result.Composite(left, 0, 0, CompositeOperator.Over);
            // 把右图贴在左图右边
            result.Composite(right, left.Width, 0, CompositeOperator.Over);
            result.Write(outputPath);
        }
    }
}

上下拼接逻辑一样,Y坐标累加就行。

多张图片合成GIF动画

csharp 复制代码
public void CreateGif(string[] imagePaths, string outputPath)
{
    using (var collection = new MagickImageCollection())
    {
        foreach (var path in imagePaths)
        {
            collection.Read(path);
        }
        // 每帧延迟100ms(单位是1/100秒)
        collection.AnimationDelay = 10;  // 10 = 100ms
        collection.Write(outputPath);
    }
}

六、图像信息读取

有时候需要先看看图片尺寸、格式、颜色空间,再决定怎么处理:

csharp 复制代码
public void GetImageInfo(string path)
{
    using (var image = new MagickImage(path))
    {
        Console.WriteLine($"宽: {image.Width}, 高: {image.Height}");
        Console.WriteLine($"格式: {image.Format}");
        Console.WriteLine($"颜色空间: {image.ColorSpace}");
        Console.WriteLine($"文件大小: {image.FileSize} bytes");
    }
}

七、性能优化建议

1. 及时释放资源

MagickImageMagickImageCollection都实现了IDisposable,务必用using包起来。

2. 设置内存限制

处理超大图像时(比如工业相机出来的几十MB TIFF),可以限制内存使用防止OOM:

csharp 复制代码
MagickNET.SetMemoryLimit(1024 * 1024 * 1024); // 限制1GB

3. 处理PDF/EPS需要Ghostscript

如果涉及到PDF转图片或EPS转PNG,需要额外安装Ghostscript,64位Magick.NET配64位Ghostscript。

4. 批量处理用Parallel

处理大量图片时,可以用Parallel.ForEach并行处理,但注意MagickImage不是线程安全的,每个线程独立创建自己的实例。

八、什么时候用Magick.NET,什么时候自己写

场景 推荐方案
偶尔处理几张图、功能单一 自己写(依赖少)
高频采集实时处理(100fps+) 自己写 + ArrayPool + Span(零GC)
功能多样(缩放+格式转换+水印+合成) Magick.NET
需要处理GIF动画、PDF、EPS等特殊格式 Magick.NET
跨平台部署(Linux工控机) Magick.NET(.NET Core原生支持)

上一篇文章的最近邻和双线性插值,适合高频实时场景------每帧都要处理,对延迟敏感,需要精细控制内存分配。

Magick.NET适合非实时或准实时场景------比如保存前的格式转换、生成缩略图、添加水印、合成报告图。功能全、代码少、质量高,那点性能开销在非实时场景下完全可以接受。

九、总结

Magick.NET把ImageMagick上百种图像处理功能封装成了简洁的C# API。像素放大、格式转换、水印、合成,全都能用几行代码搞定。

把之前自己写的插值算法换成Magick.NET之后,代码量从几百行缩到了几十行,还顺便支持了彩色图、PNG透明通道、JPEG质量控制这些之前不支持的功能。

如果项目里图像处理需求越来越杂,可以考虑换Magick.NET。NuGet装完就能用,学习曲线比想象中平缓得多。

小提示:NuGet上Magick.NET-Q16-AnyCPUMagick.NET-Q8-AnyCPU的区别是颜色精度。工业场景一般8位够用(Q8),文件更小;做图像算法研究或者需要保留更多色彩细节,用Q16。

相关推荐
丁常彦-自媒体-常言道1 小时前
工业强桂深化AI与制造业融合,华为助力广西共筑新型工业化高地
人工智能·华为
胖纸不争5 小时前
Clasp:一个带插件系统的 .NET 10 命令行工具箱
c#·net core
wifi___6 小时前
全局异常处理的原理
java·开发语言
火山引擎开发者社区7 小时前
七夕漫谈|向量检索界的超强 CP:DiskANN 铺路,RaBitQ 加速,又准又快还能省
人工智能
雨白8 小时前
深入理解 Java/Kotlin 反射、注解与泛型:从原理到实战
android·架构
平常心的技术小牛9 小时前
Qt-快速上手-QMenuBar
开发语言·qt
孙启超9 小时前
【大模型应用开发】LLM 到底是什么,以及它是怎么训练的
人工智能·lora·llm·微调·sft·token·rlhf
新知图书10 小时前
7.1 需求分析与规划 《AI Agent智能体开发实践》
人工智能·agent·ai agent·智能体
青 春 记 忆10 小时前
零基础入门Python11|Git实战:为任务管理器建立版本历史
开发语言·git·vscode·python·python3.11