📢作者: 小小明-代码实体
📢博客主页:https://blog.csdn.net/as604049322
📢欢迎点赞 👍 收藏 ⭐留言 📝 欢迎讨论!
openpyxl
支持以下几种颜色类型:
RGB (Red, Green, Blue) : 这是最常用的颜色类型,允许通过指定红、绿、蓝三原色的组合来自定义颜色。RGB值通常以十六进制格式表示。Theme : Excel有一套主题颜色,可以通过指定主题颜色的索引来使用这些颜色。Indexed : 这是Excel早期版本中使用的一种颜色系统,它通过索引号来引用一组预定义的颜色。
对于RGB类型的颜色直接使用cell.fill.start_color.rgb即可获取其颜色,但是对于Theme类型的单元格获取颜色却返回一个错误。
这是因为主题色会随着主题的变化而变化,如下图:
可以看到每个主题有10个基础色,然后受到透明度的影响,我将第一个单元格设置了上图的主题色。
我们创建Excel文件进行测试:
from openpyxl import load_workbook
wb = load_workbook( "color_test.xlsx" )
wbs = wb. active
cell = wbs. cell( 1 , 1 )
cell. fill. start_color
<openpyxl.styles.colors.Color object>
Parameters:
rgb=None, indexed=None, auto=None, theme=5, tint=0.4, type='theme'
可以看到这就是一个theme类型的颜色,确实是索引5的位置,透明度40%。
我们尝试获取rgb颜色:
cell. fill. start_color. rgb
会返回Values must be of type <class 'str'>
这样一个带有错误信息的字符串。
当然也可以调用index属性自动获取rgb或者在主题色中的索引:
cell. fill. start_color. index
5
如果是一个RGB 类型的颜色:
cell = wbs. cell( 1 , 3 )
cell. fill. start_color
<openpyxl.styles.colors.Color object>
Parameters:
rgb='FFF4B382', indexed=None, auto=None, theme=None, tint=0.0, type='rgb'
此时调用index或rgb属性都可以获取rgb颜色值。
那么我们如何获取主题色对应的RGB颜色呢?这个openpyxl并没有提供一个直接的方式,我们只能自己做xml解析了。下面我封装了一个工具类:
from colorsys import rgb_to_hls, hls_to_rgb
class ThemeColorConverter :
RGBMAX = 0xff
HLSMAX = 240
def __init__ ( self, wb) :
self. colors = self. get_theme_colors( wb)
@staticmethod
def tint_luminance ( tint, lum) :
if tint < 0 :
return int ( round ( lum * ( 1.0 + tint) ) )
return int ( round ( ( ThemeColorConverter. HLSMAX - lum) * tint) ) + lum
@staticmethod
def ms_hls_to_rgb ( hue, lightness= None , saturation= None ) :
if lightness is None :
hue, lightness, saturation = hue
hlsmax = ThemeColorConverter. HLSMAX
return hls_to_rgb( hue / hlsmax, lightness / hlsmax, saturation / hlsmax)
@staticmethod
def rgb_to_hex ( red, green= None , blue= None ) :
if green is None :
red, green, blue = red
return '{:02X}{:02X}{:02X}' . format (
int ( red * ThemeColorConverter. RGBMAX) ,
int ( green * ThemeColorConverter. RGBMAX) ,
int ( blue * ThemeColorConverter. RGBMAX)
)
@staticmethod
def rgb_to_ms_hls ( red, green= None , blue= None ) :
if green is None :
if isinstance ( red, str ) :
if len ( red) > 6 :
red = red[ - 6 : ] # Ignore preceding '#' and alpha values
rgbmax = ThemeColorConverter. RGBMAX
blue = int ( red[ 4 : ] , 16 ) / rgbmax
green = int ( red[ 2 : 4 ] , 16 ) / rgbmax
red = int ( red[ 0 : 2 ] , 16 ) / rgbmax
else :
red, green, blue = red
h, l, s = rgb_to_hls( red, green, blue)
hlsmax = ThemeColorConverter. HLSMAX
return ( int ( round ( h * hlsmax) ) , int ( round ( l * hlsmax) ) ,
int ( round ( s * hlsmax) ) )
@staticmethod
def get_theme_colors ( wb) :
from openpyxl. xml. functions import QName, fromstring
xlmns = 'http://schemas./drawingml/2006/main'
root = fromstring( wb. loaded_theme)
themeEl = root. find( QName( xlmns, 'themeElements' ) . text)
colorSchemes = themeEl. findall( QName( xlmns, 'clrScheme' ) . text)
firstColorScheme = colorSchemes[ 0 ]
colors = [ ]
for c in [ 'lt1' , 'dk1' , 'lt2' , 'dk2' , 'accent1' , 'accent2' , 'accent3' , 'accent4' , 'accent5' , 'accent6' ] :
accent = firstColorScheme. find( QName( xlmns, c) . text)
for i in list ( accent) :
if 'window' in i. attrib[ 'val' ] :
colors. append( i. attrib[ 'lastClr' ] )
else :
colors. append( i. attrib[ 'val' ] )
return colors
def theme_and_tint_to_rgb ( self, theme, tint) :
rgb = self. colors[ theme]
h, l, s = self. rgb_to_ms_hls( rgb)
return self. rgb_to_hex( self. ms_hls_to_rgb( h, self. tint_luminance( tint, l) , s) )
具体如何xml解析可以看上面的get_theme_colors函数。
下面我们获取一下当前Excel选中主题的10个基础色调:
theme_color = ThemeColorConverter( wb)
print ( theme_color. colors)
['FFFFFF', '000000', 'E7E6E6', '44546A', '4874CB', 'EE822F', 'F2BA02', '75BD42', '30C0B4', 'E54C5E']
然后我们传入索引和透明度获取颜色:
theme_color. theme_and_tint_to_rgb( 5 , 0.4 )
'F4B281'
但使用取色工具测量第一个单元格的颜色值为#f4b382,有微量误差,这属于正常现象,也完全不会影响视觉。这是因为hls+透明度转rgb颜色的过程中存在小数运算,四舍五入后就会造成一定误差。
人眼对低位数据变化不敏感
在24位位图中高8位构成蓝色通道,中8位构成绿色通道,低8位构成红色通道。经测试,在删除各通道的低4位数据并加入随机噪音后,图片用肉眼无法观察到任何变化。现在展示一张图片在删除各通道的低位数据,并加入随机噪音后图片的变化。
可以看到在每个通道低三位的数据进行随意修改,肉眼几乎看不出变化。低三位,意味着7以内的变化都不会有影响。
最后我们封装一个可以查看任何单元格颜色的函数:
from openpyxl. styles. colors import COLOR_INDEX
def get_cell_color ( cell) :
color = cell. fill. start_color
if color. type == "rgb" :
return color. rgb
elif color. type == "indexed" :
color_index = color. indexed
if color_index is None or color_index < len ( COLOR_INDEX) :
raise Exception( "Invalid indexed color" )
return COLOR_INDEX[ color_index]
elif color. type == "theme" :
return "FF" + theme_color. theme_and_tint_to_rgb( color. theme, color. tint)
else :
raise Exception( f"Other type: { color. type } " )
下面我们将这些主题色都测一测:
theme_color = ThemeColorConverter( wb)
wbs = wb. active
for r in range ( 1 , 4 ) :
colors = [ get_cell_color( wbs. cell( r, c) ) for c in range ( 1 , 8 ) ]
print ( f"第 { r} 行的单元格的颜色为" , colors)
第1行的单元格的颜色为 ['FFFFFFFF', 'FF000000', 'FFE7E6E6', 'FF44546A', 'FF4772CA', 'FFEE802E', 'FFF2BC02']
第2行的单元格的颜色为 ['FFF2F2F2', 'FF7F7F7F', 'FFD0CECE', 'FFD5DBE4', 'FFDAE3F4', 'FFFBE5D5', 'FFFEF2CA']
第3行的单元格的颜色为 ['FFBFBFBF', 'FF3F3F3F', 'FF757070', 'FF8496AF', 'FF90A9DF', 'FFF4B281', 'FFFDDA60']
可以看到,全部获取到低位误差小于1的RGB颜色。
附录
openpyxl获取的颜色值由四组16进制数表示,分别是:
Alpha(透明度):范围也是00
到FF
,其中FF
表示完全不透明,而00
表示完全透明。 红色(Red) 绿色(Green) 蓝色(Blue)
不过在wps中测试,透明度不起任何效果,不排除office或WPS未来版本支持ARGB的颜色,但目前WPS对A通道的透明度值会直接忽略。
本文链接:https://blog.csdn.net/as604049322/article/details/134470419