Module:Sandbox/isaacl/ColourSpace
This module implements the template {{User:Isaacl/Colour convert}}.
Overview
Module name: Module:Sandbox/isaacl/ColourSpace
local me = { }
local bc = require('Module:BaseConvert')
local Tuple = require('Module:Sandbox/isaacl/ColourSpace/Tuple')
local Formats = require('Module:Sandbox/isaacl/ColourSpace/Formats')
local infoFor = {
sRGB = {
colourSpace = 'sRGB',
formatType = 'float',
defaultConversion = 'sRGB24bit',
parseInput = function(args)
local digitPattern = '^([%.%d]+)%%?$'
local red = string.match(args[1], digitPattern)
local green = string.match(args[2], digitPattern)
local blue = string.match(args[3], digitPattern)
return { red, green, blue }
end,
isInputFormat = function(args)
local sRGBPattern = '^[%.%d]+%%$'
if ( args[3] ~= nil and
string.match(args[1], sRGBPattern) and
string.match(args[2], sRGBPattern) and
string.match(args[3], sRGBPattern) ) then
return true
end
return false
end, -- end of isInputFormat function
display = function(self, separator)
local red = self[1] .. '%'
local green = self[2] .. '%'
local blue = self [3] .. '%'
return Tuple.display({ red, green, blue }, separator)
end,
mapParametersFrom = {
sRGB24bit =
function( colourValue )
local red = colourValue[1] / 255 * 100
local green = colourValue[2] / 255 * 100
local blue = colourValue[3] / 255 * 100
return { red, green, blue }
end,
}, -- end of mapping functions
}, -- info for sRGB
sRGB24bit = {
colourSpace = 'sRGB',
formatType = '24bit',
defaultConversion = 'sRGB',
isInputFormat = function(args)
local digitPattern = '^%d+$'
if ( args[3] ~= nil and
string.match(args[1], digitPattern) and
string.match(args[2], digitPattern) and
string.match(args[3], digitPattern)
-- for some reason, tonumber() is required for range checking to work
and (tonumber(args[1]) <= 255)
and (tonumber(args[2]) <= 255)
and (tonumber(args[3]) <= 255)
) then
return true
end
return false
end,
display = function(self, separator)
return Tuple.display(self, separator)
end,
mapParametersFrom = {
sRGB = function(colourValue)
local red = math.floor(colourValue[1] * 255 / 100 + 0.5)
local green = math.floor(colourValue[2] * 255 / 100 + 0.5)
local blue = math.floor(colourValue[3] * 255 / 100 + 0.5)
return { red, green, blue }
end,
sRGB24bitHexString = function(colourValue)
return colourValue
end,
}, -- end of mapping functions
}, -- info for sRGB24bit
sRGB24bitHexString = {
colourSpace = 'sRGB',
formatType = '24bit',
defaultConversion = 'sRGB24bit',
parseInput = function(args)
local red
local green
local blue
local hexString = args[1]
local hexCharPattern = '^#?(%x%x)(%x%x)(%x%x)$'
local fDoubleChar = false
if ( #hexString == 3 or #hexString == 4 ) then
hexCharPattern = '^#?(%x)(%x)(%x)$'
fDoubleChar = true
end
red, green, blue = string.match(hexString, hexCharPattern)
if ( fDoubleChar ) then
red = red .. red;
green = green .. green;
blue = blue .. blue;
end
red = bc.convert({n = red, base = 10, from = 16})
green = bc.convert({n = green, base = 10, from = 16})
blue = bc.convert({n = blue, base = 10, from = 16})
return { red, green, blue }
end,
isInputFormat = function(args)
if ( string.match(args[1], '^#%x%x%x$')
or string.match(args[1], '^#%x%x%x%x%x%x$' ) ) then
return true
end
return false
end,
display = function(self, separator)
local red = string.format('#%02X', self[1])
local green = string.format('%02X', self[2])
local blue = string.format('%02X', self[3])
return Tuple.display({ red, green, blue }, '')
end,
mapParametersFrom = {
sRGB24bit = function( colourValue )
return colourValue
end,
}, -- end of mapping functions
}, -- info for sRGB24bitHexString
} -- data for formats
function me.buildColourTuple(args, parameters)
local result = Tuple.clone(args)
result.format = parameters.format
result.colourSpace = parameters.colourSpace
result.defaultConversion = parameters.defaultConversion
result.fValid = true
result.display = function(self, separator)
return parameters.displayFunc(self, separator)
end
return result
end -- function buildColourTuple
local options = {
separator = ', ',
displayPrefix = '',
displaySuffix = '',
}
local formatTypeFor = { }
local checkInputFormatFor = { }
me.create = { }
local createFromParsedInput = { }
me.mapTo = { }
local colourSpaceFor = { }
local commonFormatForColourSpace = {
sRGB = {
andFormatType = {
float = 'sRGB',
['24bit'] = 'sRGB24bit',
},
},
}
local function createInvalidColourValue(errorMsg)
local invalidColourValue = {
-1, -1, -1,
fValid = false,
errorMessage = errorMsg,
display = function(self, separator)
return 'InvalidValue ' .. self.errorMessage
end,
}
return invalidColourValue
end
me.configureFormatInfo = function(infoFor)
for format, info in pairs(infoFor) do
-- If basic information for the format has not been defined
-- already, configure it
if ( me.create[format] == nil ) then
createFromParsedInput[format] = function(parsedArgs)
return me.buildColourTuple(parsedArgs, {
format = format,
colourSpace = info.colourSpace,
defaultConversion = info.defaultConversion,
displayFunc = info.display,
})
end -- function createFromParsedInput[format]
me.create[format] = function (args)
local parsedArgs
if ( info.parseInput ~= nil ) then
parsedArgs = info.parseInput(args)
else
parsedArgs = args
end
if ( parsedArgs == nil ) then
return createInvalidColourValue('badInputValues')
end
return createFromParsedInput[format](parsedArgs)
end -- function me.create[format]
formatTypeFor[format] = info.formatType
colourSpaceFor[format] = info.colourSpace
if ( info.isInputFormat ~= nil ) then
checkInputFormatFor[format] = info.isInputFormat
end
end -- if me.create[format] == nil, configure basic info for format
-- Define mapping functions from other formats to the
-- current format being configured.
for startFormat, mapper in pairs(info.mapParametersFrom) do
if ( me.mapTo[format] == nil ) then
me.mapTo[format] = { from = { } }
end
me.mapTo[format].from[startFormat] =
function(parameters)
local copy = Tuple.clone(parameters)
local mappedParameters = mapper(copy)
if ( mappedParameters == nil ) then
return createInvalidColourValue('conversionError '
.. parameters:display()
)
end
return createFromParsedInput[format]( mappedParameters )
end
end -- loop over info.mapParametersFrom
end -- loop over infoFor table
end
me.configureFormatInfo(infoFor)
for idx=1, #Formats do
local formatInfo = require('Module:Sandbox/isaacl/ColourSpace/Formats/' .. Formats[idx])
me.configureFormatInfo(formatInfo.infoFor)
end
function me.loadFormatInfo(format)
-- try to load the required module for the format
local formatInfo = require('Module:Sandbox/isaacl/ColourSpace/Formats/'
.. format)
if ( formatInfo ~= nil ) then
me.configureFormatInfo(formatInfo.infoFor)
return format
end
return nil
end
function me.determineInputFormat(frame)
local args = frame.args
local fromFormat = frame.args["from"]
if (fromFormat ~= nil) then
if ( me.create[fromFormat] ~= nil ) then
return fromFormat
else
-- try to load the required module for the format
return me.loadFormatInfo(fromFormat)
end
end
for format, isInputFormat in pairs(checkInputFormatFor) do
if ( isInputFormat(args) ) then
return format
end
end
-- unable to deduce format
return nil
end -- function determineInputFormat()
local function determineOutputFormat(frame, startValue)
local toFormat = frame.args["to"]
if (toFormat ~= nil) then
if ( me.create[toFormat] ~= nil ) then
return toFormat
else
-- try to load the required module for the format
return me.loadFormatInfo(toFormat)
end
end
-- use default conversion
return startValue.defaultConversion
end -- function determineOutputFormat()
local function convertBetweenFormats(colourValue, listOfFormats)
local convertedValue = colourValue
for idx, nextFormat in ipairs(listOfFormats) do
if (convertedValue.format ~= nextFormat) then
if ( me.mapTo[nextFormat].from[convertedValue.format] == nil ) then
return createInvalidColourValue('noConversionAvailable from '
.. convertedValue.format .. ' to ' .. nextFormat)
end
convertedValue = me.mapTo[nextFormat].from[convertedValue.format](convertedValue)
if (not convertedValue.fValid) then
-- error in conversion; return immediately with the invalidValue
return convertedValue
end
end
end -- loop over list of formats to convert between
return convertedValue
end -- function convertBetweenFormats
function me.convertColour(frame)
if ( frame.args[1] == nil ) then
return ''
end
if ( frame.args.separator ~= nil ) then
options.separator = frame.args.separator
end
local startFormat = me.determineInputFormat(frame)
if ( startFormat == nil ) then
return 'badInputFormat'
end
local startValue = me.create[startFormat](frame.args)
if ( not startValue.fValid ) then
return startValue:display()
end
local endFormat = determineOutputFormat(frame, startValue)
if ( endFormat == nil ) then
return 'badOutputFormat'
end
if ( startFormat == endFormat ) then
return startValue:display(options.separator)
end
local result = { }
-- If a direct conversion exists, use it
if (me.mapTo[endFormat].from[startFormat] ~= nil) then
result = me.mapTo[endFormat].from[startFormat](startValue)
return result:display(options.separator)
end
local listOfFormats = { }
-- If the start and end formats are in the same colour space:
-- first, convert to the common format for the starting colour space and format type
-- second, convert to the common format for the ending colour space and format type
-- third, convert to the ending format type
if (colourSpaceFor[startFormat] == colourSpaceFor[endFormat]) then
table.insert(listOfFormats,
commonFormatForColourSpace[colourSpaceFor[startFormat]].andFormatType[formatTypeFor[startFormat]] )
table.insert(listOfFormats,
commonFormatForColourSpace[colourSpaceFor[endFormat]].andFormatType[formatTypeFor[endFormat]] )
table.insert(listOfFormats, endFormat)
result = convertBetweenFormats(startValue, listOfFormats)
else
-- if the start and end formats are in different colour spaces:
-- first, convert to the common format for the starting colour space and format type
-- second, convert to the common floating point format for the starting colour space
-- third, convert to the common floating point format for the ending colour space
-- fourth, convert to the common format for the ending colour space and format type
-- fifth, convert to the ending format type
table.insert(listOfFormats,
commonFormatForColourSpace[colourSpaceFor[startFormat]].andFormatType[formatTypeFor[startFormat]] )
table.insert(listOfFormats,
commonFormatForColourSpace[colourSpaceFor[startFormat]].andFormatType.float )
table.insert(listOfFormats,
commonFormatForColourSpace[colourSpaceFor[endFormat]].andFormatType.float )
table.insert(listOfFormats,
commonFormatForColourSpace[colourSpaceFor[endFormat]].andFormatType[formatTypeFor[endFormat]] )
table.insert(listOfFormats, endFormat)
result = convertBetweenFormats(startValue, listOfFormats)
end
return result:display(options.separator)
end -- function convertColour()
function me.convertColour_fromTemplate(frame)
return me.convertColour(frame:getParent())
end -- function templateConvertColour()
return me
Content Disclaimer
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.
- The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
- There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
- It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
- Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
- Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.