它这个代码不在onpaint里面,是在某个函数体里,所以资源应该是被托管的,无所谓dispose了吧。
透明度贴图则不能直接绘制到原图上,步骤可以如下,先单独测量字符串。
下面给你一个我通过了我自己的测试的刚写的代码。注意,没有检查水印的边界是否超出图片范围(如果水印超出图片范围,将导致访问超出范围的内存而产生异常)。注意:使用下面的代码还要把在项目属性里把允许不安全代码的选项勾选。
/// <summary>
/// 给一个位图绘制水印文字
/// </summary>
/// <param name="text">水印文本</param>
/// <param name="x">起始点</param>
/// <param name="y">起始点</param>
/// <param name="opacity">不透明度,0~1</param>
private Bitmap DrawWatermark(Image image,string text, Font font,Brush brush,int x,int y,double opacity)
{
Bitmap bm1 = new Bitmap(this.m_Bitmap);
Graphics g1=Graphics.FromImage(bm1);
//测量水印文字的大小,然后申请一个新的位图
SizeF sizef=g1.MeasureString(text,font);
Bitmap bm2=new Bitmap((int)sizef.Width,(int)sizef.Height);
Graphics g2=Graphics.FromImage(bm2);
g2.DrawImage(bm1, 0,0,new Rectangle(x, y, bm2.Width, bm2.Height),GraphicsUnit.Pixel);
g2.DrawString(text,font,brush,0,0);
BitmapData data1=bm1.LockBits(new Rectangle(0,0,bm1.Width,bm1.Height),ImageLockMode.ReadWrite,PixelFormat.Format24bppRgb);
BitmapData data2=bm2.LockBits(new Rectangle(0,0,bm2.Width,bm2.Height),ImageLockMode.ReadWrite,PixelFormat.Format24bppRgb);
unsafe
{
byte* p1=(byte*)(void*)data1.Scan0;
byte* p2=(byte*)(void*)data2.Scan0;
for(int j=0;j<bm2.Height;j++)
{
for(int i=0;i<bm2.Width;i++)
{
p1[(y+j) * data1.Stride+ (x+i) *3]=(byte)(p1[(y+j)*data1.Stride+(x+i)*3]*(1-opacity)+opacity*p2[j*data2.Stride+i*3]);
p1[(y+j) * data1.Stride + (x+i) * 3 + 1] = (byte)(p1[(y+j) * data1.Stride + (x+i) * 3 + 1] * (1-opacity) + opacity * p2[j * data2.Stride + i * 3+1]);
p1[(y+j) * data1.Stride + (x+i) * 3 + 2] = (byte)(p1[(y+j) * data1.Stride + (x+i) * 3 + 2] * (1-opacity) + opacity* p2[j * data2.Stride + i * 3+2]);
}
}
bm1.UnlockBits(data1);
bm2.UnlockBits(data2);
}
return bm1;
}
函数里的bm2就是水印,当然如果你的水印是一个图片也可以,上面的函数只要稍加修改作为参数传进去,但水印图片需要指定透明色。然后可以用类似上面的方法用imageattibutes指定透明色直接绘制好水印图片好按照同样的方法进行合成,或者在处理像素数据的时候判断根据是否是透明色决定如何处理(这会比较复杂些)。