给你的图片打上LOGO

2023-10-29 11:32
文章标签 图片 logo 打上

本文主要是介绍给你的图片打上LOGO,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

做图片处理软件,肯定会遇到这样的需求:如何把一张图片放在另一张图片上,比如在大图片中打上公司或个人的Logo等等。

其实原理很简单。假设我们有一张 800 * 600 的大图片(Bitmap b0),想在(10,10)的位置上打上Logo(Bitmap b1),Logo图片大小是 150 * 30。很简单,我们以大图片的(10,10)位置作为起始位置,做一个150 * 30 的矩形,把Logo图片整个替换这个矩形。

老规矩,还是用BitmapData来帮助我们实现这个功能。

// 取以大图(X,Y)为起点,w * h 的矩形区域
BitmapData srcData = b0.LockBits(new Rectangle(X,Y,w,h),ImageLockMode.WriteOnly,PixelFormat.Format24bppRgb);

// 取整个Logo
BitmapData dstData = b1.LockBits(new Rectangle(0,0,w,h),ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

unsafe
{
    byte* pIn = (byte*)srcData.Scan0.ToPointer();  
    byte* pLogo = (byte*)dstData.Scan0.ToPointer();

    for (int y = 0; y < h; y++)
    {
        for (int x = 0; x < w; x++)
        {

  // 复制Logo图的像素   
  pIn[0] = (byte)pLogo[0];
  pIn[1] = (byte)pLogo[1];
  pIn[2] = (byte)pLogo[2];

  pIn += 3;
  pLogo += 3;
        }

        pIn += srcData.Stride - w * 3;
        pLogo += dstData.Stride - w * 3;
    }

    b0.UnlockBits(srcData);
    b1.UnlockBits(dstData);
}

这样,为图片打Logo的功能就实现了。当然,还可以有别的方法,比如用BitBlt这个API函数,或者使用GDI+的DrawImage函数。

但这样有个小问题,Logo区域永远是个矩形。假如我的Logo是个圆形,只希望在大图上出现圆形的Logo而不是整块矩形,那又该如何实现呢?

这个问题其实可以这样理解:我们让Logo的背景变透明。而所谓透明,就是两张图片叠加时,上层图片“透明”区域中的像素,仍然使用下层图的相应像 素来代替。但在RGB模式下,并没有“透明”这个概念(我们的讨论都在用 PixelFormat.Format24bppRgb,PixelFormat.Format32bppArgb中的Alpha分量支持“透明度”), 因此我们需要自己规定一种颜色,凡是这个颜色的,都作为“透明”处理。

比如,我们的Logo是黑底的,那么就指定黑色作为透明色。

修改算法也很简单,凡是遇到Logo图中像素颜色是黑色(当然这是个参数,可以自己改)的,就用大图相应位置的颜色来代替,否则还是使用Logo的像素色。下面是算法:

// 因为有可能要回写,所以原图的 ImageLockMode 这次是 ReadWrite
BitmapData srcData = b0.LockBits(new Rectangle(X, Y, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

BitmapData dstData = b1.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

unsafe
{
    byte* pIn = (byte*)srcData.Scan0.ToPointer();
    byte* pLogo = (byte*)dstData.Scan0.ToPointer();

    for (int y = 0; y < h; y++)
    {
        for (int x = 0; x < w; x++)
        {

  // 判断当前点是否透明色
  // 取得当前色
  Color c = Color.FromArgb(pLogo[2], pLogo[1], pLogo[0]);
  if (!ColorIsSimilar(c, TransColor, delta))
  {
   // 不是透明色,b0当前位置的颜色用b1对应位置的来代替
   pIn[0] = (byte)pLogo[0];
   pIn[1] = (byte)pLogo[1];
   pIn[2] = (byte)pLogo[2];
  }

  pIn += 3;
  pLogo += 3;
        }

        pIn += srcData.Stride - w * 3;
        pLogo += dstData.Stride - w * 3;
    }

    b0.UnlockBits(srcData);
    b1.UnlockBits(dstData);
}

我们在上面的算法中出现了另一个小算法,判断颜色C0,C1是否相等。当然如果两个颜色的RGB分量都相等那就肯定是相等了,但考虑到容差方面的因素,我们需要一个更灵活的算法。

我们知道,一个颜色由RGB三个分量组成,每个分量取值[0,255]的整数。这样,任意一个颜色都是这个有限空间中的一个点。两个颜色的“相似度”是否在阀值范围内的问题,最简单的思路也就可以认为求证空间两点的距离是否在阀值范围内。

空间两点距离公式:r2 = (x0-x1)2 + (y0-y1)2 + (z0-z1)2

下面是我的算法。

        /// <summary>
        /// 颜色是否近似
        /// </summary>
        /// <param name="c0">颜色0</param>
        /// <param name="c1">颜色1</param>
        /// <param name="delta">容差</param>
        /// <returns>是/否</returns>
        public static bool ColorIsSimilar(Color c0, Color c1, int delta)
        {
            int r0, r1, g0, g1, b0, b1;

            r0 = c0.R;
            r1 = c1.R;

            g0 = c0.G;
            g1 = c1.G;

            b0 = c0.B;
            b1 = c1.B;

            if  ((r0-r1)*(r0-r1) + (g0-g1) * (g0-g1) + (b0-b1) * (b0-b1) <= delta * delta)
            {
                return true;
            }
            else
            {
                return false;
            }           

        }

 最后再来看看一种情况。我们需要Logo半透明的呈现,貌似水印样的效果。有了上面两种处理图片的经验,不难认识到,大图b0的指定区域中需要混合原始像素和Logo图片b1像素后的新像素填充。

不难想象,新像素值应该结合了大图和Logo图两方面因素的。Logo图越透明,大图受的影响越小。所以这里我们可以采用加权平均的方法来得到混合后的新值。

新值 = (1 - 不透明度%)* 大图像素值 + 不透明度% * Logo图像素值

完整的函数如下:

        /// <summary>
        /// 合并两张图片,支持不透明度和透明色
        /// </summary>
        /// <param name="b0">图片一</param>
        /// <param name="b1">图片二</param>
        /// <param name="X">起始坐标X</param>
        /// <param name="Y">起始坐标Y</param>
        /// <param name="b1_alpha">图片二的不透明度</param>
        /// <param name="TransColor">被作为透明色处理的颜色</param>
        /// <param name="delta">透明色的容差</param>
        /// <returns>合并后的图片</returns>
        public static Bitmap KiMerge(Bitmap b0, Bitmap b1, int X, int Y, int b1_alpha,Color TransColor,int delta)
        {
            if (b0.Equals(null) || b1.Equals(null))
            {
                return null;
            }

            int w0 = b0.Width;
            int h0 = b0.Height;

            int w1 = b1.Width;
            int h1 = b1.Height;

            int w, h;

            if (X + w1 > w0)
            {
                w = w0 - X;
            }
            else
            {
                w = w1;
            }

            if (Y + h1 > h0)
            {
                h = h0 - Y;
            }
            else
            {
                h = h1;
            }

            BitmapData srcData = b0.LockBits(new Rectangle(X, Y, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData dstData = b1.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            unsafe
            {
                byte* pIn = (byte*)srcData.Scan0.ToPointer();
                byte* pLogo = (byte*)dstData.Scan0.ToPointer();

                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {

                        // 判断透明色
                        Color c = Color.FromArgb(pLogo[2], pLogo[1], pLogo[0]);
                        if (!ColorIsSimilar(c, TransColor, delta))
                        {                           

                            float bili = (float)b1_alpha / (float)255; // 不是透明色,加权平均
                            float inbili = 1.0f - bili;

                            int r, g, b;

                            b = (int)(pIn[0] * inbili + pLogo[0] * bili);
                            g = (int)(pIn[1] * inbili + pLogo[1] * bili);
                            r = (int)(pIn[2] * inbili + pLogo[2] * bili);

                            pIn[0] = (byte)b;
                            pIn[1] = (byte)g;
                            pIn[2] = (byte)r;
                        }
                        pIn += 3;
                        pLogo += 3;
                    }


                    pIn += srcData.Stride - w * 3;
                    pLogo += dstData.Stride - w * 3;
                }

                b0.UnlockBits(srcData);
                b1.UnlockBits(dstData);
            }

            return b0;
        }


当然方法有很多,这里只是从原理的角度阐述了一下我的观点,谁有更好的方法请让我知道。

这篇关于给你的图片打上LOGO的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/300362

相关文章

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

Java实现在Word文档中添加文本水印和图片水印的操作指南

《Java实现在Word文档中添加文本水印和图片水印的操作指南》在当今数字时代,文档的自动化处理与安全防护变得尤为重要,无论是为了保护版权、推广品牌,还是为了在文档中加入特定的标识,为Word文档添加... 目录引言Spire.Doc for Java:高效Word文档处理的利器代码实战:使用Java为Wo

基于C#实现PDF转图片的详细教程

《基于C#实现PDF转图片的详细教程》在数字化办公场景中,PDF文件的可视化处理需求日益增长,本文将围绕Spire.PDFfor.NET这一工具,详解如何通过C#将PDF转换为JPG、PNG等主流图片... 目录引言一、组件部署二、快速入门:PDF 转图片的核心 C# 代码三、分辨率设置 - 清晰度的决定因

Python从Word文档中提取图片并生成PPT的操作代码

《Python从Word文档中提取图片并生成PPT的操作代码》在日常办公场景中,我们经常需要从Word文档中提取图片,并将这些图片整理到PowerPoint幻灯片中,手动完成这一任务既耗时又容易出错,... 目录引言背景与需求解决方案概述代码解析代码核心逻辑说明总结引言在日常办公场景中,我们经常需要从 W

使用Python实现无损放大图片功能

《使用Python实现无损放大图片功能》本文介绍了如何使用Python的Pillow库进行无损图片放大,区分了JPEG和PNG格式在放大过程中的特点,并给出了示例代码,JPEG格式可能受压缩影响,需先... 目录一、什么是无损放大?二、实现方法步骤1:读取图片步骤2:无损放大图片步骤3:保存图片三、示php

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

基于Python实现一个图片拆分工具

《基于Python实现一个图片拆分工具》这篇文章主要为大家详细介绍了如何基于Python实现一个图片拆分工具,可以根据需要的行数和列数进行拆分,感兴趣的小伙伴可以跟随小编一起学习一下... 简单介绍先自己选择输入的图片,默认是输出到项目文件夹中,可以自己选择其他的文件夹,选择需要拆分的行数和列数,可以通过

利用Python脚本实现批量将图片转换为WebP格式

《利用Python脚本实现批量将图片转换为WebP格式》Python语言的简洁语法和库支持使其成为图像处理的理想选择,本文将介绍如何利用Python实现批量将图片转换为WebP格式的脚本,WebP作为... 目录简介1. python在图像处理中的应用2. WebP格式的原理和优势2.1 WebP格式与传统

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,

Python如何去除图片干扰代码示例

《Python如何去除图片干扰代码示例》图片降噪是一个广泛应用于图像处理的技术,可以提高图像质量和相关应用的效果,:本文主要介绍Python如何去除图片干扰的相关资料,文中通过代码介绍的非常详细,... 目录一、噪声去除1. 高斯噪声(像素值正态分布扰动)2. 椒盐噪声(随机黑白像素点)3. 复杂噪声(如伪