' ========================================================================================================================
' ____,__, __, ____,_, _, ____ ____,__, ,____,____,
' (-/_|(-| (-| (-|_,(-|\ | (-|__|-/_|( |_/(-|_,(-|__)
' _/ |,_|__,_|__,_|__,_| \|, _|__)/ |,_| \,_|__,_| \,
'
' Copyright � 2009 Allen Baker
'
' ------------------------------------------------------------------------------------------------------------------------
' File: M033_Color
' Originator: Allen Baker (2009.08.23 17:36)
' ------------------------------------------------------------------------------------------------------------------------
' $RCSfile$
' $Revision$
' $Date$
' ========================================================================================================================
Option Explicit
' ========================================================================================================================
' Description
' This module contains routines and functions for manipulating colors. In particular, it provides tools for using the
' RGB, HSL, and HSV color representations and for moving back and forth between them. The RGB color representation is
' used by most applications but the HSL color space is much easier for mathematically manipulating colors.
' ========================================================================================================================
' =====================================================================================================================
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[ Constants ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' =====================================================================================================================
' ==============================================================================================
' This is the default color component max value and it is:
' => old:
' = 7,323,600
' = LCM(255,359,240,100)
' Public Const cDefaultCCMax As Double = 7323600#
' => new:
' = 351,532,800
' Lcm(255,256,359,360,240,100)
' ----------------------------------------------------------------------------------------------
Public Const cDefaultCCMax As Double = 351532800
' =====================================================================================================================
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[ Types ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' =====================================================================================================================
' ==============================================================================================
' This is the color representation used for all the color manipulations in this module. It is
' essentially a color triplet just like VBA's native rgb representation (which from this point
' forward will simply be called "rgb"). However, it stores the 3 color components as Doubles
' instead of as bytes. It also maintains additional information about the valid ranges of the 3
' color components as well as the ratio of each color component to its range maximum.
'
' A ColorVector is a more flexible representation than an rgb because, among other things, it
' supports all the same color representations that rgb supports such as rgb and HSL and then in
' addition, it supports representations like HSV that are not supported by rgb.
'
' rgb: An rgb is stored as a 32-bit COLORREF value. The COLORREF value has the following
' hexadecimal form: 0x00bbggrr
' The low-order byte contains a value for the relative intensity of red; the second
' byte contains a value for green; and the third byte contains a value for blue. The
' high-order byte must be zero. The maximum value for a single byte is 0xFF.
'
' Functions are provided to convert an rgb to ColorVector and visa versa.
'
' Note: All Objects are REFERENCE TYPES in VBA. All the other built-in data types in VBA are
' VALUE TYPES. In addition, *all user defined types declared with the Type keyword*, all
' enums, and all arrays are VALUE TYPES.
'
' Assignment of a VALUE TYPE variable to another variable of the same VALUE TYPE copies
' the value from one variable to the other so that each variable contains its own
' separate instance of the value. Assignment of a REFERENCE TYPE variable to another
' variable of the same REFERENCE TYPE copies the reference from one variable to the other
' so that both variables "point to" the same instance of the value.
'
' Notice that this means that assigning an array *copies* the entire contents of the
' array.
' ----------------------------------------------------------------------------------------------
Public Type ColorVector
x As Double ' A color is represented as a triple, or set of 3 values. The x, y, and z
y As Double ' members of this type are those 3 values.
z As Double
xMax As Double ' the range of possible values for x is >=0 and <=xMax
yMax As Double ' the range of possible values for y is >=0 and <=yMax
zMax As Double ' the range of possible values for z is >=0 and <=zMax
xRatio As Double ' the ratio x / xMax, can be interpreted as the percentage of xMax represented by x
yRatio As Double ' the ratio y / yMax, can be interpreted as the percentage of yMax represented by y
zRatio As Double ' the ratio z / zMax, can be interpreted as the percentage of zMax represented by z
End Type
' =====================================================================================================================
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[ Module Variables ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' =====================================================================================================================
' =====================================================================================================================
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[ Public Routines ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' =====================================================================================================================
' =====================================================================================================================
' <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[ cDefaultCCMax Conversions ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
' =====================================================================================================================
' ==============================================================================================
' A function to give a worksheet access to the default color component max value
' ----------------------------------------------------------------------------------------------
Public Function defaultCMax() As Double
defaultCMax = cDefaultCCMax
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts a value in the range [0..pOldMax] to a proportionaly equivalent value in the
' range [0..cDefaultCCMax].
'
' return
' This function returns a Double in the range [0..cDefaultCCMax].
'
' param
' pValue is the value to convert
' param
' pOldMax is the max value of the range that pValue is in.
' -----------------------------------------------------------------------------------------------------------
Public Function convertToDefaultMax(ByVal pValue As Double, ByVal pOldMax As Double) As Double
convertToDefaultMax = equivalentNumerator(pValue, pOldMax, cDefaultCCMax)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts a value in the range [0..cDefaultCCMax] to a proportionaly equivalent value in the
' range [0..pNewMax].
'
' return
' This function returns a Double in the range [0..pNewMax].
'
' param
' pValue is the value to convert
' param
' pNewMax is the max value of the range to convert pValue to.
' -----------------------------------------------------------------------------------------------------------
Public Function convertFromDefaultMax(ByVal pValue As Double, ByVal pNewMax As Double) As Double
convertFromDefaultMax = equivalentNumerator(pValue, cDefaultCCMax, pNewMax)
End Function
' =====================================================================================================================
' <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[ ColorVector Creation Functions ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
' =====================================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function packages the values passed into it through its parameters as a new ColorVector. The
' ColorVector's color component ratios (which represent scaling factors for each component and are in the
' range of [0..1]) are calculated internally by dividing the color component values by their corresponding
' maximums.
'
' return
' This function returns a new ColorVector.
'
' param
' pX is the rgb red component or an hsl or hsv hue component
' param
' pY is the rgb green component or an hsl or hsv saturation component
' param
' pZ is the rgb blue component or an hsl luminosity component or an hsv value component
' param (optional)
' pXMax is maximum value allowed for the pX component. As an example value: it would be 255 for the rgb
' red component or the hsl hue component used by Windows. If no argument value is passed to this procedure
' through this optional parameter, its value defaults to cDefaultCCMax
' param (optional)
' pYMax is maximum value allowed for the pY component. As an example value: it would be 255 for the rgb
' green component or the hsl saturation component used by Windows. If no argument value is passed to this
' procedure through this optional parameter, its value defaults to cDefaultCCMax.
' param (optional)
' pZMax is maximum value allowed for the pZ component. As an example value: it would be 255 for the rgb
' blue component or the hsl luminosity component used by Windows. If no argument value is passed to this
' procedure through this optional parameter, its value defaults to cDefaultCCMax.
' -----------------------------------------------------------------------------------------------------------
Public Function newColorVector _
( _
ByVal pX As Double, _
ByVal pY As Double, _
ByVal pZ As Double, _
Optional ByVal pXMax As Double = cDefaultCCMax, _
Optional ByVal pYMax As Double = cDefaultCCMax, _
Optional ByVal pZMax As Double = cDefaultCCMax _
) _
As ColorVector
Dim result As ColorVector
Dim xRatioD As Double
Dim yRatioD As Double
Dim zRatioD As Double
Dim xL As Long
Dim yL As Long
Dim zL As Long
Dim xMaxL As Long
Dim yMaxL As Long
Dim zMaxL As Long
'
' ==============================================================================================
' we have to catch Max values of zero here to prevent divide by zero crashes. Might as well
' make sure the maxes are alltogether valid and not just check for zero values.
' ----------------------------------------------------------------------------------------------
If (pXMax < 1#) Then Call raiseException _
( _
"The ColorVector XMax value of: " & pXMax & _
" is not within the valid range for Max values, which is [>=1]", "newColorVectorFromRatios", "M033_Color" _
)
If (pYMax < 1#) Then Call raiseException _
( _
"The ColorVector YMax value of: " & pYMax & _
" is not within the valid range for Max values, which is [>=1]", "newColorVectorFromRatios", "M033_Color" _
)
If (pZMax < 1#) Then Call raiseException _
( _
"The ColorVector ZMax value of: " & pZMax & _
" is not within the valid range for Max values, which is [>=1]", "newColorVectorFromRatios", "M033_Color" _
)
'
' ==============================================================================================
' round to the nearest integer
' ----------------------------------------------------------------------------------------------
xL = normalRoundLng(pX)
yL = normalRoundLng(pY)
zL = normalRoundLng(pZ)
xMaxL = normalRoundLng(pXMax)
yMaxL = normalRoundLng(pYMax)
zMaxL = normalRoundLng(pZMax)
'
' ==============================================================================================
' force into valid range of [0..max-1]
' ----------------------------------------------------------------------------------------------
xL = xL Mod (xMaxL + 1)
yL = yL Mod (yMaxL + 1)
zL = zL Mod (zMaxL + 1)
'
' ==============================================================================================
' ratios are always real numbers in the range [0..1]
' ----------------------------------------------------------------------------------------------
xRatioD = CDbl(xL) / CDbl(xMaxL)
yRatioD = CDbl(yL) / CDbl(yMaxL)
zRatioD = CDbl(zL) / CDbl(zMaxL)
'
' ==============================================================================================
' load up a color vector with the values all as real numbers
' ----------------------------------------------------------------------------------------------
With result
.x = CDbl(xL)
.xMax = CDbl(xMaxL)
.xRatio = xRatioD
.y = CDbl(yL)
.yMax = CDbl(yMaxL)
.yRatio = yRatioD
.z = CDbl(zL)
.zMax = CDbl(zMaxL)
.zRatio = zRatioD
End With
'
' ==============================================================================================
' check the result and return it
' ----------------------------------------------------------------------------------------------
Call validateColorVector(result, "newColorVector")
newColorVector = result '
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function packages the values passed into it through its parameters as a new ColorVector. The
' ColorVector's color component triple values (which are in the range of [0..Max]) are calculated internally
' by multiplying the color component ratios by their corresponding maximums.
'
' param
' pXRatio is the ratio of the rgb red component or an hsl or hsv hue component
' param
' pYRatio is the ratio of the rgb green component or an hsl or hsv saturation component
' param
' pZRatio is the ratio of the rgb blue component or an hsl luminosity component or an hsv value component
' param (optional)
' pXMax is maximum value allowed for the pX component. As an example value: it would be 255 for the rgb
' red component or the hsl hue component used by Windows. If no argument value is passed to this procedure
' through this optional parameter, its value defaults to cDefaultCCMax.
' param (optional)
' pYMax is maximum value allowed for the pY component. As an example value: it would be 255 for the rgb
' green component or the hsl saturation component used by Windows. If no argument value is passed to this
' function through this optional parameter, its value defaults to cDefaultCCMax.
' param (optional)
' pZMax is maximum value allowed for the pZ component. As an example value: it would be 255 for the rgb
' blue component or the hsl luminosity component used by Windows. If no argument value is passed to this
' function through this optional parameter, its value defaults to cDefaultCCMax.
' -----------------------------------------------------------------------------------------------------------
Public Function newColorVectorFromRatios _
( _
ByVal pXRatio As Double, _
ByVal pYRatio As Double, _
ByVal pZRatio As Double, _
Optional ByVal pXMax As Double = cDefaultCCMax, _
Optional ByVal pYMax As Double = cDefaultCCMax, _
Optional ByVal pZMax As Double = cDefaultCCMax _
) _
As ColorVector
Dim result As ColorVector
Dim xL As Long
Dim yL As Long
Dim zL As Long
Dim xMaxL As Long
Dim yMaxL As Long
Dim zMaxL As Long
'
' ==============================================================================================
' we have to catch Max values of zero here to prevent divide by zero crashes. Might as well
' make sure the maxes are altogether valid and not limit the check to one for zero values.
' ----------------------------------------------------------------------------------------------
If (pXMax < 1#) Then Call raiseException _
( _
"The ColorVector XMax value of: " & pXMax & _
" is not within the valid range for Max values, which is [>=1]", "newColorVectorFromRatios", "M033_Color" _
)
If (pYMax < 1#) Then Call raiseException _
( _
"The ColorVector YMax value of: " & pYMax & _
" is not within the valid range for Max values, which is [>=1]", "newColorVectorFromRatios", "M033_Color" _
)
If (pZMax < 1#) Then Call raiseException _
( _
"The ColorVector ZMax value of: " & pZMax & _
" is not within the valid range for Max values, which is [>=1]", "newColorVectorFromRatios", "M033_Color" _
)
'
' ==============================================================================================
' round to the nearest integer
' ----------------------------------------------------------------------------------------------
xMaxL = normalRoundLng(pXMax)
yMaxL = normalRoundLng(pYMax)
zMaxL = normalRoundLng(pZMax)
'
' ==============================================================================================
' compute component values and round to the nearest integer
' ----------------------------------------------------------------------------------------------
xL = normalRoundLng(pXRatio * CDbl(xMaxL))
yL = normalRoundLng(pYRatio * CDbl(yMaxL))
zL = normalRoundLng(pZRatio * CDbl(zMaxL))
'
' ==============================================================================================
' force into valid range of [0..max-1]
' ----------------------------------------------------------------------------------------------
xL = xL Mod (xMaxL + 1)
yL = yL Mod (yMaxL + 1)
zL = zL Mod (zMaxL + 1)
'
' ==============================================================================================
' make sure the ratios are exactly right -- taking into account rounding and Double arithmetic
' error
' ----------------------------------------------------------------------------------------------
pXRatio = CDbl(xL) / CDbl(xMaxL)
pYRatio = CDbl(yL) / CDbl(yMaxL)
pZRatio = CDbl(zL) / CDbl(zMaxL)
'
' ==============================================================================================
' load up a color vector with the values all as real numbers
' ----------------------------------------------------------------------------------------------
With result
.x = CDbl(xL)
.xMax = CDbl(xMaxL)
.xRatio = pXRatio
.y = CDbl(yL)
.yMax = CDbl(yMaxL)
.yRatio = pYRatio
.z = CDbl(zL)
.zMax = CDbl(zMaxL)
.zRatio = pZRatio
End With
'
' ==============================================================================================
' check the result and return it
' ----------------------------------------------------------------------------------------------
Call validateColorVector(result, "newColorVectorFromRatios")
newColorVectorFromRatios = result
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function changes the scale of an existing newColorVector.
'
' return
' This function returnes a new newColorVector, it does not modify the newColorVector passed to it as an
' argument through the pColorVector parameter. The new newColorVector's x, y, and z component values are
' each equal to the original newColorVector's correspopnding component scaled to its new maximums. In
' other words,
' rescaledColorVector.x = pColorVector.x * (rescaledColorVector.xMax / pColorVector.xMax)
'
' param
' pColorVector is the newColorVector to be rescaled
' param
' pXMax is the new scale for x, i.e, the maximum value allowed for the x component.
' param
' pYMax is the new scale for y, i.e, the maximum value allowed for the y component.
' param
' pZMax is the new scale for z, i.e, the maximum value allowed for the z component.
' -----------------------------------------------------------------------------------------------------------
Public Function rescaledColorVector(ByRef pColorVector As ColorVector, ByVal pXMax As Double, ByVal pYMax As Double, ByVal pZMax As Double) As ColorVector
With pColorVector
rescaledColorVector = newColorVectorFromRatios(.xRatio, .yRatio, .zRatio, pXMax, pYMax, pZMax)
End With
End Function
' =====================================================================================================================
' <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[ Conversion Functions Between rgb and ColorVector ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
' =====================================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts from a color represented as a Long in VBA's native rgb format to a ColorVector
' containing an RGB representation of the same color
'
' return
' A ColorVector that is initialized with the data from a Long in VBA's native rgb format
'
' param
' pRgb is the Long in VBA's native rgb format that is converted to a ColorVector
' param (optional)
' pXMax is maximum value allowed for the pX component. As an example value: it would be 255 for the rgb
' red component or the hsl hue component used by Windows. If no argument value is passed to this procedure
' through this optional parameter, its value defaults to 255.
' param (optional)
' pYMax is maximum value allowed for the pY component. As an example value: it would be 255 for the rgb
' green component or the hsl saturation component used by Windows. If no argument value is passed to this
' procedure through this optional parameter, its value defaults to 255.
' param (optional)
' pZMax is maximum value allowed for the pZ component. As an example value: it would be 255 for the rgb
' blue component or the hsl luminosity component used by Windows. If no argument value is passed to this
' procedure through this optional parameter, its value defaults to 255.
' -----------------------------------------------------------------------------------------------------------
Public Function RGBvecFromRgb _
( _
ByVal pRgb As Long, _
Optional ByVal pXMax As Double = 255#, _
Optional ByVal pYMax As Double = 255#, _
Optional ByVal pZMax As Double = 255# _
) _
As ColorVector
'
' ==============================================================================================
' pick the RGB components out of the rgb Long
' ----------------------------------------------------------------------------------------------
Dim rgbR As Double
Dim rgbG As Double
Dim rgbB As Double
rgbR = rgbComponent(pRgb, 1)
rgbG = rgbComponent(pRgb, 2)
rgbB = rgbComponent(pRgb, 3)
'
' ==============================================================================================
' The components come into here as 255ths. If that's not what's wanted (rarely if ever the
' case), then convert.
' ----------------------------------------------------------------------------------------------
If (pXMax <> 255#) Then rgbR = equivalentNumerator(rgbR, 255#, pXMax)
If (pYMax <> 255#) Then rgbG = equivalentNumerator(rgbG, 255#, pYMax)
If (pZMax <> 255#) Then rgbB = equivalentNumerator(rgbB, 255#, pZMax)
'
' ==============================================================================================
' make a ColorVector out of it all and return it.
' ----------------------------------------------------------------------------------------------
RGBvecFromRgb = newColorVector(rgbR, rgbG, rgbB, pXMax, pYMax, pZMax)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts from a color represented as a Long in VBA's native rgb format to a ColorVector
' containing an HSL representation of the same color
'
' return
' A ColorVector that is initialized with the data from a Long in VBA's native rgb format
'
' param
' pRgb is the Long in VBA's native rgb format that is converted to a ColorVector
' param (optional)
' pXMax is maximum value allowed for the pX component. As an example value: it would be 255 for the rgb
' red component or the hsl hue component used by Windows. If no argument value is passed to this procedure
' through this optional parameter, its value defaults to 359.
' param (optional)
' pYMax is maximum value allowed for the pY component. As an example value: it would be 255 for the rgb
' green component or the hsl saturation component used by Windows. If no argument value is passed to this
' procedure through this optional parameter, its value defaults to 100.
' param (optional)
' pZMax is maximum value allowed for the pZ component. As an example value: it would be 255 for the rgb
' blue component or the hsl luminosity component used by Windows. If no argument value is passed to this
' procedure through this optional parameter, its value defaults to 100.
' -----------------------------------------------------------------------------------------------------------
Public Function HSLvecFromRgb _
( _
ByVal pRgb As Long, _
Optional ByVal pXMax As Double = 359#, _
Optional ByVal pYMax As Double = 100#, _
Optional ByVal pZMax As Double = 100# _
) _
As ColorVector
Dim rgbVector As ColorVector
Dim hslVector As ColorVector
rgbVector = RGBvecFromRgb(pRgb)
hslVector = HSLvecFromRGBvec(rgbVector, pXMax, pYMax, pZMax)
HSLvecFromRgb = hslVector
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts from a color represented as a Long in VBA's native rgb format to a ColorVector
' containing an HSL representation of the same color
'
' return
' A ColorVector that is initialized with the data from a Long in VBA's native rgb format
'
' param
' pRgb is the Long in VBA's native rgb format that is converted to a ColorVector
' param (optional)
' pXMax is maximum value allowed for the pX component. As an example value: it would be 255 for the rgb
' red component or the hsl hue component used by Windows. If no argument value is passed to this procedure
' through this optional parameter, its value defaults to 359.
' param (optional)
' pYMax is maximum value allowed for the pY component. As an example value: it would be 255 for the rgb
' green component or the hsl saturation component used by Windows. If no argument value is passed to this
' procedure through this optional parameter, its value defaults to 100.
' param (optional)
' pZMax is maximum value allowed for the pZ component. As an example value: it would be 255 for the rgb
' blue component or the hsl luminosity component used by Windows. If no argument value is passed to this
' procedure through this optional parameter, its value defaults to 100.
' -----------------------------------------------------------------------------------------------------------
Public Function HSVvecFromRgb _
( _
ByVal pRgb As Long, _
Optional ByVal pXMax As Double = 359#, _
Optional ByVal pYMax As Double = 100#, _
Optional ByVal pZMax As Double = 100# _
) _
As ColorVector
Dim rgbVector As ColorVector
Dim hsvVector As ColorVector
rgbVector = RGBvecFromRgb(pRgb)
hsvVector = HSVvecFromRGBvec(rgbVector, pXMax, pYMax, pZMax)
HSVvecFromRgb = hsvVector
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts from a ColorVector containing an RGB representation of a color to a Long in VBA's
' native rgb format
'
' return
' A long in VBA's rgb format. The value returned from this function is usable anywhere that the value
' returned from VBA's rgb() function is usable
'
' param
' pRGBvec is the ColorVector that is converted to a Long in VBA's native rgb format. This parameter is
' assumed to be a ColorVector containing an RGB color representation.
' -----------------------------------------------------------------------------------------------------------
Public Function rgbFromRGBvec(ByRef pRGBvec As ColorVector) As Long
Dim rgbR As Long
Dim rgbG As Long
Dim rgbB As Long
'
' ==============================================================================================
' the VBA rgb() function expects all three of the values (rgbR, rgbG, and rgbB) to be scaled
' to 255
' ----------------------------------------------------------------------------------------------
With pRGBvec
rgbR = normalRoundLng(equivalentNumerator(.x, .xMax, 255#)) Mod 256&
rgbG = normalRoundLng(equivalentNumerator(.y, .yMax, 255#)) Mod 256&
rgbB = normalRoundLng(equivalentNumerator(.z, .zMax, 255#)) Mod 256&
End With
rgbFromRGBvec = toRgb(rgbR, rgbG, rgbB, 255&, 255&, 255&)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts from a ColorVector containing an HSL representation of a color to a Long in VBA's
' native rgb format
'
' return
' A long in VBA's rgb format. The value returned from this function is usable anywhere that the value
' returned from VBA's rgb() function is usable
'
' param
' pHSLvec is the ColorVector that is converted to a Long in VBA's native rgb format. This parameter is
' assumed to be a ColorVector containing an HSL color representation.
' -----------------------------------------------------------------------------------------------------------
Public Function rgbFromHSLvec(ByRef pHSLvec As ColorVector) As Long
rgbFromHSLvec = rgbFromRGBvec(RGBvecFromHSLvec(pHSLvec, 255#, 255#, 255#))
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts from a ColorVector containing an HSV representation of a color to a Long in VBA's
' native rgb format
'
' return
' A long in VBA's rgb format. The value returned from this function is usable anywhere that the value
' returned from VBA's rgb() function is usable
'
' param
' pHSVvec is the ColorVector that is converted to a Long in VBA's native rgb format. This parameter is
' assumed to be a ColorVector containing an HSV color representation.
' -----------------------------------------------------------------------------------------------------------
Public Function rgbFromHSVvec(ByRef pHSVvec As ColorVector) As Long
rgbFromHSVvec = rgbFromRGBvec(RGBvecFromHSVvec(pHSVvec, 255#, 255#, 255#))
End Function
' =====================================================================================================================
' <<<<<<<<<<<<<<<<<<<<<<[ Conversion Functions Between Color Models: RGB, HSL, HSV, and etc. ]>>>>>>>>>>>>>>>>>>>>>>>
' =====================================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts an RGB representation of a color to an HSV representation of the same color.
'
' return
' This function returns an HSV representation, stored as a ColorVector, of the color passed in through the
' pRGBvec parameter
'
' param
' pRGBvec is a ColorVector containing an RGB representation of a color. This color is translated into an
' HSV representation of the same color.
' param (optional)
' pHueMax is maximum value allowed for the hue component of the resulting HSV representation of the color.
' Another way of viewing it is that it is the number of segments or chunks or discrete values that the
' continuous hue space is broken down into. It is usually 359, 1 for each degree of the color circle
' (0..359) of the hue space for HSV, but it doesn't have to be. It can be any value >= 0. This parameter
' is used to compute the HSV components of the output ColorVector that this function creates and is itself
' stored in that output ColorVector. It is not used to describe the input ColorVector. The comparable
' value for the input ColorVector is already stored inside that ColorVector when this function is called.
' If no argument value is passed to this function through this optional parameter, its value defaults to
' 359.
' param (optional)
' pSaturationMax is maximum value allowed for the saturation component of the resulting HSV representation
' of the color. Another way of viewing it is that it is the number of segments or chunks or discrete
' values that the continuous saturation space is broken down into. It is usually 100, 1 for each
' percentage point (0..100) of the saturation space for HSV, but it doesn't have to be. It can be any
' value >= 0. This parameter is used to compute the HSV components of the output ColorVector that this
' function creates and is itself stored in that output ColorVector. It is not used to describe the input
' ColorVector. The comparable value for the input ColorVector is already stored inside that ColorVector
' when this function is called. If no argument value is passed to this function through this optional
' parameter, its value defaults to 100.
' param (optional)
' pValueMax is maximum value allowed for the "value" component of the resulting HSV representation of the
' color. Another way of viewing it is that it is the number of segments or chunks or discrete values that
' the continuous "value" space is broken down into. It is usually 100, 1 for each percentage point
' (0..100) of the "value" space for HSV, but it doesn't have to be. It can be any value >= 0. This
' parameter is used to compute the HSV components of the output ColorVector that this function creates and
' is itself stored in that output ColorVector. It is not used to describe the input ColorVector. The
' comparable value for the input ColorVector is already stored inside that ColorVector when this function
' is called. If no argument value is passed to this function through this optional parameter, its value
' defaults to 100.
' -----------------------------------------------------------------------------------------------------------
Public Function HSVvecFromRGBvec _
( _
ByRef pRGBvec As ColorVector, _
Optional ByVal pHueMax As Double = 359#, _
Optional ByVal pSaturationMax As Double = 100#, _
Optional ByVal pValueMax As Double = 100# _
) _
As ColorVector
Dim rRatio As Double
Dim gRatio As Double
Dim bRatio As Double
Dim hRatio As Double
Dim sRatio As Double
Dim vRatio As Double
Dim rgbMin As Double
Dim rgbMax As Double
Dim rgbSpan As Double
Dim rSpan As Double
Dim gSpan As Double
Dim bSpan As Double
'
' ==============================================================================================
' all computations are done in terms of the color component ratios. This makes this function
' independent of whatever the color component values or their allowed maximums are.
' ----------------------------------------------------------------------------------------------
rRatio = pRGBvec.xRatio
gRatio = pRGBvec.yRatio
bRatio = pRGBvec.zRatio
'
' ==============================================================================================
' get the min and max of the RGB color components and the distance between them
' ----------------------------------------------------------------------------------------------
rgbMin = min(rRatio, gRatio, bRatio)
rgbMax = max(rRatio, gRatio, bRatio)
rgbSpan = rgbMax - rgbMin
'
' ==============================================================================================
' the HSV value component is equivalent to the max RGB color component value and is in the
' range [0..1]
' ----------------------------------------------------------------------------------------------
vRatio = rgbMax
'
' ==============================================================================================
' if all the RGB color components are the same, then this is gray -- no chroma
' ----------------------------------------------------------------------------------------------
If (rgbSpan = 0#) Then
hRatio = 0#
sRatio = 0#
Else
'
' ==============================================================================================
' compute HSV saturation component which will be in the range [0..1]
' ----------------------------------------------------------------------------------------------
sRatio = rgbSpan / rgbMax
'
' ==============================================================================================
' ----------------------------------------------------------------------------------------------
rSpan = (((rgbMax - rRatio) / 6#) + (rgbSpan / 2#)) / rgbSpan
gSpan = (((rgbMax - gRatio) / 6#) + (rgbSpan / 2#)) / rgbSpan
bSpan = (((rgbMax - bRatio) / 6#) + (rgbSpan / 2#)) / rgbSpan
If (rRatio = rgbMax) Then
hRatio = bSpan - gSpan
ElseIf (gRatio = rgbMax) Then
hRatio = (1# / 3#) + rSpan - bSpan
ElseIf (bRatio = rgbMax) Then
hRatio = (2# / 3#) + gSpan - rSpan
End If
If (hRatio < 0#) Then hRatio = hRatio + 1#
If (hRatio > 1#) Then hRatio = hRatio - 1#
End If
'
' ==============================================================================================
' create the output ColorVector
' ----------------------------------------------------------------------------------------------
HSVvecFromRGBvec = newColorVectorFromRatios(hRatio, sRatio, vRatio, pHueMax, pSaturationMax, pValueMax)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts an HSV representation of a color to an RGB representation of the same color.
'
' return
' This function returns an RGB representation, stored as a ColorVector, of the color passed in through the
' pHSVvec parameter
'
' param
' pHSVvec is a ColorVector containing an HSV representation of a color. This color is translated into an
' RGB representation of the same color.
' param (optional)
' pRedMax is maximum value allowed for the red component of the resulting RGB representation of the color.
' Another way of viewing it is that it is the number of segments or chunks or discrete values that the
' continuous red space is broken down into. It is usually 255, which is a value in the range (0..255) and
' can be stored in a single byte, but it doesn't have to be. It can be any value >= 0. This parameter is
' used to compute the RGB components of the output ColorVector that this function creates and is itself
' stored in that output ColorVector. It is not used to describe the input ColorVector. The comparable
' value for the input ColorVector is already stored inside that ColorVector when this function is called.
' If no argument value is passed to this function through this optional parameter, its value defaults to
' 255.
' param (optional)
' pGreenMax is maximum value allowed for the green component of the resulting RGB representation of the
' color. Another way of viewing it is that it is the number of segments or chunks or discrete values that
' the continuous green space is broken down into. It is usually 255, which is a value in the range
' (0..255) and can be stored in a single byte, but it doesn't have to be. It can be any value >= 0. This
' parameter is used to compute the RGB components of the output ColorVector that this function creates and
' is itself stored in that output ColorVector. It is not used to describe the input ColorVector. The
' comparable value for the input ColorVector is already stored inside that ColorVector when this function
' is called. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' param (optional)
' pBlueMax is maximum value allowed for the blue component of the resulting RGB representation of the
' color. Another way of viewing it is that it is the number of segments or chunks or discrete values that
' the continuous blue space is broken down into. It is usually 255, which is a value in the range (0..255)
' and can be stored in a single byte, but it doesn't have to be. It can be any value >= 0. This parameter
' is used to compute the RGB components of the output ColorVector that this function creates and is itself
' stored in that output ColorVector. It is not used to describe the input ColorVector. The comparable
' value for the input ColorVector is already stored inside that ColorVector when this function is called.
' If no argument value is passed to this function through this optional parameter, its value defaults to
' 255.
' -----------------------------------------------------------------------------------------------------------
Public Function RGBvecFromHSVvec _
( _
ByRef pHSVvec As ColorVector, _
Optional ByVal pRedMax As Double = 255#, _
Optional ByVal pGreenMax As Double = 255#, _
Optional ByVal pBlueMax As Double = 255# _
) _
As ColorVector
Dim h As Double
Dim s As Double
Dim v As Double
Dim R As Double
Dim G As Double
Dim B As Double
Dim p As Double
Dim q As Double
Dim t As Double
Dim hsvVec As ColorVector
'
' ==============================================================================================
' this algorithm expects the HSV color representation to be in the traditional 359, 100, 100
' form. Make sure the input color's HSV representation is in that form.
' ----------------------------------------------------------------------------------------------
hsvVec = rescaledColorVector(pHSVvec, 359#, 100#, 100#)
'
' ==============================================================================================
' With the exception of computation involving the hue value, the computations are done in terms
' of the color component ratios. This makes this those parts of this function independent of
' whatever the color component values or their allowed maximums are.
' ----------------------------------------------------------------------------------------------
h = hsvVec.x
s = hsvVec.yRatio
v = hsvVec.zRatio
'
' ==============================================================================================
' if all the saturation is 0 (ome shade of gray between white and black)then all the RGB color
' components are just equal to the value, so we're done
' ----------------------------------------------------------------------------------------------
If (s = 0) Then
R = v
G = v
B = v
RGBvecFromHSVvec = newColorVectorFromRatios(v, v, v, pRedMax, pGreenMax, pBlueMax)
Exit Function
End If
'
' ==============================================================================================
' convert the hue to a number between 0 and 5 and then break it into its integral and fractional
' parts.
' usually HSV colors have hue that is a number >= 0 and <= 359, but it doesnt have to be.
' HSVvec.xMax is our maximum hue value and it will almost always be 359.
' ----------------------------------------------------------------------------------------------
Dim oneSixthOfMax As Double
Dim integralPartOfHue As Integer
Dim fractionalPartOfHue As Double
oneSixthOfMax = hsvVec.xMax / 6
h = h / oneSixthOfMax
integralPartOfHue = Application.Floor(h, 1)
fractionalPartOfHue = h - integralPartOfHue
'
' ==============================================================================================
' compute the RGB components as ratios in the range [0..1]
' ----------------------------------------------------------------------------------------------
p = v * (1# - s)
q = v * (1# - (s * fractionalPartOfHue))
t = v * (1# - (s * (1# - fractionalPartOfHue)))
If (integralPartOfHue = 0) Then
R = v
G = t
B = p
ElseIf (integralPartOfHue = 1) Then
R = q
G = v
B = p
ElseIf (integralPartOfHue = 2) Then
R = p
G = v
B = t
ElseIf (integralPartOfHue = 3) Then
R = p
G = q
B = v
ElseIf (integralPartOfHue = 4) Then
R = t
G = p
B = v
Else ' (integralPartOfHue = 5)
R = v
G = p
B = q
End If
'
' ==============================================================================================
' create the output ColorVector
' ----------------------------------------------------------------------------------------------
RGBvecFromHSVvec = newColorVectorFromRatios(R, G, B, pRedMax, pGreenMax, pBlueMax)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts an HSL representation of a color to an RGB representation of the same color.
'
' Note: I found this algorithm on the web and can no longer identify the source. If you know the original
' source of this algorithm please reference the site so that I can give the author due credit.
'
' return
' This function returns an RGB representation, stored as a ColorVector, of the color passed in through the
' pHSLvec parameter
'
' param
' pHSLvec is a ColorVector containing an HSL representation of a color. This color is translated into an
' RGB representation of the same color.
' param (optional)
' pRedMax is maximum value allowed for the red component of the resulting RGB representation of the color.
' Another way of viewing it is that it is the number of segments or chunks or discrete values that the
' continuous red space is broken down into. It is usually 255, which is a value in the range (0..255) and
' can be stored in a single byte, but it doesn't have to be. It can be any value >= 0. This parameter is
' used to compute the RGB components of the output ColorVector that this function creates and is itself
' stored in that output ColorVector. It is not used to describe the input ColorVector. The comparable
' value for the input ColorVector is already stored inside that ColorVector when this function is called.
' If no argument value is passed to this function through this optional parameter, its value defaults to
' 255.
' param (optional)
' pGreenMax is maximum value allowed for the green component of the resulting RGB representation of the
' color. Another way of viewing it is that it is the number of segments or chunks or discrete values that
' the continuous green space is broken down into. It is usually 255, which is a value in the range
' (0..255) and can be stored in a single byte, but it doesn't have to be. It can be any value >= 0. This
' parameter is used to compute the RGB components of the output ColorVector that this function creates and
' is itself stored in that output ColorVector. It is not used to describe the input ColorVector. The
' comparable value for the input ColorVector is already stored inside that ColorVector when this function
' is called. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' param (optional)
' pBlueMax is maximum value allowed for the blue component of the resulting RGB representation of the
' color. Another way of viewing it is that it is the number of segments or chunks or discrete values that
' the continuous blue space is broken down into. It is usually 255, which is a value in the range (0..255)
' and can be stored in a single byte, but it doesn't have to be. It can be any value >= 0. This parameter
' is used to compute the RGB components of the output ColorVector that this function creates and is itself
' stored in that output ColorVector. It is not used to describe the input ColorVector. The comparable
' value for the input ColorVector is already stored inside that ColorVector when this function is called.
' If no argument value is passed to this function through this optional parameter, its value defaults to
' 255.
' -----------------------------------------------------------------------------------------------------------
Public Function RGBvecFromHSLvec _
( _
ByRef pHSLvec As ColorVector, _
Optional ByVal pRedMax As Double = 255#, _
Optional ByVal pGreenMax As Double = 255#, _
Optional ByVal pBlueMax As Double = 255# _
) _
As ColorVector
Dim rgbR As Double
Dim rgbG As Double
Dim rgbB As Double
If (pHSLvec.yRatio = 0#) Then ' If saturation is 0 the image is monochrome
rgbR = pHSLvec.zRatio
rgbG = pHSLvec.zRatio
rgbB = pHSLvec.zRatio
Else
Dim q As Double
If (pHSLvec.zRatio < 0.5) Then
q = pHSLvec.zRatio * (1# + pHSLvec.yRatio)
Else
q = pHSLvec.zRatio + pHSLvec.yRatio - (pHSLvec.zRatio * pHSLvec.yRatio)
End If
Dim p As Double
p = (2# * pHSLvec.zRatio) - q
rgbR = hueToRGB(p, q, pHSLvec.xRatio + (1# / 3#))
rgbG = hueToRGB(p, q, pHSLvec.xRatio)
rgbB = hueToRGB(p, q, pHSLvec.xRatio - (1# / 3#))
End If
RGBvecFromHSLvec = newColorVectorFromRatios(rgbR, rgbG, rgbB, pRedMax, pGreenMax, pBlueMax)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts an HSV representation of a color to an HSL representation of the same color.
'
' return
' This function returns an HSL representation, stored as a ColorVector, of the color passed in through the
' pHSVvec parameter
'
' param
' pHSVvec is a ColorVector containing an HSV representation of a color. This color is translated into an
' HSL representation of the same color.
' param (optional)
' pHueMax is maximum value allowed for the hue component of the resulting HSL representation of the color.
' Another way of viewing it is that it is the number of segments or chunks or discrete values that the
' continuous hue space is broken down into. It is usually 255, which is a value in the range (0..255) and
' can be stored in a single byte, but it doesn't have to be. It can be any value >= 0. This parameter is
' used to compute the HSL components of the output ColorVector that this function creates and is itself
' stored in that output ColorVector. It is not used to describe the input ColorVector. The comparable
' value for the input ColorVector is already stored inside that ColorVector when this function is called.
' If no argument value is passed to this function through this optional parameter, its value defaults to
' 255.
' param (optional)
' pSaturationMax is maximum value allowed for the saturation component of the resulting HSL representation
' of the color. Another way of viewing it is that it is the number of segments or chunks or discrete
' values that the continuous saturation space is broken down into. It is usually 255, which is a value in
' the range (0..255) and can be stored in a single byte, but it doesn't have to be. It can be any value >=
' 0. This parameter is used to compute the HSL components of the output ColorVector that this function
' creates and is itself stored in that output ColorVector. It is not used to describe the input
' ColorVector. The comparable value for the input ColorVector is already stored inside that ColorVector
' when this function is called. If no argument value is passed to this function through this optional
' parameter, its value defaults to 255.
' param (optional)
' pLuminosityMax is maximum value allowed for the luminosity component of the resulting HSL representation
' of the color. Another way of viewing it is that it is the number of segments or chunks or discrete
' values that the continuous luminosity space is broken down into. It is usually 255, which is a value in
' the range (0..255) and can be stored in a single byte, but it doesn't have to be. It can be any value >=
' 0. This parameter is used to compute the HSL components of the output ColorVector that this function
' creates and is itself stored in that output ColorVector. It is not used to describe the input
' ColorVector. The comparable value for the input ColorVector is already stored inside that ColorVector
' when this function is called. If no argument value is passed to this function through this optional
' parameter, its value defaults to 255.
' -----------------------------------------------------------------------------------------------------------
Public Function HSLvecFromHSVvec _
( _
ByRef pHSVvec As ColorVector, _
Optional ByVal pHueMax As Double = 359#, _
Optional ByVal pSaturationMax As Double = 100#, _
Optional ByVal pLuminosityMax As Double = 100# _
) _
As ColorVector
Dim hslH As Double
Dim hslS As Double
Dim hslL As Double
hslH = pHSVvec.xRatio
hslL = (2 - pHSVvec.yRatio) * pHSVvec.zRatio
hslS = pHSVvec.yRatio * pHSVvec.zRatio
If (hslL <= 1#) Then
hslS = hslS / hslL
Else
hslS = hslS / (2# - hslL)
End If
hslL = hslL / 2#
HSLvecFromHSVvec = newColorVectorFromRatios(hslH, hslS, hslL, pHueMax, pSaturationMax, pLuminosityMax)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts an HSL representation of a color to an HSV representation of the same color.
'
' return
' This function returns an HSV representation, stored as a ColorVector, of the color passed in through the
' pHSLvec parameter
'
' param
' pHSLvec is a ColorVector containing an HSL representation of a color. This color is translated into an
' HSV representation of the same color.
' param (optional)
' pHueMax is maximum value allowed for the hue component of the resulting HSV representation of the color.
' Another way of viewing it is that it is the number of segments or chunks or discrete values that the
' continuous hue space is broken down into. It is usually 359, 1 for each degree of the color circle
' (0..359) of the hue space for HSV, but it doesn't have to be. It can be any value >= 0. This parameter
' is used to compute the HSV components of the output ColorVector that this function creates and is itself
' stored in that output ColorVector. It is not used to describe the input ColorVector. The comparable
' value for the input ColorVector is already stored inside that ColorVector when this function is called.
' If no argument value is passed to this function through this optional parameter, its value defaults to
' 359.
' param (optional)
' pSaturationMax is maximum value allowed for the saturation component of the resulting HSV representation
' of the color. Another way of viewing it is that it is the number of segments or chunks or discrete
' values that the continuous saturation space is broken down into. It is usually 100, 1 for each
' percentage point (0..100) of the saturation space for HSV, but it doesn't have to be. It can be any
' value >= 0. This parameter is used to compute the HSV components of the output ColorVector that this
' function creates and is itself stored in that output ColorVector. It is not used to describe the input
' ColorVector. The comparable value for the input ColorVector is already stored inside that ColorVector
' when this function is called. If no argument value is passed to this function through this optional
' parameter, its value defaults to 100.
' param (optional)
' pValueMax is maximum value allowed for the "value" component of the resulting HSV representation of the
' color. Another way of viewing it is that it is the number of segments or chunks or discrete values that
' the continuous "value" space is broken down into. It is usually 100, 1 for each percentage point
' (0..100) of the "value" space for HSV, but it doesn't have to be. It can be any value >= 0. This
' parameter is used to compute the HSV components of the output ColorVector that this function creates and
' is itself stored in that output ColorVector. It is not used to describe the input ColorVector. The
' comparable value for the input ColorVector is already stored inside that ColorVector when this function
' is called. If no argument value is passed to this function through this optional parameter, its value
' defaults to 100.
' -----------------------------------------------------------------------------------------------------------
Public Function HSVvecFromHSLvec _
( _
ByRef pHSLvec As ColorVector, _
Optional ByVal pHueMax As Double = 359#, _
Optional ByVal pSaturationMax As Double = 100#, _
Optional ByVal pValueMax As Double = 100# _
) _
As ColorVector
Dim hslH As Double
Dim hslS As Double
Dim hslL As Double
Dim hsvH As Double
Dim hsvS As Double
Dim hsvV As Double
'
' ==============================================================================================
' all computations are done in terms of the color component ratios. This makes this function
' independent of whatever the color component values or their allowed maximums are.
' ----------------------------------------------------------------------------------------------
hslH = pHSLvec.xRatio
hslS = pHSLvec.yRatio
hslL = pHSLvec.zRatio
hsvH = hslH
hslL = hslL * 2#
If (hslL <= 1#) Then
hslS = hslS * hslL
Else
hslS = hslS * (2# - hslL)
End If
hsvV = (hslL + hslS) / 2#
hsvS = (2# * hslS) / (hslL + hslS)
HSVvecFromHSLvec = newColorVectorFromRatios(hsvH, hsvS, hsvV, pHueMax, pSaturationMax, pValueMax)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts an RGB representation of a color to an HSL representation of the same color.
'
' return
' This function returns an HSL representation, stored as a ColorVector, of the color passed in through the
' pRGBvec parameter
'
' param
' pRGBvec is a ColorVector containing an RGB representation of a color. This color is translated into an
' HSL representation of the same color.
' param (optional)
' pHueMax is maximum value allowed for the hue component of the resulting HSL representation of the color.
' Another way of viewing it is that it is the number of segments or chunks or discrete values that the
' continuous hue space is broken down into. It is usually 255, which is a value in the range (0..255) and
' can be stored in a single byte, but it doesn't have to be. It can be any value >= 0. This parameter is
' used to compute the HSL components of the output ColorVector that this function creates and is itself
' stored in that output ColorVector. It is not used to describe the input ColorVector. The comparable
' value for the input ColorVector is already stored inside that ColorVector when this function is called.
' If no argument value is passed to this function through this optional parameter, its value defaults to
' 359.
' param (optional)
' pSaturationMax is maximum value allowed for the saturation component of the resulting HSL representation
' of the color. Another way of viewing it is that it is the number of segments or chunks or discrete
' values that the continuous saturation space is broken down into. It is usually 255, which is a value in
' the range (0..255) and can be stored in a single byte, but it doesn't have to be. It can be any value >=
' 0. This parameter is used to compute the HSL components of the output ColorVector that this function
' creates and is itself stored in that output ColorVector. It is not used to describe the input
' ColorVector. The comparable value for the input ColorVector is already stored inside that ColorVector
' when this function is called. If no argument value is passed to this function through this optional
' parameter, its value defaults to 100.
' param (optional)
' pLuminosityMax is maximum value allowed for the luminosity component of the resulting HSL representation
' of the color. Another way of viewing it is that it is the number of segments or chunks or discrete
' values that the continuous luminosity space is broken down into. It is usually 255, which is a value in
' the range (0..255) and can be stored in a single byte, but it doesn't have to be. It can be any value >=
' 0. This parameter is used to compute the HSL components of the output ColorVector that this function
' creates and is itself stored in that output ColorVector. It is not used to describe the input
' ColorVector. The comparable value for the input ColorVector is already stored inside that ColorVector
' when this function is called. If no argument value is passed to this function through this optional
' parameter, its value defaults to 100.
' -----------------------------------------------------------------------------------------------------------
Public Function HSLvecFromRGBvec _
( _
ByRef pRGBvec As ColorVector, _
Optional ByVal pHueMax As Double = 359#, _
Optional ByVal pSaturationMax As Double = 100#, _
Optional ByVal pLuminosityMax As Double = 100# _
) _
As ColorVector
Dim rgbR As Double
Dim rgbG As Double
Dim rgbB As Double
Dim hslH As Double
Dim hslS As Double
Dim hslL As Double
Dim maxRgb As Double
Dim minRgb As Double
Dim minToMaxSpan As Double
'
' ==============================================================================================
' all computations are done in terms of the color component ratios. This makes this function
' independent of whatever the color component values or their allowed maximums are.
' ----------------------------------------------------------------------------------------------
rgbR = pRGBvec.xRatio
rgbG = pRGBvec.yRatio
rgbB = pRGBvec.zRatio
'
' ==============================================================================================
' get the min and max of the RGB color components and the distance between them
' ----------------------------------------------------------------------------------------------
minRgb = min(rgbR, rgbG, rgbB)
maxRgb = max(rgbR, rgbG, rgbB)
minToMaxSpan = maxRgb - minRgb
hslL = (maxRgb + minRgb) / 2#
If (maxRgb = minRgb) Then
hslH = 0#
hslS = 0#
Else
If (hslL > 0.5) Then
hslS = minToMaxSpan / (2# - maxRgb - minRgb)
Else
hslS = minToMaxSpan / (maxRgb + minRgb)
End If
If (maxRgb = rgbR) Then
If (rgbG < rgbB) Then
hslH = (rgbG - rgbB) / minToMaxSpan + 6#
Else
hslH = (rgbG - rgbB) / minToMaxSpan
End If
ElseIf (maxRgb = rgbG) Then
hslH = (rgbB - rgbR) / minToMaxSpan + 2#
Else
hslH = (rgbR - rgbG) / minToMaxSpan + 4#
End If
hslH = hslH / 6#
End If
HSLvecFromRGBvec = newColorVectorFromRatios(hslH, hslS, hslL, pHueMax, pSaturationMax, pLuminosityMax)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function builds two ColorVectors with the input color's two split compliment colors. The split
' compliment colors' ColorVectors are scaled to the same scale as pAnchorColor and are set at the same
' saturation and luminosity as pAnchorColor.
'
' return
' This function returns a 1-based array containing the two split compliment colors' ColorVectors
'
' param
' pAnchorColor is a ColorVector containing an HSL representation of the color from which the two split
' compliments are computed.
' param (optional)
' pArcDegree is the angle subtended by the arc defined by the two points on the perimeter of the color
' circle representing the locations of the two split compliment hues. IOW, it's the angle between the
' two split compliment hues. If no argument value is passed to this function through this optional
' parameter, its value defaults to 40 degrees.
' -----------------------------------------------------------------------------------------------------------
Public Function splitComplimentsFromHSLvec _
( _
ByRef pAnchorColor As ColorVector, _
Optional ByVal pArcDegree As Double = 40# _
) _
As ColorVector()
Dim halfArc As Double
Dim convertTo359 As Double
Dim convertToInputScale As Double
Dim anchorHue As Double
Dim firstHueClockwiseFromAnchor As Double
Dim secondHueClockwiseFromAnchor As Double
Dim firstColorClockwiseFromAnchor As ColorVector
Dim secondColorClockwiseFromAnchor As ColorVector
Dim result(1 To 2) As ColorVector
'
' ==============================================================================================
' conversion factors for going between pAnchorColor's hue scale and the 359 degree hue scale
' ----------------------------------------------------------------------------------------------
convertTo359 = (359# / pAnchorColor.xMax)
convertToInputScale = (pAnchorColor.xMax / 359#)
'
' ==============================================================================================
' pAnchorColor's hue converted to the 359 degree hue scale
' ----------------------------------------------------------------------------------------------
anchorHue = pAnchorColor.x * convertTo359
'
' ==============================================================================================
' the two split compliment colors in the 359 degree hue scale
' ----------------------------------------------------------------------------------------------
halfArc = pArcDegree / 2#
firstHueClockwiseFromAnchor = CDbl(normalRoundLng(anchorHue + 180# - halfArc) Mod 360&)
secondHueClockwiseFromAnchor = CDbl(normalRoundLng(anchorHue + 180# + halfArc) Mod 360&)
'
' ==============================================================================================
' the two split compliment colors in pAnchorColor's hue scale
' ----------------------------------------------------------------------------------------------
firstHueClockwiseFromAnchor = firstHueClockwiseFromAnchor * convertToInputScale
secondHueClockwiseFromAnchor = secondHueClockwiseFromAnchor * convertToInputScale
'
' ==============================================================================================
' new color vectors for the two spit compliment colors
' ----------------------------------------------------------------------------------------------
firstColorClockwiseFromAnchor = newColorVector(firstHueClockwiseFromAnchor, pAnchorColor.y, pAnchorColor.z, pAnchorColor.xMax, pAnchorColor.yMax, pAnchorColor.zMax)
secondColorClockwiseFromAnchor = newColorVector(secondHueClockwiseFromAnchor, pAnchorColor.y, pAnchorColor.z, pAnchorColor.xMax, pAnchorColor.yMax, pAnchorColor.zMax)
'
' ==============================================================================================
' an array of ColorVectors containg the two split compliment colors to return
' ----------------------------------------------------------------------------------------------
result(1) = firstColorClockwiseFromAnchor
result(2) = secondColorClockwiseFromAnchor
splitComplimentsFromHSLvec = result
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function builds three ColorVectors with the input color's three rectangular tetrad colors. The
' rectangular tetrad colors' ColorVectors are scaled to the same scale as pAnchorColor and are set at the
' same saturation and luminosity as pAnchorColor.
'
' return
' This function returns a 1-based array containing the three rectangular tetrad colors' ColorVectors
'
' param
' pAnchorColor is a ColorVector containing an HSL representation of the color from which the three
' rectangular tetrad are computed.
' -----------------------------------------------------------------------------------------------------------
Public Function rectangularTetradFromHSLvec(ByRef pAnchorColor As ColorVector) As ColorVector()
Dim convertTo359 As Double
Dim convertToInputScale As Double
Dim anchorHue359 As Double
Dim hueAt180ClockWise As Double
Dim hueAt140ClockWise As Double
Dim hueAt320ClockWise As Double
Dim colorAt180Clockwise As ColorVector
Dim colorAt140Clockwise As ColorVector
Dim colorAt320Clockwise As ColorVector
Dim result(1 To 3) As ColorVector
'
' ==============================================================================================
' conversion factors for going between pAnchorColor's hue scale and the 359 degree hue scale
' ----------------------------------------------------------------------------------------------
convertTo359 = (359# / pAnchorColor.xMax)
convertToInputScale = (pAnchorColor.xMax / 359#)
'
' ==============================================================================================
' pAnchorColor's hue converted to the 359 degree hue scale
' ----------------------------------------------------------------------------------------------
anchorHue359 = pAnchorColor.x * convertTo359
'
' ==============================================================================================
' the two rectangular tetrad colors in the 359 degree hue scale
' ----------------------------------------------------------------------------------------------
hueAt180ClockWise = CDbl(normalRoundLng(anchorHue359 + 180#) Mod 360&)
hueAt140ClockWise = CDbl(normalRoundLng(anchorHue359 + 140#) Mod 360&)
hueAt320ClockWise = CDbl(normalRoundLng(anchorHue359 + 320#) Mod 360&)
'
' ==============================================================================================
' the two rectangular tetrad colors in pAnchorColor's hue scale
' ----------------------------------------------------------------------------------------------
hueAt180ClockWise = hueAt180ClockWise * convertToInputScale
hueAt140ClockWise = hueAt140ClockWise * convertToInputScale
hueAt320ClockWise = hueAt320ClockWise * convertToInputScale
'
' ==============================================================================================
' new color vectors for the two spit compliment colors
' ----------------------------------------------------------------------------------------------
colorAt180Clockwise = newColorVector(hueAt180ClockWise, pAnchorColor.y, pAnchorColor.z, pAnchorColor.xMax, pAnchorColor.yMax, pAnchorColor.zMax)
colorAt140Clockwise = newColorVector(hueAt140ClockWise, pAnchorColor.y, pAnchorColor.z, pAnchorColor.xMax, pAnchorColor.yMax, pAnchorColor.zMax)
colorAt320Clockwise = newColorVector(hueAt320ClockWise, pAnchorColor.y, pAnchorColor.z, pAnchorColor.xMax, pAnchorColor.yMax, pAnchorColor.zMax)
'
' ==============================================================================================
' an array of ColorVectors containg the two rectangular tetrad colors to return
' ----------------------------------------------------------------------------------------------
result(1) = colorAt180Clockwise
result(2) = colorAt140Clockwise
result(3) = colorAt320Clockwise
rectangularTetradFromHSLvec = result
End Function
' =====================================================================================================================
' <<<<<<<<<<<<<<<<<[ DEPRECATED Conversion Functions Between Color Models: RGB, HSL, HSV, and etc. ]>>>>>>>>>>>>>>>>>
' =====================================================================================================================
' ---------------------------------------------------------------------------------------------------------------------
' The functions in this section that involve HSL representations default to HSL component value maximums of 255, 255,
' 255. This is the old standard, the new standard is 359, 100, 100. All the older code that uses this module was built
' assuming the old standard and would require modification to upgrade to the new standard. Consequently, to avoid that
' significant rework, I've added optional parameters to the functions in this section that involve HSL which default to
' the old standard so that the old code that does not use those parameters will continue to work. New code that uses
' these functions and that use the new HSL standard will need to utilize the new optional parameters to pass in the new
' standard maximums.
'
' Note also that the functions in this section that return a packed Long representation of the 3 color components use
' 255, 255, 255 as the maximums for the HSL and HSV outputs. This is because the value 359 does not fit into a 1 byte
' portion of the packed Long output as required by the standard for packed Longs established by the built-in VBA
' function RGB().
' ---------------------------------------------------------------------------------------------------------------------
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts an HSV representation of a color to an HSL representation
'
' return
' this function returns a Long whole number representing an HSL color value. See the built in VBA
' function RGB() for an explanation of this representation.
'
' param (input)
' pHsvH is where the HSV hue value (H) will be stored when this function exits and it's value is in the
' range [0..359]
' param (input)
' pHsvS is the HSV saturation value (S) will be stored when this function exits and it's value is in the
' range [0..100]
' param (input)
' pHsvL is the HSV luminosity value (L) will be stored when this function exits and it's value is in the
' range [0..100]
' param (output)
' pHslH is where the HSL hue value (H) will be stored when this function exits and it's value is in the
' range [0..255]
' param (output)
' pHslS is the HSL saturation value (S) will be stored when this function exits and it's value is in the
' range [0..255]
' param (output)
' pHslL is the HSL luminosity value (L) will be stored when this function exits and it's value is in the
' range [0..255]
' param (optional)
' pHsvHMax is maximum value allowed for the hue component of the HSV input If no argument value is passed
' to this function through this optional parameter, its value defaults to 359.
' param (optional)
' pHsvSMax is maximum value allowed for the saturation component of the HSV input If no argument value is
' passed to this function through this optional parameter, its value defaults to 100.
' param (optional)
' pHsvVMax is maximum value allowed for the value component of the HSV input If no argument value is
' passed to this function through this optional parameter, its value defaults to 100.
' param (optional)
' pHslHMax is maximum value allowed for the hue component of the resulting HSL representation of the color.
' If no argument value is passed to this function through this optional parameter, its value defaults to
' 255.
' param (optional)
' pHslSMax is maximum value allowed for the saturation component of the resulting HSL representation of
' the color. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' param (optional)
' pHslLMax is maximum value allowed for the luminosity component of the resulting HSL representation of
' the color. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' -----------------------------------------------------------------------------------------------------------
Public Function hsvToHsl _
( _
ByVal pHsvH As Long, _
ByVal pHsvS As Long, _
ByVal pHsvV As Long, _
ByRef pHslH As Long, _
ByRef pHslS As Long, _
ByRef pHslL As Long, _
Optional ByVal pHsvHmax As Long = 359&, _
Optional ByVal pHsvSmax As Long = 100&, _
Optional ByVal pHsvVmax As Long = 100&, _
Optional ByVal pHslHmax As Long = 255&, _
Optional ByVal pHslSmax As Long = 255&, _
Optional ByVal pHslLmax As Long = 255& _
) _
As Long
Dim hsvVec As ColorVector
Dim hslVec As ColorVector
hsvVec = newColorVector(CDbl(pHsvH), CDbl(pHsvS), CDbl(pHsvV), CDbl(pHsvHmax), CDbl(pHsvSmax), CDbl(pHsvVmax))
hslVec = HSLvecFromHSVvec(hsvVec, CDbl(pHslHmax), CDbl(pHslSmax), CDbl(pHslLmax))
pHslH = normalRoundLng(hslVec.x)
pHslS = normalRoundLng(hslVec.y)
pHslL = normalRoundLng(hslVec.z)
hsvToHsl = toRgb(pHslH, pHslS, pHslL, pHslHmax, pHslSmax, pHslLmax)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' These functions convert an HSV representation of a color to an HSL representation and return one of the HSL
' components
'
' return
' These functions return one ofg the HSL components
'
' param (input)
' pHsvH is where the HSV hue value (H) will be stored when this function exits and it's value is in the
' range [0..359]
' param (input)
' pHsvS is the HSV saturation value (S) will be stored when this function exits and it's value is in the
' range [0..100]
' param (input)
' pHsvL is the HSV luminosity value (L) will be stored when this function exits and it's value is in the
' range [0..100]
' param (optional)
' pHsvHMax is maximum value allowed for the hue component of the HSV input If no argument value is passed
' to this function through this optional parameter, its value defaults to 359.
' param (optional)
' pHsvSMax is maximum value allowed for the saturation component of the HSV input If no argument value is
' passed to this function through this optional parameter, its value defaults to 100.
' param (optional)
' pHsvVMax is maximum value allowed for the value component of the HSV input If no argument value is
' passed to this function through this optional parameter, its value defaults to 100.
' param (optional)
' pHslHMax is maximum value allowed for the hue component of the resulting HSL representation of the color.
' If no argument value is passed to this function through this optional parameter, its value defaults to
' 255.
' param (optional)
' pHslSMax is maximum value allowed for the saturation component of the resulting HSL representation of
' the color. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' param (optional)
' pHslLMax is maximum value allowed for the luminosity component of the resulting HSL representation of
' the color. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' -----------------------------------------------------------------------------------------------------------
Public Function hsvToHslHue _
( _
ByVal pHsvH As Long, _
ByVal pHsvS As Long, _
ByVal pHsvV As Long, _
Optional ByVal pHsvHmax As Long = 359&, _
Optional ByVal pHsvSmax As Long = 100&, _
Optional ByVal pHsvVmax As Long = 100&, _
Optional ByVal pHslHmax As Long = 255&, _
Optional ByVal pHslSmax As Long = 255&, _
Optional ByVal pHslLmax As Long = 255& _
) _
As Long
Dim hslH As Long
Dim hslS As Long
Dim hslL As Long
Dim junk As Long
junk = hsvToHsl(pHsvH, pHsvS, pHsvV, hslH, hslS, hslL, pHsvHmax, pHsvSmax, pHsvVmax, pHslHmax, pHslSmax, pHslLmax)
hsvToHslHue = hslH Mod (pHslHmax + 1)
End Function
Public Function hsvToHslSat _
( _
ByVal pHsvH As Long, _
ByVal pHsvS As Long, _
ByVal pHsvV As Long, _
Optional ByVal pHsvHmax As Long = 359&, _
Optional ByVal pHsvSmax As Long = 100&, _
Optional ByVal pHsvVmax As Long = 100&, _
Optional ByVal pHslHmax As Long = 255&, _
Optional ByVal pHslSmax As Long = 255&, _
Optional ByVal pHslLmax As Long = 255& _
) _
As Long
Dim hslH As Long
Dim hslS As Long
Dim hslL As Long
Dim junk As Long
junk = hsvToHsl(pHsvH, pHsvS, pHsvV, hslH, hslS, hslL, pHsvHmax, pHsvSmax, pHsvVmax, pHslHmax, pHslSmax, pHslLmax)
hsvToHslSat = hslS Mod (pHslSmax + 1)
End Function
Public Function hsvToHslLum _
( _
ByVal pHsvH As Long, _
ByVal pHsvS As Long, _
ByVal pHsvV As Long, _
Optional ByVal pHsvHmax As Long = 359&, _
Optional ByVal pHsvSmax As Long = 100&, _
Optional ByVal pHsvVmax As Long = 100&, _
Optional ByVal pHslHmax As Long = 255&, _
Optional ByVal pHslSmax As Long = 255&, _
Optional ByVal pHslLmax As Long = 255& _
) _
As Long
Dim hslH As Long
Dim hslS As Long
Dim hslL As Long
Dim junk As Long
junk = hsvToHsl(pHsvH, pHsvS, pHsvV, hslH, hslS, hslL, pHsvHmax, pHsvSmax, pHsvVmax, pHslHmax, pHslSmax, pHslLmax)
hsvToHslLum = hslL Mod (pHslLmax + 1)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts an RGB color to an HSL color.
'
' return
' this function returns a Long whole number representing an HSL color value. See the built in VBA
' function RGB() for an explanation of this representation.
'
' param
' pRgb is a Long whole number representing an RGB color value. See the built in VBA function RGB() for
' an explanation of this representation.
' param (output)
' pH is where the HSL hue value (H) will be stored when this function exits and it's value is in the
' range [0, 255]
' param (output)
' pS is the HSL saturation value (S) will be stored when this function exits and it's value is in the
' range [0, 255]
' param (output)
' pL is the HSL luminosity value (L) will be stored when this function exits and it's value is in the
' range [0, 255]
' param (optional)
' pRgbRMax is maximum value allowed for the red component of the RGB input If no argument value is passed
' to this function through this optional parameter, its value defaults to 255.
' param (optional)
' pRgbGMax is maximum value allowed for the green component of the RGB input If no argument value is
' passed to this function through this optional parameter, its value defaults to 255.
' param (optional)
' pRgbBMax is maximum value allowed for the blue component of the RGB input If no argument value is
' passed to this function through this optional parameter, its value defaults to 255.
' param (optional)
' pHslHMax is maximum value allowed for the hue component of the resulting HSL representation of the color.
' If no argument value is passed to this function through this optional parameter, its value defaults to
' 255.
' param (optional)
' pHslSMax is maximum value allowed for the saturation component of the resulting HSL representation of
' the color. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' param (optional)
' pHslLMax is maximum value allowed for the luminosity component of the resulting HSL representation of
' the color. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' -----------------------------------------------------------------------------------------------------------
Public Function rgbToHsl _
( _
ByVal pRgb As Long, _
ByRef pH As Long, _
ByRef pS As Long, _
ByRef pL As Long, _
Optional ByVal pRgbRmax As Long = 255&, _
Optional ByVal pRgbGmax As Long = 255&, _
Optional ByVal pRgbBmax As Long = 255&, _
Optional ByVal pHslHmax As Long = 255&, _
Optional ByVal pHslSmax As Long = 255&, _
Optional ByVal pHslLmax As Long = 255& _
) _
As Long
Dim rgbVec As ColorVector
Dim hslVec As ColorVector
rgbVec = newColorVector(CDbl(rgbComponent(pRgb, 1&)), CDbl(rgbComponent(pRgb, 2&)), CDbl(rgbComponent(pRgb, 3&)), CDbl(pRgbRmax), CDbl(pRgbGmax), CDbl(pRgbBmax))
hslVec = HSLvecFromRGBvec(rgbVec, CDbl(pHslHmax), CDbl(pHslSmax), CDbl(pHslLmax))
pH = normalRoundLng(hslVec.x)
pS = normalRoundLng(hslVec.y)
pL = normalRoundLng(hslVec.z)
rgbToHsl = toRgb(pH, pS, pL, pHslHmax, pHslSmax, pHslLmax)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' These functions each return one part of the HSL representation of a color given by an RGB representation of
' the color
'
' param
' pRgb is the RGB representation of the color for which one HSL component is returned
' param (optional)
' pRgbRMax is maximum value allowed for the red component of the RGB input If no argument value is passed
' to this function through this optional parameter, its value defaults to 255.
' param (optional)
' pRgbGMax is maximum value allowed for the green component of the RGB input If no argument value is
' passed to this function through this optional parameter, its value defaults to 255.
' param (optional)
' pRgbBMax is maximum value allowed for the blue component of the RGB input If no argument value is
' passed to this function through this optional parameter, its value defaults to 255.
' param (optional)
' pHslHMax is maximum value allowed for the hue component of the resulting HSL representation of the color.
' If no argument value is passed to this function through this optional parameter, its value defaults to
' 255.
' param (optional)
' pHslSMax is maximum value allowed for the saturation component of the resulting HSL representation of
' the color. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' param (optional)
' pHslLMax is maximum value allowed for the luminosity component of the resulting HSL representation of
' the color. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' -----------------------------------------------------------------------------------------------------------
Public Function rgbToHue _
( _
ByVal pRgb As Long, _
Optional ByVal pRgbRmax As Long = 255&, _
Optional ByVal pRgbGmax As Long = 255&, _
Optional ByVal pRgbBmax As Long = 255&, _
Optional ByVal pHslHmax As Long = 255&, _
Optional ByVal pHslSmax As Long = 255&, _
Optional ByVal pHslLmax As Long = 255& _
) _
As Long
Dim hue As Long
Dim sat As Long
Dim lum As Long
Dim jnk As Long
jnk = rgbToHsl(pRgb, hue, sat, lum, pRgbRmax, pRgbGmax, pRgbBmax, pHslHmax, pHslSmax, pHslLmax)
rgbToHue = hue
End Function
Public Function rgbToSaturation _
( _
ByVal pRgb As Long, _
Optional ByVal pRgbRmax As Long = 255&, _
Optional ByVal pRgbGmax As Long = 255&, _
Optional ByVal pRgbBmax As Long = 255&, _
Optional ByVal pHslHmax As Long = 255&, _
Optional ByVal pHslSmax As Long = 255&, _
Optional ByVal pHslLmax As Long = 255& _
) _
As Long
Dim hue As Long
Dim sat As Long
Dim lum As Long
Dim jnk As Long
jnk = rgbToHsl(pRgb, hue, sat, lum, pRgbRmax, pRgbGmax, pRgbBmax, pHslHmax, pHslSmax, pHslLmax)
rgbToSaturation = sat
End Function
Public Function rgbToLuminosity _
( _
ByVal pRgb As Long, _
Optional ByVal pRgbRmax As Long = 255&, _
Optional ByVal pRgbGmax As Long = 255&, _
Optional ByVal pRgbBmax As Long = 255&, _
Optional ByVal pHslHmax As Long = 255&, _
Optional ByVal pHslSmax As Long = 255&, _
Optional ByVal pHslLmax As Long = 255& _
) _
As Long
Dim hue As Long
Dim sat As Long
Dim lum As Long
Dim jnk As Long
jnk = rgbToHsl(pRgb, hue, sat, lum, pRgbRmax, pRgbGmax, pRgbBmax, pHslHmax, pHslSmax, pHslLmax)
rgbToLuminosity = lum
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts an RGB color to an HSV color.
'
' return
' this function returns a Long whole number representing an HSV color value. See the built in VBA
' function RGB() for an explanation of this representation.
'
' param
' pRgb is a Long whole number representing an RGB color value. See the built in VBA function RGB() for
' an explanation of this representation.
' param (output)
' pH is where the HSV hue value (H) will be stored when this function exits and it's value is in the
' range [0, 359]
' param (output)
' pS is the HSV saturation value (S) will be stored when this function exits and it's value is in the
' range [0, 100]
' param (output)
' pVal is the HSV value value (L) will be stored when this function exits and it's value is in the
' range [0, 100]
' param (optional)
' pRgbRMax is maximum value allowed for the red component of the RGB input If no argument value is passed
' to this function through this optional parameter, its value defaults to 255.
' param (optional)
' pRgbGMax is maximum value allowed for the green component of the RGB input If no argument value is
' passed to this function through this optional parameter, its value defaults to 255.
' param (optional)
' pRgbBMax is maximum value allowed for the blue component of the RGB input If no argument value is
' passed to this function through this optional parameter, its value defaults to 255.
' param (optional)
' pHsvHMax is maximum value allowed for the hue component of the resulting HSV representation of the color.
' If no argument value is passed to this function through this optional parameter, its value defaults to
' 255.
' param (optional)
' pHsvSMax is maximum value allowed for the saturation component of the resulting HSV representation of
' the color. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' param (optional)
' pHsvVMax is maximum value allowed for the value component of the resulting HSV representation of
' the color. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' -----------------------------------------------------------------------------------------------------------
Public Function rgbToHsv _
( _
ByVal pRgb As Long, _
ByRef pH As Long, _
ByRef pS As Long, _
ByRef pVal As Long, _
Optional ByVal pRgbRmax As Long = 255&, _
Optional ByVal pRgbGmax As Long = 255&, _
Optional ByVal pRgbBmax As Long = 255&, _
Optional ByVal pHsvHmax As Long = 255&, _
Optional ByVal pHsvSmax As Long = 255&, _
Optional ByVal pHsvVmax As Long = 255& _
) _
As Long
Dim rgbVec As ColorVector
Dim hsvVec As ColorVector
rgbVec = newColorVector(CDbl(rgbComponent(pRgb, 1&)), CDbl(rgbComponent(pRgb, 2&)), CDbl(rgbComponent(pRgb, 3&)), CDbl(pRgbRmax), CDbl(pRgbGmax), CDbl(pRgbBmax))
hsvVec = HSVvecFromRGBvec(rgbVec, CDbl(pHsvHmax), CDbl(pHsvSmax), CDbl(pHsvVmax))
pH = normalRoundLng(hsvVec.x)
pS = normalRoundLng(hsvVec.y)
pVal = normalRoundLng(hsvVec.z)
rgbToHsv = toRgb(pH, pS, pVal, pHsvHmax, pHsvSmax, pHsvVmax)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' These functions each return one part of the HSV representation of a color given by an RGB representation of
' the color
'
' param
' pRgb is the RGB representation of the color for which one HSV component is returned
' param (optional)
' pRgbRMax is maximum value allowed for the red component of the RGB input If no argument value is passed
' to this function through this optional parameter, its value defaults to 255.
' param (optional)
' pRgbGMax is maximum value allowed for the green component of the RGB input If no argument value is
' passed to this function through this optional parameter, its value defaults to 255.
' param (optional)
' pRgbBMax is maximum value allowed for the blue component of the RGB input If no argument value is
' passed to this function through this optional parameter, its value defaults to 255.
' param (optional)
' pHsvHMax is maximum value allowed for the hue component of the resulting HSV representation of the color.
' If no argument value is passed to this function through this optional parameter, its value defaults to
' 255.
' param (optional)
' pHsvSMax is maximum value allowed for the saturation component of the resulting HSV representation of
' the color. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' param (optional)
' pHsvVMax is maximum value allowed for the value component of the resulting HSV representation of
' the color. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' -----------------------------------------------------------------------------------------------------------
Public Function rgbToHsvHue _
( _
ByVal pRgb As Long, _
Optional ByVal pRgbRmax As Long = 255&, _
Optional ByVal pRgbGmax As Long = 255&, _
Optional ByVal pRgbBmax As Long = 255&, _
Optional ByVal pHsvHmax As Long = 255&, _
Optional ByVal pHsvSmax As Long = 255&, _
Optional ByVal pHsvVmax As Long = 255& _
) _
As Long
Dim hue As Long
Dim sat As Long
Dim vlu As Long
Dim jnk As Long
jnk = rgbToHsv(pRgb, hue, sat, vlu, pRgbRmax, pRgbGmax, pRgbBmax, pHsvHmax, pHsvSmax, pHsvVmax)
rgbToHsvHue = hue
End Function
Public Function rgbToHsvSaturation _
( _
ByVal pRgb As Long, _
Optional ByVal pRgbRmax As Long = 255&, _
Optional ByVal pRgbGmax As Long = 255&, _
Optional ByVal pRgbBmax As Long = 255&, _
Optional ByVal pHsvHmax As Long = 255&, _
Optional ByVal pHsvSmax As Long = 255&, _
Optional ByVal pHsvVmax As Long = 255& _
) _
As Long
Dim hue As Long
Dim sat As Long
Dim vlu As Long
Dim jnk As Long
jnk = rgbToHsv(pRgb, hue, sat, vlu, pRgbRmax, pRgbGmax, pRgbBmax, pHsvHmax, pHsvSmax, pHsvVmax)
rgbToHsvSaturation = sat
End Function
Public Function rgbToHsvValue _
( _
ByVal pRgb As Long, _
Optional ByVal pRgbRmax As Long = 255&, _
Optional ByVal pRgbGmax As Long = 255&, _
Optional ByVal pRgbBmax As Long = 255&, _
Optional ByVal pHsvHmax As Long = 255&, _
Optional ByVal pHsvSmax As Long = 255&, _
Optional ByVal pHsvVmax As Long = 255& _
) _
As Long
Dim hue As Long
Dim sat As Long
Dim vlu As Long
Dim jnk As Long
jnk = rgbToHsv(pRgb, hue, sat, vlu, pRgbRmax, pRgbGmax, pRgbBmax, pHsvHmax, pHsvSmax, pHsvVmax)
rgbToHsvValue = vlu
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function converts an HSL color to an RGB color.
'
' return
' this function returns a Long whole number representing an RGB color value. See the built in VBA
' function RGB() for an explanation of this representation.
'
' param
' pH is the HSL hue value (H) and it's value is in the range [0..255]
' param
' pS is the HSL saturation value (S) and it's value is in the range [0..255]
' param
' pL is the HSL luminosity value (L) and it's value is in the range [0..255]
' param (optional)
' pHslHMax is maximum value allowed for the hue component of the input HSL representation of the color.
' If no argument value is passed to this function through this optional parameter, its value defaults to
' 255.
' param (optional)
' pHslSMax is maximum value allowed for the saturation component of the input HSL representation of
' the color. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' param (optional)
' pHslLMax is maximum value allowed for the luminosity component of the input HSL representation of
' the color. If no argument value is passed to this function through this optional parameter, its value
' defaults to 255.
' -----------------------------------------------------------------------------------------------------------
Public Function hslToRgb _
( _
ByVal pH As Double, _
ByVal pS As Double, _
ByVal pL As Double, _
Optional ByVal pHslHmax As Double = 255#, _
Optional ByVal pHslSmax As Double = 255#, _
Optional ByVal pHslLmax As Double = 255# _
) _
As Long
Dim rgbVec As ColorVector
Dim hslVec As ColorVector
hslVec = newColorVector(pH, pS, pL, pHslHmax, pHslSmax, pHslLmax)
rgbVec = RGBvecFromHSLvec(hslVec, 255#, 255#, 255#)
hslToRgb = toRgb(normalRoundLng(rgbVec.x), normalRoundLng(rgbVec.y), normalRoundLng(rgbVec.z), 255&, 255&, 255&)
End Function
' =====================================================================================================================
' <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[ Color Utilities ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
' =====================================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function returns the red, green, or blue color component value from a whole number representing a
' native VBA rgb color value. See the built in VBA functionRGB() for an explanation of this representation.
'
' return
' The R, G, or B color component (0 - 255) as a Long
'
' param
' pRgb is the Long in VBA's native rgb format from which one color component (R, G, or B) will be
' extracted.
' param
' pComponent is the component number as a Long that represents the component color to return (1=red,
' 2=green, 3=blue).
' -----------------------------------------------------------------------------------------------------------
Public Function rgbComponent(ByVal pRgb As Long, ByVal pComponent As Long) As Long
Dim shifts As Long
Dim result As Long
shifts = forceIntoRange(pComponent, 1&, 4&)
shifts = (shifts - 1&)
result = (pRgb And cSixHexDigitsMask)
result = shiftBytesRight(result, shifts)
result = result And cFirstByteMask
rgbComponent = result
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function packs three color component values into a single Long. If the three components Y, Y, and Z
' represent the Red, Green, Blue components of an RGB value, then this function is effectively a cover
' function for the VBA RGB() function. This allows the RGB value to be retrieved from a worksheet function.
'
' return
' an Long value representing a color value from a set of x, y and z color components
'
' param
' pX is the x component value of the resulting value
' param
' pY is the y component value of the resulting value
' param
' pZ is the z component value of the resulting value
' param (optional)
' pXMax is maximum value allowed for the pX component. As an example value: it would be 255 for the rgb
' red component or the hsl hue component used by Windows. If no argument value is passed to this procedure
' through this optional parameter, its value defaults to 255.
' param (optional)
' pYMax is maximum value allowed for the pY component. As an example value: it would be 255 for the rgb
' green component or the hsl saturation component used by Windows. If no argument value is passed to this
' procedure through this optional parameter, its value defaults to 255.
' param (optional)
' pZMax is maximum value allowed for the pZ component. As an example value: it would be 255 for the rgb
' blue component or the hsl luminosity component used by Windows. If no argument value is passed to this
' procedure through this optional parameter, its value defaults to 255.
' -----------------------------------------------------------------------------------------------------------
Public Function toRgb _
( _
ByVal pX As Long, _
ByVal pY As Long, _
ByVal pZ As Long, _
Optional ByVal pXMax As Long = 255&, _
Optional ByVal pYMax As Long = 255&, _
Optional ByVal pZMax As Long = 255& _
) _
As Long
'
' ==============================================================================================
' convert x, Y, and Z to the range [0..255] so they fit in a byte
' ----------------------------------------------------------------------------------------------
If (pXMax <> 255&) Then pX = normalRoundLng(equivalentNumerator(CDbl(pX), CDbl(pXMax), 255#))
If (pYMax <> 255&) Then pY = normalRoundLng(equivalentNumerator(CDbl(pY), CDbl(pYMax), 255#))
If (pZMax <> 255&) Then pZ = normalRoundLng(equivalentNumerator(CDbl(pZ), CDbl(pZMax), 255#))
'
' ==============================================================================================
' do these separately so that they don't get skipped because of being in an if statement
' ----------------------------------------------------------------------------------------------
pX = pX Mod 256&
pY = pY Mod 256&
pZ = pZ Mod 256&
'
' ==============================================================================================
' load them each into one byte of a Long and return the resulting Long
' ----------------------------------------------------------------------------------------------
toRgb = rgb(pX, pY, pZ)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This utility function is used to convert a long back and forth between rgb and html format
'
' return
' an Long value representing a value that's been transformed from rgb to html or visa versa.
'
' param
' pValue is the Long to change either from rgb to html or theother way around.
' -----------------------------------------------------------------------------------------------------------
Public Function swapFirstAndThirdByte(ByVal pValue As Long) As Long
Dim byte1 As Long
Dim byte2 As Long
Dim byte3 As Long
byte1 = rgbComponent(pValue, 1&)
byte2 = rgbComponent(pValue, 2&)
byte3 = rgbComponent(pValue, 3&)
swapFirstAndThirdByte = toRgb(byte3, byte2, byte1, 255&, 255&, 255&)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function adjusts an RGB color by the specified HSL deltas
'
' return
' this function returns a Long whole number representing an RGB color value. See the built in VBA
' function RGB() for an explanation of this representation.
'
' param
' pRgb is a Long whole number representing an RGB color value. See the built in VBA function RGB() for
' an explanation of this representation.
' param
' pDeltaH is the specified delta to the HSL hue value (H)
' param
' pDeltaS is the specified delta to the HSL saturation value (S)
' param
' pDeltaL is the specified delta to the HSL luminosity value (L)
' -----------------------------------------------------------------------------------------------------------
Public Function transformedRgbToHslToRgb(ByVal pRgb As Long, ByVal pDeltaH As Long, ByVal pDeltaS As Long, ByVal pDeltaL As Long) As Long
Dim tH As Long
Dim tS As Long
Dim tL As Long
Dim tRgb As Long
tRgb = rgbToHsl(pRgb, tH, tS, tL)
tH = (tH + pDeltaH) Mod 256&
tS = (tS + pDeltaS) Mod 256&
tL = (tL + pDeltaL) Mod 256&
transformedRgbToHslToRgb = hslToRgb(CDbl(tH), CDbl(tS), CDbl(tL))
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function returns the RGB value from the fill value of the specified
' cell.
'
' return
' The Long whole number representing an RGB color value.
'
' param
' pCell is the worksheet cell for which the color component is returned.
' -----------------------------------------------------------------------------------------------------------
Public Function cellRgbValue(ByRef pCell As Range) As Long
cellRgbValue = pCell.Interior.Color
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function returns the red, green, or blue color component value from the fill value of the specified
' cell.
'
' return
' The intensity of the color component (0 - 255) as an integer or -1 indicating that an argument was
' invalid.
'
' param
' pCell is the worksheet cell for which the color component is returned.
' param
' pComponent is the component number as integer that represents the component color to return (1=red,
' 2=green, 3=blue).
' -----------------------------------------------------------------------------------------------------------
Public Function cellRgbComponent(ByRef pCell As Range, ByVal pComponent As Long) As Long
cellRgbComponent = rgbComponent(pCell.Interior.Color, pComponent)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function returns the percieved brightness of an RGB color. I found it along with the following
' narative at:
' http://www.nbdtech.com/blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx
'
' I needed a way to test if a background color is light or dark in order to choose an appropriate text color
' (black on light colors and white on dark colors), you can find yourself in the same problem if you try to
' convert an image to grayscale.
'
' I found many approaches that didn�t work well, I�ll describe them and the problems I discovered below �
' but first � the successful solution.
'
' I finally found a solution that actually works on this web page (http://alienryderflex.com/hsp.html) the
' formula is:
'
' brightness = sqrt( .241 R2 + .691 G2 + .068 B2 )
'
' Or, in C# using the WPFs Color structure System.Windows.Media.Color (the same exact code should also work
' with the System.Drawing.Color structure used in WinForms and WebForms):
'
' private static int Brightness(Color c)
' {
' return (int)Math.Sqrt
' (
' c.R * c.R * .241 +
' c.G * c.G * .691 +
' c.B * c.B * .068
' );
' }
'
' This subroutine will return a number in the rage of 0 (black) to 255 (White) and to set the foreground
' color based on the Brightness method:
'
' Color textColor = Brightness(backgroundColor) < 130 ? Colors.White : Colors.Black;
'
' I selected cutoff value of 130 by trial and error and it reflects my taste, every value in the rage
' 128-145 will give acceptable results.
'
' Here is a table of all the named colors in .net 3.0, each with its name in readable text on it based on
' the code above, the number in parenthesis is the brightness � click on the image to view it in full size
' (in a new browser window).
'
'
' Usually, when talking about color theory the range 0-1 is used for each component � so (0,0,0) is black,
' (1,1,1) is white and (0.5,0.5,0.5) is 50% gray, I�m not using this range, I�m using the 0-255 range used
' in most programming environments.
'
' Why Not HSL or HSV?
'
' You may think that the luminance (or luminosity) component of the HSL color system or the value
' component of HSV will solve this problem, I did, but I was wrong.
'
' The L component of the HSL and the V component of HSV describe the brightness of a color relative to a
' base color, if this base color is blue you will get a darker color than if this base color is yellow, HSL
' and HSV are very useful if you need to create a lighter or darker version of a color but aren�t very
' useful if you want to know how bright a color is.
'
' The Na�ve RGB Algorithm
'
' If RGB 0,0,0 is black and RGB 255,255,255 is white then R+B+G should give us a good approximation of
' the color brightness, shouldn�t it?
'
' The problem is that some colors are brighter than others, red is brighter then blue and green is
' brighter then red, maybe we just need to find the right coefficients for them?
'
' The W3C Algorithm
'
' The W3C working draft on accessibility has a formula for the perceived brightness of a color (based on
' the YIQ color system):
'
' ((Red value X 299) + (Green value X 587) + (Blue value X 114)) / 1000
'
' This formula and references to it dominate the search results, probably because the W3C has high search
' engine rank.
'
' This is better than using HSL, but it tends to give wrong results for many colors, especially shades of
' yellow.
'
' RGB Color Difference
'
' The W3C also has an algorithm to calculate the difference between colors:
'
' (maximum (Red value 1, Red value 2) - minimum (Red value 1, Red value 2)) + (maximum (Green value 1,
' Green value 2) - minimum (Green value 1, Green value 2)) + (maximum (Blue value 1, Blue value 2) -
' minimum (Blue value 1, Blue value 2))
'
' Or, in shorter form:
'
' dR + dG + dB
'
' Where dR, dG and dB are the difference in the Red, Green and Blue component.
'
' If you calculate difference from white and difference from black � and compare them (if difference from
' black>difference from white then the color is dark) you actually get better results than using the
' brightness formula, but then you get wrong results for light greens and dark blues (probably because
' this formula doesn�t take into account the brightness difference of the colors).
'
' 3D Distance in RGB Space
'
' You can think of the RGB color space as a cube where each of the 3 colors are axis, in one corner you
' have black (RGB 0,0,0) and in the opposite corner you have white RGB (255,255,255), so if a color is
' closer to black it should be darker.
'
' The formula for 3D distance is:
'
' Sqrt(dx2+dy2+dz2)
'
' Where dx, dy and dz are the difference on the x, y and z axis.
'
' This algorithm also gives mixed results because it doesn�t take into account the fact that some colors
' look brighter than others - and that�s gets us back to �
'
' Weighted Distance in 3D RGB Space (or the HSP algorithm)
'
' If you scroll up to the beginning of this post and look at the brightness formula there you will see
' it�s just like the 3D distance formula except it gives different weight to each axis.
'
' So now we finished our tour to color brightness land we have a good formula for calculating perceived
' brightness and (if my explanations where clear) we can actually understand why it works.
'
' return
' The percieved brightness (0 - 255) of an RGB color.
'
' param
' pRgb is the Long whole number representing an RGB color value.
' -----------------------------------------------------------------------------------------------------------
Public Function brightness(ByVal pRgb As Long) As Double
'
' ==============================================================================================
' Are we using the old or new algorithm?
' => old: http://www.nbdtech.com/blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx
' => new: http://colaargh.blogspot.co.uk/2016/02/readable-text-in-colour.html
' ----------------------------------------------------------------------------------------------
Const algo = "new"
'
' ==============================================================================================
' If it's the new algorithm...
' ----------------------------------------------------------------------------------------------
If (algo = "new") Then
Dim R As Double
Dim G As Double
Dim B As Double
Dim exp As Double
Dim expInv As Double
Dim coeffR As Double
Dim coeffG As Double
Dim coeffB As Double
Dim termR As Double
Dim termG As Double
Dim termB As Double
R = CDbl(rgbComponent(pRgb, 1&))
G = CDbl(rgbComponent(pRgb, 2&))
B = CDbl(rgbComponent(pRgb, 3&))
exp = 2.235
expInv = 1 / exp
coeffR = 0.22475
coeffG = 0.7154
coeffB = 0.05575
termR = coeffR * (R ^ exp)
termG = coeffG * (G ^ exp)
termB = coeffB * (B ^ exp)
brightness = (termR + termG + termB) ^ expInv
'
' ==============================================================================================
' Else it's the old algorithm...
' ----------------------------------------------------------------------------------------------
Else
'
' ==============================================================================================
' the original brightness factors for each RGB component (from the algorithm found on the web)
' ----------------------------------------------------------------------------------------------
Const briteFactorR = 0.241
Const briteFactorG = 0.691
Const briteFactorB = 0.068
'
' ==============================================================================================
' some relationships among the original factors because I'm going to change them and need to do
' some calculations
' ----------------------------------------------------------------------------------------------
Const RB = briteFactorR + briteFactorB
Const RdivRB = briteFactorR / RB
Const BdivRB = briteFactorB / RB
'
' ==============================================================================================
' change the brightness factor for the green component (which seems over valued on my screen)
' there doesnt seem to be a factor change I can make that works acroos the color
' luminescence range
' ----------------------------------------------------------------------------------------------
Const CG = briteFactorG
Const CHG_G = (briteFactorG - CG)
'
' ==============================================================================================
' now make a compensating change to the red and blue components' brightness factors
' ----------------------------------------------------------------------------------------------
Const CR = briteFactorR + (RdivRB * CHG_G)
Const CB = briteFactorB + (BdivRB * CHG_G)
'
' ==============================================================================================
' get the RGB components as Doubles (for precision calculations)
' ----------------------------------------------------------------------------------------------
Dim rComponent As Double
Dim gComponent As Double
Dim bComponent As Double
rComponent = CDbl(rgbComponent(pRgb, 1&))
gComponent = CDbl(rgbComponent(pRgb, 2&))
bComponent = CDbl(rgbComponent(pRgb, 3&))
'
' ==============================================================================================
' finally, compute the brightness with the modified factors. For reference, here's the
' original calculation:
' brightness = Sqr((rComponent * rComponent * 0.241) + (gComponent * gComponent * 0.691) +
' (bComponent * bComponent * 0.068))
' ----------------------------------------------------------------------------------------------
brightness = Sqr((rComponent * rComponent * CR) + (gComponent * gComponent * CG) + (bComponent * bComponent * CB))
End If
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function adjusts the brightness of one RGB value (pRgb2) to match the brightness of another RGB value
' (pRgb1)
'
' ** NOTICE ** This function does not work consistently across the color luminescence range so dont use it.
'
' return
' Long whole number representing an RGB color value that is an adjustment of pRgb2 to match the
' brightness of pRgb1
'
' param
' pRgb1 is the Long whole number representing the RGB color value whose brightness is to be matched.
' param
' pRgb2 is the Long whole number representing the RGB color value whose brightness is to be adjusted.
' -----------------------------------------------------------------------------------------------------------
Public Function matchBrightness(ByVal pRgb1 As Long, ByVal pRgb2 As Long) As Long
'
' ==============================================================================================
' if pRgb1 and pRgb2 are the same there is no adjustment to make
' ----------------------------------------------------------------------------------------------
If (pRgb1 = pRgb2) Then
matchBrightness = pRgb2
Exit Function
End If
'
' ==============================================================================================
' a place to store the HSL components as Longs
' ----------------------------------------------------------------------------------------------
Dim lH As Long
Dim lS As Long
Dim lL As Long
'
' ==============================================================================================
' a place to store the HSL components as Doubles (for precision calculations)
' ----------------------------------------------------------------------------------------------
Dim dH As Double
Dim dS As Double
Dim dL As Double
'
' ==============================================================================================
' a place to store the evolving value of the new RGB being computed from pRgb2
' ----------------------------------------------------------------------------------------------
Dim nRgb2 As Long
'
' ==============================================================================================
' a place to store the brightness of pRgb1 and nRgb2
' ----------------------------------------------------------------------------------------------
Dim b1 As Double
Dim b2 As Double
'
' ==============================================================================================
' other vars
' ----------------------------------------------------------------------------------------------
Dim hsl As Long
'
' ==============================================================================================
' calc the starting brightness and get the HSL components for the RGB we're gonna be adjusting
' - pRgb2
' ----------------------------------------------------------------------------------------------
b1 = brightness(pRgb1)
b2 = brightness(pRgb2)
hsl = rgbToHsl(pRgb2, lH, lS, lL)
dH = CDbl(lH)
dS = CDbl(lS)
dL = CDbl(lL)
'
' ==============================================================================================
' while the evolving new RGB is too dark compared to pRgb1, make it brighter by incrementing
' its luminosity
' ----------------------------------------------------------------------------------------------
While (b2 < b1) And (dL < 255#)
dL = dL + 1#
nRgb2 = hslToRgb(dH, dS, dL)
b2 = brightness(nRgb2)
Wend
'
' ==============================================================================================
' while the evolving new RGB is too bright compared to pRgb1, make it darker by decrementing
' its luminosity
' ----------------------------------------------------------------------------------------------
While (b2 > b1) And (dL > 0#)
dL = dL - 1#
nRgb2 = hslToRgb(dH, dS, dL)
b2 = brightness(nRgb2)
Wend
'
' ==============================================================================================
' return the fully evolved (brightness adjusted) version of pRgb2
' ----------------------------------------------------------------------------------------------
matchBrightness = nRgb2
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function returns the best font color (white or black) for a given fill area color as specified by a
' whole number representing an RGB color value. See the description of the brightness() function for an
' explanation of the "best font color"
'
' return
' Long whole number representing an RGB color value of black or white
'
' param
' pRgb is the Long whole number representing an RGB color value of the fill area.
' -----------------------------------------------------------------------------------------------------------
Public Function bestRgbFontBlackOrWhite(ByVal pRgb As Long) As Long
Dim luminosity As Long
luminosity = hslLuminosity(pRgb)
If Abs(luminosity - 120) < 75& Then
If brightness(pRgb) >= 130# Then
bestRgbFontBlackOrWhite = vbBlack
Else
bestRgbFontBlackOrWhite = vbWhite
End If
ElseIf luminosity > 120& Then
bestRgbFontBlackOrWhite = vbBlack
Else
bestRgbFontBlackOrWhite = vbWhite
End If
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function returns the best font color (white or black) for a given fill area color as specified by a
' whole number representing an RGB color value. See the description of the brightness() function for an
' explanation of the "best font color"
'
' return
' Long whole number representing an RGB color value
'
' param
' pH is the HSL hue value (H) and it's value is in the range [0..255]
' param
' pS is the HSL saturation value (S) and it's value is in the range [0..255]
' param
' pL is the HSL luminosity value (L) and it's value is in the range [0..255]
' param (optional)
' pHueMax is maximum value allowed for the hue component of the HSL representation of the color. Another
' way of viewing it is that it is the number of segments or chunks or discrete values that the continuous
' hue space is broken down into. It is usually 255, which is a value in the range (0..255) and can be
' stored in a single byte, but it doesn't have to be. It can be any value >= 0. This parameter is used to
' characterize the HSL components that are passed into this function. If no argument value is passed to
' this function through this optional parameter, its value defaults to 255.
' param (optional)
' pSaturationMax is maximum value allowed for the saturation component of the HSL representation of the
' color. Another way of viewing it is that it is the number of segments or chunks or discrete values that
' the continuous saturation space is broken down into. It is usually 255, which is a value in the range
' (0..255) and can be stored in a single byte, but it doesn't have to be. It can be any value >= 0. This
' parameter is used to characterize the HSL components that are passed into this function. If no argument
' value is passed to this function through this optional parameter, its value defaults to 255.
' param (optional)
' pLuminosityMax is maximum value allowed for the luminosity component of the HSL representation of the
' color. Another way of viewing it is that it is the number of segments or chunks or discrete values that
' the continuous luminosity space is broken down into. It is usually 255, which is a value in the range
' (0..255) and can be stored in a single byte, but it doesn't have to be. It can be any value >= 0. This
' parameter is used to characterize the HSL components that are passed into this function. If no argument
' value is passed to this function through this optional parameter, its value defaults to 255.
' -----------------------------------------------------------------------------------------------------------
Public Function bestRgbFontColor _
( _
ByVal pH As Double, _
ByVal pS As Double, _
ByVal pL As Double, _
Optional ByVal pHueMax As Double = 255#, _
Optional ByVal pSaturationMax As Double = 255#, _
Optional ByVal pLuminosityMax As Double = 255# _
) _
As Long
'
' ==============================================================================================
' offset from either white or black
' ----------------------------------------------------------------------------------------------
Const LITE_LUM = 255# - 24#
Const DARK_LUM = 0# + 48#
'
' ==============================================================================================
' variables used
' ----------------------------------------------------------------------------------------------
Dim hslVector As ColorVector
Dim hslH As Double
Dim hslS As Double
Dim hslL As Double
'
' ==============================================================================================
' we want to work with HSL components that are scaled to 255.
' ----------------------------------------------------------------------------------------------
hslVector = newColorVector(pH, pS, pL, pHueMax, pSaturationMax, pLuminosityMax)
hslVector = rescaledColorVector(hslVector, 255#, 255#, 255#)
With hslVector
hslH = .x
hslS = .y
hslL = .z
End With
'
' ==============================================================================================
' variables used
' ----------------------------------------------------------------------------------------------
Dim rgbVal As Long
Dim fontHue As Double
Dim fontSat As Double
Dim fontLum As Double
'
' ==============================================================================================
' fontHue and fontSat will be the hue on the other side of the color wheel from pH and pS
' respectively
' ----------------------------------------------------------------------------------------------
fontHue = fmod((hslH + 128#), 256#)
fontSat = fmod((hslS + 128#), 256#)
If (hslL < 16#) Then
fontLum = 255#
ElseIf (hslL > 254#) Then
fontLum = 0#
Else
'
' ==============================================================================================
' convert the original HSL values to Long whole number representing an RGB color
' ----------------------------------------------------------------------------------------------
rgbVal = hslToRgb(hslH, hslS, hslL)
'
' ==============================================================================================
' adjust the luminosity of the font to contrast with the luminosity of the original HSL values
' ----------------------------------------------------------------------------------------------
If Abs(hslL - 120#) < 75# Then
'
' ==============================================================================================
' dark font
' ----------------------------------------------------------------------------------------------
If brightness(rgbVal) >= 130# Then
fontLum = hslL * (70# / 255#) 'DARK_LUM
'
' ==============================================================================================
' light font
' ----------------------------------------------------------------------------------------------
Else
fontLum = 255# - (hslL * (70# / 255#)) 'LITE_LUM
End If
'
' ==============================================================================================
' dark font
' ----------------------------------------------------------------------------------------------
ElseIf hslL > 120# Then
fontLum = hslL * (70# / 255#) 'DARK_LUM
'
' ==============================================================================================
' light font
' ----------------------------------------------------------------------------------------------
Else
fontLum = 255# - (hslL * (70# / 255#)) 'LITE_LUM
End If
End If
'
' ==============================================================================================
' return the font color as an rgb value
' ----------------------------------------------------------------------------------------------
hslVector = newColorVector(fontHue, fontSat, fontLum, 255#, 255#, 255#)
With hslVector
hslH = .x
hslS = .y
hslL = .z
End With
bestRgbFontColor = hslToRgb(hslH, hslS, hslL, 255#, 255#, 255#)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function returns the HSL L value (Luminosity) for a Long whole number representing an RGB color
' value.
'
' The HSL L value is defined as (MAX + Min) / 2 where MAX is the greatest of r, g, and b, and Min is
' the least.
'
' return
' The HSL luminosity component (0 - 255) for a Long whole number representing an RGB color value.
'
' param
' pRgb is the Long whole number representing an RGB color value.
' -----------------------------------------------------------------------------------------------------------
Public Function hslLuminosity(ByVal pRgb As Long) As Long
Dim rgbMax As Long
Dim rgbMin As Long
Dim rComponent As Long
Dim gComponent As Long
Dim bComponent As Long
rComponent = rgbComponent(pRgb, 1)
gComponent = rgbComponent(pRgb, 2)
bComponent = rgbComponent(pRgb, 3)
rgbMax = max(rComponent, gComponent, bComponent)
rgbMin = min(rComponent, gComponent, bComponent)
hslLuminosity = (rgbMax + rgbMin) / 2&
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This subroutine, given a saturation and luminosity, computes a contrasting saturation and luminosity
'
' param
' pSin is the given saturation
' param
' pLin is the given luminosity
' param (output)
' pSout is where the contrasting saturation will be stored when this function returns
' param (output)
' pLout is where the contrasting luminosity will be stored when this function returns
' -----------------------------------------------------------------------------------------------------------
Public Sub contrastingSL(ByVal pSin As Double, ByVal pLin As Double, ByRef pSout As Double, ByRef pLout As Double)
pSout = fmod(Abs(255# - (pSin * 6# / 7#)), 255#)
pLout = fmod(Abs(255# - (pLin * 6# / 7#)), 255#)
End Sub
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This subroutine returns a numerical value indicating the difference between two colors. The number is in
' the range 0 to 765 (= 3 * 255). If 2 colors have a colorDifference of >= 510 (= 2* 255), they are
' candidates for using together as forground/background colors in applications where the forground colored
' objects must be easily visible against the background color.
'
' return
' a number in the range 0 .. 765 where 0 means no difference and 765 mean maximum possible difference
'
' param
' pColor1 is an RGB color value to compare against pColor2
' param
' pColor2 is an RGB color value to compare against pColor1
' -----------------------------------------------------------------------------------------------------------
Public Function colorDifference(ByVal pColor1 As Long, ByVal pColor2 As Long) As Long
'
' ==============================================================================================
' variables used
' ----------------------------------------------------------------------------------------------
Dim c1Red As Long
Dim c1Grn As Long
Dim c1Blu As Long
Dim c2Red As Long
Dim c2Grn As Long
Dim c2Blu As Long
Dim minRed As Long
Dim minGrn As Long
Dim minBlu As Long
Dim maxRed As Long
Dim maxGrn As Long
Dim maxBlu As Long
'
' ==============================================================================================
' compute the difference
' ----------------------------------------------------------------------------------------------
c1Red = rgbComponent(pColor1, 1&)
c1Grn = rgbComponent(pColor1, 2&)
c1Blu = rgbComponent(pColor1, 3&)
c2Red = rgbComponent(pColor2, 1&)
c2Grn = rgbComponent(pColor2, 2&)
c2Blu = rgbComponent(pColor2, 3&)
minRed = min(c1Red, c2Red)
minGrn = min(c1Grn, c2Grn)
minBlu = min(c1Blu, c2Blu)
maxRed = max(c1Red, c2Red)
maxGrn = max(c1Grn, c2Grn)
maxBlu = max(c1Blu, c2Blu)
colorDifference = (maxRed - minRed) + (maxGrn - minGrn) + (maxBlu - minBlu)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This subroutine returns true if there is a strong color difference between two colors. Two colors are
' defined to have a strong color difference if their colorDifference score is >= 510
'
' return
' True is there is a strong color difference between the two colors, False otherwise.
'
' param
' pColor1 is an RGB color value to compare against pColor2
' param
' pColor2 is an RGB color value to compare against pColor1
' -----------------------------------------------------------------------------------------------------------
Public Function isStrongColorDifference(ByVal pColor1 As Long, ByVal pColor2 As Long) As Boolean
isStrongColorDifference = (colorDifference(pColor1, pColor2) >= 510&)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This subroutine returns a numerical value indicating the difference in brightness between two colors. The
' number is in the range 0 to 255. If 2 colors have a brightnessDifference of >= 127, they are candidates
' for using together as forground/background colors in applications where the forground colored objects must
' be easily visible against the background color.
'
' return
' a number in the range 0 .. 255 where 0 means no difference and 255 mean maximum possible difference
'
' param
' pColor1 is an RGB color value to compare against pColor2
' param
' pColor2 is an RGB color value to compare against pColor1
' -----------------------------------------------------------------------------------------------------------
Public Function brightnessDifference(ByVal pColor1 As Long, ByVal pColor2 As Long) As Long
Dim c1Brt As Double
Dim c2Brt As Double
c1Brt = brightness(pColor1)
c2Brt = brightness(pColor2)
brightnessDifference = normalRoundLng(Abs(c1Brt - c2Brt))
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This subroutine returns true if there is a strong color brightnessdifference between two colors. Two
' colors are defined to have a strong color brightness difference if their brightnessDifference score is >=
' 127
'
' return
' True is there is a strong color brightness difference between the two colors, False otherwise.
'
' param
' pColor1 is an RGB color value to compare against pColor2
' param
' pColor2 is an RGB color value to compare against pColor1
' -----------------------------------------------------------------------------------------------------------
Public Function isStrongBrightnessDifference(ByVal pColor1 As Long, ByVal pColor2 As Long) As Boolean
isStrongBrightnessDifference = (brightnessDifference(pColor1, pColor2) >= 127&)
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This utility function adds an number to a color component (RGB component, Hue, Sat, or Lum) and returns
' the result as a number between 0 and 255 inclusive.
'
' return
' a number between 0 and 255 inclusive
'
' param
' pComponent is a color component
' param
' pAddend is the number to add to the componebt
' -----------------------------------------------------------------------------------------------------------
Public Function colorAddDouble(ByVal pComponent As Double, ByVal pAddend As Double) As Double
colorAddDouble = fmod(Abs(pComponent + pAddend), 255#)
End Function
Public Function colorAddDoubleToLong(ByVal pComponent As Double, ByVal pAddend As Double) As Long
colorAddDoubleToLong = normalRoundLng(colorAddDouble(pComponent, pAddend))
End Function
Public Function colorAddLong(ByVal pComponent As Long, ByVal pAddend As Long) As Long
colorAddLong = colorAddDoubleToLong(CDbl(pComponent), CDbl(pAddend))
End Function
Public Function colorAddLongToDouble(ByVal pComponent As Long, ByVal pAddend As Long) As Double
colorAddLongToDouble = colorAddDouble(CDbl(pComponent), CDbl(pAddend))
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function increments an HSL or HSV hue value by multiple of a proportion of the color wheel.
'
' For example, if have a given hue - h in the range [0..255], and you wanted the value of the hue 1/16th of
' the way around the color wheel clockwise, you would call this function like this:
' hueOneSixteenthFurtherAround = proportionallyIncrementedHue(h, 255, 16, 1)
'
' If you wanted the value of the hue 9/16ths of the way around the color wheel clockwise, you would call this
' function like this:
' hueOneSixteenthFurtherAround = proportionallyIncrementedHue(h, 255, 16, 9)
'
' If your hue was measured in the range [0..359] and wanted the value of the hue 5/16ths of the way around
' the color wheel clockwise, you would call this function like this:
' hueOneSixteenthFurtherAround = proportionallyIncrementedHue(h, 359, 16, 5)
'
' return
' This subroutine returns a Long containing a HSL hue value in the range [0..pHueScale-1]
'
' param
' pHue is the starting hue from which a hue offset by (pMultiple * pProportion) of the color wheel in the
' clockwise direction is returned
' param
' pHueScale is the valid range of hue values plus 1. Another way to see it is that pHueScale is the number
' of hues the color wheel is segmented into, i.e. - how many slices of the color wheel pie there are.
' param
' pProportion is the proportion of the hue range that will be added to pHue to makes up 1 increment
' param
' pMultiple is the number of pProportions thast are added to pHue to get the hue value that this function
' returns.
' -----------------------------------------------------------------------------------------------------------
Public Function proportionallyIncrementedHue _
( _
ByVal pHue As Double, _
ByVal pHueScale As Double, _
ByVal pProportion As Double, _
ByVal pMultiple As Double _
) _
As Double
Dim lcm As Double
Dim inc As Double
Dim hue As Double
Dim hue2LcmFactor As Double
Dim lcm2HueFactor As Double
lcm = Application.lcm(pHueScale, pProportion)
hue2LcmFactor = lcm / pHueScale
lcm2HueFactor = pHueScale / lcm
hue = pHue * hue2LcmFactor
inc = pMultiple * (lcm / pProportion)
hue = hue + inc
hue = fmod(hue * lcm2HueFactor, pHueScale)
proportionallyIncrementedHue = hue
End Function
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This subroutine uses output parameters to return the three RGB components from an Rgb Long
'
' param
' pRgb is the Rgb Long value from which the separate R, G, and B components will be returned
' param (output)
' pRgbR is the red (R) component
' param (output)
' pRgbG is the green (G) component
' param (output)
' pRgbB is the blue (B) component
' -----------------------------------------------------------------------------------------------------------
Public Sub RGBfromRgb(ByVal pRgb As Long, pRgbR As Integer, pRgbG As Integer, pRgbB As Integer)
pRgbR = pRgb Mod 256
pRgb = pRgb \ 256
pRgbG = pRgb Mod 256
pRgb = pRgb \ 256
pRgbB = pRgb Mod 256
End Sub
' =====================================================================================================================
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[ Private Routines ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' =====================================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This subroutine validates a ColorVector and if it finds anything wrong it throws an exception to stop the
' application. It validates the ColorVector by:
' => checking that its color component values are within the range of [0..the value specified by their
' corresponding maximum]
' => checking that the color component maximums are all greater than or equal to 1
' => checking that the color component ratios are all in the range of [0..1]
' => checking that the color component ratios multipled by their corresponding maximum is equal to the
' corresponding color component value.
'
' param
' pColorVector is the ColorVector to validate
' param (optional)
' pProcedureName is the name of the procedure that called this validation subroutine. If no argument value
' is passed to this procedure through this optional parameter, its value defaults to the name of this
' procedure.
' param (optional)
' pModuleName is the name of the module containing the procedure that called this validation subroutine If
' no argument value is passed to this procedure through this optional parameter, its value defaults to
' the name of the module containing this procedure.
' -----------------------------------------------------------------------------------------------------------
Private Sub validateColorVector _
( _
ByRef pColorVector As ColorVector, _
Optional ByVal pProcedureName As String = "validateColorVector", _
Optional ByVal pModuleName As String = "M033_Color" _
)
With pColorVector
If (Not isInRange(.x, 0#, .xMax)) Then Call raiseException _
( _
"The ColorVector.x value of: " & .x & " is not within the valid range for .x values, which is [0.." & .xMax & "]", _
pProcedureName, _
pModuleName _
)
If (Not isInRange(.y, 0#, .yMax)) Then Call raiseException _
( _
"The ColorVector.y value of: " & .y & " is not within the valid range for .y values, which is [0.." & .yMax & "]", _
pProcedureName, _
pModuleName _
)
If (Not isInRange(.z, 0#, .zMax)) Then Call raiseException _
( _
"The ColorVector.z value of: " & .z & " is not within the valid range for .z values, which is [0.." & .zMax & "]", _
pProcedureName, _
pModuleName _
)
If (.xMax < 1#) Then Call raiseException _
( _
"The ColorVector.xMax value of: " & .xMax & " is not within the valid range for .xMax values, which is [>=1]", _
pProcedureName, _
pModuleName _
)
If (.yMax < 1#) Then Call raiseException _
( _
"The ColorVector.yMax value of: " & .yMax & " is not within the valid range for .yMax values, which is [>=1]", _
pProcedureName, _
pModuleName _
)
If (.zMax < 1#) Then Call raiseException _
( _
"The ColorVector.zMax value of: " & .zMax & " is not within the valid range for .zMax values, which is [>=1]", _
pProcedureName, _
pModuleName _
)
If (Not isInRange(.xRatio, 0#, 1#)) Then Call raiseException _
( _
"The ColorVector.xRatio value of: " & .xRatio & " is not within the valid range for .xRatio values, which is [0..1]", _
pProcedureName, _
pModuleName _
)
If (Not isInRange(.yRatio, 0#, 1#)) Then Call raiseException _
( _
"The ColorVector.yRatio value of: " & .yRatio & " is not within the valid range for .yRatio values, which is [0..1]", _
pProcedureName, _
pModuleName _
)
If (Not isInRange(.zRatio, 0#, 1#)) Then Call raiseException _
( _
"The ColorVector.zRatio value of: " & .zRatio & " is not within the valid range for .zRatio values, which is [0..1]", _
pProcedureName, _
pModuleName _
)
If (Not doublesAreEqual((.xRatio * .xMax), .x)) Then Call raiseException _
( _
"The ColorVector.x, .xMax, and .xRatio values [" & .x & ", " & .xMax & ", " & .xRatio & _
"] are inconsistent because the value of (.xRatio X .xMax) is " & (.xRatio * .xMax) & _
" and does not equal the value of .x, which is " & .x, _
pProcedureName, _
pModuleName _
)
If (Not doublesAreEqual((.yRatio * .yMax), .y)) Then Call raiseException _
( _
"The ColorVector.y, .yMax, and .yRatio values [" & .y & ", " & .yMax & ", " & .yRatio & _
"] are inconsistent because the value of (.yRatio X .yMax) is " & (.yRatio * .yMax) & _
" and does not equal the value of .y, which is " & .y, _
pProcedureName, _
pModuleName _
)
If (Not doublesAreEqual((.zRatio * .zMax), .z)) Then Call raiseException _
( _
"The ColorVector.z, .zMax, and .zRatio values [" & .z & ", " & .zMax & ", " & .zRatio & _
"] are inconsistent because the value of (.zRatio X .zMax) is " & (.zRatio * .zMax) & _
" and does not equal the value of .z, which is " & .z, _
pProcedureName, _
pModuleName _
)
End With
End Sub
' ===========================================================================================================
' ===========================================================================================================
' ===========================================================================================================
' This function is factored from the RGBvecFromHSLvec function above.
'
' Note: I found this algorithm on the web and can no longer identify the source. If you know the original
' source of this algorithm please reference the site so that I can give the author due credit.
' -----------------------------------------------------------------------------------------------------------
Private Function hueToRGB(ByVal p As Double, ByVal q As Double, ByVal t As Double) As Double
If (t < 0#) Then t = t + 1#
If (t > 1#) Then t = t - 1#
If (t < (1# / 6#)) Then
hueToRGB = p + ((q - p) * 6# * t)
Exit Function
End If
If (t < (1# / 2#)) Then
hueToRGB = q
Exit Function
End If
If (t < (2# / 3#)) Then
hueToRGB = p + (q - p) * ((2# / 3#) - t) * 6#
Exit Function
End If
hueToRGB = p
End Function