Skip to content

lastonesky/SharpImageConverter

Repository files navigation

SharpImageConverter

简体中文 | English Version

一个用 C# 编写的图像处理与格式转换库,尽量减少第三方托管依赖(不使用 System.Drawing)。支持 JPEG/PNG/BMP/WebP/GIF 格式的相互转换(包含 JPEG 解码与 JPEG 编码输出)。目前主要面向 API 调用;命令行(CLI)已独立为单独项目。

开发初衷

本库最初是为了解决在生产环境中使用现有 .NET 图像库时遇到的一些实际问题:

  • 需要真正的跨平台支持:我们的服务必须能在 Linux 等非 Windows 环境中稳定运行,因此不能依赖实质上仅在 Windows 上受支持的 System.Drawing。在较新的 .NET 版本中继续使用 System.Drawing 还会在编译阶段产生大量“只在 Windows 支持”的警告,不利于长期维护。
  • 授权与成本的不确定性:不希望引入对企业有营收门槛的组件,例如 ImageSharp 要求年收入超过 100 万美元的公司购买商业授权,这会给后续商业化带来额外的不确定成本。
  • 稳定性与可运维性:在托管服务中使用 SkiaSharp 时,我们曾多次遇到非托管层崩溃直接拖垮整个 .NET 进程、导致服务重启的问题,而崩溃原因难以从托管栈追踪。我们希望构建一个完全托管、行为可控、出问题时更容易排查的解决方案。
  • 内部系统使用,没有使用并发压力,能正常应对常见的产品图片。

功能特性

JPEG 支持

  • 基线(Baseline)与渐进式(Progressive)解码
  • Huffman 解码、反量化、整数 IDCT、YCbCr 转 RGB
  • 支持 EXIF Orientation 自动旋转/翻转
  • 支持将中间 RGB 图像编码输出为基线 JPEG(Baseline,quality 可调)
  • 支持常见采样因子(如 4:4:4/4:2:2/4:2:0),色度上采样使用最近邻回采样

PNG 支持

  • 读取:
    • 支持关键块(IHDR, PLTE, IDAT, IEND)
    • 透明度:解析 tRNS 与带 Alpha 的色彩类型(Grayscale+Alpha / Truecolor+Alpha),支持 RGB24 与 RGBA32 输出(使用 RGBA 接口以保留 Alpha)
    • 支持所有过滤器(None, Sub, Up, Average, Paeth)
    • 支持 Adam7 隔行扫描
    • 支持灰度、真彩色、索引色;位深覆盖 1/2/4/8/16(转换时缩放到 8-bit)
  • 写入:
    • 保存为 Truecolor PNG(RGB24)与 Truecolor+Alpha PNG(RGBA32)
    • 使用 Zlib 压缩(Deflate),行过滤使用 Up(逐行差分),并在 Up 过滤过程里使用 SIMD 加速
    • 可写入 EXIF/iCCP/sRGB 元数据

BMP 支持

  • 读取:支持无压缩的 8/24/32 位 BMP(统一输出为 RGB24)
  • 写入:24-bit RGB BMP
  • 支持自动填充对齐

GIF 支持

  • 读取:
    • 支持 GIF87a/GIF89a 格式
    • LZW 解码、全局/局部调色板
    • 透明度:解析透明索引(Graphic Control Extension),支持处置方法 Restore to Background/Restore to Previous 的帧合成
    • 支持隔行扫描;可导出所有帧到 RGB
  • 写入:
    • 单帧 GIF89a;Octree 颜色量化(24-bit RGB -> 8-bit Index)
    • LZW 压缩;不写入透明度与动画元数据(延时、循环)

WebP 支持

  • 读取/写入 WebP(通过 runtimes/ 下的原生 libwebp
  • 统一解码为 RGB24,再根据输出扩展名选择编码器写回
  • WebP 编码质量与并发策略可配置
  • WebP 实现依赖 Google 的 libwebp 及相关组件(BSD-3-Clause License),其版权与许可信息详见 THIRD-PARTY-NOTICES.md

中间格式

  • 引入 ImageFrame 作为格式转换的中间数据结构(当前为 Rgb24
  • 统一加载为 RGB,再根据输出扩展名选择编码器写回

What's New / 更新亮点

目录结构

SharpImageConverter/
├── src/                         # 库主体(对外 API)
│  ├── Core/                     # Image/Configuration 等基础类型
│  ├── Formats/                  # 格式嗅探与 Adapter(JPEG/PNG/BMP/WebP/GIF)
│  ├── Processing/               # Mutate/Resize/Grayscale 等处理管线
│  ├── Metadata/                 # 元数据结构(Orientation 等)
│  ├── runtimes/                 # WebP 原生库(win-x64/linux-x64/osx-arm64)
│  └── SharpImageConverter.csproj
├── Cli/                         # 独立命令行项目
│  ├── Program.cs
│  └── SharpImageConverter.Cli.csproj
├── SharpImageConverter.Tests/   # 单元测试工程
└── README.md / README.en.md

使用方式(API)

环境要求:

  • .NET SDK 8.0 或更高版本(本库目标框架:net8.0;net10.0
  • Windows/Linux/macOS(WebP 对应平台需加载 runtimes/ 下原生库)

安装(NuGet)

dotnet add package SharpImageConverter --version 0.1.6.1-preview

引用命名空间:

using SharpImageConverter.Core;
using SharpImageConverter.Processing;

常用示例:

  • 加载、处理并保存(自动嗅探输入格式;按输出扩展名选择编码器)
// 加载为 RGB24
var image = Image.Load("input.jpg"); // 参见 API 入口 [Image](src/Core/Image.cs)

// 处理:缩放到不超过 320x240,转灰度
image.Mutate(ctx => ctx
    .ResizeToFit(320, 240)       // 最近邻或双线性请选用不同 API
    .Grayscale());               // 参见处理管线 [Processing](src/Processing/Processing.cs)

// 保存(根据扩展名选择编码器)
Image.Save(image, "output.png");
  • 克隆并处理(不修改原图)
// 基于已有图像创建处理后的副本
var processed = image.Clone(ctx => ctx
    .ResizeToFit(320, 240)
    .Grayscale());

// image 保持不变,processed 为处理结果
Image.Save(processed, "output_clone.png");
  • RGBA 模式(保留 Alpha 的加载/保存;不支持的目标格式会自动回退为 RGB 保存)
// 加载为 RGBA32(优先使用原生 RGBA 解码)
var rgba = Image.LoadRgba32("input.png");
// 保存为支持 Alpha 的格式(如 PNG/WebP/GIF);格式不支持则回退为 RGB
Image.Save(rgba, "output.webp");
  • 流式操作(Stream):
using SharpImageConverter; // ImageFrame

// 从流加载(自动嗅探格式)
using var input = File.OpenRead("input.jpg");
var frame = ImageFrame.Load(input);

// 如需处理,转换为 Image<Rgb24>
var image = new Image<Rgb24>(frame.Width, frame.Height, frame.Pixels);
image.Mutate(ctx => ctx.Grayscale());

// 保存到流(需明确指定格式,或封装回 ImageFrame 使用便捷方法)
using var output = new MemoryStream();
// 方式 A: 使用 ImageFrame 便捷方法
new ImageFrame(image.Width, image.Height, image.Buffer).SaveAsPng(output);
// 方式 B: 使用特定编码器
// new SharpImageConverter.Formats.PngEncoderAdapter().EncodeRgb24(output, image);

命令行工具 (CLI)

位于 Cli/ 目录下,提供便捷的格式转换与简单处理功能。

运行方式

# 在 Cli 目录下运行
dotnet run -- <输入文件或文件夹路径> [输出文件或文件夹路径] [操作] [参数]

支持格式

  • 输入: .jpg/.jpeg/.png/.bmp/.webp/.gif
  • 输出: .jpg/.jpeg/.png/.bmp/.webp/.gif

特殊情况:

  • GIF → WebP:当输入为动图 GIF、输出扩展名为 .webp 时,会编码为动图 WebP(尽量保留帧间隔与循环次数)

操作 (Operations)

  • resize:WxH : 强制缩放到指定宽 (W) 高 (H)
  • resizebilinear:WxH : 使用双线性插值缩放到指定尺寸
  • resizefit:WxH : 等比缩放到适应指定矩形框 (W x H)
  • grayscale : 转为灰度图

参数 (Options)

  • --quality N : 设置 JPEG 编码质量 (0-100),默认 75
  • --subsample 420|444 : 设置 JPEG 色度采样,默认 420
  • --keep-metadata : 在重新编码 JPEG 时尽量保留 EXIF/ICC 等基础元数据
  • --jpeg-debug : 启用 JPEG 解码调试输出
  • --gif-frames : 将动图 GIF 的每一帧导出为独立图片,方便调试与检查
  • --gray : 强制输出为灰度(对 JPEG/PNG/BMP/WebP 生效)
  • --stream : 针对 JPEG 使用流式解码以降低内存占用,其他格式会回退为常规解码
  • --idct int|float : 选择 JPEG IDCT 实现(整数/浮点),仅对 JPEG 解码有效

文件夹批量转换

  • 递归:--recursive(遍历子目录)
  • 指定输出格式:--to bmp|png|jpg|webp--out-ext .bmp|.png|.jpg|.webp
  • 并行:--parallel N(默认使用逻辑 CPU 数;输出为 .webp 时为确保线程安全自动降为 1)
  • 跳过已存在:--skip-existing(目标文件已存在则跳过)
  • 输出位置:第二个参数为文件夹时,保持源目录的相对结构;未指定时输出到源文件所在目录
  • 默认扩展名:无操作默认 .png,存在操作默认 .bmp;显式指定优先生效

示例

# 转换格式
dotnet run -- input.png output.jpg

# 调整大小并转换
dotnet run -- input.jpg output.png resize:800x600

# 缩放适应并设置 JPEG 质量
dotnet run -- big.png thumb.jpg resizefit:200x200 --quality 90

# 批量:将整个文件夹转为 PNG(默认)
dotnet run -- d:\images

# 批量:指定输出文件夹与递归
dotnet run -- d:\images d:\out --recursive

# 批量:指定目标格式为 BMP,并设置并行度
dotnet run -- d:\images d:\out --to bmp --parallel 8

# 批量:跳过已存在文件
dotnet run -- d:\images d:\out --skip-existing

许可证

本项目主要在 AI 辅助下生成,并遵循 MIT 许可证。

About

Pure C# implementation of a Jpeg/GIF/PNG Decoder and Encoder.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages