由於該工具是用 Swift 寫的,本人雖然使用過很多程式語言,但我不喜歡蘋果,故我也不會想去學蘋果體系的東西。
所以我只是簡單下個指示。
There is a tool in the folder of original_tool. It is wriiten by Swift.
Please rewrite the tool by Python.
Please use git to record your porting.
Please put all codes in python_tool folder.
一開始還以為 token 會爆掉,沒想到也是不到 20 分鐘就 porting 完畢。
當然從圖片看不出 bug,目前 porting 的版本有兩個 bug:
1. render 區會一直閃爍,我猜程式寫得不好,變成一直 loop 更新。
2. 雖說可以區分哪些字體無法用在直式閱讀,但直式顯示畫面標點符號並沒有變成直式格式。
(我猜是報告中提到的限制?)
下面是請 AI 整理的報告
================================================================
DEVELOPMENT REPORT: Chinese Vertical Font Viewer (Python Port)
================================================================
Date : 2026-04-25
Author : tylpk (assisted by Claude Sonnet 4.6)
Project : c_font_tool
Repo : C:\Users\tylpk\Desktop\AI\c_font_tool
----------------------------------------------------------------
1. PROJECT OVERVIEW
----------------------------------------------------------------
Goal
Port the macOS Swift app "Chinese-Vertical-font-reading-test"
(found in original_tool/) to Python so it can run on Windows
and other platforms without Xcode or macOS.
Original tool
- Language : Swift 5 / SwiftUI
- Platform : macOS 13.0+, built with Xcode 15+
- Source : original_tool/Chinese-Vertical-font-reading-test/
- Key files :
ChineseVerticalApp.swift -- app entry point
ContentView.swift -- main UI, font loading, EPUB handling,
font analysis logic
VerticalTextView.swift -- CoreText-based vertical text rendering
FontDetailView.swift -- details panel sub-view
Python tool output
- Language : Python 3.10+
- Platform : Windows / macOS / Linux (anywhere Python + tkinter run)
- Source : python_tool/
- Entry : python_tool/main.py
----------------------------------------------------------------
2. FILE STRUCTURE
----------------------------------------------------------------
python_tool/
main.py ( 23 lines) Entry point; launches TkinterDnD
or plain tkinter root window.
app.py ( 522 lines) Main GUI application class.
font_analyzer.py ( 321 lines) Font metadata extraction and
vertical-support analysis.
vertical_renderer.py ( 124 lines) Pillow-based vertical text renderer.
epub_reader.py ( 132 lines) EPUB / TXT text extraction.
requirements.txt ( 3 lines) Python package dependencies.
Total Python source: 1,122 lines
----------------------------------------------------------------
3. DEPENDENCIES
----------------------------------------------------------------
Package Version Purpose
--------------- ------- --------------------------------------
fonttools >=4.40 Parse font binary tables (cmap, name,
GSUB, OS/2) for metadata and glyph
coverage analysis.
Pillow >=10.0 Render TrueType/OpenType glyphs onto
an in-memory image for the vertical
text display canvas.
tkinterdnd2 >=0.3 Enable drag-and-drop of font/book files
onto the tkinter window. Gracefully
absent — file dialogs work as fallback.
All three were already installed or installed successfully via:
pip install -r python_tool/requirements.txt
----------------------------------------------------------------
4. FEATURE MAPPING (Swift → Python)
----------------------------------------------------------------
4.1 Font Loading
Swift : CTFontManagerCreateFontDescriptorsFromURL + CTFontCreate
Python : fonttools TTFont / TTCollection
Notes : TTC collections are fully supported; all sub-fonts are
exposed as separate entries (Font Name [0], [1], …).
4.2 Font Metadata (details panel)
Fields ported:
Full Name, Family, Chinese Name, Chinese Family,
PostScript Name, Style, File Size, File Path,
Glyph Count, Ascent / Descent,
CJK Punctuation (24 chars), Vertical Forms (20 forms),
Rotation correctness summary.
Chinese name extraction
Swift : Parse raw 'name' table bytes manually.
Python : fonttools NameRecord.toUnicode(); filter by
Windows platform Chinese language IDs
(0x0804 zh-CN, 0x0404 zh-TW, 0x0C04 zh-HK, …)
and Mac platform IDs (33 zh-Hans, 19 zh-Hant).
4.3 CJK Punctuation Coverage
Checks 24 standard CJK punctuation code points against the
font's cmap. Missing glyphs are listed by character and
flagged as warnings. Their code points are passed to the
renderer which replaces them with □ drawn in red.
4.4 Vertical Forms Coverage (U+FE10–FE44)
Checks 20 vertical presentation form code points against cmap.
Reports: ✓ complete / △ incomplete / ✗ none.
4.5 Rotation Check (CLREQ compliance)
The most technically involved analysis:
Swift : Shape each character in both a horizontal and a
vertical CTFrame, compare resulting glyph IDs via
CoreText. A changed glyph ID means GSUB 'vert'
substituted it.
Python : Traverse the GSUB table with fonttools; collect all
glyph-name → glyph-name mappings from lookups
referenced by 'vert' and 'vrt2' features.
Compare base glyph name to the substitution target.
Rules applied (matching Swift logic exactly):
shouldRotate = True (brackets, em-dash, ellipsis):
GSUB substitutes base → correct
base cmap == vert-form cmap (already vertical) → correct
no substitution, not already vertical → WRONG (highlighted)
shouldRotate = False (fullwidth colon, semicolon):
GSUB substitutes base → WRONG (font incorrectly rotates)
base cmap == vert-form cmap → WRONG (glyph is vertical form)
no substitution → correct
Checked characters (20 total):
:;()《》「」『』〈〉【】〔〕〖〗—…
4.6 Vertical Text Rendering
Swift : CoreText CTFramesetter + CTFrameDraw into NSView,
right-to-left CTFrameProgression, verticalGlyphForm=true.
Python : Pillow ImageDraw.text() draws each character one at a
time into an RGB image:
• Columns progress right → left
• Characters within a column progress top → bottom
• Cell size derived from font bbox of a reference
CJK character ("字")
• Missing-glyph code points replaced with □ in red
• Wrong-rotation code points drawn in red
Limitation: Pillow does not apply OpenType GSUB features, so
glyphs are not automatically substituted to their vertical forms
during rendering. The rendered preview is useful for glyph
presence and layout; the analysis panel provides the authoritative
vertical-support verdict.
4.7 EPUB / TXT Reading Mode
Swift : Manual ZIP parsing with raw byte offsets + Apple
Compression framework for DEFLATE.
Python : stdlib zipfile module (handles both STORE and DEFLATE).
OPF spine order preserved via regex parsing of
<item> / <itemref> elements.
HTML stripped with a custom html.parser subclass that
inserts newlines at block-level tags and decodes
common HTML entities.
TXT: tried utf-8, utf-8-sig, gbk, big5 in order.
4.8 GUI
Swift : SwiftUI (macOS only), declarative two-mode layout.
Python : tkinter + ttk, imperative class-based layout.
Comparison mode:
• Top area: one Canvas column per loaded font, positioned with
place() so they divide the width equally.
• Font name label above each column; click to select.
• Right-click context menu: "Remove <name>".
• Bottom panel (fixed 300 px): toolbar + scrollable key-value
details list.
• Toolbar: font name display, Remove Font, Open Font…,
Open Book…, Edit Text, font size Spinbox.
Reading mode:
• Top bar: Back button, font name, page N/M counter.
• Full-area Canvas showing one page of vertical text.
• Navigation:
Click left half → next page (vertical-RL: earlier content
Click right half → prev page is on the right)
← / → arrow keys, Space bar.
Drag-and-drop (tkinterdnd2):
• .ttf / .otf / .ttc / .dfont → load font, add column
• .epub / .txt → enter reading mode
• Falls back to "Open Font…" / "Open Book…" dialogs if
tkinterdnd2 is not available.
Font size: Spinbox (12–200 pt); triggers full re-render.
Window resize: debounced 150 ms, then re-renders all columns
or the current reading page.
----------------------------------------------------------------
5. GIT HISTORY
----------------------------------------------------------------
Commit 22c0b07 Port: app.py + main.py — tkinter GUI
Commit 8b623a0 Port: vertical_renderer.py — Pillow rendering
Commit fd0abb6 Port: epub_reader.py — EPUB/TXT extraction
Commit 1cd5dd1 Port: font_analyzer.py — analysis logic
Commit 6373068 Port: add requirements.txt
Commit 134a91e Add original Swift tool and spec
----------------------------------------------------------------
6. HOW TO RUN
----------------------------------------------------------------
# Install dependencies (one-time)
pip install -r python_tool/requirements.txt
# Launch
python python_tool/main.py
Tested on: Windows 11 Home 10.0.26200, Python 3.14
Runtime output on first launch: one benign fonttools warning
"114685 extra bytes in post.stringData array"
(non-conforming post table in a system font; not an error)
----------------------------------------------------------------
7. KNOWN DIFFERENCES FROM THE SWIFT ORIGINAL
----------------------------------------------------------------
1. No real GSUB shaping in the renderer.
The Swift app uses CoreText which applies GSUB features
(including 'vert') during glyph layout. The Python renderer
draws Unicode code points directly with Pillow; vertical form
substitution is not applied visually. The analysis panel
correctly identifies which fonts support it.
2. No pinch-to-zoom.
The Swift app supports trackpad pinch gestures. Python/tkinter
has no cross-platform pinch support. Font size is controlled
via the Spinbox in the toolbar instead.
3. Column drop target highlight.
The Swift app highlights the specific column being hovered
during a drag. tkinterdnd2 provides only window-level drop
events, so per-column hover highlight is not implemented.
4. .dfont support.
fonttools can open .dfont files on macOS. On Windows this
format is unlikely to be encountered; the code accepts the
extension but fonttools may raise an error for some .dfont files.
================================================================


沒有留言:
張貼留言