保存Bitmap到内存流中引发“GDI+中发生一般性错误”

本文介绍了一种在.NET中处理图像时遇到的“GDI+中发生一般性错误”的问题及解决方案。通过克隆Bitmap对象避免了从PictureBox保存图像时出现的错误。

保存Bitmap到流中引发“GDI+中发生一般性错误”

 

 -----------------------------------------------------------------------------------------

 

在.NET中进行图像很容易处理引发“GDI+中发生一般性错误”,最近我就碰到了一次。其场景如下:

 

SQL Server数据库表中有一CoverImage字段,其类型为varbinary,用于保存图像的二进制数据。

 

我需要在一个Windows Form应用程序中使用PictureBox(名为picCoverImage)从本地硬盘加载图片文件显示,然后,再将图像本身塞入到数据库中。

 

我采用的方法是将PictureBox的Image属性引用的图像对象先转换为字节数组,再使用LINQ to SQL更新回数据库:

 

//……

           if (picCoverImage.Image != null)
            {

               using (MemoryStream mem = new MemoryStream())
                {
                    picCoverImage.Image.Save(mem, picCoverImage.Image.RawFormat);

                    //book是LINQ to SQL生成的数据实体对象
                    book.CoverImage = new Binary(mem.ToArray());
                   
                }

}

//……

 

然而,很奇怪的是,上述代码在往数据库中新加图像时是成功的,而一旦要修改时picCoverImage.Image.Save(...)一句总引发“GDI+中发生一般性错误”。

 

仔细对比“新建”与“修改”的不同流程:

 

“新建”时,我是使用OpenFileDialog选择文件,然后设置PictureBox的ImageLocation属性装载并显示图片,上述代码运行正常。

 

“修改”时,我从数据库中取出图像数据,使用以下方法在PictureBox中显示图片:

 

//显示图像
            if (book.CoverImage != null)
            {
                using (MemoryStream mem = new MemoryStream(book.CoverImage.ToArray()))
                {
                    picCoverImage.Image = new Bitmap(mem);
                }
            }

 

现在,再次尝试将PictureBox中的Image写入到内存流中,picCoverImage.Image.Save(...)一句就引发“GDI+中发生一般性错误”。

 

百思不得其解。估计是PictureBox内部对Image引用的图像进行了特殊处理,也没时间去用Reflector等工具去深挖细掘,最后是用这个笨方法解决的:

 

克隆一个新的Bitmap对象。

 

修正后的代码如下:

 

//更新图像
            if (picCoverImage.Image != null)
            {

                using (MemoryStream mem = new MemoryStream())
                {
                    //克隆Bitmap对象
                    Bitmap bmp = new Bitmap(picCoverImage.Image);
                    bmp.Save(mem, picCoverImage.Image.RawFormat);
                    book.CoverImage = new Binary(mem.ToArray());
                     bmp.Dispose();
                }
            }

 

修正后的代码工作正常。

 

 

 

 

<think>我们正在使用ImageProcessor库来处理图像二值化。根据用户的问题,他想使用ImageProcessor库中的Bitmap ConvertToBinary方法,并通过threshold参数进行图像二值化处理。 首先,我们需要了解ImageProcessor库中关于二值化处理的部分。根据引用[3]中提到的二值化原理,通常将阈值设置为128,即像素的平均亮度值大于或等于128时设置为白色(255),否则设置为黑色(0)。 在ImageProcessor库中,我们可以使用`ImageFactory`类来加载图像,然后使用`Binary`方法进行二值化处理。但是,需要注意的是,ImageProcessor库的具体方法可能随着版本变化而有所不同。根据常见的用法,我们可以这样操作: 步骤: 1. 创建ImageFactory实例并加载图像。 2. 使用Binary方法,并传入阈值(threshold)参数。 3. 处理图像并保存或显示。 然而,在ImageProcessor库中,二值化处理通常是通过`BinaryThreshold`处理器来实现的。具体方法名可能为`BinaryThreshold`,并且需要指定阈值。 参考代码: ```csharp using ImageProcessor; using ImageProcessor.Imaging; using ImageProcessor.Imaging.Filters.Binarization; using System.Drawing; // 加载图像 using (var factory = new ImageFactory()) { // 加载图像文件 factory.Load("input.jpg"); // 创建二值化处理器,阈值设为128 var binaryThreshold = new BinaryThreshold(128); // 应用二值化处理 factory.Filter(binaryThreshold); // 保存处理后的图像 factory.Save("output.jpg"); } ``` 但是,请注意,上述代码中使用的`BinaryThreshold`类可能位于`ImageProcessor.Imaging.Filters.Binarization`命名空间中。在ImageProcessor库中,二值化处理通常是通过这种方式实现的。 另外,用户提到了`ConvertToBinary`方法,但在ImageProcessor库的公开文档中,我们更常见的是使用`Filter`方法应用各种图像处理器,包括二值化处理器。因此,我们使用`BinaryThreshold`处理器。 如果用户希望直接使用`Bitmap`对象进行处理,可以这样: ```csharp using (var bitmap = new Bitmap("input.jpg")) using (var factory = new ImageFactory()) { factory.Load(bitmap); factory.Filter(new BinaryThreshold(128)); Bitmap result = (Bitmap)factory.Image; // 使用result } ``` 关于阈值参数:`BinaryThreshold`构造函数的参数就是阈值,范围是0-255。用户可以根据需要调整。 注意:ImageProcessor库的版本可能会影响具体类的可用性。如果用户使用的是较新的版本,可能需要查看对应版本的文档。 如果用户没有安装ImageProcessor库,可以通过NuGet安装: ``` Install-Package ImageProcessor ``` 因此,针对用户的问题,我们使用`BinaryThreshold`处理器,并传入阈值参数来实现二值化。 如果用户需要更高级的二值化方法(如自适应阈值),ImageProcessor库可能不直接支持,但可以通过其他方式实现,或者考虑使用OpenCV等库(如引用[2]中使用了OpenCVSharp)。 根据引用[4],二值化处理对于二维码识别非常重要,因为彩色图像在二值化后可能会丢失信息,所以选择合适的阈值很关键。 因此,我们给出使用ImageProcessor库进行二值化的示例代码,并说明阈值参数的使用。 如果用户需要进一步处理,比如保存为特定格式,可以调整保存的参数。 注意:二值化后的图像通常是灰度图,但每个像素只有0或255(黑或白)两个值。 下面是一个完整的示例: ```csharp using System.Drawing; using ImageProcessor; using ImageProcessor.Imaging.Filters.Binarization; public class ImageBinaryConverter { public Bitmap ConvertToBinary(string imagePath, int threshold) { using (var factory = new ImageFactory()) { // 加载图像 factory.Load(imagePath); // 应用二值化 factory.Filter(new BinaryThreshold(threshold)); // 返回处理后的位图 return (Bitmap)factory.Image; } } } ``` 使用方式: ```csharp var converter = new ImageBinaryConverter(); Bitmap binaryImage = converter.ConvertToBinary("input.jpg", 128); // 保存或显示binaryImage ``` 注意:由于`ImageFactory`在`Dispose`时会释放其内部的图像资源,所以我们在方法内使用`using`语句来确保资源被正确释放,然后返回一个新的位图对象。但是,请注意,返回的位图对象需要由调用者负责释放,否则可能导致内存泄漏。 另一种做法是不使用`using`语句,而是将`ImageFactory`的生存期交给调用者管理,但这样会增加复杂性。因此,我们在这里返回一个新的位图,调用者使用完后需要负责释放。 如果用户需要处理多个图像,可以考虑将`ImageFactory`的实例化放在循环外部,但这里每次调用都会创建一个新的`ImageFactory`。 另外,如果加载的图像是索引像素格式(如8位调色板图像),可能需要先转换为24位或32位格式,因为二值化处理可能需要直接操作像素值。ImageProcessor库可能会自动处理,但为了确保正确,可以检查图像格式。 总结:我们使用ImageProcessor库的`BinaryThreshold`处理器,通过传入阈值参数实现二值化,并封装了一个简单的方法。 如果用户在使用过程中遇到问题,可以检查阈值是否合适,或者尝试其他阈值(如Otsu方法自动确定阈值,但ImageProcessor库可能不支持,需要自己实现)。 希望这能帮助用户解决问题。</think>在C#中使用ImageProcessor库进行图像二值化处理,可以通过`BinaryThreshold`方法实现。以下是详细步骤和代码示例: ### 核心步骤 1. **安装ImageProcessor库** 通过NuGet安装: ```bash Install-Package ImageProcessor ``` 2. **二值化处理代码** 使用`ImageFactory`加载图像并应用`BinaryThreshold`方法: ```csharp using ImageProcessor; using ImageProcessor.Imaging; using System.Drawing; public void ConvertToBinary(string inputPath, string outputPath, int threshold) { using (var imageFactory = new ImageFactory()) { // 加载图像 imageFactory.Load(inputPath); // 应用二值化处理 imageFactory.Filter(new BinaryThreshold(threshold)); // 保存结果 imageFactory.Save(outputPath); } } ``` ### 参数说明 - **`threshold`(阈值)**: `0-255`之间的整数,决定像素点转换为黑/白的临界值: - **像素值 ≥ threshold** → 白色 (`255`) - **像素值 < threshold** → 黑色 (`0`) ### 使用示例 ```csharp // 示例:将图像阈值设为128进行二值化 ConvertToBinary("input.jpg", "output.jpg", 128); ``` ### 注意事项 1. **阈值选择** - 典型值:`128`(中间值) - 光照不均时需调整(如`100`或`180`) - 可通过直方图分析最佳阈值 2. **图像格式** 支持常见格式:`JPG`、`PNG`、`BMP`等 3. **效果对比** - 低阈值(如`50`):更多像素变白,图像整体偏亮 - 高阈值(如`200`):更多像素变黑,图像整体偏暗 ### 替代方案(无ImageProcessor) 若需原生实现,参考像素级处理: ```csharp public Bitmap ManualThreshold(Bitmap source, int threshold) { var result = new Bitmap(source.Width, source.Height); for (int x = 0; x < source.Width; x++) { for (int y = 0; y < source.Height; y++) { Color pixel = source.GetPixel(x, y); int avg = (pixel.R + pixel.G + pixel.B) / 3; result.SetPixel(x, y, avg >= threshold ? Color.White : Color.Black); } } return result; } ``` > **提示**:ImageProcessor内部优化了像素处理效率,推荐优先使用库方法[^3]。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值