我编写了一个小型“水印”程序来为图像添加自定义水印。有两个水印,一个是白色的,一个是黑色的。水印始终位于图像的左下角。我克隆图像的该区域以确定应根据该点放置哪个水印(亮区域上的黑色水印和暗区域上的白色水印)。
当我在我的机器上使用应用程序(调试或正常)时 - 没问题。所有图像都经过处理,并在正确的位置添加水印。
但是,在客户端计算机上,程序会中断所有图像,并在克隆部分引发 OutOfMemory 异常。
我知道,通常情况下,当我指定一个超出范围的区域时,也会抛出 OutOfMemory 异常,但由于该函数在我的机器上就像一个魅力一样工作,我无法想象会出现这种情况。除此之外,该程序在几次尝试后不会中断,它会在所有尝试克隆时中断。
是否有文本(DrawString 方法)无关紧要。它在克隆上中断。
正在处理的图像很大,但不是“巨大”(最多 6016 x 4000 像素),但即使是较小的图像(3264 x 2448 像素),客户端也会中断。
变量:
bmOriginal
: 原始位图
processImage
: 原始图像 (pictureBox) -bmOriginal
是这个的位图副本
watermarkText
: 水印下方额外信息的文本框
black
和white
:包含水印图像的图片框
watermarkCombo
: 用于选择自动、白色或黑色的组合框(自动失败)
代码:
using (Graphics gWatermark = Graphics.FromImage(bmOriginal))
{
gWatermark.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
System.Drawing.SolidBrush drawBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black);
// position watermark - watermark should be 10% of the image height
int watermarkHeight = (int)(processImage.Image.Height * 0.1);
int watermarkPadding = (int)(watermarkHeight * 0.1); // not completely true, but asume watermark is square
Rectangle watermarkArea = new Rectangle(watermarkPadding, processImage.Image.Height - (watermarkPadding + (watermarkText.Text.Length == 0 ? 0 : watermarkPadding) + watermarkHeight), watermarkHeight, watermarkHeight);
// determine color watermark
bmWatermark = (Bitmap)black.Image;
if (watermarkCombo.SelectedIndex == 0)
{
using (Bitmap watermarkClone = bmOriginal.Clone(watermarkArea, bmOriginal.PixelFormat))
{
var pixels = Pixels(watermarkClone);
if (pixels.Average((Func<Color, decimal>)Intensity) < 110) // human eye adoption; normal threshold should be 128
{
bmWatermark = (Bitmap)white.Image;
drawBrush = new System.Drawing.SolidBrush(System.Drawing.Color.White);
}
}
}
else if (watermarkCombo.SelectedIndex == 1)
{
bmWatermark = (Bitmap)white.Image;
drawBrush = new System.Drawing.SolidBrush(System.Drawing.Color.White);
}
// draw the watermark
gWatermark.DrawImage(bmWatermark, watermarkArea.X, watermarkArea.Y, watermarkArea.Width, watermarkArea.Height);
// draw the text (if needed)
if (watermarkText.Text.Length > 0)
{
System.Drawing.Font drawFont = new System.Drawing.Font("Tahoma", (float)watermarkPadding);
gWatermark.DrawString(watermarkText.Text, drawFont, drawBrush, watermarkPadding, bmOriginal.Height - (watermarkPadding * 2));
}
}
bmOriginal.Save(System.IO.Path.Combine(diWatermarked.FullName, fileName), System.Drawing.Imaging.ImageFormat.Jpeg);
错误行:using (Bitmap watermarkClone = bmOriginal.Clone(watermarkArea, bmOriginal.PixelFormat))
现在的大问题:我如何摆脱 OutOfMemory 异常.. 任何人的想法?
编辑当我选择不自动确定水印的颜色而只添加水印(比如说白色)时,程序正常运行。我在错误日志中看到了堆栈跟踪(在函数的捕获中,我输出了异常和 - 如果有的话 - 内部异常)。
我知道很多使用 Clone 函数的 OOM 异常发生在指定区域越界时;但这里不是这样。
当我在调试模式下使用应用程序时查看我的内存时,我从 5.36 Gb 程序开始,在运行我提到的执行时标准化的 5.39 Gb(最大峰值为 5.42 Gb),它并没有像疯了一样消耗内存。
我使用的代码确定了平均“颜色”(它来自 StackOverflow 上的某个人 - 我只是从其他答案中复制了它,但找不到链接);
// functions used to determine watermark color
private static decimal ComponentAverage(decimal a, decimal b)
{
return Math.Min(a, b) + Math.Abs(a - b) / 2M;
}
private static decimal Intensity(Color color)
{
decimal result = color.A;
result = ComponentAverage(result, color.R);
result = ComponentAverage(result, color.G);
result = ComponentAverage(result, color.B);
return result;
}
private static IEnumerable<Color> Pixels(Bitmap bitmap)
{
for (int x = 0; x < bitmap.Width; x++)
for (int y = 0; y < bitmap.Height; y++)
yield return bitmap.GetPixel(x, y);
}
SOURCE这里有一个测试项目:http: //hotpepper.nu/oomtestapp.zip