Microsoft Small Basic

Program Listing: JKQ371
' HueAndTone v0.1 - (C) 2011 Nonki Takahashi
' shows hue and tone
'
' History
' 2011/04/07 Created (429 lines)
'
' Reference
' [1] James D. Foley, Andries Van Dam "Fundamentals of Interactive Computer Graphics" 1982
' [2] Japan Color Institute "Digital Color Manual" 2004
'
' Constant
VERSION = "v0.1"
UNDEFINED = "N/A"
CRLF = Text.GetCharacter(13) + Text.GetCharacter(10)
COLORPICK_X = 170
COLORPICK_Y = 82

' Main
GraphicsWindow.Show()
iX0 = 50
iY0 = 50
GraphicsWindow.Width = 256 * 2 + iX0 * 3 + COLORPICK_X
GraphicsWindow.Height = 256 + iY0 * 2 + COLORPICK_Y
GraphicsWindow.Title = "Hue and Tone " + VERSION
Console_Init()
ColorPick_Init()
' RGB Hue = 0 Lightness x Saturation
uFolder = "http://homepage2.nifty.com/nobukit/smallbasic.files/"
sURL = uFolder + "RGB_Hue0LS.png"
GraphicsWindow.DrawImage(sURL, iX0, iY0)
' Web safe color Hue = 0 Lightness x Saturation
sURL = uFolder + "WSC_Hue0LS.png"
GraphicsWindow.DrawImage(sURL, 256 + iX0 * 2, iY0)
Goto lSkip
rHue = 210
' RGB Lightness x Saturation
For iL = 255 To 0 Step -1
iY = iY0 + (255 - iL)
rLightness = iL / 255
For iS = 0 To 255
iX = iX0 + iS
rSaturation = iS / 255
Color_HSLtoRGB()
GraphicsWindow.SetPixel(iX, iY, sColor)
EndFor
EndFor
' Web safe color Lightness x Saturation
For iL = 255 To 0 Step -1
iY = iY0 + (255 - iL)
rLightness = iL / 255
For iS = 0 To 255
iX = 256 + iX0 * 2 + iS
rSaturation = iS / 255
Color_HSLtoRGB()
Color_ColorToSafe()
GraphicsWindow.SetPixel(iX, iY, sColor)
EndFor
EndFor
lSkip:
ColorPick_Show()
HueAndTone_Init()
bMouseMoved = "False"
While "True"
If bMouseMoved Then
Shapes.Move(oRect, iMX + 10, iMY + 10)
Shapes.Move(oText, iMX + 14, iMY + 14)
sColor = GraphicsWindow.GetPixel(iMX, iMY)
Color_RGBtoHSL()
Color_HSLtoRGB()
If rHue = UNDEFINED Then
iHue = rHue
Else
iHue = Math.Round(rHue * 256 / 360)
EndIf
sText = sColor + CRLF + "H=" + iHue + CRLF + "S=" + Math.Round(rSaturation * 255) + CRLF + "L=" + Math.Round(rLightness * 255)
HueAndTone_ColorToName()
sText = sText + CRLF + sName
Shapes.SetText(oText, sText)
bMouseMoved = "False"
Else
Program.Delay(200)
EndIf
EndWhile

' Color | Convert Color to RGB
' in: sColor - "#rrggbb"
' out: iR, iG, iB - [0, 255]
Sub Color_ColorToRGB
sR = Text.GetSubText(sColor, 2, 2)
sG = Text.GetSubText(sColor, 4, 2)
sB = Text.GetSubText(sColor, 6, 2)
sHex = sR
Math_Hex2Dec()
iR = iDec
sHex = sG
Math_Hex2Dec()
iG = iDec
sHex = sB
Math_Hex2Dec()
iB = iDec
EndSub

' Color | Convert HSL to RGB
' in: rHue - [0, 360) or UNDEFINED
' in: rLightness - [0, 1]
' in: rSaturation - [0, 1]
' out: sColor - "#rrggbb"
Sub Color_HSLtoRGB
If rLightness <= 0.5 Then
rN2 = rLightness * (1 + rSaturation)
Else
rN2 = rLightness + rSaturation - rLightness * rSaturation
EndIf
rN1 = 2 * rLightness - rN2
If rSaturation = 0 Then
iR = Math.Round(rLightness * 255)
iG = Math.Round(rLightness * 255)
iB = Math.Round(rLightness * 255)
Else
rH = rHue + 120
Color_Value()
iR = iValue
rH = rHue
Color_Value()
iG = iValue
rH = rHue - 120
Color_Value()
iB = iValue
EndIf
sColor = GraphicsWindow.GetColorFromRGB(iR, iG, iB)
EndSub

' Color | Function value
' in: rN1, rN2
' in: rH - [-120, 480)
' out: iValue - 0..255
Sub Color_Value
If rH >= 360 Then
rH = rH - 360
EndIF
If rH < 0 Then
rH = rH + 360
EndIF
If rH < 60 Then
rV = rN1 + (rN2 - rN1) * rH / 60
ElseIf rH < 180 Then
rV = rN2
ElseIf rH < 240 Then
rV = rN1 + (rN2 - rN1) * (240 - rH) / 60
Else
rV = rN1
EndIf
iValue = Math.Round(rV * 255)
EndSub

' Color | Convert RGB to HSL
' in: sColor - "#rrggbb"
' out: rHue - [0, 360) or UNDEFINED
' out: rLightness - (0, 1)
' out: rSaturation - (0, 1)
Sub Color_RGBtoHSL
Color_ColorToRGB()
' rR = iR / 255 ' occurs Math.Max() bug
rR = Math.Round(iR / 255 * 10000) / 10000
' rG = iG / 255 ' occurs Math.Max() bug
rG = Math.Round(iG / 255 * 10000) / 10000
' rB = iB / 255 ' occurs Math.Max() bug
rB = Math.Round(iB / 255 * 10000) / 10000
rMax = Math.Max(rR, rG)
rMax = Math.Max(rMax, rB)
rMin = Math.Min(rR, rG)
rMin = Math.Min(rMin, rB)
rLightness = (rMax + rMin) / 2
If rMax = rMin Then ' rR = rG = rB
rSaturation = 0
rHue = UNDEFINED
Else
If rLightness <= 0.5 Then
rSaturation = (rMax - rMin) / (rMax + rMin)
Else
rSaturation = (rMax - rMin) / (2 - rMax - rMin)
EndIf
rRC = (rMax - rR) / (rMax - rMin)
rGC = (rMax - rG) / (rMax - rMin)
rBC = (rMax - rB) / (rMax - rMin)
If rR = rMax Then ' between Yellow and Magenta
rHue = rBC - rGC
ElseIf rG = rMax Then ' between Cyan and Yellow
rHue = 2 + rRC - rBC
ElseIf rB = rMax Then ' between Magenta and Cyan
rHue = 4 + rGC - rRC
Else
TextWindow.WriteLine("Error:")
TextWindow.WriteLine("rMax=" + rMax)
TextWindow.WriteLine("rR=" + rR + ",sR=" + sR)
TextWindow.WriteLine("rG=" + rG + ",sG=" + sG)
TextWindow.WriteLine("rB=" + rB + ",sB=" + sB)
EndIf
rHue = rHue * 60
If rHue < 0 Then
rHue = rHue + 360
EndIf
EndIf
EndSub

' Color | Convert safe color to number
' in: sColor - "#rrggbb"
' out: iNum - web safe color number
Sub Color_SafeToNum
Color_ColorToRGB()
iNum = (iB / 51) * 36 + (iG / 51) * 6 + (iR / 51)
EndSub

' Color | Convert number to safe color
' in: iNum - web safe color number
' out: sColor - "#rrggbb"
Sub Color_NumToSafe
iR = Math.Remainder(iNum, 6) * 51
iG = Math.Remainder(Math.Floor(iNum / 6), 6) * 51
iB = Math.Floor(iNum / 36) * 51
sColor = GraphicsWindow.GetColorFromRGB(iR, iG, iB)
EndSub

' Color | Convert color to safe color
' in/out: sColor - "#rrggbb"
Sub Color_ColorToSafe
Color_ColorToRGB()
iR = Math.Floor(iR / (256 / 6)) * 51
iG = Math.Floor(iG / (256 / 6)) * 51
iB = Math.Floor(iB / (256 / 6)) * 51
sColor = GraphicsWindow.GetColorFromRGB(iR, iG, iB)
EndSub

' Color pick | Initialize
Sub ColorPick_Init
GraphicsWindow.PenColor = "Black"
GraphicsWindow.BrushColor = "White"
oRect = Shapes.AddRectangle(COLORPICK_X, COLORPICK_Y)
Shapes.HideShape(oRect)
GraphicsWindow.BrushColor = "Black"
oText = Shapes.AddText("")
Shapes.HideShape(oText)
EndSub

' Color pick | Show
Sub ColorPick_Show
iMX = GraphicsWindow.MouseX
iMY = GraphicsWindow.MouseY
Shapes.Move(oRect, iMX + 10, iMY + 10)
Shapes.Move(oText, iMX + 14, iMY + 14)
sRGB = GraphicsWindow.GetPixel(iMX, iMY)
Shapes.SetText(oText, sRGB)
Shapes.ShowShape(oRect)
Shapes.ShowShape(oText)
GraphicsWindow.MouseMove = ColorPick_OnMouseMove
EndSub

' Color pick | On mouse move
Sub ColorPick_OnMouseMove
iMX = GraphicsWindow.MouseX
iMY = GraphicsWindow.MouseY
bMouseMoved = "True"
EndSub

' Hue and tone | Initialization
Sub HueAndTone_Init
HueAndTone_sTone[1] = "ごくうすい" ' very pale
HueAndTone_iS[1] = 255
HueAndTone_iL[1] = 230
HueAndTone_sTone[2] = "うすい" ' pale
HueAndTone_iS[2] = 255
HueAndTone_iL[2] = 204
HueAndTone_sTone[3] = "明るい" ' light
HueAndTone_iS[3] = 255
HueAndTone_iL[3] = 178
HueAndTone_sTone[4] = "明るい" ' light
HueAndTone_iS[4] = 255
HueAndTone_iL[4] = 153
HueAndTone_sTone[5] = "あざやかな" ' light
HueAndTone_iS[5] = 255
HueAndTone_iL[5] = 128
HueAndTone_sTone[6] = "こい" ' deep
HueAndTone_iS[6] = 255
HueAndTone_iL[6] = 102
HueAndTone_sTone[7] = "暗い" ' deep
HueAndTone_iS[7] = 255
HueAndTone_iL[7] = 76
HueAndTone_sTone[8] = "暗い" ' deep
HueAndTone_iS[8] = 255
HueAndTone_iL[8] = 51
HueAndTone_sTone[9] = "ごく暗い" ' deep
HueAndTone_iS[9] = 255
HueAndTone_iL[9] = 26
HueAndTone_sTone[10] = "明るい灰みの" ' light grayish
HueAndTone_iS[10] = 85
HueAndTone_iL[10] = 178
HueAndTone_sTone[11] = "やわらかい" ' soft
HueAndTone_iS[11] = 128
HueAndTone_iL[11] = 153
HueAndTone_sTone[12] = "つよい" ' strong
HueAndTone_iS[12] = 153
HueAndTone_iL[12] = 128
HueAndTone_sTone[13] = "くすんだ" ' soft
HueAndTone_iS[13] = 128
HueAndTone_iL[13] = 102
HueAndTone_sTone[14] = "暗い灰みの" ' dark grayish
HueAndTone_iS[14] = 85
HueAndTone_iL[14] = 76
HueAndTone_sTone[15] = "灰みの" ' dark grayish
HueAndTone_iS[15] = 51
HueAndTone_iL[15] = 128
HueAndTone_sTone[16] = "白" ' white
HueAndTone_iS[16] = 0
HueAndTone_iL[16] = 255
HueAndTone_sTone[17] = "うすい灰色" ' pale gray
HueAndTone_iS[17] = 0
HueAndTone_iL[17] = 204
HueAndTone_sTone[18] = "明るい灰色" ' light gray
HueAndTone_iS[18] = 0
HueAndTone_iL[18] = 153
HueAndTone_sTone[19] = "灰色" ' medium gray
HueAndTone_iS[19] = 0
HueAndTone_iL[19] = 102
HueAndTone_sTone[20] = "暗い灰色" ' dark gray
HueAndTone_iS[20] = 0
HueAndTone_iL[20] = 51
HueAndTone_sTone[21] = "黒" ' black
HueAndTone_iS[21] = 0
HueAndTone_iL[21] = 0
HueAndTone_sHue[1] = "赤" ' red
HueAndTone_iHMax[1] = 9
HueAndTone_sHue[2] = "黄みの赤" ' yellowish red
HueAndTone_iHMax[2] = 14
HueAndTone_sHue[3] = "黄赤" ' yellow red (orange)
HueAndTone_iHMax[3] = 26
HueAndTone_sHue[4] = "赤みの黄" ' reddish yellow
HueAndTone_iHMax[4] = 32
HueAndTone_sHue[5] = "黄" ' yellow
HueAndTone_iHMax[5] = 51
HueAndTone_sHue[6] = "黄みの緑" ' yellowish green
HueAndTone_iHMax[6] = 57
HueAndTone_sHue[7] = "黄緑" ' yellow green
HueAndTone_iHMax[7] = 68
HueAndTone_sHue[8] = "緑みの黄" ' greenish yellow
HueAndTone_iHMax[8] = 75
HueAndTone_sHue[9] = "緑" ' green
HueAndTone_iHMax[9] = 96
HueAndTone_sHue[10] = "青みの緑" ' blueish green
HueAndTone_iHMax[10] = 114
HueAndTone_sHue[11] = "青緑" ' blueish green
HueAndTone_iHMax[11] = 139
HueAndTone_sHue[12] = "緑みの青" ' greenish blue
HueAndTone_iHMax[12] = 156
HueAndTone_sHue[13] = "青" ' blue
HueAndTone_iHMax[13] = 179
HueAndTone_sHue[14] = "紫みの青" ' purplish blue
HueAndTone_iHMax[14] = 185
HueAndTone_sHue[15] = "青紫" ' purple blue (violet)
HueAndTone_iHMax[15] = 185
HueAndTone_sHue[16] = "青みの紫" ' purplish blue
HueAndTone_iHMax[16] = 203
HueAndTone_sHue[17] = "紫" ' purple
HueAndTone_iHMax[17] = 222
HueAndTone_sHue[18] = "赤みの紫" ' reddish purple
HueAndTone_iHMax[18] = 228
HueAndTone_sHue[19] = "赤紫" ' red purple
HueAndTone_iHMax[19] = 239
HueAndTone_sHue[20] = "紫みの赤" ' purplish red
HueAndTone_iHMax[20] = 245
HueAndTone_sHue[21] = "赤" ' red
HueAndTone_iHMax[21] = 255
EndSub

' Hue and tone | Convert color to name
' in: sColor - "#rrggbb"
' out: sName - hue and tone name
' out: iHue - [1..21]
' out: iTone - [1, 19]
Sub HueAndTone_ColorToName
sColorSaved = sColor
Color_RGBtoHSL()
iH = Math.Round(rHue * 256 / 360)
Color_ColorToSafe()
Color_RGBtoHSL()
iS = Math.Round(rSaturation * 255)
iL = Math.Round(rLightness * 255)
For iHue = 1 To 21
If iH <= HueAndTone_iHMax[iHue] Then
Goto lFoundHue
EndIf
EndFor
TextWindow.WriteLine("Error: hue not found for " + sColorSaved)
lFoundHue:
For iTone = 1 To 21
If HueAndTone_iS[iTone] = iS And HueAndTone_iL[iTone] = iL Then
Goto lFoundTone
EndIf
EndFor
TextWindow.WriteLine("Error: tone not found for " + sColorSaved + " H=" + iH + " S=" + iS + " L=" + iL)
lFoundTone:
If iTone >= 16 Then
sName = HueAndTone_sTone[iTone]
Else
iPtr = Text.GetIndexOf(HueAndTone_sHue[iHue], "の")
If iPtr > 0 And Text.IsSubText(HueAndTone_sTone[iTone], "の") Then
sName = Text.GetSubText(HueAndTone_sHue[iHue], 1, iPtr - 1) + "を帯びた" + Text.GetSubTextToEnd(HueAndTone_sHue[iHue], iPtr + 1)
Else
sName = HueAndTone_sHue[iHue]
EndIf
sName = HueAndTone_sTone[iTone] + sName
EndIf
EndSub

' Console | Initialization
Sub Console_Init
GraphicsWindow.BrushColor = "Gray"
GraphicsWindow.FillRectangle(0, 0, GraphicsWindow.Width, GraphicsWindow.Height)
EndSub

' Math | Convert hexadecimal to decimal
' in: sHex
' out: iDec
Sub Math_Hex2Dec
iDec = 0
iLen = Text.GetLength(sHex)
For iPtr = 1 To iLen
iDec = iDec * 16 + Text.GetIndexOf("0123456789ABCDEF", Text.GetSubText(sHex, iPtr, 1)) - 1
EndFor
EndSub