Microsoft Small Basic

Program Listing: KZM872
' Color mixture v0.1 - (C) 2011 Nonki Takahashi
' shows sample of color mixture
'
' History
' 2011/04/08 Created (632 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
COLORPICK_OPACITY = 80

' Main
GraphicsWindow.Title = "Color Mixture " + VERSION

' 1) CRT simulation with big pixels
STRIPE_WIDTH = 3 ' for big pixel
PIXEL_SIZE = STRIPE_WIDTH * 3 + 1 ' for big pixel
iX0 = 100
iY0 = 50
GraphicsWindow.BackgroundColor = "Black"
sColor = "#FFFFFF"
For iYB = 20 To 29
For iXB = 10 To 19
BigPixel_SetPixel()
EndFor
EndFor
sColor = "#FF0000"
For iYB = 20 To 29
For iXB = 20 To 29
BigPixel_SetPixel()
EndFor
EndFor
sColor = "#00FF00"
For iYB = 20 To 29
For iXB = 30 To 39
BigPixel_SetPixel()
EndFor
EndFor
sColor = "#FFFF00"
For iYB = 20 To 29
For iXB = 40 To 49
BigPixel_SetPixel()
EndFor
EndFor

' 2) Gradation ribbon
sColor1 = "#FF0000"
sColor2 = "#00FF00"
iXG0 = 100
iXG1 = 520
iYG0 = 320
iYG1 = 370
Gradation_DrawRibbon()

' 3) Additive color mixture
iPercent = 20
iDiameter = Math.Round(300 * iPercent / 100)
iXS = 400 ' x source
iYS = iY0 ' y source
iWidth = iDiameter
iHeight = iDiameter
GraphicsWindow.BrushColor = "Red"
iLeft = iX0 + Math.Round(200 * iPercent / 100)
iTop = iY0 + Math.Round(173 * iPercent / 100)
GraphicsWindow.FillEllipse(iLeft, iTop, iWidth, iHeight)
GraphicsWindow.BrushColor = "Lime"
iLeft = iXS
iTop = iYS
GraphicsWindow.FillEllipse(iLeft, iTop, iWidth, iHeight)
Bitblt_GetBlock()
iLeft = iX0 + Math.Round(100 * iPercent / 100)
iTop = iY0
Bitblt_PutBlockAsAdd()
GraphicsWindow.BrushColor = "Blue"
iLeft = iXS
iTop = iYS
GraphicsWindow.FillEllipse(iLeft, iTop, iWidth, iHeight)
Bitblt_GetBlock()
iLeft = iX0
iTop = iY0 + Math.Round(173 * iPercent / 100)
Bitblt_PutBlockAsAdd()

' 4) Subtructive color mixture
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(iXS - 10, iYS - 10, iWidth + 20, iHeight + 20)
iX0 = iX0 + Math.Round(800 * iPercent / 100)
GraphicsWindow.FillRectangle(iX0 - 10, iY0 - 10, Math.Round(iWidth * 500 / 300) + 20, Math.Round(iHeight * 473 / 300) + 20)
GraphicsWindow.BrushColor = "Cyan"
iLeft = iX0 + Math.Round(200 * iPercent / 100)
iTop = iY0 + Math.Round(173 * iPercent / 100)
GraphicsWindow.FillEllipse(iLeft, iTop, iWidth, iHeight)
GraphicsWindow.BrushColor = "Magenta"
iLeft = iXS
iTop = iYS
GraphicsWindow.FillEllipse(iLeft, iTop, iWidth, iHeight)
Bitblt_GetBlock()
iLeft = iX0 + Math.Round(100 * iPercent / 100)
iTop = iY0
Bitblt_PutBlockAsSubtract()
GraphicsWindow.BrushColor = "Yellow"
iLeft = iXS
iTop = iYS
GraphicsWindow.FillEllipse(iLeft, iTop, iWidth, iHeight)
Bitblt_GetBlock()
iLeft = iX0
iTop = iY0 + Math.Round(173 * iPercent / 100)
Bitblt_PutBlockAsSubtract()

' 5) Color pick and show RGB, HSL, hue and tone name
ColorPick_Init()
ColorPick_Show()

'' Big pixel | Set pixel
' in: sColor - color to set
' in: iXB, iYB - big pixel cordinate
Sub BigPixel_SetPixel
Color_ColorToRGB()
GraphicsWindow.BrushColor = GraphicsWindow.GetColorFromRGB(iR, 0, 0)
GraphicsWindow.FillRectangle(iXB * PIXEL_SIZE, iYB * PIXEL_SIZE, STRIPE_WIDTH, PIXEL_SIZE - 1)
GraphicsWindow.BrushColor = GraphicsWindow.GetColorFromRGB(0, iG, 0)
GraphicsWindow.FillRectangle(iXB * PIXEL_SIZE + STRIPE_WIDTH, iYB * PIXEL_SIZE, STRIPE_WIDTH, PIXEL_SIZE - 1)
GraphicsWindow.BrushColor = GraphicsWindow.GetColorFromRGB(0, 0, iB)
GraphicsWindow.FillRectangle(iXB * PIXEL_SIZE + STRIPE_WIDTH * 2, iYB * PIXEL_SIZE, STRIPE_WIDTH, PIXEL_SIZE - 1)
EndSub

' Bitblt | Get block
' in: iLeft, iTop, iWidth, iHeight - block position and size
' out: Bitblt_sColor[][] - pixel color
' out: Bitblt_iWidth, Bitblt_iHeight - block size
Sub Bitblt_GetBlock
Bitblt_iWidth = iWidth
Bitblt_iHeight = iHeight
For iYB = iTop To iTop + iHeight - 1
For iXB = iLeft To iLeft + iWidth - 1
Bitblt_sColor[iXB - iLeft][iYB - iTop] = GraphicsWindow.GetPixel(iXB, iYB)
EndFor
EndFor
EndSub

' Bitblt | Put block as copy
' in: iLeft, iTop - block position
' in: Bitblt_iWidth, Bitblt_iHeight - block size
' in: Bitblt_sColor[][] - pixel color
Sub Bitblt_PutBlockAsCopy
For iYB = 0 To Bitblt_iHeight - 1
For iXB = 0 To Bitblt_iWidth - 1
GraphicsWindow.SetPixel(iXB + iLeft, iYB + iTop, Bitblt_sColor[iXB][iYB])
EndFor
EndFor
EndSub

' Bitblt | Put block as add
' in: iLeft, iTop - block position
' in: Bitblt_iWidth, Bitblt_iHeight - block size
' in: Bitblt_sColor[][] - pixel color
Sub Bitblt_PutBlockAsAdd
For iYB = 0 To Bitblt_iHeight - 1
For iXB = 0 To Bitblt_iWidth - 1
sColor1 = GraphicsWindow.GetPixel(iXB + iLeft, iYB + iTop)
sColor2 = Bitblt_sColor[iXB][iYB]
Color_Add()
GraphicsWindow.SetPixel(iXB + iLeft, iYB + iTop, sColor)
EndFor
EndFor
EndSub

' Bitblt | Put block as subtract
' in: iLeft, iTop - block position
' in: Bitblt_iWidth, Bitblt_iHeight - block size
' in: Bitblt_sColor[][] - pixel color
Sub Bitblt_PutBlockAsSubtract
For iYB = 0 To Bitblt_iHeight - 1
For iXB = 0 To Bitblt_iWidth - 1
sColor1 = GraphicsWindow.GetPixel(iXB + iLeft, iYB + iTop)
sColor2 = Bitblt_sColor[iXB][iYB]
Color_Subtract()
GraphicsWindow.SetPixel(iXB + iLeft, iYB + iTop, sColor)
EndFor
EndFor
EndSub

' Color | Subtract colors
' in: sColor1, sColor2
' out: sColor - sColor1 - sColor2
Sub Color_Subtract
sColor = sColor1
Color_ColorToRGB()
iC1 = 255 - iR
iM1 = 255 - iG
iY1 = 255 - iB
sColor = sColor2
Color_ColorToRGB()
iC2 = 255 - iR
iM2 = 255 - iG
iY2 = 255 - iB
iC = iC1 + iC2
If iC > 255 Then
iC = 255
EndIf
iM = iM1 + iM2
If iM > 255 Then
iM = 255
EndIf
iY = iY1 + iY2
If iY > 255 Then
iY = 255
EndIf
sColor = GraphicsWindow.GetColorFromRGB(255 - iC, 255 - iM, 255 - iY)
EndSub

' Color | Add colors
' in: sColor1, sColor2
' out: sColor - sColor1 + sColor2
Sub Color_Add
sColor = sColor1
Color_ColorToRGB()
iR1 = iR
iG1 = iG
iB1 = iB
sColor = sColor2
Color_ColorToRGB()
iR2 = iR
iG2 = iG
iB2 = iB
iR = iR1 + iR2
If iR > 255 Then
iR = 255
EndIf
iG = iG1 + iG2
If iG > 255 Then
iG = 255
EndIf
iB = iB1 + iB2
If iB > 255 Then
iB = 255
EndIf
sColor = GraphicsWindow.GetColorFromRGB(iR, iG, iB)
EndSub

' 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
HueAndTone_Init()
GraphicsWindow.PenColor = "White"
GraphicsWindow.BrushColor = "White"
oRect = Shapes.AddRectangle(COLORPICK_X, COLORPICK_Y)
Shapes.SetOpacity(oRect, COLORPICK_OPACITY)
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
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
EndSub

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

' Gradation | Draw ribbon
' in: iXG0, iYG0, iXG1, iYG1 - ribbon coordinate
' in: sColor1, sColor2 - colors
Sub Gradation_DrawRibbon
sColor = sColor1
Color_ColorToRGB()
iR1 = iR
iG1 = iG
iB1 = iB
sColor = sColor2
Color_ColorToRGB()
iR2 = iR
iG2 = iG
iB2 = iB
For iX = iXG0 To iXG1
iR = Math.Floor((iR2 - iR1) * (iX - iXG0) / (iXG1 - iXG0)) + iR1
iG = Math.Floor((iG2 - iG1) * (iX - iXG0) / (iXG1 - iXG0)) + iG1
iB = Math.Floor((iB2 - iB1) * (iX - iXG0) / (iXG1 - iXG0)) + iB1
GraphicsWindow.PenColor = GraphicsWindow.GetColorFromRGB(iR, iG, iB)
GraphicsWindow.DrawLine(iX, iYG0, iX, iYG1)
EndFor
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

' 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