当前位置: 首页 > article >正文

C#将1GB大图裁剪为8张图片

C#处理超大图片(1GB)需要特别注意内存管理和性能优化。以下是几种高效裁剪方案:

方法1:使用System.Drawing分块处理(内存优化版)

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;class Program
{static void Main(){string sourceImagePath = "1GB_Image.bmp";string outputFolder = "CroppedImages";if (!Directory.Exists(outputFolder)){Directory.CreateDirectory(outputFolder);}// 获取图片尺寸但不加载全部内容using (var image = Image.FromFile(sourceImagePath)){int totalWidth = image.Width;int totalHeight = image.Height;// 计算每块尺寸 (2x4网格)int chunkWidth = totalWidth / 2;int chunkHeight = totalHeight / 4;// 分块裁剪for (int row = 0; row < 4; row++){for (int col = 0; col < 2; col++){int x = col * chunkWidth;int y = row * chunkHeight;// 确保最后一块包含剩余部分int width = (col == 1) ? totalWidth - x : chunkWidth;int height = (row == 3) ? totalHeight - y : chunkHeight;CropImage(sourceImagePath,Path.Combine(outputFolder, $"part_{row}_{col}.jpg"),x, y, width, height);}}}}static void CropImage(string sourcePath, string destPath, int x, int y, int width, int height){// 使用流式处理避免全图加载using (var source = new Bitmap(sourcePath))using (var dest = new Bitmap(width, height))using (var graphics = Graphics.FromImage(dest)){graphics.DrawImage(source,new Rectangle(0, 0, width, height),new Rectangle(x, y, width, height),GraphicsUnit.Pixel);// 保存为JPEG减少体积dest.Save(destPath, ImageFormat.Jpeg);Console.WriteLine($"已保存: {destPath} ({width}x{height})");}}
}

方法2:使用ImageSharp(现代跨平台方案)

首先安装NuGet包:

Install-Package SixLabors.ImageSharp

实现代码:

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Formats.Jpeg;class Program
{static async Task Main(){string sourcePath = "1GB_Image.jpg";string outputDir = "CroppedImages";Directory.CreateDirectory(outputDir);// 配置内存选项处理大图var configuration = Configuration.Default.Clone();configuration.MemoryAllocator = new SixLabors.ImageSharp.Memory.ArrayPoolMemoryAllocator();// 分块加载和处理using (var image = await Image.LoadAsync(configuration, sourcePath)){int totalWidth = image.Width;int totalHeight = image.Height;int chunkWidth = totalWidth / 2;int chunkHeight = totalHeight / 4;for (int row = 0; row < 4; row++){for (int col = 0; col < 2; col++){int x = col * chunkWidth;int y = row * chunkHeight;int width = (col == 1) ? totalWidth - x : chunkWidth;int height = (row == 3) ? totalHeight - y : chunkHeight;// 克隆并裁剪区域using (var cropped = image.Clone(ctx => ctx.Crop(new Rectangle(x, y, width, height)))){string outputPath = Path.Combine(outputDir, $"part_{row}_{col}.jpg");await cropped.SaveAsync(outputPath, new JpegEncoder {Quality = 80 // 适当压缩});Console.WriteLine($"已保存: {outputPath}");}}}}}
}

方法3:使用内存映射文件处理超大图

using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Drawing;
using System.Drawing.Imaging;class Program
{static void Main(){string sourcePath = "1GB_Image.bmp";string outputDir = "CroppedImages";Directory.CreateDirectory(outputDir);// 获取BMP文件头信息var bmpInfo = GetBmpInfo(sourcePath);int width = bmpInfo.Width;int height = bmpInfo.Height;int bytesPerPixel = bmpInfo.BitsPerPixel / 8;int stride = width * bytesPerPixel;// 计算分块int chunkWidth = width / 2;int chunkHeight = height / 4;// 使用内存映射文件处理using (var mmf = MemoryMappedFile.CreateFromFile(sourcePath, FileMode.Open)){for (int row = 0; row < 4; row++){for (int col = 0; col < 2; col++){int x = col * chunkWidth;int y = row * chunkHeight;int cropWidth = (col == 1) ? width - x : chunkWidth;int cropHeight = (row == 3) ? height - y : chunkHeight;// 创建目标位图using (var dest = new Bitmap(cropWidth, cropHeight, PixelFormat.Format24bppRgb)){var destData = dest.LockBits(new Rectangle(0, 0, cropWidth, cropHeight),ImageLockMode.WriteOnly,dest.PixelFormat);try{// 计算源文件偏移量(BMP文件头54字节 + 数据偏移)long offset = 54 + (height - y - 1) * stride + x * bytesPerPixel;// 逐行复制for (int line = 0; line < cropHeight; line++){using (var accessor = mmf.CreateViewAccessor(offset - line * stride, cropWidth * bytesPerPixel)){byte[] lineData = new byte[cropWidth * bytesPerPixel];accessor.ReadArray(0, lineData, 0, lineData.Length);IntPtr destPtr = destData.Scan0 + (line * destData.Stride);System.Runtime.InteropServices.Marshal.Copy(lineData, 0, destPtr, lineData.Length);}}}finally{dest.UnlockBits(destData);}string outputPath = Path.Combine(outputDir, $"part_{row}_{col}.jpg");dest.Save(outputPath, ImageFormat.Jpeg);Console.WriteLine($"已保存: {outputPath}");}}}}}static (int Width, int Height, int BitsPerPixel) GetBmpInfo(string filePath){using (var fs = new FileStream(filePath, FileMode.Open))using (var reader = new BinaryReader(fs)){// 读取BMP头if (reader.ReadChar() != 'B' || reader.ReadChar() != 'M')throw new Exception("不是有效的BMP文件");fs.Seek(18, SeekOrigin.Begin); // 跳转到宽度信息int width = reader.ReadInt32();int height = reader.ReadInt32();fs.Seek(28, SeekOrigin.Begin); // 跳转到位深信息int bitsPerPixel = reader.ReadInt16();return (width, height, bitsPerPixel);}}
}

方法4:使用Magick.NET(专业图像处理)

首先安装NuGet包:

Install-Package Magick.NET-Q16-x64

实现代码:

using ImageMagick;
using System;
using System.IO;class Program
{static void Main(){string sourcePath = "1GB_Image.tif";string outputDir = "CroppedImages";Directory.CreateDirectory(outputDir);// 设置资源限制MagickNET.SetResourceLimit(ResourceType.Memory, 1024 * 1024 * 1024); // 1GB// 使用像素流处理大图using (var image = new MagickImage(sourcePath)){int width = image.Width;int height = image.Height;int chunkWidth = width / 2;int chunkHeight = height / 4;for (int row = 0; row < 4; row++){for (int col = 0; col < 2; col++){int x = col * chunkWidth;int y = row * chunkHeight;int cropWidth = (col == 1) ? width - x : chunkWidth;int cropHeight = (row == 3) ? height - y : chunkHeight;using (var cropped = image.Clone(new MagickGeometry{X = x,Y = y,Width = cropWidth,Height = cropHeight})){string outputPath = Path.Combine(outputDir, $"part_{row}_{col}.jpg");cropped.Quality = 85;cropped.Write(outputPath);Console.WriteLine($"已保存: {outputPath}");}}}}}
}

裁剪方案选择建议

方法        优点缺点使用场景
System.Drawing内置库,简单内存占用高Windows小图处理
ImageSharp跨平台,现代API    学习曲线需要跨平台支持
内存映射内存效率高复杂,仅限BMP超大图处理
Magick.NET功能强大需要安装专业图像处理

注意事项

  1. 内存管理:处理1GB图片需要至少2-3GB可用内存
  2. 文件格式:BMP/TIFF适合处理,JPEG可能有压缩问题
  3. 磁盘空间:确保有足够空间存放输出文件
  4. 异常处理:添加try-catch处理IO和内存不足情况
  5. 性能优化:
  • 使用64位应用程序
  • 增加GC内存限制:<gcAllowVeryLargeObjects enabled="true"/>
  • 分批处理减少内存压力
http://www.lryc.cn/news/2378398.html

相关文章:

  • 数据库——SQL约束窗口函数介绍
  • Linux系统启动相关:vmlinux、vmlinuz、zImage,和initrd 、 initramfs,以及SystemV 和 SystemD
  • JSP链接MySQL8.0(Eclipse+Tomcat9.0+MySQL8.0)
  • Python爬虫-爬取百度指数之人群兴趣分布数据,进行数据分析
  • SEO长尾词与关键词优化实战
  • 机器学习-人与机器生数据的区分模型测试-数据处理1
  • HelloWorld
  • 令牌桶和漏桶算法使用场景解析
  • 轻量、优雅、高扩展的事件驱动框架——Hibiscus-Signal
  • SEO 优化实战:ZKmall模板商城的 B2C商城的 URL 重构与结构化数据
  • 2020CCPC河南省赛题解
  • 数字万用表与指针万用表使用方法及注意事项
  • 虚拟主播肖像权保护,数字时代的法律博弈
  • 【读代码】端到端多模态语言模型Ultravox深度解析
  • RabbitMQ工作流程及使用方法
  • Java 面向对象进阶:解锁多态、内部类与包管理
  • 算法:分治法
  • MySQL初阶:sql事务和索引
  • docker部署第一个Go项目
  • day27 python 装饰器
  • Visual Studio2022跨平台Avalonia开发搭建
  • css iconfont图标样式修改,js 点击后更改样式
  • 开源项目实战学习之YOLO11:12.4 ultralytics-models-sam-memory_attention.py源码分析
  • 【沉浸式求职学习day42】【算法题:滑动窗口】
  • LIIGO ❤️ RUST 12 YEARS
  • Linux基础开发工具二(gcc/g++,自动化构建makefile)
  • Linux zip、unzip 压缩和解压
  • muduo库TcpConnection模块详解——C++
  • Node.js 源码架构详解
  • 全局异常处理:如何优雅地统一管理业务异常