office
PowerShell

Officeの色をRGBに分解する PowerShell編

COMのAPI経由でMS Office関連の操作を行う場合、色の設定に注意する必要があります。

Officeの場合、色は32bit整数で表現されるのですが、中の赤と青を示すビットの順番が、一般的なものと逆になっています。

Officeの色の16進数表記
__BBGGRR
一般的な色の16進数表記
__RRGGBB

この記事では、Officeの色をRGBに分解してSystem.Drawing.Color等に変換してみます。

確認

まず、本当に中のビットの順番が異なるのか確認してみます。

今回はOfficeから色を取得する代わりに、VBAのRGB関数互換のVBのRGB関数で色の整数を作成し、[Drawing.Color]::FromArgbに渡してみます。

Add-Type -AssemblyName Microsoft.VisualBasic, System.Drawing

# Officeで使われている色
[int]$offceColor = [Microsoft.VisualBasic.Information]::RGB(240, 160, 80)

# intをそのまま受け取るオーバーロードはあるが……
# static System.Drawing.Color FromArgb(int argb)
[Drawing.Color]::FromArgb( $offceColor )
<#
R             : 80  # RとBが逆
G             : 160
B             : 240 # RとBが逆
A             : 0
IsKnownColor  : False
IsEmpty       : False
IsNamedColor  : False
IsSystemColor : False
Name          : 50a0f0
#>

結果からもわかるように、そのままだと赤と青が逆になってしまいます。

分解して.NETの色に変換する

本題のRGBに分解→変換をしてみます。

intをbyte単位に分解したい場合、地道に数値演算する手もありますが、System,BitConverterのGetBytesメソッドを使用すると簡単にbyte配列に変換できます。

PowerShellの記法も利用すると以下のように記述できます。

Add-Type -AssemblyName Microsoft.VisualBasic, System.Drawing, PresentationCore

# Officeで使われている色
[int]$offceColor = [Microsoft.VisualBasic.Information]::RGB(240, 160, 80)

# byte配列に変換[R,G,B,A] => 0,1,2番目を変数に代入(3番目以降は破棄)
[byte]$drwR, [byte]$drwG, [byte]$drwB, $null = [BitConverter]::GetBytes($offceColor)

# static System.Drawing.Color FromArgb(int red, int green, int blue)
[Drawing.Color]::FromArgb($drwR, $drwG, $drwB)
<#
R             : 240
G             : 160
B             : 80
A             : 255
IsKnownColor  : False
IsEmpty       : False
IsNamedColor  : False
IsSystemColor : False
Name          : fff0a050
#>


# static System.Windows.Media.Color FromRgb(byte r, byte g, byte b)
[Windows.Media.Color]::FromRgb($drwR, $drwG, $drwB)
<#
ColorContext : 
A            : 255
R            : 240
G            : 160
B            : 80
ScA          : 1
ScR          : 0.8713671
ScG          : 0.3515326
ScB          : 0.08021983
#>