0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Excel 今日のトリビア ExcelのHSLは白の色相を170と表示するバグがある。そのほかWithRGB HSL変換

Posted at

前回

Excel 今日のトリビア HSLも実は選べるがExcel色ダイアログボックスのHEXはインチキ
に続きこのHSLについて

白のRGBとHSL

白(&HFFFFFF)はRGB(255,255,255)
これを手動でHSL変換する
まずHUEは最大、最小がないので
Hue=0となる(はずである)
次にSaturationは
(nMax - nMin) / (nMax + nMin)
この式からSaturation=0となる
さらにLightness

255
でOK。3つが同じなら2つたして2つで割るからこうなる。

すると
HLS(0,0,255)
が答えである。

Excelが表示する白のHSLの値

それではExcelを見てみよう
image.png

ここでHSLに変換する
image.png
170,0,255...
ちなみに170の値を変化させても色は変わらない。
なぜならHSLの角度は無彩色には無関係だから。
純粋に彩度だけで決まる。

もとからExcelのHSLはおかしい

次に、ExcelのHSLは非常におかしい

Hue(色相)

彩度は角度で0~360(マイナスの時は360を足す)
これを無理やり0~255で表現している。
おそらくこの360を255に変換するときにバグがあるのだろう。

Saturation(彩度) Lightness(輝度)

こちらは0~100だが、Excelはこれを0~255にする。

この結果、色相は360を255であらわすため不正確で、残りの2つは大体再現できるということになる。
というかHSLの場合この色相環が重要なのが…

Excel用のVBA RGB、HSL変換関数

これはまず色番号(10進)をRGBに分解し、そのうえでHSLにするというもの
http://yamatyuu.net/other/color/hsl/index.html
を参考にしているが、無彩色の場合をの例外を加えている。

Public Type rgbnum
Red As Long
Gre As Long
BLu As Long
End Type
Public Type HSLNum
Hue As Double
Saturation As Double
Lightness As Double
End Type

Function ColorToRGB(num As Long) As rgbnum
'色番号をRGBに変換する
'https://excel.syogyoumujou.com/memorandum/rgb.html
With ColorToRGB
.Red = num Mod 256
.Gre = Int(num / 256) Mod 256
.BLu = Int(num / 256 / 256)
End With
End Function
Function RGBtoHSL2(num As Long) As HSLNum
Dim nMax As Long, nMin As Long, Ldash As Long, Sdash As Long
Dim ar As rgbnum
With ColorToRGB(num)
ar.Red = .Red
ar.Gre = .Gre
ar.BLu = .BLu
End With
If ar.Red = ar.Gre And ar.BLu = ar.Gre Then
RGBtoHSL2.Hue = 0
Else
nMax = WorksheetFunction.Max(ar.Red, ar.Gre, ar.BLu)
nMin = WorksheetFunction.Min(ar.Red, ar.Gre, ar.BLu)
Select Case nMax
Case Is = ar.Red
RGBtoHSL2.Hue = IIf(60 * (ar.Gre - ar.BLu) / (nMax - nMin) >= 0, 60 * (ar.Gre - ar.BLu) / (nMax - nMin), 60 * (ar.Gre - ar.BLu) / (nMax - nMin) + 360)
Case Is = ar.Gre
RGBtoHSL2.Hue = IIf((60 * (ar.BLu - ar.Red) / (nMax - nMin)) + 120 >= 0, (60 * (ar.BLu - ar.Red) / (nMax - nMin)) + 120, (60 * (ar.BLu - ar.Red) / (nMax - nMin)) + 120 + 360)
Case Is = ar.BLu
RGBtoHSL2.Hue = IIf((60 * (ar.Red - ar.Gre) / (nMax - nMin)) + 240 >= 0, (60 * (ar.Red - ar.Gre) / (nMax - nMin)) + 240, (60 * (ar.Red - ar.Gre) / (nMax - nMin)) + 240 + 360)
End Select
End If
If (nMax + nMin) / 2 < 127 Then
   If nMax = nMin Then
   RGBtoHSL2.Saturation = 0
   Else
   RGBtoHSL2.Saturation = (nMax - nMin) / (nMax + nMin)
   End If
Else
RGBtoHSL2.Saturation = Int((255 * ((nMax - nMin) / (510 - nMax - nMin))) + 0.5)
End If
If ar.Red = ar.Gre And ar.BLu = ar.Gre Then
RGBtoHSL2.Lightness = ar.Gre ' 無彩色の時例外処理
Else
RGBtoHSL2.Lightness = (nMax + nMin) / 2
End If
End Function

ついでにChatGPTがつくったやつ(もちろん修正)

r,g,bをDoubleにしていたが255までの整数値しか相手にしないので、Integerにしている。
他もおかしい

    ' RGB値を0-1の範囲に正規化
  rNorm = r / 255
  gNorm = g / 255
  bNorm = b / 255

この部分はr,g,bはDoubleと言いながら0~1の値に変換しており、最初からRGB的な値を前提としている。
本来ここで1を超えることはあり得ないはずである。

' RGBからHSLに変換する関数
Function RGBtoHSL(ByVal r As Integer, ByVal g As Integer, ByVal b As Integer) As Variant
    Dim maxRGB As Double
    Dim minRGB As Double
    Dim delta As Double
    Dim h As Double
    Dim s As Double
    Dim l As Double
    Dim rNorm As Double
    Dim gNorm As Double
    Dim bNorm As Double

    ' RGB値を0-1の範囲に正規化
    rNorm = r / 255
    gNorm = g / 255
    bNorm = b / 255

    ' 最大値と最小値を取得
    maxRGB = Excel.Application.WorksheetFunction.Max(rNorm, gNorm, bNorm)
    minRGB = Excel.Application.WorksheetFunction.Min(rNorm, gNorm, bNorm)

    ' 輝度の計算
    l = (maxRGB + minRGB) / 2

    If maxRGB = minRGB Then
        ' グレースケールの色の場合
        h = 0
        s = 0
    Else
        ' 差分の計算
        delta = maxRGB - minRGB

        ' 彩度の計算
        If l < 0.5 Then
            s = delta / (maxRGB + minRGB)
        Else
            s = delta / (2 - maxRGB - minRGB)
        End If

        ' 色相の計算
        Select Case maxRGB
            Case rNorm
                h = (gNorm - bNorm) / delta + (IIf(gNorm < bNorm, 6, 0))
            Case gNorm
                h = (bNorm - rNorm) / delta + 2
            Case bNorm
                h = (rNorm - gNorm) / delta + 4
        End Select

        h = h / 6
    End If

    ' HSL値を返す
    RGBtoHSL = Array(h * 360, s, l)
End Function

実際に使うコード

Excelのセルの色を横にRGB、16進数RGB、色番号、色番号Excel版、HSL(ChatGPT)、HSL(作成版)
で変換し出力する。

chatGPTは変換が必要

色相は角度で出力されるので255に変換
ほかも、ChatGPTの変換関数は0~1の値で出てくるためそれを255を乗じて変換している。
当方で作成したものはこの問題を解決している。

Intで切れるか?

いくつか試験して調整しているが、端数処理の関係で正しい値と1違う可能性がある
特に角度は誤差が大きい。端数が.5でも切り捨てたほうが表示される値と一致する。

Excel試験用コード

Sub test()
Dim hsl As Variant
Dim r As Integer
Dim g As Integer
Dim b As Integer

    
With ColorToRGB(ActiveCell.Interior.Color)
ActiveCell.Offset(, 1) = .Red
r = .Red: g = .Gre: b = .BLu
ActiveCell.Offset(, 2) = .Gre
ActiveCell.Offset(, 3) = .BLu
ActiveCell.Offset(, 4) = ActiveCell.Interior.Color
ActiveCell.Offset(, 5) = Hex(ActiveCell.Interior.Color)
With Excel.Application.WorksheetFunction
ActiveCell.Offset(, 6) = .Dec2Hex(ActiveCell.Offset(, 1), 2) & .Dec2Hex(ActiveCell.Offset(, 2), 2) & .Dec2Hex(ActiveCell.Offset(, 3), 2)
End With
End With
hsl = RGBtoHSL(r, g, b)
ActiveCell.Offset(, 7) = Int(hsl(0) / 360 * 255)
ActiveCell.Offset(, 8) = Int(hsl(1) * 255)
ActiveCell.Offset(, 9) = Int(hsl(2) * 255)
With RGBtoHSL2(ActiveCell.Interior.Color)
ActiveCell.Offset(, 10) = .Hue
ActiveCell.Offset(, 11) = .Saturation
ActiveCell.Offset(, 12) = .Lightness
End With
End Sub

タイトル回収

そうすると白は次のような並びになる
image.png
255 255 255 16777215 FFFFFF FFFFFF 0 0 255 0 0 0
つまり、HSLは0,0,255が正しい
にも拘わらず170となる。一体どういうことなのか?

170はExcelしか表示しない

この無意味な170は度数法で言うと240度である。ラジアンで言うと$2/3π$となる。
しかしHLSで白の色相は常に0であり、240度、$2/3π$、0.75とするサイトは一つもない
おそらく、何らかの形で0で処理が止まるため、それを回避したものと思われる。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?