65.9K
CodeProject 正在变化。 阅读更多。
Home

对图像应用颜色叠加

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.65/5 (15投票s)

2005年3月4日

CPOL

7分钟阅读

viewsIcon

110676

downloadIcon

1105

本文演示了如何在 .NET 中为图像应用色彩叠加,以补充 CSS 的功能。

引言

您是否曾遇到过一个网站需要为各个客户进行品牌定制,但发现图像元素的存在使这个过程变得复杂,因为您无法通过简单的样式表调整它们的颜色?如果能使用一组基础的灰度图像,并自动为它们应用色彩叠加,使其符合客户的配色方案,而无需修改图形包,那该多好啊?

背景

我参与开发的一个 Web 应用程序使用样式表来允许定制应用程序的外观和感觉,以匹配每个客户的企业形象。这对于网站的大部分元素来说都很好;然而,我们在应用程序中使用了一些双色调品牌图像,要确保这些图像与配色方案匹配,比简单地编辑 CSS 文件要麻烦得多。由于 .NET Framework 为开发人员提供了更多的强大功能,我决定自动化应用色彩叠加到这些图像的过程,以简化客户定制流程。

图 1 - 色彩叠加效果。

虽然我已在 Web 应用程序和灰度图像上使用了此功能,但该库并不局限于 Web 开发或灰度图像。

该方法

我并非来自图形背景,因此我的方法可能不是最佳解决方案,但它似乎效果很好。

理论

要应用色彩叠加,需要确定一个基础 RGB 颜色值作为参考点,并计算要应用的色彩叠加的 RGB 值的调整值。这个调整值是为红色、绿色和蓝色三个分量分别计算的。一旦完成,图像中每个像素的红色、绿色和蓝色分量将通过计算出的量进行调整,以产生色彩叠加效果。

颜色的每个 RGB 分量都可以用 0 到 255 的值表示,因此以 127 的中点作为基础参考点,并取要应用的色彩叠加的所需 RGB 分量值,我们可以计算出需要对每个像素进行的调整。

调整红色、绿色和蓝色分量值有时会导致值超出允许的 0 到 255 的范围;在这种情况下,我们进行折衷,仅使用允许的最小值或最大值,视情况而定。

下表说明了如何调整值

十六进制值 红色 绿色 蓝色 Color
基础颜色 7F7F7F 127 127 127
要应用的色彩叠加 1280AA 18 128 170
要使用的调整值 18 - 127 = -109 128 - 127 = 1 170 - 127 = 43
示例像素 1 原始颜色 A5A5A5 165 165 165
示例像素 1 色彩叠加后的颜色 38A6D0 165 - 109 = 56 165 + 1 = 166 165 + 43 = 208
示例像素 2 原始颜色 545454 84 84 84
示例像素 2 色彩叠加后的颜色 00557F 84 - 109 = -25 = 0 * 84 + 1 = 85 84 + 43 = 127
示例像素 3 原始颜色 2E2E2E 46 46 46
示例像素 3 色彩叠加后的颜色 002F59 46 - 109 = -63 = 0 * 46 + 1 = 47 46 + 43 = 89

* 该值小于允许的最小值,因此我们使用最小值代替.

实现

此技术的实现实际上非常简单

  1. 加载要进行色彩叠加的图像。
  2. 使用不会产生索引调色板的格式克隆图像(以防止在开始操作像素颜色时出现错误)。
  3. 计算需要对每个像素的红色、绿色和蓝色分量进行的调整。

    请注意,RedGreenBlue 是指我们要应用的色彩叠加的颜色值

    'Approx non-fraction mid point between 0 and 255
    Const cintAdjustAgainstBase As Integer = 127
    
    ...
    
    'Calculate base adjustment values
    Dim intAdjustR As Integer = Red - cintAdjustAgainstBase
    Dim intAdjustG As Integer = Green - cintAdjustAgainstBase
    Dim intAdjustB As Integer = Blue - cintAdjustAgainstBase
  4. 遍历图像中的每个像素,调整红色、绿色和蓝色分量以产生所需的色彩叠加效果。
    'Adjust RGB values for every pixel 
    Dim iX As Integer
    Dim iY As Integer
    iX = 0
    Do While iX <= bmp.Width - 1
        iY = 0
        Do While iY <= bmp.Height - 1
            Dim c As System.Drawing.Color = bmp.GetPixel(iX, iY)
            bmp.SetPixel(iX, iY, c.FromArgb(c.A,_
                 AdjustRGBValue(c.R, intAdjustR),_
                 AdjustRGBValue(c.G, intAdjustG),_
                 AdjustRGBValue(c.B, intAdjustB)))
            iY += 1
        Loop
        iX += 1
    Loop

    以下是用于计算要使用的新的红色、绿色和蓝色分量并确保值保持在可接受限制内的函数

    Private Shared Function AdjustRGBValue(ByVal Value As Integer, _
                ByVal Adjust As Integer) As Integer
        Dim intReturn As Integer = Value + Adjust
        If intReturn > 255 Then intReturn = 255
        If intReturn < 0 Then intReturn = 0
        Return intReturn
    End Function
  5. 保存生成的色彩叠加图像。

使用代码

要在您的项目中启用此功能,只需下载本文档附带的源文件,将 GavDev.Image.dll 放入您的项目 bin 目录中,然后为类库 GavDev.Image.dll 添加引用。为了方便您的使用,我们提供了两个接口

第一个接口接受单独的红色、绿色和蓝色值

ColorWashImage(ByVal FilePathOriginal As String,_
    ByVal FilePathNew As String,_
    ByVal Red As Integer,_
    ByVal Green As Integer,_
    ByVal Blue As Integer,_
    Optional ByVal Quality As Integer = 100,_
    Optional ByVal Encoding As String = "image/jpeg")

第二个接口允许您将单个组合的 6 位十六进制 RGB 值作为色彩叠加值传入

ColorWashImage(ByVal FilePathOriginal As String,_
    ByVal FilePathNew As String,_
    ByVal HexRGBValue As String,_
    Optional ByVal Quality As Integer = 100,_
    Optional ByVal Encoding As String = "image/jpeg")

两个接口都期望参数 FilePathOriginal(原始灰度图像的物理位置)和 FilePathNew(保存生成的色彩叠加图像的物理位置)。还提供了可选参数来指定输出图像的质量和编码。

以下是类在附带的演示项目中使用的示例

GavDev.Image.Manipulate.ColorWashImage(_
    Server.MapPath("Images/Gav.jpg"),_
    Server.MapPath("Images/Gav." & txtColorWash.Text & ".jpg"),_
    txtColorWash.Text)

图 2 - 演示项目截图。

在您的项目中更好地应用此功能的方法可能是将客户要使用的 RGB 值设置在 Web.config 中,并在尚未生成色彩叠加文件时应用色彩叠加(例如,客户首次运行 Web 应用程序)。显然,只创建一次色彩叠加图像比每次 Web 应用程序启动时都创建要好。

Web.config 条目可能看起来像这样

<!--
Style sheet for customer’s look and feel.
-->
<add key="StyleSheet" value="GavDev.css"/>

<!--
The hex RGB colour value to apply to brand images.
-->
<add key="BrandImageRGB" value="447777"/>

以及 Global.asax 中的代码

Sub Application_Start(ByVal sender As Object, _
                                ByVal e As EventArgs)
    Dim strImages As String() = _
      {"HelpDesk", "DeskBooking", "FacilityBooking",_
      "TopLeftCorner", "TopRightCorner", "BottomLeftCorner", _
      "BottomRightCorner"}
    Dim strHexRGB As String = _
        ConfigurationSettings.AppSettings("BrandImageRGB")
    Dim blnImageMissing As Boolean

    'Check all color washed images are present
    For Each str As String In strImages
        If Not System.IO.File.Exists(Server.MapPath("~") & _
               "\Images\" & str & "." & strHexRGB & ".jpg") Then
             blnImageMissing = True
             Exit For
        End If
    Next

    'Generate color washed images if they aren't present
    If blnImageMissing Then
        For Each str As String In strImageIdentifiers
          GavDev.Image.Manipulate.ColorWashImage(Server.MapPath("~") & _
             "\Images\" & str & ".jpg", Server.MapPath("~") & "\Images\" _
             & str & "." & strHexRGB & ".jpg", strHexRGB)
        Next
    End If

End Sub

备用使用场景

尽管本文和演示代码侧重于将色彩叠加应用于照片类图像,但另一种有用的应用是对通常用于提供演示效果的小图像进行着色,例如,在网站上为包含内容的框添加圆角。在这种情况下,您将使这类小图像的主要颜色与我们在计算红色、绿色和蓝色调整值时用作基础值的颜色相匹配。如前所述,对于红色、绿色和蓝色分量,此值为 127(十六进制为 #7F7F7F)。

观察

尽管使用的方法非常有效,但调整图像的调色板值比调整图像中的每个像素更有效。然而,我没有找到实现这一目标的明显方法。

可能的增强

使用上述方法应用色彩叠加并不总是能获得令人满意的色彩叠加图像,有时色调会太浅或太深,需要对应用的色彩叠加值进行一些实验才能获得最佳效果。

我认为,与其将颜色范围的中点(#7F7F7F)作为应用色彩叠加的参考点,不如在开始时解析整个源图像,以确定图像中最主要的颜色。然后,将最主要的颜色用作应用未经修改的色彩叠加的参考点,并根据这个图像依赖的参考点而不是全局中点(#7F7F7F)来计算变异。

尽管我没有尝试过这个理论,但我相信它会产生更令人满意的结果。当我有更多空闲时间时,我可能会重新审视我的代码并进行实验,看看是否能获得更好的结果。

额外库功能

GavDev.Image.Manipulate 类库中,您还会找到 ImposeUpperLimitOnDimensions 函数,它对于创建缩略图非常有用,尽管我不会在这里详细介绍,因为已有许多文章对此类功能进行了介绍。

历史

  • 2005 年 3 月 4 日 - 原始文章和代码。
  • 2005 年 3 月 11 日 - 添加了对具有索引像素格式的图像的支持。
  • 2005 年 3 月 13 日 - 更新了文章,加入了代码重点介绍。
  • 2005 年 12 月 13 日 - 提出了可能的增强建议。
© . All rights reserved.