Skip to content

07 cli and api guide

github-actions[bot] edited this page Aug 25, 2026 · 4 revisions

07 - CLI & Python API Guide

中文

This chapter provides instructions for using the Document Parser for GoodNotes command-line interface (CLI) tools and the Python API library.


1. CLI Tool Suite

After installation, the package provides 10 global command-line tools (which can also be invoked via python3 -m goodnotes_re.cli):

                                ┌── gn-inspect (Inspect ZIP file directory and SHA256)
                                ├── gn-dump (Lossless dump to JSON)
                                ├── gn-diff (Compare differences between two .goodnotes members)
                                ├── gn-recordings (List audio sessions and synchronized stroke timelines)
                                ├── gn-export-audio (Extract audio track from document)
python3 -m goodnotes_re.cli ───┼── gn-export-video (Export synchronized MP4 video with handwriting animations)
                                ├── gn-export-html (Export interactive multi-page standalone HTML5 player)
                                ├── gn-export-json (Export full structure as JSON)
                                ├── gn-export-svg (Export vector SVG pages)
                                └── gn-export-pdf (Compile vector pages directly into PDF)

1.1 gn-inspect - Inspect Inventory and SHA256 Checksums

Used to quickly inspect which Protobuf members and media attachments are included inside a .goodnotes file, listing sizes and the first 12 characters of their SHA256 checksums.

gn-inspect samples/Teat.goodnotes

Example Output:

protobuf      2 byte  schema.pb  sha256:0a2e38c119d4
protobuf     148 byte  index.notes.pb  sha256:5b839f201d4a
protobuf      84 byte  index.attachments.pb  sha256:19e48102fa9c
protobuf   12840 byte  notes/31BE4069-02E5-4C5D-BFF9-2A8DCBC744E9  sha256:e3b0c44298fc
asset    1082491 byte  attachments/31BE4069-02E5-4C5D-BFF9-2A8DCBC744E9  sha256:8f3c7a...

1.2 gn-dump - Lossless Conversion of Single Protobuf Member to JSON

Decodes any .pb or notes/<UUID> field inside a .goodnotes file, outputting lossless JSON containing Tag numbers, Wire Types, Offsets, and Base64 data.

gn-dump samples/Teat.goodnotes index.notes.pb

1.3 gn-diff - Compare Differences Between Two .goodnotes Files

When conducting format analysis controlled experiments, compares two files with only a single modification (such as before.goodnotes before an operation and after.goodnotes after an operation).

gn-diff before.goodnotes after.goodnotes

Example Output:

CHANGED  index.notes.pb
ADDED    attachments/7F129B44-55C1-4D30-8812-4E1B88944E1B
CHANGED  notes/31BE4069-02E5-4C5D-BFF9-2A8DCBC744E9

1.4 gn-export-json - Export Full JSON Structure

Exports all pages, ink strokes, pressure data, RGBA colors, shapes, typewriter text, and raw wire data of the entire notebook into a single JSON file.

gn-export-json samples/Teat.goodnotes -o document.json

1.5 gn-export-svg - Export High-Fidelity SVG Vector Pages

Renders each page of the entire notebook as independent, high-resolution SVG vector graphics.

gn-export-svg samples/Teat.goodnotes -o pages-svg/

Advanced Parameters:

  • -s, --sticky-note-state {open,close,auto}: Controls sticky note state (open expands the card, close collapses the icon).
  • -b, --textbox [open|close]: Controls whether to draw the text box bounding border.
  • -a, --parse-all: Parses all pages in the document instead of only the active page.
  • --no-fill: Disables filling for vector shapes.
  • --pdf [filename.pdf]: Packages all exported SVG pages in sequence into a single PDF document.
# Example: Generate SVGs and compile directly into PDF
gn-export-svg samples/Teat.goodnotes -o output_svgs/ --pdf

1.6 gn-export-pdf - Direct Multi-Page PDF Exporter

Renders all pages according to the vector SVG pipeline and compiles them directly into a multi-page PDF document.

gn-export-pdf samples/Teat.goodnotes -o Teat.pdf

1.7 gn-recordings - Audio Sessions and Stroke Sync Timeline

Inspects all recorded audio sessions and their associated handwriting stroke timelines inside the document.

gn-recordings samples/record.goodnotes

1.8 gn-export-audio - Extract Raw Audio Track

Extracts the original AAC audio track (.m4a) recorded inside the document.

gn-export-audio samples/record.goodnotes -o audio.m4a

1.9 gn-export-video - Synchronized MP4 Handwriting Animation

Renders a synchronized MP4 video combining the spoken audio with animated handwriting stroke appearances, with automatic multi-page transition following the speaker.

gn-export-video samples/record.goodnotes -o replay.mp4 --fps 15 -s open -b -a

Parameters:

  • -o, --output: Output MP4 video path.
  • --fps: Frame rate (default: 15).
  • --resolution-scale: Rendering scale factor (default: 1.0).
  • -s, --sticky-note-state {open,close,auto}: Sticky note display mode.
  • -b, --textbox [open|close]: Text box border rendering.
  • -a, --parse-all: Parse and follow all active pages.

1.10 gn-export-html - Standalone Interactive HTML5 Player

Exports a self-contained, offline HTML5 web player with multi-page navigation, dual view modes (Single Page vs Continuous Stack), synchronized timeline inking, and click-to-seek strokes.

gn-export-html samples/record.goodnotes -o player.html -s open -b -a

2. Python API Guide

The core API is encapsulated in the GoodNotesDocument class and export modules.

2.1 Opening and Reading Documents

from goodnotes_re import GoodNotesDocument

with GoodNotesDocument.open("samples/Teat.goodnotes") as doc:
    # Get internal file inventory
    members = doc.inventory()
    for m in members:
        print(m.path, m.size, m.sha256)
        
    # Read member bytes directly
    raw_data = doc.read("schema.pb")

2.2 Iterating Over Pages, Strokes, and Pressure Points

with GoodNotesDocument.open("samples/Teat.goodnotes") as doc:
    pages = doc.pages(parse_all=True)
    for page in pages:
        print(f"=== Page {page.index + 1} (UUID: {page.uuid}) ===")
        print(f"Dimensions: {page.dimensions.width} x {page.dimensions.height} pt, Landscape: {page.dimensions.is_landscape}")
        
        # Iterate over strokes
        for stroke in page.strokes:
            print(f"Stroke UUID: {stroke.uuid}")
            print(f"  Color: {stroke.color_hex}, Alpha: {stroke.alpha}")
            print(f"  Width: {stroke.width}, Highlighter: {stroke.is_highlighter}")
            print(f"  Control points count: {len(stroke.points)}")
            
            # Read specific control points (x, y, pressure)
            for pt in stroke.points[:3]:
                print(f"    Point: ({pt.x:.2f}, {pt.y:.2f}), pressure={pt.pressure:.2f}")

2.3 Reading Shapes and Typewriter Text Elements

with GoodNotesDocument.open("samples/Teat.goodnotes") as doc:
    for page in doc.pages(parse_all=True):
        # Read vector shapes
        for shape in page.shapes:
            print(f"Shape type: {shape.shape_type}, Color: {shape.color_hex}")
            print(f"  Vertices count: {len(shape.points)}")
            if shape.start_arrow or shape.end_arrow:
                print(f"  With arrow Marker: start={shape.start_arrow}, end={shape.end_arrow}")
                
        # Read typewriter rich text elements
        for te in page.text_elements:
            print(f"Text block [{te.x}, {te.y}]: {te.text}")
            print(f"  Font: {te.font_family}, Size: {te.font_size}, Bold: {te.is_bold}")

2.4 Directly Invoking the Vector SVG and PDF Exporters

from pathlib import Path
from goodnotes_re import GoodNotesDocument, page_to_svg, write_svg, write_pdf, svgs_to_pdf, svg_to_pdf_bytes

with GoodNotesDocument.open("samples/Teat.goodnotes") as doc:
    pages = doc.pages(parse_all=True)

    # 1. Render single page directly in memory (zero disk I/O)
    single_svg = page_to_svg(pages[0], doc, fill_shapes=True)

    # 2. Export all SVG pages to disk
    svg_paths = write_svg(
        document=doc,
        directory="output_svgs",
        fill_shapes=True,
        sticky_note_state="open",
        textbox_state=True,
        parse_all=True,
    )
    print("Generated SVG files:", svg_paths)

    # 3. Export direct multi-page PDF
    pdf_path = write_pdf(
        document=doc,
        output="output_svgs/Teat.pdf",
        sticky_note_state="open",
        parse_all=True,
    )
    print("Generated PDF file:", pdf_path)

2.5 Audio Recordings & Timed Inking Playback

from goodnotes_re import (
    GoodNotesDocument,
    write_recording_audio,
    write_recording_video,
    write_recording_html,
)

with GoodNotesDocument.open("samples/record.goodnotes") as doc:
    # 1. Query all audio sessions and stroke timestamps
    recordings = doc.recordings()
    for rec in recordings:
        print(f"Session {rec.id}: duration={rec.duration:.2f}s, timed strokes={len(rec.stroke_timings)}")

    # 2. Extract audio track
    audio_path = write_recording_audio(doc, "output/audio.m4a")

    # 3. Export animated MP4 video with multi-page tracking
    video_path = write_recording_video(doc, "output/replay.mp4", fps=15, parse_all=True)

    # 4. Export standalone interactive HTML5 player
    html_path = write_recording_html(doc, "output/player.html", parse_all=True)

In the next chapter, 08 - Testing, Building, and Publishing, we will explain how to set up the development environment, execute unit tests, maintain controlled format analysis experiment protocols, and package for publishing to PyPI.


07 - CLI 工具與 Python API 指南 (CLI & API Guide)

English

本章節提供 Document Parser for GoodNotes 的命令行 CLI 工具說明與 Python API 程式庫調用指南。


1. CLI 工具套件 (CLI Tool Suite)

套件安裝後會提供 10 個全域命令列工具(亦可透過 python3 -m goodnotes_re.cli 調用):

                                ┌── gn-inspect (檢視 ZIP 檔案目錄與 SHA256)
                                ├── gn-dump (無損 dump 成 JSON)
                                ├── gn-diff (比較兩個 .goodnotes 成員差異)
                                ├── gn-recordings (檢視錄音清單與筆跡時間軸)
                                ├── gn-export-audio (提取文件錄音原始音訊)
python3 -m goodnotes_re.cli ───┼── gn-export-video (匯出時間筆跡隨語音同步動畫之 MP4 影片)
                                ├── gn-export-html (匯出多頁獨立離線互動式 HTML5 網頁播放器)
                                ├── gn-export-json (匯出完整結構為 JSON)
                                ├── gn-export-svg (匯出向量 SVG 頁面)
                                └── gn-export-pdf (直接將向量頁面編譯為 PDF)

1.1 gn-inspect - 檢視清單與 SHA256 校驗碼

用於快速檢視 .goodnotes 檔案內部包含哪些 Protobuf 成員與媒體附件,並列出大小與 SHA256 前 12 碼。

gn-inspect samples/Teat.goodnotes

輸出範例:

protobuf      2 byte  schema.pb  sha256:0a2e38c119d4
protobuf     148 byte  index.notes.pb  sha256:5b839f201d4a
protobuf      84 byte  index.attachments.pb  sha256:19e48102fa9c
protobuf   12840 byte  notes/31BE4069-02E5-4C5D-BFF9-2A8DCBC744E9  sha256:e3b0c44298fc
asset    1082491 byte  attachments/31BE4069-02E5-4C5D-BFF9-2A8DCBC744E9  sha256:8f3c7a...

1.2 gn-dump - 無損轉換單一 Protobuf 成員為 JSON

.goodnotes 檔案內部的任意 .pbnotes/<UUID> 欄位解碼,輸出帶有 Tag 號碼、Wire Type、Offset 與 Base64 的無損 JSON。

gn-dump samples/Teat.goodnotes index.notes.pb

1.3 gn-diff - 比較兩個 .goodnotes 檔案差異

在進行格式分析控制實驗 (Controlled Experiments) 時,比較兩個僅有一處修改的檔案(如操作前 before.goodnotes 與操作後 after.goodnotes)。

gn-diff before.goodnotes after.goodnotes

輸出範例:

CHANGED  index.notes.pb
ADDED    attachments/7F129B44-55C1-4D30-8812-4E1B88944E1B
CHANGED  notes/31BE4069-02E5-4C5D-BFF9-2A8DCBC744E9

1.4 gn-export-json - 匯出完整 JSON 結構

將整本筆記的所有頁面、筆跡點陣、壓感、RGBA 顏色、圖形、打字機文本與 raw wire 數據導出為單一 JSON 檔案。

gn-export-json samples/Teat.goodnotes -o document.json

1.5 gn-export-svg - 匯出高忠實度 SVG 向量頁面

將整本筆記的每一頁渲染為獨立的高解析度 SVG 向量圖形。

gn-export-svg samples/Teat.goodnotes -o pages-svg/

高級參數:

  • -s, --sticky-note-state {open,close,auto}:控制便條紙狀態 (open 展開卡片, close 折疊圖示)。
  • -b, --textbox [open|close]:控制是否繪製藍色文字選取框。
  • -a, --parse-all:解析並匯出整份文件所有的頁面(而非僅活動頁)。
  • --no-fill:關閉向量圖形填色。
  • --pdf [filename.pdf]:將所有匯出的 SVG 頁面依序打包成單一多頁 PDF 檔案。
# 範例:匯出 SVG 並同步打包成 PDF
gn-export-svg samples/Teat.goodnotes -o output_svgs/ --pdf

1.6 gn-export-pdf - 直接匯出多頁 PDF

將各頁依照向量 SVG 渲染邏輯直接編譯打包為單一多頁 PDF 文件。

gn-export-pdf samples/Teat.goodnotes -o Teat.pdf

1.7 gn-recordings - 檢視錄音階段與筆跡時間軸

檢視文件內包含的所有錄音階段資訊、時長、關聯頁面與筆畫時間戳記。

gn-recordings samples/record.goodnotes

1.8 gn-export-audio - 提取原始音訊檔

提取文件內所錄製之原始 AAC 音訊檔案 (.m4a)。

gn-export-audio samples/record.goodnotes -o audio.m4a

1.9 gn-export-video - 匯出筆畫同步動畫之 MP4 影片

將語音錄音與隨時間動態書寫的筆劃動畫合成匯出為 MP4 影片,具備隨演講進度自動跨頁切換之功能。

gn-export-video samples/record.goodnotes -o replay.mp4 --fps 15 -s open -b -a

參數選項:

  • -o, --output:輸出 MP4 影片路徑。
  • --fps:影片幀率(預設:15)。
  • --resolution-scale:畫面解析度縮放倍率(預設:1.0)。
  • -s, --sticky-note-state {open,close,auto}:便條紙展開狀態。
  • -b, --textbox [open|close]:文字框外框繪製。
  • -a, --parse-all:解析並追蹤所有有效頁面。

1.10 gn-export-html - 匯出獨立互動式 HTML5 播放器

產生單一檔案且不依賴外部伺服器的互動式 HTML5 網頁播放器,支援多頁切換、單頁/垂直捲動雙視圖模式,以及點擊任意筆跡跳轉對應語音段落。

gn-export-html samples/record.goodnotes -o player.html -s open -b -a

2. Python 程式庫 API 指南 (Python API Guide)

核心 API 封裝於 GoodNotesDocument 類別與 export 模組中。

2.1 開啟與讀取文件

from goodnotes_re import GoodNotesDocument

with GoodNotesDocument.open("samples/Teat.goodnotes") as doc:
    # 取得內部檔案列表
    members = doc.inventory()
    for m in members:
        print(m.path, m.size, m.sha256)
        
    # 直接讀取成員 bytes
    raw_data = doc.read("schema.pb")

2.2 遍歷頁面、筆跡與壓感點

with GoodNotesDocument.open("samples/Teat.goodnotes") as doc:
    pages = doc.pages(parse_all=True)
    for page in pages:
        print(f"=== 頁面 {page.index + 1} (UUID: {page.uuid}) ===")
        print(f"尺寸: {page.dimensions.width} x {page.dimensions.height} pt, 橫向: {page.dimensions.is_landscape}")
        
        # 遍歷筆跡 (Strokes)
        for stroke in page.strokes:
            print(f"筆跡 UUID: {stroke.uuid}")
            print(f"  顏色: {stroke.color_hex}, 透明度 Alpha: {stroke.alpha}")
            print(f"  筆寬: {stroke.width}, 螢光筆: {stroke.is_highlighter}")
            print(f"  控制點數量: {len(stroke.points)}")
            
            # 讀取具體控制點 (x, y, pressure)
            for pt in stroke.points[:3]:
                print(f"    Point: ({pt.x:.2f}, {pt.y:.2f}), pressure={pt.pressure:.2f}")

2.3 讀取圖形 (Shapes) 與打字機文字 (Text Elements)

with GoodNotesDocument.open("samples/Teat.goodnotes") as doc:
    for page in doc.pages(parse_all=True):
        # 讀取向量圖形
        for shape in page.shapes:
            print(f"圖形類型: {shape.shape_type}, 顏色: {shape.color_hex}")
            print(f"  頂點數量: {len(shape.points)}")
            if shape.start_arrow or shape.end_arrow:
                print(f"  帶有箭頭 Marker: start={shape.start_arrow}, end={shape.end_arrow}")
                
        # 讀取打字機富文本框
        for te in page.text_elements:
            print(f"文字區塊 [{te.x}, {te.y}]: {te.text}")
            print(f"  字型: {te.font_family}, 字號: {te.font_size}, 粗體: {te.is_bold}")

2.4 直接調用向量 SVG 與 PDF 匯出器

from pathlib import Path
from goodnotes_re import GoodNotesDocument, page_to_svg, write_svg, write_pdf, svgs_to_pdf, svg_to_pdf_bytes

with GoodNotesDocument.open("samples/Teat.goodnotes") as doc:
    pages = doc.pages(parse_all=True)

    # 1. 純記憶體渲染單頁 SVG (零磁碟 I/O)
    single_svg = page_to_svg(pages[0], doc, fill_shapes=True)

    # 2. 匯出各頁 SVG 向量圖至磁碟
    svg_paths = write_svg(
        document=doc,
        directory="output_svgs",
        fill_shapes=True,
        sticky_note_state="open",
        textbox_state=True,
        parse_all=True,
    )
    print("生成的 SVG 檔案列表:", svg_paths)

    # 3. 直接編譯為多頁 PDF
    pdf_path = write_pdf(
        document=doc,
        output="output_svgs/Teat.pdf",
        sticky_note_state="open",
        parse_all=True,
    )
    print("生成的 PDF 檔案路徑:", pdf_path)

2.5 錄音分析與時間筆跡播放

from goodnotes_re import (
    GoodNotesDocument,
    write_recording_audio,
    write_recording_video,
    write_recording_html,
)

with GoodNotesDocument.open("samples/record.goodnotes") as doc:
    # 1. 查詢所有錄音階段與筆劃時間戳記
    recordings = doc.recordings()
    for rec in recordings:
        print(f"錄音 {rec.id}: 時長={rec.duration:.2f} 秒, 關聯筆跡數={len(rec.stroke_timings)}")

    # 2. 提取音訊檔案
    audio_path = write_recording_audio(doc, "output/audio.m4a")

    # 3. 匯出自動跨頁追蹤的 MP4 筆跡同步影片
    video_path = write_recording_video(doc, "output/replay.mp4", fps=15, parse_all=True)

    # 4. 匯出獨立離線互動式 HTML5 網頁播放器
    html_path = write_recording_html(doc, "output/player.html", parse_all=True)

在下一章 08 - 開發、測試、打包與發佈 中,我們將說明如何設置開發環境、執行單元測試、維護受控格式分析實驗協議以及打包發佈至 PyPI。

Clone this wiki locally