如何在Python中使用UTF-16编码正确读写BCRF文件?
读取并保存SPIP生成的BCRF文件时图像错位问题
我尝试读取SPIP工具生成的*.bcrf文件,再将内容原样保存回*.bcrf文件,但结果不理想,生成的新图像出现错位。
以下是我使用的代码:
import struct def read_bcrf_file(filename): header_size = 2048 data_size = 900 * 900 * 4 # Assuming 32-bit floating point data (bcrf format) with open(filename, 'rb') as file: # Read the header header = file.read(header_size) # Parse the header values header_dict = {} decoded_header = header.decode('utf-16').replace('\x00', '') for line in decoded_header.split('\n'): if '=' in line: key, value = line.strip().split('=') header_dict[key.strip()] = value.strip() # Read the data data = file.read(data_size) return header_dict, data def convert_data_to_float(data): float_data = struct.unpack('<' + 'f' * (len(data) // 4), data) return float_data def write_bcr_file(filename, header_dict, data): header_size = 2048 # Create the header string header = "" for key, value in header_dict.items(): header += key + " = " + value + "\n" # Pad the header to the required size header = header.ljust(header_size, '\x00') with open(filename, 'wb') as file: # Write the header file.write(header.encode('utf-16')[2:]) # Write the data data_bytes = struct.pack('<' + 'f' * len(data), *data) file.write(data_bytes) # Example usage header, binary_data = read_bcrf_file('test_file.bcrf') data = convert_data_to_float(binary_data) write_bcr_file('new.bcrf', header_dict=header, data=data) # Process the data as needed
运行后生成的新BCRF文件打开时图像错位。
问题原因及修正方案
硬编码数据尺寸:原代码固定假设图像为900×900,但实际应从header中读取
Width和Height字段,非该尺寸的文件会因读取错误长度的数据导致错位。Header编码与填充错误:
- BCRF的header是UTF-16LE编码(带BOM),原代码写入时用
utf-16编码后去掉前2字节(BOM),且填充单字节\x00,导致header总字节数不足2048,数据偏移。 - 解析header时,应按UTF-16的换行符
\r\n分割,而非\n,避免解析出无效内容。
- BCRF的header是UTF-16LE编码(带BOM),原代码写入时用
数据读写冗余转换:读取时直接保留二进制数据即可,无需先转成float再打包,减少不必要的转换步骤,避免潜在格式错误。
修正后的代码
import struct def read_bcrf_file(filename): header_size = 2048 with open(filename, 'rb') as file: # 读取header二进制数据 header_bytes = file.read(header_size) # 按UTF-16(带BOM)解析header decoded_header = header_bytes.decode('utf-16') header_dict = {} # 按\r\n分割行并过滤空行 for line in decoded_header.split('\r\n'): line = line.strip() if '=' in line: key, value = line.split('=', 1) header_dict[key.strip()] = value.strip() # 从header获取实际宽高,兼容默认值 width = int(header_dict.get('Width', 900)) height = int(header_dict.get('Height', 900)) data_size = width * height * 4 # 读取原始数据字节 data_bytes = file.read(data_size) return header_dict, data_bytes, width, height def write_bcr_file(filename, header_dict, data_bytes, width, height): header_size = 2048 # 重构header字符串,保留原始\r\n换行格式 header_lines = [f"{key} = {value}" for key, value in header_dict.items()] header_str = '\r\n'.join(header_lines) + '\r\n' # 末尾补充换行 # 编码为UTF-16(带BOM) header_encoded = header_str.encode('utf-16') # 计算需要填充的双字节空字符数量 padding_len = (header_size - len(header_encoded)) // 2 if padding_len > 0: header_encoded += b'\x00\x00' * padding_len with open(filename, 'wb') as file: # 写入完整header(含BOM) file.write(header_encoded) # 写入原始数据字节 file.write(data_bytes) # 示例使用 header, data_bytes, width, height = read_bcrf_file('test_file.bcrf') # 如需处理数据,可在此转换为float数组,处理后再转回字节 # float_data = struct.unpack('<' + 'f' * (width * height), data_bytes) # # 数据处理逻辑... # data_bytes = struct.pack('<' + 'f' * len(float_data), *float_data) write_bcr_file('new.bcrf', header_dict=header, data_bytes=data_bytes, width=width, height=height)
关键修正点
- 从header动态获取图像宽高,适配不同尺寸的BCRF文件。
- 严格按照UTF-16LE编码处理header,填充双字节空字符确保header总字节数为2048。
- 保留原始header的
\r\n换行格式,避免重构时的格式偏差。 - 直接读写原始数据字节,保证数据一致性。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

