#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (c) 2025 Any2MIF Project # All rights reserved. """ Any2MIF - MIF格式转换器 负责将任意文件转换为MIF格式 """ import os import math from datetime import datetime class MifConverter: """MIF格式转换器""" def __init__(self): """初始化转换器""" pass def convert_from_image(self, image, output_file, params): """ 将PIL图像对象直接转换为MIF格式 参数: image (PIL.Image): PIL图像对象 output_file (str): 输出文件路径 params (dict): 转换参数 width (int): 数据宽度 (8/16/32) auto_depth (bool): 是否自动计算深度 depth (int): 深度 (如果auto_depth为False) radix (str): 数据格式 (HEX/BIN/DEC) offset (int): 地址偏移量 header (bool): 是否添加文件头注释 addr_format (str): 地址格式 (standard/compact) data_per_line (int): 每行数据数量 返回: bool: 转换是否成功 """ try: # 将图像转换为字节数据 if image.mode != 'L': image = image.convert('L') # 转换为灰度图像 # 将图像转换为字节数组 data = bytearray() for y in range(image.height): for x in range(image.width): pixel = image.getpixel((x, y)) data.append(pixel) # 计算深度 - 使用图像的当前尺寸(可能是标准化后的尺寸) if params['auto_depth']: # 如果启用了自动计算深度,根据图像的当前尺寸和数据宽度计算深度 bytes_per_word = params['width'] // 8 # 使用图像的实际尺寸计算深度 depth = math.ceil((image.width * image.height) / bytes_per_word) else: depth = params['depth'] # 打开输出文件 with open(output_file, 'w', encoding='utf-8') as f: # 根据参数决定是否写入文件头 if params.get('header', True): self._write_header(f, "内存中图像", params, depth) # 写入数据 self._write_data(f, data, params, depth) return True except Exception as e: print(f"转换错误: {str(e)}") return False def convert(self, input_file, output_file, params): """ 将输入文件转换为MIF格式 参数: input_file (str): 输入文件路径 output_file (str): 输出文件路径 params (dict): 转换参数 width (int): 数据宽度 (8/16/32) auto_depth (bool): 是否自动计算深度 depth (int): 深度 (如果auto_depth为False) radix (str): 数据格式 (HEX/BIN/DEC) offset (int): 地址偏移量 header (bool): 是否添加文件头注释 addr_format (str): 地址格式 (standard/compact) data_per_line (int): 每行数据数量 返回: bool: 转换是否成功 """ try: # 读取输入文件 with open(input_file, 'rb') as f: data = f.read() # 计算深度 if params['auto_depth']: bytes_per_word = params['width'] // 8 depth = math.ceil(len(data) / bytes_per_word) else: depth = params['depth'] # 打开输出文件 with open(output_file, 'w', encoding='utf-8') as f: # 根据参数决定是否写入文件头 if params.get('header', True): self._write_header(f, input_file, params, depth) # 写入数据 self._write_data(f, data, params, depth) return True except Exception as e: print(f"转换错误: {str(e)}") return False def _write_header(self, file, input_file, params, depth): """ 写入MIF文件头 参数: file: 输出文件对象 input_file: 输入文件路径 params: 转换参数 depth: 深度 """ file.write("WIDTH=%d;\n" % params['width']) file.write("DEPTH=%d;\n" % depth) file.write("\n") file.write("ADDRESS_RADIX=%s;\n" % params.get('addr_radix', 'HEX')) file.write("DATA_RADIX=%s;\n" % params['radix']) file.write("\n") file.write("CONTENT BEGIN\n") def _write_data(self, file, data, params, depth): """写入MIF数据部分""" bytes_per_word = params['width'] // 8 words_per_line = params['data_per_line'] # 处理每个地址 for addr in range(depth): # 计算实际地址(加上偏移量) actual_addr = addr + params['offset'] # 计算数据索引 start_idx = addr * bytes_per_word end_idx = start_idx + bytes_per_word # 如果超出数据范围,填充0 if start_idx >= len(data): word_data = 0 else: # 读取数据 word_bytes = data[start_idx:min(end_idx, len(data))] # 如果数据不足,填充0 if len(word_bytes) < bytes_per_word: word_bytes = word_bytes + b'\x00' * (bytes_per_word - len(word_bytes)) # 转换为整数 word_data = int.from_bytes(word_bytes, byteorder='little') # 格式化地址 addr_radix = params.get('addr_radix', 'HEX') if addr_radix == 'HEX': addr_format = "@%X" if params['addr_format'] == 'standard' else "%X:" addr_str = addr_format % actual_addr elif addr_radix == 'BIN': # 计算二进制位数(根据深度和偏移量) max_addr = depth + params['offset'] - 1 bin_digits = len(bin(max_addr)[2:]) if params['addr_format'] == 'standard': addr_str = "@" + bin(actual_addr)[2:].zfill(bin_digits) else: # compact addr_str = bin(actual_addr)[2:].zfill(bin_digits) + ":" else: # DEC if params['addr_format'] == 'standard': addr_str = "@%d" % actual_addr else: # compact addr_str = "%d:" % actual_addr # 格式化数据 if params['radix'] == 'HEX': # 计算十六进制位数(每4位二进制对应1位十六进制) hex_digits = math.ceil(params['width'] / 4) data_str = format(word_data, 'X').zfill(hex_digits) elif params['radix'] == 'BIN': data_str = bin(word_data)[2:].zfill(params['width']) else: # DEC # 对于十进制,根据位宽计算最大可能的位数 max_dec_digits = len(str(2**params['width'] - 1)) data_str = str(word_data).zfill(max_dec_digits) # 写入一行 if (addr + 1) % words_per_line == 0 or addr == depth - 1: file.write(f"{addr_str} {data_str};\n") else: file.write(f"{addr_str} {data_str},\n") # 写入文件尾 file.write("END;\n") def estimate_output_size(self, input_file, params): """ 估计输出文件大小 参数: input_file (str): 输入文件路径 params (dict): 转换参数 返回: int: 估计的输出文件大小(字节) """ try: # 获取输入文件大小 input_size = os.path.getsize(input_file) # 计算深度 bytes_per_word = params['width'] // 8 if params['auto_depth']: depth = math.ceil(input_size / bytes_per_word) else: depth = params['depth'] # 估计每行平均长度 if params['radix'] == 'HEX': avg_data_len = params['width'] // 4 elif params['radix'] == 'BIN': avg_data_len = params['width'] else: # DEC avg_data_len = len(str(2 ** params['width'] - 1)) # 估计地址长度 addr_radix = params.get('addr_radix', 'HEX') if addr_radix == 'HEX': addr_len = len(hex(depth + params['offset'])[2:]) + 2 elif addr_radix == 'BIN': addr_len = len(bin(depth + params['offset'])[2:]) + 2 else: # DEC addr_len = len(str(depth + params['offset'])) + 2 # 估计每行长度 line_len = addr_len + avg_data_len + 3 # 包括空格、分隔符和换行符 # 估计总大小(不包含文件头) total_size = depth * line_len return total_size except Exception: # 如果估计失败,返回一个保守的估计值 return input_size * 5