1836 lines
71 KiB
Python
1836 lines
71 KiB
Python
# 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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
#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 |