# -*- coding: UTF-8 -*- """ 数据范围转换器 将 Full Range (0–65535) 转换为 Limited Range(SolidColor 刻度) """ from app.solid_color_scale import ( LIMITED_SOLID_COLOR_BLACK, LIMITED_SOLID_COLOR_WHITE, SOLID_COLOR_MAX, SOLID_COLOR_MIN, clamp_solid_color, ) class DataRangeConverter: """数据范围转换器""" def __init__(self, verbose=True): """ 初始化转换器 Args: verbose: 是否打印详细日志 """ self.verbose = verbose def convert_value(self, value): """ 将单个 Full Range 值转换为 Limited Range(SolidColor 刻度)。 转换公式(归一化后线性映射): limited = L_black + (value / MAX) × (L_white - L_black) """ value = clamp_solid_color(value) if value <= SOLID_COLOR_MIN: return LIMITED_SOLID_COLOR_BLACK if value >= SOLID_COLOR_MAX: return LIMITED_SOLID_COLOR_WHITE span = LIMITED_SOLID_COLOR_WHITE - LIMITED_SOLID_COLOR_BLACK limited = LIMITED_SOLID_COLOR_BLACK + round((value / SOLID_COLOR_MAX) * span) return max(LIMITED_SOLID_COLOR_BLACK, min(LIMITED_SOLID_COLOR_WHITE, limited)) def convert_rgb(self, r, g, b): """转换单个 RGB 值(SolidColor Full → Limited)。""" return (self.convert_value(r), self.convert_value(g), self.convert_value(b)) def convert(self, pattern_params, data_range="Full"): """ 转换图案参数列表 Args: pattern_params: 图案参数列表 [[r,g,b], [r,g,b], ...] data_range: "Full" 或 "Limited" Returns: list: 转换后的图案参数列表 """ # Full Range 不需要转换 if data_range == "Full": if self.verbose: print(f"使用 Full Range (0–{SOLID_COLOR_MAX}),无需转换") return pattern_params # Limited Range 需要转换 if data_range == "Limited": if self.verbose: self._print_header() converted = [] for i, rgb in enumerate(pattern_params): # 获取原始值 r_orig, g_orig, b_orig = rgb[0], rgb[1], rgb[2] # 转换 r_new, g_new, b_new = self.convert_rgb(r_orig, g_orig, b_orig) # 保存 converted.append([r_new, g_new, b_new]) # 打印日志(关键值) if self.verbose: self._print_conversion( i, r_orig, g_orig, b_orig, r_new, g_new, b_new ) if self.verbose: self._print_footer(len(pattern_params)) return converted # 未知范围,返回原始值 else: if self.verbose: print(f"⚠ 未知的数据范围: {data_range},使用原始值") return pattern_params def _print_header(self): """打印转换头部信息""" print("=" * 80) print("【数据范围转换】Limited Range (SolidColor 刻度)") print( f" 映射: {SOLID_COLOR_MIN}–{SOLID_COLOR_MAX} → " f"{LIMITED_SOLID_COLOR_BLACK}–{LIMITED_SOLID_COLOR_WHITE}" ) print("=" * 80) def _print_conversion(self, index, r_orig, g_orig, b_orig, r_new, g_new, b_new): """ 打印转换日志 策略:只打印关键值,避免刷屏 - 第一个和最后一个图案 - 0, 128, 255 等关键值 """ # 判断是否需要打印 should_print = False label = "" mid = SOLID_COLOR_MAX // 2 if index == 0: should_print = True label = "黑色" elif index == len([]) - 1: # 需要在外部判断 should_print = True label = "白色" elif ( r_orig in [SOLID_COLOR_MIN, mid, SOLID_COLOR_MAX] or g_orig in [SOLID_COLOR_MIN, mid, SOLID_COLOR_MAX] or b_orig in [SOLID_COLOR_MIN, mid, SOLID_COLOR_MAX] ): should_print = True if r_orig == mid: label = "50% 灰" if should_print: diff = abs(r_new - r_orig) print( f" 图案 {index+1:2d} {label:8s}: " f"RGB({r_orig:3d},{g_orig:3d},{b_orig:3d}) → " f"RGB({r_new:3d},{g_new:3d},{b_new:3d}) " f"(差值: {diff:+3d})" ) def _print_footer(self, total_count): """打印转换尾部信息""" print(f"转换完成,共 {total_count} 个图案") print("=" * 80) def get_info(self): """获取转换器信息""" return { "name": "Data Range Converter", "version": "1.0.0", "full_range": f"0-{SOLID_COLOR_MAX}", "limited_range": f"{LIMITED_SOLID_COLOR_BLACK}-{LIMITED_SOLID_COLOR_WHITE}", "formula": "L_black + (value / MAX) × (L_white - L_black)", } # ========== 便捷函数 ========== def convert_pattern_params(pattern_params, data_range="Full", verbose=True): """ 便捷函数:转换图案参数 Args: pattern_params: 图案参数列表 [[r,g,b], [r,g,b], ...] data_range: "Full" 或 "Limited" verbose: 是否打印日志 Returns: list: 转换后的图案参数列表 示例: >>> from app.data_range_converter import convert_pattern_params >>> params = [[0,0,0], [65535,65535,65535]] >>> converted = convert_pattern_params(params, "Limited") [[4112,4112,4112], [60492,60492,60492]] """ converter = DataRangeConverter(verbose=verbose) return converter.convert(pattern_params, data_range) def convert_single_rgb(r, g, b, data_range="Full"): """ 便捷函数:转换单个 RGB 值 Args: r, g, b: RGB 值 (0–65535) data_range: "Full" 或 "Limited" Returns: tuple: 转换后的 RGB 值 示例: >>> from app.data_range_converter import convert_single_rgb >>> r, g, b = convert_single_rgb(0, 0, 0, "Limited") (16, 16, 16) """ if data_range == "Full": return (r, g, b) converter = DataRangeConverter(verbose=False) return converter.convert_rgb(r, g, b) # ========== 测试代码 ========== if __name__ == "__main__": """测试转换器""" print("=" * 80) print("数据范围转换器 - 测试") print("=" * 80) # 测试 1: 基本转换 print("\n[测试 1] 基本转换...") converter = DataRangeConverter(verbose=False) test_values = [0, LIMITED_SOLID_COLOR_BLACK, SOLID_COLOR_MAX // 4, SOLID_COLOR_MAX // 2, SOLID_COLOR_MAX * 3 // 4, LIMITED_SOLID_COLOR_WHITE, SOLID_COLOR_MAX] print(" Full Range → Limited Range:") for v in test_values: limited = converter.convert_value(v) diff = limited - v print(f" {v:3d} → {limited:3d} (差值: {diff:+3d})") # 测试 2: RGB 转换 print("\n[测试 2] RGB 转换...") test_rgb = [ (0, 0, 0), (SOLID_COLOR_MAX // 2, SOLID_COLOR_MAX // 2, SOLID_COLOR_MAX // 2), (SOLID_COLOR_MAX, SOLID_COLOR_MAX, SOLID_COLOR_MAX), ] for r, g, b in test_rgb: r_new, g_new, b_new = converter.convert_rgb(r, g, b) print(f" RGB({r},{g},{b}) → RGB({r_new},{g_new},{b_new})") # 测试 3: 完整转换流程 print("\n[测试 3] 完整转换流程...") from app.ucd.solid_color_scale import byte_to_solid_color as _sc pattern_params = [ [_sc(255)] * 3, [_sc(230)] * 3, [_sc(204)] * 3, [_sc(128)] * 3, [0, 0, 0], ] converted = converter.convert(pattern_params, "Limited") print("\n 对比:") for i, (orig, conv) in enumerate(zip(pattern_params, converted)): print(f" [{i+1}] {orig} → {conv}") # 测试 4: 便捷函数 print("\n[测试 4] 便捷函数...") result = convert_pattern_params( [[0, 0, 0], [SOLID_COLOR_MAX, SOLID_COLOR_MAX, SOLID_COLOR_MAX]], "Limited", verbose=False ) print(f" 结果: {result}") r, g, b = convert_single_rgb(SOLID_COLOR_MAX // 2, SOLID_COLOR_MAX // 2, SOLID_COLOR_MAX // 2, "Limited") print(f" RGB(128,128,128) → RGB({r},{g},{b})") # 测试 5: 获取信息 print("\n[测试 5] 转换器信息...") info = converter.get_info() for key, value in info.items(): print(f" {key}: {value}") print("\n" + "=" * 80) print("测试完成") print("=" * 80)