Files

PinMAP ↔ PinList 双向转换器

将 Excel 格式的 PinMAP(方形封装引脚布局图)与 PinList(引脚序号列表)互相转换,消除手动抄录的低效与错误风险。

  • PinMAP → PinList:自动识别方形/长方形结构,逆时针提取引脚,生成线性列表
  • PinList → PinMAP:根据引脚列表和网格尺寸,自动计算布局并生成方形封装图

项目简介

在 IC 封装设计中PinMAP 以方形/长方形矩阵形式展示引脚分布,而 PinList 则以线性列表形式提供引脚序号对照。本项目通过纯 Python 实现,自动完成 PinMAP 与 PinList 之间的双向转换,支持 .xls.xlsx 两种格式。

版本: v1.5.0
发布日期: 2026-06-06
运行平台: Windowstkinter GUI/ Linux命令行回退
技术栈: Python 标准库,零第三方依赖


功能特性

核心功能

功能 说明
PinMAP → PinList 自动识别方形/长方形结构,沿四条边(左→下→右→上)逆时针提取引脚,生成 PinList
PinList → PinMAP 根据引脚列表和网格尺寸,自动计算布局并生成 PinMAP
数据验证 双向验证检测序号不连续、序号重复、PinName 缺失、A1 封装信息缺失、周长匹配
模板样式 MAP→List 使用 BallList-Template.xlsxList→MAP 使用 BallMAP-Template.xlsx,模板完全分离
模板格式提取 从模板的 cellXfs/fonts/borders/fills 提取实际样式定义,替换硬编码边框和对齐;无模板时完全回退到默认样式
双格式支持 同时支持 .xlsBIFF8 引擎)和 .xlsxOOXML 引擎)
双模式运行 GUI 文件选择对话框 + 命令行参数模式

验证规则

PinMAP → PinList 验证

  • 序号连续性Pin 序号必须为 1~N 连续整数,无间隔
  • 序号唯一性:每个 Pin 序号只能出现一次,无重复
  • PinName 完整性:缺失 PinName 的引脚自动标记为 "NC"(警告级别,不中断流程)
  • 结构完整性:方形区域至少 2×2A1 单元格必须包含封装信息

PinList → PinMAP 验证

  • 序号连续性Pin 序号必须从 1 开始连续无缺失
  • 序号唯一性:每个 Pin 序号只能出现一次,无重复
  • 周长匹配Pin 总数 = 2×rows + 2×cols 4与网格周长一致
  • PinName 完整性:缺失 PinName 的引脚自动标记为 "NC"(警告级别)
  • 非 4 倍数提示Pin 数量不是 4 的倍数时提示(信息级别)

技术栈

零第三方依赖

本项目完全使用 Python 标准库实现,不依赖任何第三方包。

模块 用途 标准库
xls_reader.py BIFF8 解析引擎(~19KB OLE2 解析) struct
xlsx_reader.py XLSX 读取引擎ZIP + XML 解析) zipfile, xml.etree.ElementTree
xlsx_writer.py XLSX 写入引擎OOXML 构建) zipfile, xml.etree.ElementTree
file_selector.py 文件选择对话框 tkinter.filedialog
pinmap_parser.py PinMAP 结构解析 纯 Python
pinmap_layout.py PinMAP 布局计算 纯 Python
pinmap_generator.py PinMAP 生成与输出 纯 Python
pinlist_parser.py PinList 文件解析 纯 Python
pinlist_validator.py PinList 数据验证 collections.Counter
pinlist_generator.py PinList 生成 纯 Python
validator.py PinMAP 数据验证 collections.Counter
template_reader.py 模板样式提取(含 cellXfs/xfId/applyAlignment/wrapText zipfile, xml.etree.ElementTree
models.py 数据模型 dataclasses
utils.py 工具函数 纯 Python

核心技术亮点

  • BIFF8 手动解析:从零实现 OLE2 复合文档 + BIFF8 记录流解析,支持 SST、LABELSST、NUMBER、FORMULA、RK、MULRK、LABEL 等记录类型
  • OOXML 手动构建:不使用 openpyxl/xlrd纯手工构建 [Content_Types].xmlworkbook.xmlsharedStrings.xmlsheet1.xml 等 OOXML 结构
  • 布局算法:根据网格尺寸自动计算四边引脚分配,支持任意 rows×cols 的矩形封装
  • 模板样式引擎:从 xlsx 文件中提取字体、填充、边框、列宽、行高等样式并应用到输出文件
  • 模块化架构:解析 → 验证 → 生成 → 输出,各模块职责清晰,接口契约明确

使用方式

模板使用说明v1.5.0

从 v1.5.0 开始,两个方向的转换使用各自独立的模板文件:

转换方向 模板文件 查找位置
MAP→List BallList-Template.xlsx 项目根目录 → 当前工作目录
List→MAP BallMAP-Template.xlsx 项目根目录 → 当前工作目录

模板格式提取机制

程序从模板的 OOXML styles.xml 和 sheet1.xml 中提取具体的样式定义(字体、边框、填充、对齐、列宽、行高),然后写入输出的 <styleSheet> 中。这种方式是提取式(读取具体属性值)而非直接复制 cellXf 引用,确保即使模板结构复杂也能正确提取关键样式属性。

xl/styles.xml:
  ├── fonts:    name, size, bold, italic, color
  ├── fills:    pattern_type, fg_color
  ├── borders:  top, bottom, left, right (style + color)
  └── cellXfs:  numFmtId, fontId, fillId, borderId, alignment
                (含 xfId, applyAlignment, wrapText)

xl/worksheets/sheet1.xml:
  ├── cols:     column width (min, max, width)
  └── sheetData: row height

优雅降级

  • 模板文件不存在 → 使用硬编码默认样式Calibri 11pt、thin 边框、居中)
  • 模板解析失败(损坏/格式异常)→ 优雅回退到默认样式
  • 模板中某些样式属性缺失 → 仅应用可用属性,其余保持默认

前提条件

  • Python 3.6+(推荐 3.8+
  • Windows 环境GUI 模式需要 tkinter
  • Linux/Mac 环境(仅命令行模式)

交互式模式(推荐)

python main.py

运行后显示转换方向选择菜单:

============================================================
  PinMAP ↔ PinList 双向转换器
  支持 PinMAP→PinList 与 PinList→PinMAP 互转
  支持.xls和.xlsx格式输出.xlsx格式
============================================================

请选择转换方向:
  1 — PinMAP → PinList
  2 — PinList → PinMAP

请输入选项 (1/2):

命令行模式

PinMAP → PinList

# 基本用法
python main.py input.xlsx

# 支持 .xls 格式
python main.py input.xls

# 输出文件自动命名为 input_PinList.xlsx

PinList → PinMAP

# 命令行模式:需提供文件路径
python main.py input_PinList.xlsx

# 运行后需要手动输入 PinMAP 尺寸:
#   请输入 PinMAP 行数: 6
#   请输入 PinMAP 列数: 6
# 输出文件自动命名为 input_PinList_PinMAP.xlsx

注意:命令行模式下直接传入文件参数时,默认走 PinMAP → PinList 方向。如需 PinList → PinMAP请使用交互式模式不带参数运行选择方向 2。

GUI 模式

# 不带参数运行,弹出方向选择 + 文件选择对话框
python main.py

选择方向后,在对话框中选择 .xls.xlsx 文件,点击"打开"即可开始转换。


使用示例

示例 1PinMAP → PinList

输入 PinMAP方形封装

     A      B      C      D      E      F
1  QFP-44
2                              Pin6   6
3                              Pin5   5
4  1      Pin1
5  2      Pin2
6               Pin3   Pin4
7               3      4

运行命令

python main.py QFP44.xlsx

输出

[INFO] 正在读取文件: QFP44.xlsx
[INFO] 文件读取完成,共 16 个非空单元格
[INFO] 正在解析 PinMAP 结构...
[INFO] 解析完成: 6x6 方形,共 8 个Pin
[INFO] 封装信息: QFP-44
[INFO] 正在验证数据...
[INFO] 验证通过
[INFO] 正在生成 PinList...
[INFO] 正在写入输出文件: QFP44_PinList.xlsx

[SUCCESS] 转换完成!
  输出文件: QFP44_PinList.xlsx
  封装信息: QFP-44
  Pin数量: 8

输出 PinList

     A         B
1  QFP-44
2  Pin1      1
3  Pin2      2
4  Pin3      3
5  Pin4      4
6  Pin5      5
7  Pin6      6

示例 2PinList → PinMAP

输入 PinList

     A          B
1   QFN-20
2   VCC        1
3   GND        2
4   IO0        3
5   IO1        4
6   IO2        5
7   IO3        6
8   IO4        7
9   IO5        8
10  IO6        9
11  IO7        10
12  NC         11
13  NC         12
14  NC         13
15  NC         14
16  NC         15
17  NC         16
18  NC         17
19  NC         18
20  NC         19
21  NC         20

运行命令

python main.py
# 选择方向: 2 (PinList → PinMAP)
# 选择文件: QFN20_PinList.xlsx
# 输入行数: 6
# 输入列数: 6

输出

[INFO] 正在解析 PinList 文件: QFN20_PinList.xlsx
[INFO] 解析完成: 封装信息 'QFN-20', 共 20 个引脚
[INFO] 正在验证数据...
[INFO] 验证通过
[INFO] 正在生成 PinMAP 并写入: QFN20_PinList_PinMAP.xlsx

[SUCCESS] 转换完成!
  输出文件: QFN20_PinList_PinMAP.xlsx
  封装信息: QFN-20
  PinMAP 尺寸: 6×6
  Pin数量: 20

输出 PinMAP6×6 网格20 个引脚):

     A        B        C        D        E        F
1  QFN-20                          IO8      IO7
2  1        VCC      IO6                    IO5
3  2        GND      IO4                    IO3
4  3        IO0      IO2                    IO1
5  4        IO1      NC                     NC
6  20       19       18       17       16

示例 3尺寸不匹配错误

当 PinList 引脚数与网格周长不匹配时:

[ERROR] 验证未通过,发现 1 个错误:
  - Pin数量与网格周长不匹配: 网格 6×6 需要 20 个引脚,但 PinList 有 24 个

转换终止请修正PinList文件或网格尺寸后重试。

示例 4使用模板样式

PinList → PinMAP 转换时,程序会自动尝试从同目录下的模板文件读取样式(字体、边框、列宽等),使输出 PinMAP 的格式与目标模板保持一致。


项目结构

pinmap-to-pinlist/
├── Code/
│   ├── src/
│   │   ├── main.py              # 主入口:流程编排 + 双向转换
│   │   ├── file_selector.py     # 文件选择GUI + 命令行回退)
│   │   ├── xls_reader.py        # XLS (BIFF8) 读取引擎
│   │   ├── xlsx_reader.py       # XLSX 读取引擎
│   │   ├── xlsx_writer.py       # XLSX 写入引擎(含样式支持)
│   │   ├── pinmap_parser.py     # PinMAP 结构解析
│   │   ├── pinmap_layout.py     # PinMAP 布局计算List→MAP
│   │   ├── pinmap_generator.py  # PinMAP 生成与输出List→MAP
│   │   ├── pinlist_parser.py    # PinList 文件解析List→MAP
│   │   ├── pinlist_validator.py # PinList 数据验证List→MAP
│   │   ├── pinlist_generator.py # PinList 生成MAP→List
│   │   ├── validator.py         # PinMAP 数据验证MAP→List
│   │   ├── template_reader.py   # 模板样式提取List→MAP
│   │   ├── models.py            # 数据模型
│   │   ├── utils.py             # 工具函数
│   │   └── test_pinmap.py       # 单元测试
│   └── docs/
│       ├── README.md            # 本文档
│       ├── QUICKSTART.md        # 快速入门指南
│       ├── RELEASE.md           # 版本发布说明
│       ├── architecture-design.md  # 架构设计文档
│       └── team.md              # 团队成员
├── Test/
│   ├── fixtures/                # 测试夹具
│   │   ├── sample_4x4.xlsx      # 标准 4×4 PinMAP
│   │   ├── sample_rect.xlsx     # 长方形 PinMAP
│   │   ├── error_gap.xlsx       # 序号不连续测试
│   │   ├── error_dup.xlsx       # 序号重复测试
│   │   ├── error_empty_a1.xlsx  # A1 为空测试
│   │   ├── warning_missing.xlsx # PinName 缺失测试
│   │   ├── BallList-Template.xlsx    # MAP→List 样式模板(测试用)
│   │   ├── BallMAP-Template.xlsx     # List→MAP 样式模板(测试用)
│   │   ├── template_corrupt.xlsx     # 损坏模板回退测试
│   │   ├── template_minimal.xlsx     # 最小模板测试
│   │   └── template_narrow.xlsx      # 窄列宽模板测试
│   └── test_report.md           # 测试报告
├── README.md                    # 项目根目录 README
├── CHANGELOG.md                 # 变更日志
└── .gitignore

测试情况

单元测试

运行 python test_pinmap.py(在 Code/src/ 目录下):

基础功能测试v1.0v1.2

测试用例 说明 状态
test_4x4_parse 4×4 方形 PinMAP 解析 通过
test_4x4_validate 4×4 方形验证 通过
test_missing_names_warning PinName 缺失警告 通过
test_duplicate_numbers 序号重复检测 通过
test_gap_in_numbers 序号不连续检测 通过
test_empty_cells 空单元格处理 通过
test_no_pins 无引脚数据检测 通过
test_rectangular_parse 长方形 PinMAP 解析 通过
test_12pin_square 12 引脚方形解析 通过

F012 回归测试v1.5.0 新增)

测试用例 说明 状态
test_f012_pinname_position 5×5 往返一致性 + 上/下边 PinName 位置验证 通过

F011 模板格式提取测试v1.5.0 新增)

测试用例 说明 状态
test_template_path_generation 两个模板查找函数返回正确路径格式 通过
test_f011_default_styles_xml 无模板时回退到硬编码默认样式 通过
test_f011_template_fonts_in_styles_xml 有模板时使用模板字体信息 通过
test_f011_output_dims_determined_by_pins 输出行列由引脚数决定,非模板 通过
test_f011_template_borders_in_styles_xml 有模板时使用模板边框信息 通过
test_f011_template_fills_in_styles_xml 有模板时使用模板填充信息 通过
test_template_empty_fonts_fallback 空字体回退到默认 通过
test_template_color_prefix_auto_fix 颜色值 # 前缀自动修复 通过
test_template_no_styles_xml 无 styles.xml 时优雅降级 通过

集成测试

测试用例 输入文件 说明 状态
TC001 sample_4x4.xlsx 标准 4×4 转换8 Pin 通过
TC002 sample_rect.xlsx 长方形转换13 Pin 通过
TC003 error_gap.xlsx 序号不连续检测 通过
TC004 error_dup.xlsx 序号重复检测 通过
TC005 warning_missing.xlsx PinName 缺失警告 通过
TC006 error_empty_a1.xlsx A1 为空检测 通过

结论:所有 18 个单元测试 + 6 个集成测试全部通过,无阻塞性问题。详见 Test/test_report.md


解析算法说明

PinMAP → PinList逆时针提取

PinMAP 以方形/长方形矩阵展示引脚分布:

        col A(0)   col B(1)   col C(2)   col D(3)
row 0   [A1=封装]
row 1   [1]        [2]        [3]        [4]          ← 上边 Pin 序号
row 2   [PinName]  [          ]          [PinName]    ← PinName 行
row 3   [PinName]  [          ]          [PinName]
row 4   [13]       [12]       [11]       [10]         ← 下边 Pin 序号

引脚沿四条边逆时针提取:

  1. 左边:从上到下
  2. 下边:从左到右
  3. 右边:从下到上
  4. 上边:从右到左

角点单元格只计数一次(按单元格位置去重)。

PinList → PinMAP布局计算

根据用户输入的 rows × cols 网格尺寸,将引脚列表按逆时针分配到四条边:

总引脚数 = 2 × rows + 2 × cols  4

左边:   rows 个引脚(从上到下)
下边:   cols  1 个引脚(从左到右)
右边:   rows  2 个引脚(从下到上)
上边:   cols  1 个引脚(从右到左)

PinName 与序号的相对位置:

左边:序号在 (r, 0)PinName 在 (r, 1)         → Name 在序号右侧
下边:序号在 (rows, c)PinName 在 (rows-1, c)   → Name 在序号上方
右边:序号在 (r, cols)PinName 在 (r, cols-1)   → Name 在序号左侧
上边:序号在 (1, c)PinName 在 (2, c)           → Name 在序号下方

PinList 输出规则MAP→List

  • A1 单元格:封装信息(从 PinMAP 的 A1 复制)
  • A 列PinName缺失时自动设为 "NC"
  • B 列Pin 序号
  • 按 Pin 序号递增排序

PinMAP 输出规则List→MAP

  • A1 单元格:封装信息(从 PinList 的 A1 读取)
  • 四边分布:序号 + PinName 按布局算法填入网格
  • 缺失 PinName 自动设为 "NC"
  • 可选:应用模板样式(字体、边框、列宽、行高)

错误处理

级别 类型 行为
[FATAL] 文件格式错误 / 结构错误 / 布局计算失败 终止处理,显示错误信息
[ERROR] 数据验证错误(重复/不连续/周长不匹配) 终止处理,显示详细错误
[WARN] PinName 缺失 提示警告,自动设为 "NC",继续处理
[INFO] 解析进度信息 / 非 4 倍数提示 仅显示,不影响流程
[SUCCESS] 转换完成 显示输出文件路径和统计信息

许可证

内部项目