c# - C# 如果我需要另一个类中的位图,请使用 Dispose()
问题描述
我有这个类来裁剪图像:
public static Bitmap Crop(Bitmap img_crop, int w, int h, int x, int y)
{
Image img_crop = img_crop;
Bitmap bmp_crop = new Bitmap(w, h, PixelFormat.Format24bppRgb);
bmp_crop.SetResolution(80, 60);
Graphics gfx = Graphics.FromImage(bmp_crop);
gfx.SmoothingMode = SmoothingMode.AntiAlias;
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
gfx.DrawImage(img_cortar, new Rectangle(0, 0, w, h), x, y, w, h, GraphicsUnit.Pixel);
//bmp_crop.Save("test.bmp");
// Dispose to free up resources
img_crop.Dispose();
//bmp_crop.Dispose();// <------------ How to use this and pass Bitmap to the next class?
gfx.Dispose();
Class2(bmp_crop);
return bmp_crop;
}
我需要在另一个类中裁剪图像,如果我使用 Dispose() ( bmp_crop.Dispose();
),在下一个类中我得到一个参数错误,我怎样才能丢弃 Bitmap 并且仍然能够在下一个类中使用它?
public static Bitmap Class2(Bitmap bmp_crop)
{
...
}
解决方案
- 查看您的代码实际执行的操作,它正在调整图像大小,而不是裁剪它 - 所以您应该将此方法重命名为
Resize
,而不是Crop
. - 只有对象的“所有者”
IDisposable
才能调用.Dispose()
或使用using
块。- “所有者”是指控制
IDisposable
对象生命周期的父范围或生命周期。- 这可以是一个类(如果它
IDisposable
被存储为一个字段)或者它是一个方法(如果它IDisposable
不应该超过一个方法,或者方法内的范围)。
- 这可以是一个类(如果它
- 因为我假设您不打算让您的
Crop
方法限制Bitmap img_crop
(源输入图像)的生命周期,所以您的Crop
方法不能调用bmp_crop.Dispose()
!
- “所有者”是指控制
- 当一个方法创建一个新
IDisposable
对象并返回它时,该方法“拥有”该对象,直到它返回它 - 这意味着如果在方法内部引发异常,则该方法必须处理该对象 - 这是try/catch
立即完成的创建对象。 Graphics
在您不再需要该对象后立即处理它是非常重要的。中的一次性类型System.Drawing
是围绕本机 Windows GDI 对象的包装器,这些对象会在您的进程中用完 GDI 句柄 - 泄漏 GDI 句柄是不好的,因为最终您会用完,然后所有图形操作都会突然停止工作(这就是为什么很多写得不好的 WinForms 程序在一段时间后开始出现图形故障)。- 此外,
img_crop
andbmp_crop
是变量名的糟糕选择,因为名称没有描述变量是什么,而且匈牙利表示法不好。- 我在下面的示例中
source
用于输入图像和cropped
输出图像。
- 我在下面的示例中
这是我的做法:
public static Bitmap Resize( Bitmap source, int w, int h, int x, int y )
{
Bitmap resized = new Bitmap( w, h, PixelFormat.Format24bppRgb );
try
{
cropped.SetResolution(80, 60);
using( Graphics g = Graphics.FromImage( cropped ) )
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage( source, new Rectangle( 0, 0, w, h ), x, y, w, h, GraphicsUnit.Pixel );
}
// Pass the image to the other class/method/etc:
Class2( resized );
return resized; // Return the image to the caller, who now "owns" the image and its their responsibility to dispose of it.
}
catch( Exception ex )
{
resized.Dispose();
throw;
}
}
如果您不打算cropped
在调用您的方法后返回给调用者,Class2
那么您应该删除try/catch
方法中的 ,而是使用一个using
块,如下所示:
public static Bitmap Resize(Bitmap source, int w, int h, int x, int y)
{
using( Bitmap resized = new Bitmap( w, h, PixelFormat.Format24bppRgb ) )
{
cropped.SetResolution(80, 60);
using( Graphics g = Graphics.FromImage( resized ) )
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage( source, new Rectangle( 0, 0, w, h ), x, y, w, h, GraphicsUnit.Pixel );
}
// Pass the image to the other class/method/etc:
Class2( resized );
}
}
推荐阅读
- javascript - Google 电子表格中单元格文本的 sha3-256
- android - 如何在 Android Studio 中以编程方式将 apk 文件从 root/data/app/ 移动到 storage/emulated/0
- php - 用额外的步骤从字符串启动一个类?
- java - 无法在 Intellij 中导入 Maven 模块
- apache-spark - Spark 2 的性能偶数运行优于奇数
- java - 如何获取Java和C#中定义的元素之前和之后的所有元素
- php - Laravel VueJs Apache Virtualhost,显示Vue时虚拟主机名未出现在URL中
- javascript - 如何使页面的内容依赖于路由?
- elasticsearch - 无法使用分析器在复合查询中进行搜索
- prolog - 素数列表。为什么我的代码不起作用?