当前位置: 首页 > article >正文

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节已经学习使用颜色矩阵的基本知识。其中矩阵[RGBAW] 中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#教程 目录


http://www.kler.cn/a/531341.html

相关文章:

  • JavaFX - 3D 形状
  • MP4基础
  • G. XOUR
  • 「Unity3D」在Unity中使用C#控制显示Android的状态栏
  • C_C++输入输出(下)
  • 【深度分析】微软全球裁员计划不影响印度地区,将继续增加当地就业机会
  • Linux环境下的Java项目部署技巧:项目部署
  • 评估分类模型性能:ROC曲线和AUC值
  • 麦芯 (MachCore) 应用开发教程 6:一台设备中多台电脑主从机的设置
  • PentesterLab 24周学习计划
  • 【游戏设计原理】97 - 空间感知
  • 【翻译】OpenAI Deep Research (2025年2月2日OpenAI发布)
  • Spring中@Conditional注解详解:条件装配的终极指南
  • 8、面向对象:类、封装、构造方法
  • pandas中的关系型连接操作
  • 1.5 Go切片使用
  • 浅谈量化感知训练(QAT)
  • 机器学习--学习计划
  • Intel 与 Yocto 项目的深度融合:全面解析与平台对比
  • 变形金刚多元宇宙
  • 【汽车电子软件架构】AutoSAR从放弃到入门专栏导读
  • 【探索篇】探索部署离线AI在Android的实际体验
  • ChatGPT提问技巧:行业热门应用提示词案例--办公应用
  • SpringAI 人工智能
  • Pandas基础08(分箱操作/时间序列/画图)
  • [SAP ABAP] 性能优化