# Pigment.O is a Krita plugin and it is a Color Picker and Color Mixer. # Copyright ( C ) 2020 Ricardo Jeremias. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # ( at your option ) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . #region Imports #################################################################### import math from PyQt5 import QtCore from .pigment_o_constants import * #endregion class Geometry(): """ Geometric 1D-2D-3D operations """ #region Init ####################################################################### def __init__( self ): pass #endregion #region Limiters ################################################################### def Limit_Unit( self, value ): if value <= 1: value = 1 return value def Limit_Float( self, value ): if value <= 0: value = 0 if value >= 1: value = 1 return value def Limit_Range( self, value, minimum, maximum ): if value <= minimum: value = minimum if value >= maximum: value = maximum return value def Limit_Loop( self, value, limit ): if value < 0: value = limit if value > limit: value = 0 return value def Limit_Looper( self, value, limit ): while value < 0: value += limit while value > limit: value -= limit return value def Limit_Error( self, value, error ): if ( value > -error and value < error ): value = 0 return value def Limit_Angle( self, angle, inter ): angle = angle // inter even = angle % 2 if even == 0: # Even angle = angle * inter else: # Odd angle = ( angle + 1 ) * inter return angle #endregion #region Range ###################################################################### def Lerp_1D( self, percent, bot, top ): lerp = bot + ( ( top - bot ) * percent ) return lerp def Lerp_2D( self, percent, x1, y1, x2, y2 ): dx = x2 - x1 dy = y2 - y1 lx = x1 + ( dx * percent ) ly = y1 + ( dy * percent ) return lx, ly def Lerp_3D( self, percent, x1, y1, z1, x2, y2, z2 ): dx = x2 - x1 dy = y2 - y1 dz = z2 - z1 lx = x1 + ( dx * percent ) ly = y1 + ( dy * percent ) lz = z1 + ( dz * percent ) return lx, ly, lz def Lerp_List( self, percent, bot, top ): lista = [] for i in range( 0, len( bot ) ): lerp = bot[i] + ( ( top[i] - bot[i] ) * percent ) lista.append( lerp ) return lista def Random_Range( self, range ): time = int( QtCore.QTime.currentTime().toString( 'hhmmssms' ) ) random.seed( time ) random_value = random.randint( 0, range ) return random_value #endregion #region Statistics ################################################################# def Stat_Mean( self, lista ): length = len( lista ) add = 0 for i in range( 0, length ): add = add + lista[i] mean = add / ( length ) return mean #endregion #region Trignometry ################################################################ def Trig_2D_Angle_Circle( self, px, py, side, radius, angle ): # px - Circle center in X (pixels) # py - Circle center in Y (pixels) # side - length of the square containning the circle (pixels) # radius - how far from the center (0-1) # angle - angle delta (0-360) circle_x = ( px ) - ( ( side * radius ) * math.cos( math.radians( angle ) ) ) circle_y = ( py ) - ( ( side * radius ) * math.sin( math.radians( angle ) ) ) return circle_x, circle_y def Trig_2D_Points_Distance( self, x1, y1, x2, y2 ): dd = math.sqrt( math.pow( ( x1 - x2 ), 2 ) + math.pow( ( y1 - y2 ), 2 ) ) return dd def Trig_2D_Points_Lines_Angle( self, x1, y1, x2, y2, x3, y3 ): v1 = ( x1 - x2, y1 - y2 ) v2 = ( x3 - x2, y3 - y2 ) v1_theta = math.atan2( v1[1], v1[0] ) v2_theta = math.atan2( v2[1], v2[0] ) angle = ( v2_theta - v1_theta ) * ( 180.0 / math.pi ) if angle < 0: angle += 360.0 return angle def Trig_2D_Points_Lines_Intersection( self, x1, y1, x2, y2, x3, y3, x4, y4 ): try: xx = ( ( x2 * y1 - x1 * y2 ) * ( x4 - x3 ) - ( x4 * y3 - x3 * y4 ) * ( x2 - x1 ) ) / ( ( x2 - x1 ) * ( y4 - y3 ) - ( x4 - x3 ) * ( y2 - y1 ) ) yy = ( ( x2 * y1 - x1 * y2 ) * ( y4 - y3 ) - ( x4 * y3 - x3 * y4 ) * ( y2 - y1 ) ) / ( ( x2 - x1 ) * ( y4 - y3 ) - ( x4 - x3 ) * ( y2 - y1 ) ) except: xx = 0 yy = 0 return xx, yy def Trig_2D_Points_Rotate( self, origin_x, origin_y, dist, angle ): cx = origin_x - ( dist * math.cos( math.radians( angle ) ) ) cy = origin_y - ( dist * math.sin( math.radians( angle ) ) ) return cx, cy def Trig_2D_Triangle_Extrapolation( self, x1, y1, x2, y2, percent_12, percent_23 ): hor = x2 - x1 ver = y2 - y1 p23_hor = ( percent_23 * hor ) / percent_12 p23_ver = ( percent_23 * ver ) / percent_12 x3 = x2 + p23_hor y3 = y2 + p23_ver return x3, y3 def Trig_2D_Centroid_Triangle( self, a1, a2, b1, b2, c1, c2 ): cx = ( a1 + b1 + c1 ) / 3 cy = ( a2 + b2 + c2 ) / 3 return [ cx, cy ] def Trig_2D_Centroid_Square( self, a1, a2, b1, b2, c1, c2, d1, d2 ): cx = ( a1 + b1 + c1 + d1 ) / 4 cy = ( a2 + b2 + c2 + d2 ) / 4 return [ cx, cy ] def Trig_2D_Ortogonal_Components(self, x1, y1, x2, y2): # x1,y1 is the origin delta_x = x2 - x1 delta_y = y2 - y1 return [delta_x, delta_y] def Trig_3D_Points_Distance( self, x1, y1, z1, x2, y2, z2 ): d = math.sqrt( ( x2 - x1 ) ** 2 + ( y2 - y1 ) ** 2 + ( z2 - z1 ) ** 2 ) return d #endregion class Convert(): """ Convert range 0-1 """ #region Init ################################################################### def __init__( self ): # Modules self.geometry = Geometry() # Variables self.hue = 0 self.luminosity = "ITU-R BT.709" #endregion #region Set #################################################################### def Set_Document( self, d_cm, d_cd, d_cp ): self.d_cm = d_cm self.d_cd = d_cd self.d_cp = d_cp def Set_Hue( self, hue ): self.hue = hue def Set_Luminosity( self, luminosity ): self.luminosity == luminosity if self.luminosity == "ITU-R BT.601": self.luma_r = 0.299 self.luma_b = 0.114 self.luma_g = 1 - self.luma_r - self.luma_b # 0.587 self.luma_pr = 1.402 self.luma_pb = 1.772 if self.luminosity == "ITU-R BT.709": self.luma_r = 0.2126 self.luma_b = 0.0722 self.luma_g = 1 - self.luma_r - self.luma_b # 0.7152 self.luma_pr = 1.5748 self.luma_pb = 1.8556 if self.luminosity == "ITU-R BT.2020": self.luma_r = 0.2627 self.luma_b = 0.0593 self.luma_g = 1 - self.luma_r - self.luma_b # 0.678 self.luma_pr = 0.4969 self.luma_pb = 0.7910 def Set_Gamma( self, gamma_y, gamma_l ): self.gamma_y = gamma_y self.gamma_l = gamma_l def Set_Matrix( self, matrix, iluma ): # Origin from http://www.brucelindbloom.com/ # Standard if matrix == "sRGB": if iluma == "D50": # i=0 self.m_rgb_xyz = [ [ 0.4360747, 0.3850649, 0.1430804 ], [ 0.2225045, 0.7168786, 0.0606169 ], [ 0.0139322, 0.0971045, 0.7141733 ] ] self.m_xyz_rgb = [ [ 3.1338561, -1.6168667, -0.4906146 ], [-0.9787684, 1.9161415, 0.0334540 ], [ 0.0719453, -0.2289914, 1.4052427 ] ] if iluma == "D65": # i=1 self.m_rgb_xyz = [ [ 0.4124564, 0.3575761, 0.1804375 ], [ 0.2126729, 0.7151522, 0.0721750 ], [ 0.0193339, 0.1191920, 0.9503041 ] ] self.m_xyz_rgb = [ [ 3.2404542, -1.5371385, -0.4985314 ], [-0.9692660, 1.8760108, 0.0415560 ], [ 0.0556434, -0.2040259, 1.0572252 ] ] else: iluma = "D65" # Professional if matrix == "Adobe RGB": if iluma == "D50": # i=2 self.m_rgb_xyz = [ [ 0.6097559, 0.2052401, 0.1492240 ], [ 0.3111242, 0.6256560, 0.0632197 ], [ 0.0194811, 0.0608902, 0.7448387 ] ] self.m_xyz_rgb = [ [ 1.9624274, -0.6105343, -0.3413404 ], [-0.9787684, 1.9161415, 0.0334540 ], [ 0.0286869, -0.1406752, 1.3487655 ] ] if iluma == "D65": # i=3 self.m_rgb_xyz = [ [ 0.5767309, 0.1855540, 0.1881852 ], [ 0.2973769, 0.6273491, 0.0752741 ], [ 0.0270343, 0.0706872, 0.9911085 ] ] self.m_xyz_rgb = [ [ 2.0413690, -0.5649464, -0.3446944 ], [-0.9692660, 1.8760108, 0.0415560 ], [ 0.0134474, -0.1183897, 1.0154096 ] ] else: iluma = "D65" if matrix == "Apple RGB": if iluma == "D50": self.m_rgb_xyz = [ [ 0.4755678, 0.3396722, 0.1489800 ], [ 0.2551812, 0.6725693, 0.0722496 ], [ 0.0184697, 0.1133771, 0.6933632 ] ] self.m_xyz_rgb = [ [ 2.8510695, -1.3605261, -0.4708281 ], [-1.0927680, 2.0348871, 0.0227598 ], [ 0.1027403, -0.2964984, 1.4510659 ] ] if iluma == "D65": self.m_rgb_xyz = [ [ 0.4497288, 0.3162486, 0.1844926 ], [ 0.2446525, 0.6720283, 0.0833192 ], [ 0.0251848, 0.1411824, 0.9224628 ] ] self.m_xyz_rgb = [ [ 2.9515373, -1.2894116, -0.4738445 ], [-1.0851093, 1.9908566, 0.0372026 ], [ 0.0854934, -0.2694964, 1.0912975 ] ] else: iluma = "D65" if matrix == "Best RGB": if iluma == "D50": self.m_rgb_xyz = [ [ 0.6326696, 0.2045558, 0.1269946 ], [ 0.2284569, 0.7373523, 0.0341908 ], [ 0.0000000, 0.0095142, 0.8156958 ] ] self.m_xyz_rgb = [ [ 1.7552599, -0.4836786, -0.2530000 ], [-0.5441336, 1.5068789, 0.0215528 ], [ 0.0063467, -0.0175761, 1.2256959 ] ] else: iluma = "D50" if matrix == "Beta RGB": if iluma == "D50": self.m_rgb_xyz = [ [ 0.6712537, 0.1745834, 0.1183829 ], [ 0.3032726, 0.6637861, 0.0329413 ], [ 0.0000000, 0.0407010, 0.7845090 ] ] self.m_xyz_rgb = [ [ 1.6832270, -0.4282363, -0.2360185 ], [-0.7710229, 1.7065571, 0.0446900 ], [ 0.0400013, -0.0885376, 1.2723640 ] ] else: iluma = "D50" if matrix == "Bruce RGB": if iluma == "D50": self.m_rgb_xyz = [ [ 0.4941816, 0.3204834, 0.1495550 ], [ 0.2521531, 0.6844869, 0.0633600 ], [ 0.0157886, 0.0629304, 0.7464909 ] ] self.m_xyz_rgb = [ [ 2.6502856, -1.2014485, -0.4289936 ], [-0.9787684, 1.9161415, 0.0334540 ], [ 0.0264570, -0.1361227, 1.3458542 ] ] if iluma == "D65": self.m_rgb_xyz = [ [ 0.4674162, 0.2944512, 0.1886026 ], [ 0.2410115, 0.6835475, 0.0754410 ], [ 0.0219101, 0.0736128, 0.9933071 ] ] self.m_xyz_rgb = [ [ 2.7454669, -1.1358136, -0.4350269 ], [-0.9692660, 1.8760108, 0.0415560 ], [ 0.0112723, -0.1139754, 1.0132541 ] ] else: iluma = "D65" if matrix == "CIE RGB": if iluma == "E": self.m_rgb_xyz = [ [ 0.4887180, 0.3106803, 0.2006017 ], [ 0.1762044, 0.8129847, 0.0108109 ], [ 0.0000000, 0.0102048, 0.9897952 ] ] self.m_xyz_rgb = [ [ 2.3706743, -0.9000405, -0.4706338 ], [-0.5138850, 1.4253036, 0.0885814 ], [ 0.0052982, -0.0146949, 1.0093968 ] ] if matrix == "ColorMatch RGB": if iluma == "D50": self.m_rgb_xyz = [ [ 0.5093439, 0.3209071, 0.1339691 ], [ 0.2748840, 0.6581315, 0.0669845 ], [ 0.0242545, 0.1087821, 0.6921735 ] ] self.m_xyz_rgb = [ [ 2.6422874, -1.2234270, -0.3930143 ], [-1.1119763, 2.0590183, 0.0159614 ], [ 0.0821699, -0.2807254, 1.4559877 ] ] else: iluma = "D50" if matrix == "Don RGB 4": if iluma == "D50": self.m_rgb_xyz = [ [ 0.6457711, 0.1933511, 0.1250978 ], [ 0.2783496, 0.6879702, 0.0336802 ], [ 0.0037113, 0.0179861, 0.8035125 ] ] self.m_xyz_rgb = [ [ 1.7603902, -0.4881198, -0.2536126 ], [-0.7126288, 1.6527432, 0.0416715 ], [ 0.0078207, -0.0347411, 1.2447743 ] ] else: iluma = "D50" if matrix == "ECI RGB": if iluma == "D50": self.m_rgb_xyz = [ [ 0.6502043, 0.1780774, 0.1359384 ], [ 0.3202499, 0.6020711, 0.0776791 ], [ 0.0000000, 0.0678390, 0.7573710 ] ] self.m_xyz_rgb = [ [ 1.7827618, -0.4969847, -0.2690101 ], [-0.9593623, 1.9477962, -0.0275807 ], [ 0.0859317, -0.1744674, 1.3228273 ] ] else: iluma = "D50" if matrix == "Ekta Space PS5": if iluma == "D50": self.m_rgb_xyz = [ [ 0.5938914, 0.2729801, 0.0973485 ], [ 0.2606286, 0.7349465, 0.0044249 ], [ 0.0000000, 0.0419969, 0.7832131 ] ] self.m_xyz_rgb = [ [ 2.0043819, -0.7304844, -0.2450052 ], [-0.7110285, 1.6202126, 0.0792227 ], [ 0.0381263, -0.0868780, 1.2725438 ] ] else: iluma = "D50" if matrix == "NTSC RGB": if iluma == "C": self.m_rgb_xyz = [ [ 0.6068909, 0.1735011, 0.2003480 ], [ 0.2989164, 0.5865990, 0.1144845 ], [ 0.0000000, 0.0660957, 1.1162243 ] ] self.m_xyz_rgb = [ [ 1.9099961, -0.5324542, -0.2882091 ], [-0.9846663, 1.9991710, -0.0283082 ], [ 0.0583056, -0.1183781, 0.8975535 ] ] if matrix == "PAL/SECAM RGB": if iluma == "D50": self.m_rgb_xyz = [ [ 0.4552773, 0.3675500, 0.1413926 ], [ 0.2323025, 0.7077956, 0.0599019 ], [ 0.0145457, 0.1049154, 0.7057489 ] ] self.m_xyz_rgb = [ [ 2.9603944, -1.4678519, -0.4685105 ], [-0.9787684, 1.9161415, 0.0334540 ], [ 0.0844874, -0.2545973, 1.4216174 ] ] if iluma == "D65": self.m_rgb_xyz = [ [ 0.4306190, 0.3415419, 0.1783091 ], [ 0.2220379, 0.7066384, 0.0713236 ], [ 0.0201853, 0.1295504, 0.9390944 ] ] self.m_xyz_rgb = [ [ 3.0628971, -1.3931791, -0.4757517 ], [-0.9692660, 1.8760108, 0.0415560 ], [ 0.0678775, -0.2288548, 1.0693490 ] ] else: iluma = "D65" if matrix == "ProPhoto RGB": if iluma == "D50": self.m_rgb_xyz = [ [ 0.7976749, 0.1351917, 0.0313534 ], [ 0.2880402, 0.7118741, 0.0000857 ], [ 0.0000000, 0.0000000, 0.8252100 ] ] self.m_xyz_rgb = [ [ 1.3459433, -0.2556075, -0.0511118 ], [-0.5445989, 1.5081673, 0.0205351 ], [ 0.0000000, 0.0000000, 1.2118128 ] ] else: iluma = "D50" if matrix == "SMPTE-C RGB": if iluma == "D50": self.m_rgb_xyz = [ [ 0.4163290, 0.3931464, 0.1547446 ], [ 0.2216999, 0.7032549, 0.0750452 ], [ 0.0136576, 0.0913604, 0.7201920 ] ] self.m_xyz_rgb = [ [ 3.3921940, -1.8264027, -0.5385522 ], [-1.0770996, 2.0213975, 0.0207989 ], [ 0.0723073, -0.2217902, 1.3960932 ] ] if iluma == "D65": self.m_rgb_xyz = [ [ 0.3935891, 0.3652497, 0.1916313 ], [ 0.2124132, 0.7010437, 0.0865432 ], [ 0.0187423, 0.1119313, 0.9581563 ] ] self.m_xyz_rgb = [ [ 3.5053960, -1.7394894, -0.5439640 ], [-1.0690722, 1.9778245, 0.0351722 ], [ 0.0563200, -0.1970226, 1.0502026 ] ] else: iluma = "D65" if matrix == "Wide Gamut RGB": if iluma == "D50": self.m_rgb_xyz = [ [ 0.7161046, 0.1009296, 0.1471858 ], [ 0.2581874, 0.7249378, 0.0168748 ], [ 0.0000000, 0.0517813, 0.7734287 ] ] self.m_xyz_rgb = [ [ 1.4628067, -0.1840623, -0.2743606 ], [-0.5217933, 1.4472381, 0.0677227 ], [ 0.0349342, -0.0968930, 1.2884099 ] ] else: iluma = "D50" # Illuminants if iluma == "D50": self.ref_x = 0.96422 self.ref_y = 1.00 self.ref_z = 0.82521 if iluma == "D65": self.ref_x = 0.95047 self.ref_y = 1.00 self.ref_z = 1.08883 #endregion #region Ask #################################################################### def Ask_Document( self ): return self.d_cm, self.d_cd, self.d_cp def Ask_Hue( self ): return self.hue def Ask_Luma_RGB( self ): return self.luma_r, self.luma_b, self.luma_g, self.luma_pr, self.luma_pb def Ask_Gamma( self ): return self.gamma_y, self.gamma_l def Ask_XYZ_Matrix( self ): return self.m_rgb_xyz, self.m_xyz_rgb, self.ref_x, self.ref_y, self.ref_z #endregion #region Links ################################################################## # Formulas # link : http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html # Link: https://www.easyrgb.com/en/math.php # Pickers # link: https://colorizer.org/ #endregion #region Utility ################################################################ def Vector_Safe( self, a, b, c ): a = self.geometry.Limit_Float( a ) b = self.geometry.Limit_Float( b ) c = self.geometry.Limit_Float( c ) return a, b, c def List_Mult_3( self, la, lb ): mult = ( la[0] * lb[0] ) + ( la[1] * lb[1] ) + ( la[2] * lb[2] ) return mult def Path_Os( self, os, path ): if os == "linux": path = path.replace( '\\','//' ) return path #endregion #region LERP ################################################################### def color_vector( self, mode, color ): if mode == "A": vector = [ color["aaa_1"] ] elif ( mode == "RGB" or mode == None ): vector = [ color["rgb_1"], color["rgb_2"], color["rgb_3"] ] elif mode == "CMY": vector = [ color["cmy_1"], color["cmy_2"], color["cmy_3"] ] elif mode == "CMYK": vector = [ color["cmyk_1"], color["cmyk_2"], color["cmyk_3"], color["cmyk_4"] ] elif mode == "RYB": vector = [ color["ryb_1"], color["ryb_2"], color["ryb_3"] ] elif mode == "YUV": vector = [ color["yuv_1"], color["yuv_2"], color["yuv_3"] ] elif mode == "HSV": vector = [ color["hsv_1"], color["hsv_2"], color["hsv_3"] ] elif mode == "HSL": vector = [ color["hsl_1"], color["hsl_2"], color["hsl_3"] ] elif mode == "HSY": vector = [ color["hsy_1"], color["hsy_2"], color["hsy_3"] ] elif mode == "ARD": vector = [ color["ard_1"], color["ard_2"], color["ard_3"] ] elif mode == "XYZ": vector = [ color["xyz_1"], color["xyz_2"], color["xyz_3"] ] elif mode == "XYY": vector = [ color["xyy_1"], color["xyy_2"], color["xyy_3"] ] elif mode == "LAB": vector = [ color["lab_1"], color["lab_2"], color["lab_3"] ] elif mode == "LCH": vector = [ color["lch_1"], color["lch_2"], color["lch_3"] ] return vector def color_lerp( self, mode, channels, color_a, color_b, factor ): color = [] if channels >= 1: hue_rgb = ( "HSV", "HSL", "HSY", "ARD" ) if mode in hue_rgb: # Circular dist_a = color_b[0] - color_a[0] if color_a[0] < color_b[0]: dist_b = ( color_b[0] - 1 ) - color_a[0] unit = - 1 / 360 else: dist_b = ( color_b[0] + 1 ) - color_a[0] unit = 1 / 360 dist = [ ( abs( dist_a ), dist_a ), ( abs( dist_b + unit ), dist_b ) ] d0 = sorted( dist )[0][1] v0 = self.geometry.Limit_Looper( color_a[0] + ( d0 * factor ), 1 ) else: # Linear d0 = color_b[0] - color_a[0] v0 = color_a[0] + ( d0 * factor ) color.append( v0 ) if channels >= 2: d1 = color_b[1] - color_a[1] v1 = color_a[1] + ( d1 * factor ) color.append( v1 ) if channels >= 3: hue_xyz = ( "LCH" ) if mode in hue_xyz: # Circular dist_a = color_b[2] - color_a[2] if color_a[2] < color_b[2]: dist_b = ( color_b[2] - 1 ) - color_a[2] unit = - 1 / 360 else: dist_b = ( color_b[2] + 1 ) - color_a[2] unit = 1 / 360 dist = [ ( abs( dist_a ), dist_a ), ( abs( dist_b + unit ), dist_b ) ] d2 = sorted( dist )[0][1] v2 = self.geometry.Limit_Looper( color_a[2] + ( d2 * factor ), 1 ) else: # Linear d2 = color_b[2] - color_a[2] v2 = color_a[2] + ( d2 * factor ) color.append( v2 ) if channels >= 4: d3 = color_b[3] - color_a[3] v3 = color_a[3] + ( d3 * factor ) color.append( v3 ) return color def color_convert( self, d_cm, mode, color ): # Variables aaa = None rgb = None cmyk = None yuv = None xyz = None lab = None # Lists list_rgb = [ "A", "RGB", "CMY", "CMYK", "RYB", "YUV", "HSV", "HSL", "HSY", "ARD" ] list_xyz = [ "XYZ", "XYY", "LAB", "LCH" ] if mode in list_rgb:form = 0 if mode in list_xyz:form = 1 # Document if d_cm == "A": aaa = color rgb = self.aaa_to_rgb( color[0] ) if form == 1:xyz = self.rgb_to_xyz( rgb[0], rgb[1], rgb[2] ) elif ( d_cm == "RGB" or d_cm == None ): rgb = color if form == 1:xyz = self.rgb_to_xyz( rgb[0], rgb[1], rgb[2] ) elif d_cm == "CMYK": cmyk = color rgb = self.cmyk_to_rgb( color[0], color[1], color[2], color[3] ) if form == 1:xyz = self.rgb_to_xyz( rgb[0], rgb[1], rgb[2] ) elif d_cm == "YUV": yuv = color rgb = self.yuv_to_rgb( yuv[0], yuv[1], yuv[2] ) if form == 1:xyz = self.rgb_to_xyz( rgb[0], rgb[1], rgb[2] ) elif d_cm == "XYZ": xyz = color if form == 0:rgb = self.xyz_to_rgb( xyz[0], xyz[1], xyz[2] ) elif d_cm == "LAB": lab = color xyz = self.lab_to_xyz( lab[0], lab[1], lab[2] ) if form == 0:rgb = self.xyz_to_rgb( lab[0], lab[1], lab[2] ) # Convert if mode == "A": if aaa == None:cor = self.rgb_to_aaa( rgb[0], rgb[1], rgb[2] ) else:cor = aaa elif ( mode == "RGB" or mode == None ): cor = rgb elif mode == "CMY": cor = self.rgb_to_cmy( rgb[0], rgb[1], rgb[2] ) elif mode == "CMYK": if cmyk == None:cor = self.rgb_to_cmyk( rgb[0], rgb[1], rgb[2], None ) else:cor = cmyk elif mode == "RYB": cor = self.rgb_to_ryb( rgb[0], rgb[1], rgb[2] ) elif mode == "YUV": if yuv == None:cor = self.rgb_to_yuv( rgb[0], rgb[1], rgb[2] ) else:cor = yuv elif mode == "HSV": cor = self.rgb_to_hsv( rgb[0], rgb[1], rgb[2] ) elif mode == "HSL": cor = self.rgb_to_hsl( rgb[0], rgb[1], rgb[2] ) elif mode == "HSY": cor = self.rgb_to_hsy( rgb[0], rgb[1], rgb[2] ) elif mode == "ARD": cor = self.rgb_to_ard( rgb[0], rgb[1], rgb[2] ) elif mode == "XYZ": cor = xyz elif mode == "XYY": cor = self.xyz_to_xyy( xyz[0], xyz[1], xyz[2] ) elif mode == "LAB": if lab == None:cor = self.xyz_to_lab( xyz[0], xyz[1], xyz[2] ) else:cor = lab elif mode == "LCH": cor = self.xyz_to_lch( xyz[0], xyz[1], xyz[2] ) return cor #endregion #region RGB LINEAR ############################################################# # AAA def rgb_to_aaa( self, r, g, b ): aaa = ( self.luma_r*r ) + ( self.luma_g*g ) + ( self.luma_b*b ) return [aaa] def aaa_to_rgb( self, a ): r = a g = a b = a return [r, g, b] # RGB def srgb_to_lrgb( self, sr, sg, sb ): n = 0.055 m = 12.92 if sr > 0.04045: lr = ( ( sr + n ) / ( 1 + n ) ) ** self.gamma_l else: lr = sr / m if sg > 0.04045: lg = ( ( sg + n ) / ( 1 + n ) ) ** self.gamma_l else: lg = sg / m if sb > 0.04045: lb = ( ( sb + n ) / ( 1 + n ) ) ** self.gamma_l else: lb = sb / m return [lr, lg, lb] def lrgb_to_srgb( self, lr, lg, lb ): n = 0.055 m = 12.92 if lr > 0.0031308: sr = ( ( 1 + n ) * lr ** ( 1 / self.gamma_l ) ) - n else: sr = m * lr if lg > 0.0031308: sg = ( ( 1 + n ) * lg ** ( 1 / self.gamma_l ) ) - n else: sg = m * lg if lb > 0.0031308: sb = ( ( 1 + n ) * lb ** ( 1 / self.gamma_l ) ) - n else: sb = m * lb return [sr, sg, sb] # UVD def rgb_to_uvd( self, r, g, b ): # uv range from -1 to +1 ( 0.8 with mask ) m00 = -0.866025808; m01 = +0.866025808; m02 = -0.0000000000000000961481791 m10 = +0.500000010; m11 = +0.499999990; m12 = -1.00000000 m20 = +0.333333497; m21 = +0.333333503; m22 = +0.333333000 # MatrixInverse * RGB u = m00 * r + m01 * g + m02 * b v = m10 * r + m11 * g + m12 * b d = m20 * r + m21 * g + m22 * b m = 0.0000001 u = self.geometry.Limit_Error( u, m ) v = self.geometry.Limit_Error( v, m ) return [u, v, d] def uvd_to_rgb( self, u, v, d ): m00 = -0.57735; m01 = +0.333333; m02 = +1 m10 = +0.57735; m11 = +0.333333; m12 = +1 m20 = -0.0000000113021; m21 = -0.666667; m22 = +1 # Matrix * UVD r = m00 * u + m01 * v + m02 * d g = m10 * u + m11 * v + m12 * d b = m20 * u + m21 * v + m22 * d # Correct out of Bound values r, g, b = self.Vector_Safe( r, g, b ) return [r, g, b] # CMY def rgb_to_cmy( self, r, g, b ): c = 1 - r m = 1 - g y = 1 - b return [c, m, y] def cmy_to_rgb( self, c, m, y ): r = 1 - c g = 1 - m b = 1 - y return [r, g, b] # CMYK def rgb_to_cmyk( self, r, g, b, key ): # key = black from cmyk or key ( if key is None formula is regular ) q = max( r, g, b ) if q == 0: if key == None: c = 0 m = 0 y = 0 k = 1 else: c = 1 m = 1 y = 1 k = key else: if key == None: k = 1 - max( r, g, b ) # Standard Transform else: k = key # Key is Locked ik = 1 - k if ik == 0 : c = ( r - k ) / ( k ) m = ( g - k ) / ( k ) y = ( b - k ) / ( k ) else: c = ( 1 - r - k ) / ( 1 - k ) m = ( 1 - g - k ) / ( 1 - k ) y = ( 1 - b - k ) / ( 1 - k ) return [c, m, y, k] def cmyk_to_rgb( self, c, m, y, k ): r = ( 1 - c ) * ( 1 - k ) g = ( 1 - m ) * ( 1 - k ) b = ( 1 - y ) * ( 1 - k ) r, g, b = self.Vector_Safe( r, g, b ) return [r, g, b] def rgb_to_k( self, r, g, b ): q = max( r, g, b ) if q == 0: k = 1 else: k = 1 - max( r, g, b ) return k def cmyk_to_tic( self, c, m, y, k): tic = round( ( c + m + y + k ) * 100 ) return tic # RYB def rgb_to_ryb( self, r, g, b ): red = r green = g blue = b white = min( red, green, blue ) red -= white green -= white blue -= white maxgreen = max( red, green, blue ) yellow = min( red, green ) red -= yellow green -= yellow if ( blue > 0 and green > 0 ): blue /= 2 green /= 2 yellow += green blue += green maxyellow = max( red, yellow, blue ) if maxyellow > 0: N = maxgreen / maxyellow red *= N yellow *= N blue *= N red += white yellow += white blue += white return [red, yellow, blue] def ryb_to_rgb( self, r, y, b ): red = r yellow = y blue = b white = min( red, yellow, blue ) red -= white yellow -= white blue -= white maxyellow = max( red, yellow, blue ) green = min( yellow, blue ) yellow -= green blue -= green if ( blue > 0 and green > 0 ): blue *= 2 green *= 2 red += yellow green += yellow maxgreen = max( red, green, blue ) if maxgreen > 0: N = maxyellow / maxgreen red *= N green *= N blue *= N red += white green += white blue += white return [red, green, blue] # YUV def rgb_to_yuv( self, r, g, b ): y = self.List_Mult_3( [ self.luma_r , self.luma_g , self.luma_b ], [ r, g, b ] ) u = self.List_Mult_3( [ -0.5*((self.luma_r)/(1-self.luma_b)) , -0.5*((self.luma_g)/(1-self.luma_b)) , 0.5 ], [ r, g, b ] ) v = self.List_Mult_3( [ 0.5 , -0.5*((self.luma_g)/(1-self.luma_r)) , -0.5*((self.luma_b)/(1-self.luma_r)) ], [ r, g, b ] ) y, u, v = self.Vector_Safe( y, 0.5 + u, 0.5 + v ) return [ y, u, v ] def yuv_to_rgb( self, y, u, v ): u -= 0.5 v -= 0.5 if self.luminosity == "ITU-R BT.2020": r = self.List_Mult_3( [ 1 , 0 , 1.4746 ], [ y, u, v ] ) g = self.List_Mult_3( [ 1 , -0.16455312684366 , -0.57135312684366 ], [ y, u, v ] ) b = self.List_Mult_3( [ 1 , 1.8814 , 0 ], [ y, u, v ] ) else: r = self.List_Mult_3( [ 1 , 0 , 2-2*self.luma_r ], [ y, u, v ] ) g = self.List_Mult_3( [ 1 , -(self.luma_b/self.luma_g)*(2-2*self.luma_b) , -(self.luma_r/self.luma_g)*(2-2*self.luma_r) ], [ y, u, v ] ) b = self.List_Mult_3( [ 1 , 2-2*self.luma_b , 0 ], [ y, u, v ] ) r, g, b = self.Vector_Safe( r, g, b ) return [r,g,b] #endregion #region RGB HUE ################################################################ # HUE RGB def rgb_to_hue( self, r, g, b ): # In case Krita is in Linear Format if self.d_cd != "U8": lsl = self.lrgb_to_srgb( r, g, b ) r = lsl[0] g = lsl[1] b = lsl[2] maxc = max( r, g, b ) minc = min( r, g, b ) if minc == maxc: return self.hue # Hue = 0 rc = ( maxc-r ) / ( maxc-minc ) gc = ( maxc-g ) / ( maxc-minc ) bc = ( maxc-b ) / ( maxc-minc ) if r == maxc: h = bc-gc elif g == maxc: h = 2.0 + rc - bc else: h = 4.0 + gc - rc h = ( h / 6.0 ) % 1.0 return h def hue_to_rgb( self, h ): vh = h * 6 if vh == 6 : vh = 0 vi = int( vh ) v2 = 1 * ( 1 - 1 * ( vh - vi ) ) v3 = 1 * ( 1 - 1 * ( 1 - ( vh - vi ) ) ) if vi == 0 : r = 1 g = v3 b = 0 elif vi == 1 : r = v2 g = 1 b = 0 elif vi == 2 : r = 0 g = 1 b = v3 elif vi == 3 : r = 0 g = v2 b = 1 elif vi == 4 : r = v3 g = 0 b = 1 else: r = 1 g = 0 b = v2 # In case Krita is in Linear Format if self.d_cd != "U8": lsl = self.srgb_to_lrgb( r, g, b ) r = lsl[0] g = lsl[1] b = lsl[2] return [r, g, b] # HUE Digital-Analog or RGB-RYB def hue_to_hue( self, mode, angle ): if mode == "DIGITAL": hue_d = angle hue_a = self.hued_to_huea( angle ) if mode == "ANALOG": hue_d = self.huea_to_hued( angle ) hue_a = angle return hue_d, hue_a def hued_to_huea( self, hued ): # convertion hued = self.geometry.Limit_Looper( hued, 1 ) for i in range( len( digital_step ) ): if hued == digital_step[i]: huea = analog_step[i] for i in range( len( digital_step )-1 ): if ( hued > digital_step[i] and hued < digital_step[i+1] ): var = ( hued - digital_step[i] ) / ( digital_step[i+1] - digital_step[i] ) huea = ( analog_step[i] + ( analog_step[i+1] - analog_step[i] ) * var ) return huea def huea_to_hued( self, huea ): # convertion hued = self.geometry.Limit_Looper( huea, 1 ) for i in range( len( analog_step ) ): if huea == analog_step[i]: hued = digital_step[i] for i in range( len( analog_step )-1 ): if ( huea > analog_step[i] and huea < analog_step[i+1] ): var = ( huea - analog_step[i] ) / ( analog_step[i+1] - analog_step[i] ) hued = ( digital_step[i] + ( digital_step[i+1] - digital_step[i] ) * var ) return hued # Hue YUV def yuv_to_angle( self, y, u, v, a ): # delta du = u dv = v if du >= 0.5:du = 1 - u if dv >= 0.5:dv = 1 - v if du <= dv:ds = du else:ds = dv # Points p1x = ds p1y = ds p2x = ds p2y = 1 - ds p3x = 1 - ds p3y = 1 - ds p4x = 1 - ds p4y = ds # angles az = self.geometry.Limit_Looper( self.geometry.Trig_2D_Points_Lines_Angle( u, v, 0.5, 0.5, 0, 0 ), 360 ) aa = self.geometry.Limit_Looper( az - a*360, 360 ) if a == 0: sx = u sy = v else: if ( aa <= 90 ): sx, sy = self.geometry.Lerp_2D( aa/90, p1x, p1y, p2x, p2y ) if ( aa > 90 and aa <= 180 ): sx, sy = self.geometry.Lerp_2D( (aa-90)/90, p2x, p2y, p3x, p3y ) if ( aa > 180 and aa <= 270 ): sx, sy = self.geometry.Lerp_2D( (aa-180)/90, p3x, p3y, p4x, p4y ) if ( aa > 270 ): sx, sy = self.geometry.Lerp_2D( (aa-270)/90, p4x, p4y, p1x, p1y ) # Return return y, sx, sy # HSV def rgb_to_hsv( self, r, g, b ): # In case Krita is in Linear Format if self.d_cd != "U8": lsl = self.lrgb_to_srgb( r, g, b ) r = lsl[0] g = lsl[1] b = lsl[2] # sRGB to HSX v_min = min( r, g, b ) v_max = max( r, g, b ) d_max = v_max - v_min v = v_max if d_max == 0: h = self.hue s = 0 else: s = d_max / v_max d_r = ( ( ( v_max - r ) / 6 ) + ( d_max / 2 ) ) / d_max d_g = ( ( ( v_max - g ) / 6 ) + ( d_max / 2 ) ) / d_max d_b = ( ( ( v_max - b ) / 6 ) + ( d_max / 2 ) ) / d_max if r == v_max : h = d_b - d_g elif g == v_max : h = ( 1 / 3 ) + d_r - d_b elif b == v_max : h = ( 2 / 3 ) + d_g - d_r if h < 0 : h += 1 if h > 1 : h -= 1 return [h, s, v] def hsv_to_rgb( self, h, s, v ): # HSX to sRGB if s == 0: r = v g = v b = v else: vh = h * 6 if vh == 6 : vh = 0 vi = int( vh ) v1 = v * ( 1 - s ) v2 = v * ( 1 - s * ( vh - vi ) ) v3 = v * ( 1 - s * ( 1 - ( vh - vi ) ) ) if vi == 0 : r = v g = v3 b = v1 elif vi == 1 : r = v2 g = v b = v1 elif vi == 2 : r = v1 g = v b = v3 elif vi == 3 : r = v1 g = v2 b = v elif vi == 4 : r = v3 g = v1 b = v else: r = v g = v1 b = v2 # In case Krita is in Linear Format if self.d_cd != "U8": lsl = self.srgb_to_lrgb( r, g, b ) r = lsl[0] g = lsl[1] b = lsl[2] return [r, g, b] # HSL def rgb_to_hsl( self, r, g, b ): # In case Krita is in Linear Format if self.d_cd != "U8": lsl = self.lrgb_to_srgb( r, g, b ) r = lsl[0] g = lsl[1] b = lsl[2] # sRGB to HSX v_min = min( r, g, b ) v_max = max( r, g, b ) d_max = v_max - v_min l = ( v_max + v_min )/ 2 if d_max == 0 : h = self.hue s = 0 else: if l < 0.5 : s = d_max / ( v_max + v_min ) else: s = d_max / ( 2 - v_max - v_min ) d_r = ( ( ( v_max - r ) / 6 ) + ( d_max / 2 ) ) / d_max d_g = ( ( ( v_max - g ) / 6 ) + ( d_max / 2 ) ) / d_max d_b = ( ( ( v_max - b ) / 6 ) + ( d_max / 2 ) ) / d_max if r == v_max : h = d_b - d_g elif g == v_max: h = ( 1 / 3 ) + d_r - d_b elif b == v_max: h = ( 2 / 3 ) + d_g - d_r if h < 0: h += 1 if h > 1: h -= 1 return [h, s, l] def hsl_to_rgb( self, h, s, l ): if s == 0 : r = l g = l b = l else: if l < 0.5: v2 = l * ( 1 + s ) else: v2 = ( l + s ) - ( s * l ) v1 = 2 * l - v2 r = self.hsl_chan( v1, v2, h + ( 1 / 3 ) ) g = self.hsl_chan( v1, v2, h ) b = self.hsl_chan( v1, v2, h - ( 1 / 3 ) ) # In case Krita is in Linear Format if self.d_cd != "U8": lsl = self.srgb_to_lrgb( r, g, b ) r = lsl[0] g = lsl[1] b = lsl[2] return [r, g, b] def hsl_chan( self, v1, v2, vh ): if vh < 0 : vh += 1 if vh > 1 : vh -= 1 if ( 6 * vh ) < 1 : return ( v1 + ( v2 - v1 ) * 6 * vh ) if ( 2 * vh ) < 1 : return ( v2 ) if ( 3 * vh ) < 2 : return ( v1 + ( v2 - v1 ) * ( ( 2 / 3 ) - vh ) * 6 ) return ( v1 ) # HSY ( Krita version ) def rgb_to_hsy( self, r, g, b ): # In case Krita is NOT in Linear Format if self.d_cd == "U8": lsl = self.srgb_to_lrgb( r, g, b ) r = lsl[0] g = lsl[1] b = lsl[2] # sRGB to HSX minval = min( r, g, b ) maxval = max( r, g, b ) luma = ( self.luma_r * r + self.luma_g * g + self.luma_b * b ) luma_a = luma chroma = maxval - minval max_sat = 0.5 if chroma == 0: hue = self.hue sat = 0 else: if maxval == r: if minval == b: hue = ( g - b ) / chroma else: hue = ( g - b ) / chroma + 6 elif maxval == g: hue = ( b - r ) / chroma + 2 elif maxval == b: hue = ( r - g ) / chroma + 4 hue /= 6 # segment = 0.166667 segment = 1 / 6 if ( hue > 1 or hue < 0 ): hue = math.fmod( hue, 1 ) if ( hue >= 0 * segment and hue < 1 * segment ): max_sat = self.luma_r + self.luma_g * ( hue * 6 ) elif ( hue >= 1 * segment and hue < 2 * segment ): max_sat = ( self.luma_g + self.luma_r ) - self.luma_r * ( ( hue - segment ) * 6 ) elif ( hue >= 2 * segment and hue < 3 * segment ): max_sat = self.luma_g + self.luma_b * ( ( hue - 2 * segment ) * 6 ) elif ( hue >= 3 * segment and hue < 4 * segment ): max_sat = ( self.luma_b + self.luma_g ) - self.luma_g * ( ( hue - 3 * segment ) * 6 ) elif ( hue >= 4 * segment and hue < 5 * segment ): max_sat = ( self.luma_b ) + self.luma_r * ( ( hue - 4 * segment ) * 6 ) elif ( hue >= 5 * segment and hue <= 1 ): max_sat = ( self.luma_r + self.luma_b ) - self.luma_b * ( ( hue - 5 * segment ) * 6 ) else: max_sat = 0.5 if( max_sat > 1 or max_sat < 0 ): max_sat = math.fmod( max_sat, 1 ) if luma <= max_sat: luma_a = ( luma / max_sat ) * 0.5 else: luma_a = ( ( luma-max_sat ) / ( 1 - max_sat ) * 0.5 ) + 0.5 if ( chroma > 0 ): sat = ( ( chroma / ( 2 * luma_a ) ) if ( luma <= max_sat ) else ( chroma / ( 2 - ( 2 * luma_a ) ) ) ) if sat <= 0: sat = 0 if luma <= 0: luma = 0 h = hue s = sat y = luma ** ( 1 / self.gamma_y ) return [h, s, y] def hsy_to_rgb( self, h, s, y ): hue = 0 sat = 0 luma = 0 if ( h > 1 or h < 0 ): hue = math.fmod( h, 1 ) else: hue = h if s < 0: sat = 0 else: sat = s if y < 0: luma = 0 else: luma = y ** ( self.gamma_y ) # segment = 0.166667 segment = 1 / 6 r = 0 g = 0 b = 0 if ( hue >= 0 and hue < segment ): max_sat = self.luma_r + ( self.luma_g * ( hue * 6 ) ) if luma <= max_sat: luma_a = ( luma / max_sat ) * 0.5 chroma = sat * 2 * luma_a else: luma_a = ( ( luma-max_sat ) / ( 1 - max_sat ) * 0.5 ) + 0.5 chroma = sat * ( 2 - 2 * luma_a ) fract = hue * 6 x = ( 1 - abs( math.fmod( fract, 2 ) - 1 ) ) * chroma r = chroma g = x b = 0 m = luma - ( ( self.luma_r * r ) + ( self.luma_b * b ) + ( self.luma_g * g ) ) r += m g += m b += m elif ( hue >= ( segment ) and hue < 2 * segment ): max_sat = ( self.luma_g + self.luma_r ) - ( self.luma_r * ( hue - segment ) * 6 ) if luma < max_sat: luma_a = ( luma / max_sat ) * 0.5 chroma = sat * ( 2 * luma_a ) else: luma_a = ( ( luma-max_sat ) / ( 1 - max_sat ) * 0.5 ) + 0.5 chroma = sat * ( 2 - 2 * luma_a ) fract = hue * 6 x = ( 1 - abs( math.fmod( fract, 2 ) - 1 ) ) * chroma r = x g = chroma b = 0 m = luma - ( ( self.luma_r * r ) + ( self.luma_b * b ) + ( self.luma_g * g ) ) r += m g += m b += m elif ( hue >= 2 * segment and hue < 3 * segment ): max_sat = self.luma_g + ( self.luma_b * ( hue - 2 * segment ) * 6 ) if luma < max_sat: luma_a = ( luma / max_sat ) * 0.5 chroma = sat * ( 2 * luma_a ) else: luma_a = ( ( luma-max_sat ) / ( 1 - max_sat ) * 0.5 ) + 0.5 chroma = sat * ( 2 - 2 * luma_a ) fract = hue * 6 x = ( 1 - abs( math.fmod( fract, 2 ) - 1 ) ) * chroma r = 0 g = chroma b = x m = luma - ( ( self.luma_r * r ) + ( self.luma_b * b ) + ( self.luma_g * g ) ) r += m g += m b += m elif ( hue >= 3 * segment and hue < 4 * segment ): max_sat = ( self.luma_g + self.luma_b ) - ( self.luma_g * ( hue - 3 * segment ) * 6 ) if luma < max_sat: luma_a = ( luma / max_sat ) * 0.5 chroma = sat * ( 2 * luma_a ) else: luma_a = ( ( luma-max_sat ) / ( 1 - max_sat ) * 0.5 ) + 0.5 chroma = sat * ( 2 - 2 * luma_a ) fract = hue * 6 x = ( 1 - abs( math.fmod( fract, 2 ) - 1 ) ) * chroma r = 0 g = x b = chroma m = luma - ( ( self.luma_r * r ) + ( self.luma_b * b ) + ( self.luma_g * g ) ) r += m g += m b += m elif ( hue >= 4 * segment and hue < 5 * segment ): max_sat = self.luma_b + ( self.luma_r * ( ( hue - 4 * segment ) * 6 ) ) if luma < max_sat: luma_a = ( luma / max_sat ) * 0.5 chroma = sat * ( 2 * luma_a ) else: luma_a = ( ( luma-max_sat ) / ( 1 - max_sat ) * 0.5 ) + 0.5 chroma = sat * ( 2 - 2 * luma_a ) fract = hue * 6 x = ( 1 - abs( math.fmod( fract, 2 ) - 1 ) ) * chroma r = x g = 0 b = chroma m = luma - ( ( self.luma_r * r ) + ( self.luma_b * b ) + ( self.luma_g * g ) ) r += m g += m b += m elif ( hue >= 5 * segment and hue <= 1 ): max_sat = ( self.luma_b + self.luma_r ) - ( self.luma_b * ( hue - 5 * segment ) * 6 ) if luma < max_sat: luma_a = ( luma / max_sat ) * 0.5 chroma = sat * ( 2 * luma_a ) else: luma_a = ( ( luma-max_sat ) / ( 1-max_sat ) * 0.5 ) + 0.5 chroma = sat * ( 2 - 2 * luma_a ) fract = hue * 6 x = ( 1 - abs( math.fmod( fract, 2 ) - 1 ) ) * chroma r = chroma g = 0 b = x m = luma - ( ( self.luma_r * r ) + ( self.luma_b * b ) + ( self.luma_g * g ) ) r += m g += m b += m else: r = 0 g = 0 b = 0 if r < 0: r = 0 if g < 0: g = 0 if b < 0: b = 0 # In case Krita is NOT in Linear Format if self.d_cd == "U8": lsl = self.lrgb_to_srgb( r, g, b ) r = lsl[0] g = lsl[1] b = lsl[2] return [r, g, b] # HCY ( My Paint Version ) def rgb_to_hcy( self, r, g, b ): # In case Krita is NOT in Linear Format if self.d_cd != "U8": # == vs != lsl = self.srgb_to_lrgb( r, g, b ) r = lsl[0] g = lsl[1] b = lsl[2] # sRGB to HSX y = self.luma_r*r + self.luma_g*g + self.luma_b*b p = max( r, g, b ) n = min( r, g, b ) d = p - n if n == p: h = self.hue elif p == r: h = ( g - b )/d if h < 0: h += 6.0 elif p == g: h = ( ( b - r )/d ) + 2.0 else: # p==b h = ( ( r - g )/d ) + 4.0 h /= 6.0 if ( r == g == b or y == 0 or y == 1 ): h = self.hue c = 0.0 else: c = max( ( y-n )/y, ( p-y )/( 1-y ) ) if self.d_cd != "U8": # == vs != y = y**( 1/self.gamma_y ) # Gama compression of the luma value return [h, c, y] def hcy_to_rgb( self, h, c, y ): if self.d_cd != "U8": # == vs != y = y**( self.gamma_y ) # Gama compression of the luma value if c == 0: r = y g = y b = y h %= 1.0 h *= 6.0 if h < 1: th = h tm = self.luma_r + self.luma_g * th elif h < 2: th = 2.0 - h tm = self.luma_g + self.luma_r * th elif h < 3: th = h - 2.0 tm = self.luma_g + self.luma_b * th elif h < 4: th = 4.0 - h tm = self.luma_b + self.luma_g * th elif h < 5: th = h - 4.0 tm = self.luma_b + self.luma_r * th else: th = 6.0 - h tm = self.luma_r + self.luma_b * th # Calculate the RGB components in sorted order if tm >= y: p = y + y*c*( 1-tm )/tm o = y + y*c*( th-tm )/tm n = y - ( y*c ) else: p = y + ( 1-y )*c o = y + ( 1-y )*c*( th-tm )/( 1-tm ) n = y - ( 1-y )*c*tm/( 1-tm ) # Back to RGB order if h < 1: r = p g = o b = n elif h < 2: r = o g = p b = n elif h < 3: r = n g = p b = o elif h < 4: r = n g = o b = p elif h < 5: r = o g = n b = p else: r = p g = n b = o # In case Krita is NOT in Linear Format if self.d_cd != "U8": # == vs != lsl = self.lrgb_to_srgb( r, g, b ) r = lsl[0] g = lsl[1] b = lsl[2] return [r, g, b] # ARD def rgb_to_ard( self, r, g, b ): # In case Krita is in Linear Format if self.d_cd != "U8": lsl = self.lrgb_to_srgb( r, g, b ) r = lsl[0] g = lsl[1] b = lsl[2] # Depth uvd = self.rgb_to_uvd( r, g, b ) u = uvd[0] v = uvd[1] d = uvd[2] # Hexagon Depth di = d * 3 if ( di == 0 or di == 1 ): a = self.hue r = 0 else: # Angle a = self.rgb_to_hue( r, g, b) # Channel O1, O2, O3, O4, O5, O6, C12, C23, C34, C45, C56, C61 = self.uvd_hexagon( d, 1, 0, 1 ) c = self.ard_channel( d, a, O1, O2, O3, O4, O5, O6, C12, C23, C34, C45, C56, C61 ) # Ratio if ( r == g and g == b and b == r ): r = 0 elif ( r == 0 or g == 0 or b == 0 or r == 1 or g == 1 or b == 1 ): r = 1 else: # Neutral Value n = ( r + g + b ) / 3 # Ratio = 0 # Delta dr = r - n dg = g - n db = b - n # Ratio Distance if c == +1:r = dr / ( 1 - n ) if c == -1:r = dr / -n if c == +2:r = dg / ( 1 - n ) if c == -2:r = dg / -n if c == +3:r = db / ( 1 - n ) if c == -3:r = db / -n # Return return [ a, r, d ] def ard_to_rgb( self, a, r, d ): # QtCore.qDebug( f"value = { value }" ) # Channel di = d * 3 lu = 0 lv = 0 if di <= 0: r = 0 g = 0 b = 0 elif di >= 3: r = 1 g = 1 b = 1 else: # Hexagon O1, O2, O3, O4, O5, O6, C12, C23, C34, C45, C56, C61 = self.uvd_hexagon( d, 1, 0, 1 ) # Angle hrgb = self.hue_to_rgb( a ) huvd = self.rgb_to_uvd( hrgb[0], hrgb[1], hrgb[2] ) acc = self.geometry.Trig_2D_Points_Lines_Angle( huvd[0], huvd[1], 0, 0, C61[0], C61[1] ) / 360 # Angle a01 = self.geometry.Trig_2D_Points_Lines_Angle( O1[0], O1[1], 0, 0, C61[0], C61[1] ) / 360 a02 = self.geometry.Trig_2D_Points_Lines_Angle( O2[0], O2[1], 0, 0, C61[0], C61[1] ) / 360 a03 = self.geometry.Trig_2D_Points_Lines_Angle( O3[0], O3[1], 0, 0, C61[0], C61[1] ) / 360 a04 = self.geometry.Trig_2D_Points_Lines_Angle( O4[0], O4[1], 0, 0, C61[0], C61[1] ) / 360 a05 = self.geometry.Trig_2D_Points_Lines_Angle( O5[0], O5[1], 0, 0, C61[0], C61[1] ) / 360 a06 = self.geometry.Trig_2D_Points_Lines_Angle( O6[0], O6[1], 0, 0, C61[0], C61[1] ) / 360 a12 = self.geometry.Trig_2D_Points_Lines_Angle( C12[0], C12[1], 0, 0, C61[0], C61[1] ) / 360 a23 = self.geometry.Trig_2D_Points_Lines_Angle( C23[0], C23[1], 0, 0, C61[0], C61[1] ) / 360 a34 = self.geometry.Trig_2D_Points_Lines_Angle( C34[0], C34[1], 0, 0, C61[0], C61[1] ) / 360 a45 = self.geometry.Trig_2D_Points_Lines_Angle( C45[0], C45[1], 0, 0, C61[0], C61[1] ) / 360 a56 = self.geometry.Trig_2D_Points_Lines_Angle( C56[0], C56[1], 0, 0, C61[0], C61[1] ) / 360 # Depth if ( di > 0 and di <= 1): if ( acc <= a23 ): lu, lv = self.geometry.Trig_2D_Points_Lines_Intersection( huvd[0], huvd[1], 0, 0, C61[0], C61[1], C23[0], C23[1] ) elif ( acc > a23 and acc <= a45 ): lu, lv = self.geometry.Trig_2D_Points_Lines_Intersection( huvd[0], huvd[1], 0, 0, C23[0], C23[1], C45[0], C45[1] ) else: lu, lv = self.geometry.Trig_2D_Points_Lines_Intersection( huvd[0], huvd[1], 0, 0, C45[0], C45[1], C61[0], C61[1] ) elif ( di > 1 and di < 2): if ( acc <= a01 ): lu, lv = self.geometry.Trig_2D_Points_Lines_Intersection( huvd[0], huvd[1], 0, 0, C61[0], C61[1], O1[0], O1[1] ) elif ( acc > a01 and acc <= a02 ): lu, lv = self.geometry.Trig_2D_Points_Lines_Intersection( huvd[0], huvd[1], 0, 0, O1[0], O1[1], O2[0], O2[1] ) elif ( acc > a02 and acc <= a03 ): lu, lv = self.geometry.Trig_2D_Points_Lines_Intersection( huvd[0], huvd[1], 0, 0, O2[0], O2[1], O3[0], O3[1] ) elif ( acc > a03 and acc <= a04 ): lu, lv = self.geometry.Trig_2D_Points_Lines_Intersection( huvd[0], huvd[1], 0, 0, O3[0], O3[1], O4[0], O4[1] ) elif ( acc > a04 and acc <= a05 ): lu, lv = self.geometry.Trig_2D_Points_Lines_Intersection( huvd[0], huvd[1], 0, 0, O4[0], O4[1], O5[0], O5[1] ) elif ( acc > a05 and acc <= a06 ): lu, lv = self.geometry.Trig_2D_Points_Lines_Intersection( huvd[0], huvd[1], 0, 0, O5[0], O5[1], O6[0], O6[1] ) else: lu, lv = self.geometry.Trig_2D_Points_Lines_Intersection( huvd[0], huvd[1], 0, 0, O6[0], O6[1], C61[0], C61[1] ) elif ( di >= 2 and di < 3): if ( acc <= a12 ): lu, lv = self.geometry.Trig_2D_Points_Lines_Intersection( huvd[0], huvd[1], 0, 0, C61[0], C61[1], C12[0], C12[1] ) elif ( acc > a12 and acc <= a34 ): lu, lv = self.geometry.Trig_2D_Points_Lines_Intersection( huvd[0], huvd[1], 0, 0, C12[0], C12[1], C34[0], C34[1] ) elif ( acc > a34 and acc <= a56 ): lu, lv = self.geometry.Trig_2D_Points_Lines_Intersection( huvd[0], huvd[1], 0, 0, C34[0], C34[1], C56[0], C56[1] ) else: lu, lv = self.geometry.Trig_2D_Points_Lines_Intersection( huvd[0], huvd[1], 0, 0, C56[0], C56[1], C61[0], C61[1] ) # UVD Interpolation uvd = self.geometry.Lerp_3D( r, 0, 0, d, lu, lv, d ) rgb = self.uvd_to_rgb( uvd[0], uvd[1], uvd[2] ) r = rgb[0] g = rgb[1] b = rgb[2] # In case Krita is in Linear Format if self.d_cd != "U8": lsl = self.srgb_to_lrgb( r, g, b ) r = lsl[0] g = lsl[1] b = lsl[2] return [r, g, b] def uvd_hexagon( self, d, s, o, i ): # s = scale # o = offset center # i = invert Y axis ( panel is inverted ) # Primaries cn = [ 0, 0 ] cr = self.rgb_to_uvd( 1, 0, 0 ) cy = self.rgb_to_uvd( 1, 1, 0 ) cg = self.rgb_to_uvd( 0, 1, 0 ) cc = self.rgb_to_uvd( 0, 1, 1 ) cb = self.rgb_to_uvd( 0, 0, 1 ) cm = self.rgb_to_uvd( 1, 0, 1 ) # Single Points di = d * 3 u0 = 0 u1 = 1 u2 = 2 u3 = 3 if ( di <= u0 or di >= u3 ): # Original O1 = [ o, o ] O2 = [ o, o ] O3 = [ o, o ] O4 = [ o, o ] O5 = [ o, o ] O6 = [ o, o ] # Complementary C12 = [ o, o ] C23 = [ o, o ] C34 = [ o, o ] C45 = [ o, o ] C56 = [ o, o ] C61 = [ o, o ] else: # Original if ( di >= u0 and di <= u1): p = di o1_u, o1_v = self.geometry.Lerp_2D( p, cn[0], cn[1], cr[0], cr[1] ) o2_u, o2_v = self.geometry.Lerp_2D( p, cn[0], cn[1], cg[0], cg[1] ) o3_u, o3_v = self.geometry.Lerp_2D( p, cn[0], cn[1], cg[0], cg[1] ) o4_u, o4_v = self.geometry.Lerp_2D( p, cn[0], cn[1], cb[0], cb[1] ) o5_u, o5_v = self.geometry.Lerp_2D( p, cn[0], cn[1], cb[0], cb[1] ) o6_u, o6_v = self.geometry.Lerp_2D( p, cn[0], cn[1], cr[0], cr[1] ) elif ( di > u1 and di < u2): p = di - 1 o1_u, o1_v = self.geometry.Lerp_2D( p, cr[0], cr[1], cy[0], cy[1] ) o2_u, o2_v = self.geometry.Lerp_2D( p, cg[0], cg[1], cy[0], cy[1] ) o3_u, o3_v = self.geometry.Lerp_2D( p, cg[0], cg[1], cc[0], cc[1] ) o4_u, o4_v = self.geometry.Lerp_2D( p, cb[0], cb[1], cc[0], cc[1] ) o5_u, o5_v = self.geometry.Lerp_2D( p, cb[0], cb[1], cm[0], cm[1] ) o6_u, o6_v = self.geometry.Lerp_2D( p, cr[0], cr[1], cm[0], cm[1] ) elif ( di >= u2 and di <= u3): p = di - 2 o1_u, o1_v = self.geometry.Lerp_2D( p, cy[0], cy[1], cn[0], cn[1] ) o2_u, o2_v = self.geometry.Lerp_2D( p, cy[0], cy[1], cn[0], cn[1] ) o3_u, o3_v = self.geometry.Lerp_2D( p, cc[0], cc[1], cn[0], cn[1] ) o4_u, o4_v = self.geometry.Lerp_2D( p, cc[0], cc[1], cn[0], cn[1] ) o5_u, o5_v = self.geometry.Lerp_2D( p, cm[0], cm[1], cn[0], cn[1] ) o6_u, o6_v = self.geometry.Lerp_2D( p, cm[0], cm[1], cn[0], cn[1] ) # Original O1 = [ o1_u * s + o, i * o1_v * s + o ] O2 = [ o2_u * s + o, i * o2_v * s + o ] O3 = [ o3_u * s + o, i * o3_v * s + o ] O4 = [ o4_u * s + o, i * o4_v * s + o ] O5 = [ o5_u * s + o, i * o5_v * s + o ] O6 = [ o6_u * s + o, i * o6_v * s + o ] # Complemtary C12 = self.geometry.Lerp_2D( 0.5, O1[0], O1[1], O2[0], O2[1] ) C23 = self.geometry.Lerp_2D( 0.5, O2[0], O2[1], O3[0], O3[1] ) C34 = self.geometry.Lerp_2D( 0.5, O3[0], O3[1], O4[0], O4[1] ) C45 = self.geometry.Lerp_2D( 0.5, O4[0], O4[1], O5[0], O5[1] ) C56 = self.geometry.Lerp_2D( 0.5, O5[0], O5[1], O6[0], O6[1] ) C61 = self.geometry.Lerp_2D( 0.5, O6[0], O6[1], O1[0], O1[1] ) # Red Hue=0 # Return return O1, O2, O3, O4, O5, O6, C12, C23, C34, C45, C56, C61 def ard_channel( self, d, a, O1, O2, O3, O4, O5, O6, C12, C23, C34, C45, C56, C61 ): # Angle a01 = self.geometry.Trig_2D_Points_Lines_Angle( O1[0], O1[1], 0, 0, C61[0], C61[1] ) / 360 a02 = self.geometry.Trig_2D_Points_Lines_Angle( O2[0], O2[1], 0, 0, C61[0], C61[1] ) / 360 a03 = self.geometry.Trig_2D_Points_Lines_Angle( O3[0], O3[1], 0, 0, C61[0], C61[1] ) / 360 a04 = self.geometry.Trig_2D_Points_Lines_Angle( O4[0], O4[1], 0, 0, C61[0], C61[1] ) / 360 a05 = self.geometry.Trig_2D_Points_Lines_Angle( O5[0], O5[1], 0, 0, C61[0], C61[1] ) / 360 a06 = self.geometry.Trig_2D_Points_Lines_Angle( O6[0], O6[1], 0, 0, C61[0], C61[1] ) / 360 a12 = self.geometry.Trig_2D_Points_Lines_Angle( C12[0], C12[1], 0, 0, C61[0], C61[1] ) / 360 a23 = self.geometry.Trig_2D_Points_Lines_Angle( C23[0], C23[1], 0, 0, C61[0], C61[1] ) / 360 a34 = self.geometry.Trig_2D_Points_Lines_Angle( C34[0], C34[1], 0, 0, C61[0], C61[1] ) / 360 a45 = self.geometry.Trig_2D_Points_Lines_Angle( C45[0], C45[1], 0, 0, C61[0], C61[1] ) / 360 a56 = self.geometry.Trig_2D_Points_Lines_Angle( C56[0], C56[1], 0, 0, C61[0], C61[1] ) / 360 a61 = 1 # Channel di = d * 3 if ( di <= 0 or di >= 3 ): c = +1 elif ( di > 0 and di <= 1): if ( a <= a23 ):c = -3 elif ( a > a23 and a <= a45 ):c = -1 else:c = -2 elif ( di > 1 and di < 2): if ( a <= a01 ):c = +1 elif ( a > a01 and a <= a02 ):c = -3 elif ( a > a02 and a <= a03 ):c = +2 elif ( a > a03 and a <= a04 ):c = -1 elif ( a > a04 and a <= a05 ):c = +3 elif ( a > a05 and a <= a06 ):c = -2 else:c = +1 elif ( di >= 2 and di < 3): if ( a <= a12 ):c = +1 elif ( a > a12 and a <= a34 ):c = +2 elif ( a > a34 and a <= a56 ):c = +3 else:c = +1 # Return return c #endregion #region XYZ LINEAR ############################################################# def rgb_to_xyz( self, r, g, b ): lrgb = self.srgb_to_lrgb( r, g, b ) x = ( lrgb[0] * self.m_rgb_xyz[0][0] ) + ( lrgb[1] * self.m_rgb_xyz[0][1] ) + ( lrgb[2] * self.m_rgb_xyz[0][2] ) y = ( lrgb[0] * self.m_rgb_xyz[1][0] ) + ( lrgb[1] * self.m_rgb_xyz[1][1] ) + ( lrgb[2] * self.m_rgb_xyz[1][2] ) z = ( lrgb[0] * self.m_rgb_xyz[2][0] ) + ( lrgb[1] * self.m_rgb_xyz[2][1] ) + ( lrgb[2] * self.m_rgb_xyz[2][2] ) return [x, y, z] def xyz_to_rgb( self, x, y, z ): var_r = ( x * self.m_xyz_rgb[0][0] ) + ( y * self.m_xyz_rgb[0][1] ) + ( z * self.m_xyz_rgb[0][2] ) var_g = ( x * self.m_xyz_rgb[1][0] ) + ( y * self.m_xyz_rgb[1][1] ) + ( z * self.m_xyz_rgb[1][2] ) var_b = ( x * self.m_xyz_rgb[2][0] ) + ( y * self.m_xyz_rgb[2][1] ) + ( z * self.m_xyz_rgb[2][2] ) srgb = self.lrgb_to_srgb( var_r, var_g, var_b ) r, g, b = self.Vector_Safe( srgb[0], srgb[1], srgb[2] ) return [r, g, b] # XYY def xyz_to_xyy( self, x, y, z ): if ( x == 0 and y == 0 and z == 0 ): x1 = 0.31272660439158345 y2 = 0.3290231524027522 y3 = y else: x1 = x / ( x + y + z ) y2 = y / ( x + y + z ) y3 = y return [x1, y2, y3] def xyy_to_xyz( self, x1, y2, y3 ): if y2 == 0: x = 0 y = 0 z = 0 else: x = ( x1 * y3 ) / y2 y = y3 z = ( ( 1 - x1 - y2 ) * y3 ) / y2 return [x, y, z] def rgb_to_xyy( self, r, g, b ): xyz = self.rgb_to_xyz( r, g, b ) xyy = self.xyz_to_xyy( xyz[0], xyz[1], xyz[2] ) return [xyy[0], xyy[1], xyy[2]] def xyy_to_rgb( self, x, y1, y2 ): xyz = self.xyy_to_xyz( x, y1, y2 ) rgb = self.xyz_to_rgb( xyz[0], xyz[1], xyz[2] ) return [rgb[0], rgb[1], rgb[2]] # LAB def xyz_to_lab( self, x, y, z ): k = 903.3 # Kappa e = 0.008856 # Epsilon rx = x / self.ref_x ry = y / self.ref_y rz = z / self.ref_z if rx > e: fx = rx**( 1/3 ) else: fx = ( k*rx + 16 ) / 116 if ry > e: fy = ry**( 1/3 ) else: fy = ( k*ry + 16 ) / 116 if rz > e: fz = rz**( 1/3 ) else: fz = ( k*rz + 16 ) / 116 l = ( ( 116 * fy ) - 16 ) / 100 a = 0.5 + ( fx - fy ) b = 0.5 + ( fy - fz ) return [ l, a, b ] def lab_to_xyz( self, l, a, b ): k = 903.3 # Kappa e = 0.008856 # Epsilon l = l * 100 a = a - 0.5 b = b - 0.5 fy = ( l + 16 ) / 116 fx = a + fy fz = fy - b if fx**3 > e: rx = fx**3 else: rx = ( 116 * fx - 16 ) / k if l > k*e: ry = ( ( l + 16 ) / 116 )**3 else: ry = l / k if fz**3 > e: rz = fz**3 else: rz = ( 116 * fz - 16 ) / k x = rx * self.ref_x y = ry * self.ref_y z = rz * self.ref_z return [ x, y, z ] def rgb_to_lab( self, r, g, b ): xyz = self.rgb_to_xyz( r, g, b ) lab = self.xyz_to_lab( xyz[0], xyz[1], xyz[2] ) return [ lab[0], lab[1], lab[2] ] def lab_to_rgb( self, l, a, b ): xyz = self.lab_to_xyz( l, a, b ) rgb = self.xyz_to_rgb( xyz[0], xyz[1], xyz[2] ) return [ rgb[0], rgb[1], rgb[2] ] #endregion #region XYZ HUE ################################################################ # LCHab def lab_to_lch( self, l, a, b ): a = ( a - 0.5 ) * 2 b = ( b - 0.5 ) * 2 vh = math.atan2( b, a ) if vh > 0: vh = ( vh / math.pi ) * 180 else: vh = 360 - ( abs( vh ) / math.pi ) * 180 c = math.sqrt( a**2 + b**2 ) h = vh / 360 l, c, h = self.Vector_Safe( l, c, h ) return [ l, c, h ] def lch_to_lab( self, l, c, h ): vh = h * 360 a = math.cos( math.radians( vh ) ) * c b = math.sin( math.radians( vh ) ) * c a = a / 2 + 0.5 b = b / 2 + 0.5 l, a, b = self.Vector_Safe( l, a, b ) return [ l, a, b ] def xyz_to_lch( self, x, y, z ): lab = self.xyz_to_lab( x, y, z ) lch = self.lab_to_lch( lab[0], lab[1], lab[2] ) return [ lch[0], lch[1], lch[2] ] def lch_to_xyz( self, l, c, h ): lab = self.lch_to_lab( l, c, h ) xyz = self.lab_to_xyz( lab[0], lab[1], lab[2] ) return [ xyz[0], xyz[1], xyz[2] ] def rgb_to_lch( self, r, g, b ): xyz = self.rgb_to_xyz( r, g, b ) lab = self.xyz_to_lab( xyz[0], xyz[1], xyz[2] ) lch = self.lab_to_lch( lab[0], lab[1], lab[2] ) return [ lch[0], lch[1], lch[2] ] def lch_to_rgb( self, l, c, h ): lab = self.lch_to_lab( l, c, h ) xyz = self.lab_to_xyz( lab[0], lab[1], lab[2] ) rgb = self.xyz_to_rgb( xyz[0], xyz[1], xyz[2] ) return [ rgb[0], rgb[1], rgb[2] ] #endregion #region Non-Color ############################################################## # KELVIN ( not physical based ) def kkk_percent_to_scale( self, percent ): scale = int( ( percent * kkk_delta ) + kkk_min_scale ) return scale def kkk_scale_to_percent( self, scale ): percent = ( scale - kkk_min_scale ) / kkk_delta return percent def kkk_to_rgb( self, temp, lut ): # Entry entry = self.search_entry( temp, lut ) # RGB r = lut[entry][0] g = lut[entry][1] b = lut[entry][2] # Return return [r, g, b] def kkk_to_cd( self, temp, lut ): # Entry entry = self.search_entry( temp, lut ) # Class and Discription c = lut[entry][0] d = lut[entry][1] # Return return [c, d] def search_entry( self, temp, lut ): # Variables key = list( lut.keys() ) length = len( key ) # Search entry = key[0] if ( temp > key[0] ): for i in range( 0, length ): key_i = key[i] if temp < key_i: entry = key[i-1] break if temp == key_i: entry = key_i break entry = key_i return entry #endregion #region HEX #################################################################### def rgb_to_hex6( self, r, g, b ): hex1 = str( hex( int( r * 255 ) ) )[2:4].zfill( 2 ) hex2 = str( hex( int( g * 255 ) ) )[2:4].zfill( 2 ) hex3 = str( hex( int( b * 255 ) ) )[2:4].zfill( 2 ) hex_code = str( "#" + hex1 + hex2 + hex3 ) return hex_code def hex6_to_rgb( self, hex_code ): # Hexadecimal hex1 = int( format( int( hex_code[1:3],16 ),'02d' ) ) hex2 = int( format( int( hex_code[3:5],16 ),'02d' ) ) hex3 = int( format( int( hex_code[5:7],16 ),'02d' ) ) # Range r = hex1 / 255 g = hex2 / 255 b = hex3 / 255 rgb = [r, g, b] return rgb def hex6_to_name( self, hex_code, color_names ): search = color_names.get( hex_code ) if search == None: name = "" else: name = search[0] return name def hex3_to_rgb( self, hex_code ): # Parse hex1 = hex_code[1:2] hex2 = hex_code[2:3] hex3 = hex_code[3:4] # Hexadecimal hex1 = int( format( int( hex1+hex1 ,16 ),'02d' ) ) hex2 = int( format( int( hex2+hex2 ,16 ),'02d' ) ) hex3 = int( format( int( hex3+hex3 ,16 ),'02d' ) ) # Range r = hex1 / 255 g = hex2 / 255 b = hex3 / 255 rgb = [r, g, b] return rgb #endregion