当前位置: 代码网 > it编程>编程语言>Asp.net > C#实现将超大图片(1GB)裁剪为8张小图片

C#实现将超大图片(1GB)裁剪为8张小图片

2025年05月18日 Asp.net 我要评论
c#处理超大图片(1gb)需要特别注意内存管理和性能优化。以下是几种高效裁剪方案:方法1:使用system.drawing分块处理(内存优化版)using system;using system.dr

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#图片裁剪内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com