C#位图处理:如何避免使用Marshal.Copy?适配WebService场景
从TIF提取瓦片并转JPG的WebService兼容方案
替代Marshal.Copy的内存复制方案(推荐)
如果你的WebService基于.NET Core/.NET 5+,可以用MemoryMarshal直接操作内存区域,避开Marshal.Copy的权限限制:
using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; // ... using (var image = new Bitmap(W, H, PixelFormat.Format24bppRgb)) { var bmpData = image.LockBits( new Rectangle(0, 0, W, H), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb ); try { // 将output字节数组复制到Bitmap的内存缓冲区 var targetSpan = MemoryMarshal.CreateSpan<byte>( bmpData.Scan0.ToPointer(), bmpData.Stride * bmpData.Height ); output.AsSpan().CopyTo(targetSpan); } finally { image.UnlockBits(bmpData); } // 保存为JPG(替换原代码的PNG格式) image.Save(Path.Combine(origin, TileName), ImageFormat.Jpeg); }
逐像素设置的兼容方案(全.NET版本支持)
如果必须用逐像素方式,需注意24bppRgb格式的BGR字节顺序和扫描行的4字节对齐规则,代码如下:
using System.Drawing; using System.Drawing.Imaging; // ... using (var image = new Bitmap(W, H, PixelFormat.Format24bppRgb)) { // 计算对齐后的扫描行宽度(24bppRgb每行需是4字节的倍数) int stride = ((W * 3) + 3) & ~3; for (int y = 0; y < H; y++) { for (int x = 0; x < W; x++) { // 定位当前像素在output数组中的起始索引 int pixelIndex = y * stride + x * 3; // 24bppRgb的字节顺序是B-G-R byte blue = output[pixelIndex]; byte green = output[pixelIndex + 1]; byte red = output[pixelIndex + 2]; // 设置像素颜色 image.SetPixel(x, y, Color.FromArgb(red, green, blue)); } } image.Save(Path.Combine(origin, TileName), ImageFormat.Jpeg); }
逐像素方案注意点
- 若你的
output数组未做字节对齐(长度为W*3*H),需将pixelIndex改为y * W * 3 + x * 3 - 逐像素方式性能远低于内存复制,大尺寸瓦片建议优先用第一个方案
关于Marshal.Copy失效的排查
即使开启Full Trust,WebService环境仍可能受限:
- IIS宿主可能禁用了非托管内存访问权限
- 早期ASP.NET的沙箱环境可能仍限制此类操作
- .NET Core/.NET 5+项目需确保已安装
System.Drawing.CommonNuGet包(仅Windows环境支持)
内容的提问来源于stack exchange,提问作者gpol
相关产品推荐
相关产品推荐

