如何使用openpyxl为单元格填充50%强度的十六进制颜色
问题背景
Python 3.10环境下使用openpyxl读取sqlite数据库数据生成Excel文件,需要读取库中存储的十六进制格式颜色值,为单元格填充该颜色的50%强度版本。要求填充为纯实色,不能带线条、点阵类的图案填充效果。
现有实现代码如下:
import sqlite3, openpyxl def getRouteColor(route): cursor.execute('''SELECT route_color FROM routes WHERE route_short_name = "{}"'''.format(route)) return cursor.fetchall()[0][0] [...] color = getRouteColor(route) #hexadecimal for column in sheet.columns: for cell in column: if not cell.row % 2: cell.fill = openpyxl.styles.PatternFill(patternType = 'solid', fgColor = color)
尝试调整patternType参数模拟半透明效果未达预期,需要找可行的实现方案,包括openpyxl原生支持的方式,或者十六进制色值换算方法。
实现方案
openpyxl没有提供直接给纯色填充设置透明度的原生API,兼容性最好的方案是预计算50%强度对应的纯色十六进制值,保持solid填充模式即可,不需要调整patternType。
50%强度色值计算逻辑
50%色彩强度的视觉效果等价于目标颜色和纯白色(#FFFFFF)按1:1比例混合,计算规则:
- 将6位十六进制颜色拆分为R(红)、G(绿)、B(蓝)三个通道,分别转为0-255范围的十进制数值
- 每个通道的新值 = 原通道值 * 0.5 + 255(纯白通道值)* 0.5,结果四舍五入取整
- 将计算后的三个通道值转回两位十六进制字符串,不足两位时前面补0,拼接后就是50%强度的色值
可直接复用的代码
先写色值转换函数:
def get_half_intensity_color(hex_color: str) -> str: # 兼容带#前缀的色值输入 hex_color = hex_color.lstrip('#') # 拆分三通道转十进制 r = int(hex_color[0:2], 16) g = int(hex_color[2:4], 16) b = int(hex_color[4:6], 16) # 和白色1:1混合 r_half = round(r * 0.5 + 255 * 0.5) g_half = round(g * 0.5 + 255 * 0.5) b_half = round(b * 0.5 + 255 * 0.5) # 转回十六进制拼接返回 return f"{r_half:02X}{g_half:02X}{b_half:02X}"
修改原有填充逻辑,传入转换后的色值即可:
color = getRouteColor(route) half_strength_color = get_half_intensity_color(color) for column in sheet.columns: for cell in column: if not cell.row % 2: cell.fill = openpyxl.styles.PatternFill( patternType='solid', fgColor=half_strength_color )
额外优化建议
原有代码中SQL查询用字符串格式化拼接参数存在SQL注入风险,建议改成参数化查询写法,同时用fetchone代替fetchall取单条结果更高效:
def getRouteColor(route): cursor.execute('SELECT route_color FROM routes WHERE route_short_name = ?', (route,)) return cursor.fetchone()[0]
不要用点阵、线条类的patternType模拟半透明,这类样式在不同版本的Excel、WPS中渲染效果差异极大,预计算纯色值的方案全平台兼容,显示效果一致。
内容的提问来源于stack exchange,提问作者Eijaf
相关产品推荐
相关产品推荐

