System.Drawing.Graphics.FromImage(Image image)引发内存不足

本文探讨了在使用C#GUI进行图片加载时遇到的问题,特别是针对CMYK颜色模式的图片无法正常加载的情况。文中指出,这类问题源于位深度不兼容,并提供了将CMYK颜色转换为RGB颜色的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原因:图片位深度导致的,c# gui 应该无法将32位jpg格式的图片load到内存中

 

通过对比可成功处理的图片 和 不能处理的图片,发现 CMYK(印刷格式)的图片是无法处理的,具体需要深入 .net gdi 库查找原因

只需要将CMYK颜色 改为 RGB 颜色即可解决问题

 

参考文献:http://bbs.youkuaiyun.com/topics/390472766

https://zhidao.baidu.com/question/513862574.html

转载于:https://www.cnblogs.com/tq1226112215/p/7656820.html

<think>我们正在处理的是如何在使用System.Drawing.Image时通过JPEG压缩来减小内存占用。根据用户提供的代码片段,他正在尝试创建GIF,但现在他想要的是JPEG压缩。因此,我们需要提供使用System.Drawing进行JPEG压缩的方法。 关键点: 1. 使用System.Drawing.Imaging.EncoderParameters来设置JPEG压缩质量。 2. 使用Image.Save方法并指定JPEG编码器和质量参数。 步骤: 1. 获取JPEG编码器。注意:JPEG编码器在系统中可能不是默认安装的,但通常Windows系统都支持。 2. 设置EncoderParameters,主要是设置质量(Quality),质量值范围是0-100,数值越小压缩率越高,但图像质量越低。 3. 将图像保存到流或文件,使用JPEG编码器和参数。 另外,用户提到要减小内存占用,因此我们可能还需要考虑在内存中操作,比如使用MemoryStream,避免临时文件。 注意:在操作完成后,要确保释放所有资源(使用using语句),因为System.Drawing对象是非托管的。 根据用户之前的代码,他有一个从屏幕捕获的图像(Bitmap),我们直接对这个图像进行JPEG压缩。 示例代码:</think>### 使用 System.Drawing.Image 实现 JPEG 压缩减小内存占用的完整方案 以下是针对 `System.Drawing.Image` 进行 JPEG 压缩优化的完整实现,包含内存优化原理和关键代码示例: #### 核心压缩方法 ```csharp public byte[] CompressImageToJpeg(Image sourceImage, long quality = 75) { // 1. 获取 JPEG 编码器 ImageCodecInfo jpegEncoder = GetEncoder(ImageFormat.Jpeg); // 2. 配置压缩参数 EncoderParameters encoderParams = new EncoderParameters(1); encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, quality); // 3. 内存流压缩 using (MemoryStream ms = new MemoryStream()) { // 4. 执行 JPEG 压缩 sourceImage.Save(ms, jpegEncoder, encoderParams); return ms.ToArray(); // 返回压缩后的字节数组 } } // 获取指定格式的编码器 private ImageCodecInfo GetEncoder(ImageFormat format) { ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); foreach (ImageCodecInfo codec in codecs) { if (codec.FormatID == format.Guid) return codec; } return null; } ``` #### 内存优化原理 | 优化措施 | 内存减少公式 | 典型效果 | |----------|--------------|----------| | **JPEG 压缩** | $ \text{压缩比} = \frac{100}{\text{质量}} $ | 质量75→文件缩小3倍 | | **移除 Alpha 通道** | $ \frac{24\text{位}}{32\text{位}} = 75\% $ | 32位→24位减少25%内存 | | **尺寸缩放** | $ \text{内存} \propto \text{宽} \times \text{高} $ | 4K→1080p 减少75% | #### 完整优化流程(包含尺寸+格式+压缩) ```csharp public byte[] OptimizeImage(Image source, int maxWidth, long quality) { // 步骤1: 尺寸优化 using (Bitmap resized = ResizeImage(source, maxWidth)) { // 步骤2: 格式转换 (移除 Alpha 通道) using (Bitmap rgbImage = ConvertToRgb(resized)) { // 步骤3: JPEG 压缩 return CompressImageToJpeg(rgbImage, quality); } } } // 尺寸缩放辅助方法 private Bitmap ResizeImage(Image source, int maxWidth) { double ratio = (double)maxWidth / source.Width; int newHeight = (int)(source.Height * ratio); Bitmap bmp = new Bitmap(maxWidth, newHeight); using (Graphics g = Graphics.FromImage(bmp)) { g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.DrawImage(source, 0, 0, maxWidth, newHeight); } return bmp; } // 格式转换辅助方法 private Bitmap ConvertToRgb(Bitmap source) { Bitmap rgbImage = new Bitmap(source.Width, source.Height, PixelFormat.Format24bppRgb); using (Graphics g = Graphics.FromImage(rgbImage)) { g.DrawImage(source, new Rectangle(0, 0, rgbImage.Width, rgbImage.Height)); } return rgbImage; } ``` #### 针对屏幕捕获的优化实现(基于引用[1]) ```csharp // 优化后的屏幕捕获+JPEG压缩 GifBitmapEncoder gEnc = new GifBitmapEncoder(); while (!bStop) { using (Image img = CaptureScreen()) // 假设返回System.Drawing.Image { // 压缩当前帧 byte[] compressedFrame = CompressImageToJpeg(img, quality: 50); // 转换为BitmapSource using (MemoryStream ms = new MemoryStream(compressedFrame)) { BitmapFrame frame = BitmapFrame.Create(ms); gEnc.Frames.Add(frame); } } Thread.Sleep(200); } ``` #### 内存管理最佳实践 1. **资源释放** ```csharp // 错误示例:未释放资源导致内存泄漏 Bitmap bmp = new Bitmap(1000, 1000); // 内存泄漏 // 正确做法:使用using块自动释放 using (Bitmap bmp = new Bitmap(1000, 1000)) { // 操作代码... } // 自动调用Dispose() ``` 2. **大图像分块处理** ```csharp public void ProcessLargeImage(Image source) { int tileSize = 512; for (int y = 0; y < source.Height; y += tileSize) { int height = Math.Min(tileSize, source.Height - y); using (Bitmap tile = new Bitmap(source.Width, height)) using (Graphics g = Graphics.FromImage(tile)) { g.DrawImage(source, new Rectangle(0, 0, tile.Width, tile.Height), new Rectangle(0, y, tile.Width, height), GraphicsUnit.Pixel); CompressImageToJpeg(tile, 75); // 分块压缩 } } } ``` 3. **内存估算公式** $$ \text{原始内存} \approx \frac{\text{宽} \times \text{高} \times \text{位深}}{8 \times 1024^2} \text{MB} $$ $$ \text{压缩后内存} \approx \text{原始内存} \times \frac{\text{质量}}{100} \times \text{压缩因子} $$ #### 配置建议 ```xml <!-- ASP.NET 内存配置 (web.config) --> <system.web> <httpRuntime maxRequestLength="40960" <!-- 40MB请求限制 --> requestLengthDiskThreshold="8192"/> <!-- 8MB内存缓冲 --> </system.web> ``` > **性能对比**:1920x1080 图像优化效果 > - 原始位图:1920×1080×4 ≈ 7.9 MB > - 优化后JPEG:质量75 → 约 0.5-1.2 MB > **内存减少 85%-94%** 通过组合使用 JPEG 压缩、尺寸优化和格式转换,可将图像内存占用降低至原始大小的 **5%-15%**,有效避免 `OutOfMemoryException`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值