17.3.5 添加水印

版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。

在发布的图片上添加水印,已经成为保护图片版权的手段之一。水印可以是一段文字或是一张图片,通常情况下为了不影响图片本身的显示,往往使用半透明的水印。其实这就是对颜色中的透明度进行处理,即Color结构ARGB中的A分量(Alpha)进行处理。

【例 17.59 【项目:code17-037】文字水印。

在本例中,在图像上绘制文字使用的是DrawString方法,其中Brush参数可以设置颜色,只需要使用带有透明度分量的颜色即可实现半透明的文字水印。

Bitmap sourceImg;

private void Form1_Load(object sender, EventArgs e)

{

picSource.SizeMode = PictureBoxSizeMode.StretchImage;

picDest.SizeMode = PictureBoxSizeMode.StretchImage;

//透明度从0-255

nudAlpha.Minimum = 0;

nudAlpha.Maximum = 255;

//默认不透明

nudAlpha.Value = 255;

sourceImg = (Bitmap)Image.FromFile("c:\\lessons\\zg.jpg");

}

private void Form1_Paint(object sender, PaintEventArgs e)

{

picSource.Image = sourceImg;

}

private void btnDraw_Click(object sender, EventArgs e)

{

int logoOpacity = (int)nudAlpha.Value;

string logoText = txtString.Text;

Font logoFont =new Font(new FontFamily("隶书"), 60, FontStyle.Bold);

//绘制文字的默认颜色为白色

SolidBrush logoBrush =new SolidBrush(Color.FromArgb(logoOpacity, 255, 255, 255));

//绘制文字的起始位置

int logoLeft = 10;

int logoTop = 10;

Bitmap imgDest = (Bitmap)sourceImg.Clone();

Graphics g = Graphics.FromImage(imgDest);

g.DrawString(logoText, logoFont, logoBrush, logoLeft, logoTop);

g.Dispose();

picDest.Image = imgDest;

}

运行结果如下图所示:

\

图17-69 添加文字水印

【例 17.60 【项目:code17-038】图片水印。

本例提供过了三种生成图片水印的方法:

一是像素处理方式。先读取水印图像的所有像素颜色,然后颜色上加上Alpha分量值,最后将每个像素绘制到目标图像指定的位置。由于既要处理像素透明,又要考虑在目标图像中定位,代码难度较大,可以考虑先处理像素生成半透明水印图像,再将此图像绘制到目标图像指定位置。

二是使用内存处理方式。在使用Bitmap.LockBits方法时,format参数使用Format32bppArgb成员,确保包含Alpha分量值,修改Alpha分量的值即可。**注意:**此时透明度、红色、绿色和蓝色四个分量的排列顺序为BGRA,同种分量在数组中的间隔为3。

三是使用颜色矩阵处理。在第17.3.4.1节已经学习使用颜色矩阵的基本知识。其中矩阵[R G B A W] 中A表示透明度,不透明时的值为255。而对应的5×5的矩阵中,只需要将(3,3)位置的数值设置为透明度值/255,最终得到的A'即透明度值:

图17-70 矩阵变换:透明度

R'=R*1+G*0+B*0+A*0+W*0 =R

G'=R*0+G*1+B*0+A*0+W*0 =G

B'=R*0+G*0+B*1+A*0+W*0 =B

A'=R*0+G*0+B*0+255*( Alpha/255) +W*0 =Alpha

W'=R*0+G*0+B*0+A*0+W*1 =W

由以上公式可见,R、G、B分量的值并没有改变,A分量的值变为设定的Alpha值,W值也不会影响透明度、红色、绿色和蓝色四个分量的值。

具体代码如下:

Bitmap imgsource;

private void Form1_Load(object sender, EventArgs e)

{

picSource.SizeMode = PictureBoxSizeMode.StretchImage;

picDest.SizeMode = PictureBoxSizeMode.StretchImage;

//透明度从0-255

nudAlpha.Minimum = 0;

nudAlpha.Maximum = 255;

//默认透明度为120

nudAlpha.Value = 120;

imgsource = (Bitmap)Image.FromFile("c:\\lessons\\zg.jpg");

}

private void Form1_Paint(object sender, PaintEventArgs e)

{

picSource.Image = imgsource;

}

private void btnDraw_Click(object sender, EventArgs e)

{

OpenFileDialog ofd = new OpenFileDialog();

ofd.Filter = "图片文件|*.jpg;*.png";

if (ofd.ShowDialog() == DialogResult.Cancel)

return;

Bitmap logoImg = (Bitmap)Image.FromFile(ofd.FileName);

int logoOpacity = (int)nudAlpha.Value;

int logoLeft = 10;

int logoTop = 10;

if(rbByPixel.Checked)

DrawLogo1(logoOpacity, logoImg, logoLeft, logoTop);

if( rbByMemory.Checked)

DrawLogo2(logoOpacity, logoImg, logoLeft, logoTop);

if(rbByMatrix.Checked)

DrawLogo3(logoOpacity, logoImg, logoLeft, logoTop);

}

//像素处理

private void DrawLogo1(int logoOpacity , Bitmap logoImg , int logoLeft, int logoTop)

{

Bitmap imgDest = (Bitmap)imgsource.Clone();

Graphics g = Graphics.FromImage(imgDest);

Bitmap imgLogoDest = new Bitmap(logoImg.Width, logoImg.Height);

Color c;

for(int i = 0;i< logoImg.Width;i++)

{

for(int j = 0;j< logoImg.Height;j++)

{

//获取每个像素的颜色

c = logoImg.GetPixel(i, j);

//将颜色加上A分量,最终生成半透明水印图像

imgLogoDest.SetPixel(i, j, Color.FromArgb(logoOpacity, c));

}

}

g.DrawImage(imgLogoDest, logoLeft, logoTop);

g.Dispose();

picDest.Image = imgDest;

}

//内存处理

private void DrawLogo2(int logoOpacity, Bitmap logoImg, int logoLeft, int logoTop)

{

Bitmap imgDest = (Bitmap)imgsource.Clone();

Graphics g = Graphics.FromImage(imgDest);

Bitmap logoDestImg = new Bitmap(logoImg.Width, logoImg.Height, PixelFormat.Format32bppArgb);

logoDestImg = (Bitmap)logoImg.Clone();

//注意:这里使用的是Format32bppArgb,确保有A分量

BitmapData destData = logoDestImg.LockBits(new Rectangle(0, 0, logoDestImg.Width, logoDestImg.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

IntPtr pSource = destData.Scan0;

int allBytes = destData.Stride * destData.Height;

byte[] rgbvalues = new byte[allBytes];

Marshal.Copy(pSource, rgbvalues, 0, allBytes);

int pos = 0;

int A = logoOpacity;

for(int j = 0;j< destData.Height;j++)

{

for(int i = 0;i< destData.Width;i++)

{

//只需要每隔4位,设置为A分量值

rgbvalues[pos + 3] = (byte)A;

pos = pos + 4;

}

pos = pos + destData.Stride - destData.Width * 4;

}

IntPtr pDest = destData.Scan0;

Marshal.Copy(rgbvalues, 0, pDest, allBytes);

logoDestImg.UnlockBits(destData);

g.DrawImage(logoDestImg, logoLeft, logoTop);

g.Dispose();

picDest.Image = imgDest;

}

//矩阵处理

private void DrawLogo3(int logoOpacity, Bitmap logoImg, int logoLeft, int logoTop)

{

Bitmap imgDest = (Bitmap)imgsource.Clone();

Graphics g = Graphics.FromImage(imgDest);

float Opacity = (float)logoOpacity / 255;

//进行变换的矩阵

float[][] matrixArray = {

new float[] { 1, 0, 0, 0, 0},

new float[] { 0, 1, 0, 0, 0},

new float[] { 0, 0, 1, 0, 0},

new float[] { 0, 0, 0, Opacity, 0},

new float[] { 0, 0, 0, 0, 1} };

ColorMatrix cMatrix = new ColorMatrix(matrixArray);

ImageAttributes imgAttr = new ImageAttributes();

imgAttr.SetColorMatrix(cMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

Rectangle recDest =new Rectangle(logoLeft, logoTop, logoImg.Width, logoImg.Height);

g.DrawImage(logoImg, recDest, 0, 0, logoImg.Width, logoImg.Height, GraphicsUnit.Pixel, imgAttr);

g.Dispose();

picDest.Image = imgDest;

}

运行结果如下图所示:

图17-71 添加图片水印

学习更多vb.net知识,请参看vb.net 教程 目录

学习更多C#知识,请参看C#教程 目录

相关推荐
VB.Net6 分钟前
17.2 图形绘制4
c#
幻想趾于现实3 小时前
C# 装箱和拆箱(以及 as ,is)
开发语言·c#
xcLeigh3 小时前
WPF进阶 | WPF 动画特效揭秘:实现炫酷的界面交互效果
c#·wpf·交互
谢大旭4 小时前
ASP.NET Core自定义 MIME 类型配置
后端·c#
酒酿泡芙12175 小时前
前端力扣刷题 | 6:hot100之 矩阵
前端·leetcode·矩阵
鲤籽鲲5 小时前
C# 中 [MethodImpl(MethodImplOptions.Synchronized)] 的使用详解
java·开发语言·c#
xcLeigh6 小时前
WPF进阶 | WPF 样式与模板:打造个性化用户界面的利器
ui·c#·wpf
VB.Net6 小时前
17.2 图形绘制6
c#·图像
捞鱼哲学家9 小时前
【hot100】刷题记录(11)-搜索二维矩阵 II
数据结构·线性代数·算法·leetcode·矩阵