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"/>
- 分批处理减少内存压力
到此这篇关于c#实现将超大图片(1gb)裁剪为8张小图片的文章就介绍到这了,更多相关c#图片裁剪内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论