最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Python實(shí)現(xiàn)矢量路徑的壓縮、解壓與可視化

 更新時間:2025年04月27日 11:21:34   作者:東方佑  
在圖形設(shè)計(jì)和Web開發(fā)中,矢量路徑數(shù)據(jù)的高效存儲與傳輸至關(guān)重要,本文將通過一個Python示例,展示如何將復(fù)雜的矢量路徑命令序列壓縮為JSON格式,再將其解壓還原,并通過matplotlib進(jìn)行可視化,需要的朋友可以參考下

引言

在圖形設(shè)計(jì)和Web開發(fā)中,矢量路徑數(shù)據(jù)的高效存儲與傳輸至關(guān)重要。本文將通過一個Python示例,展示如何將復(fù)雜的矢量路徑命令序列壓縮為JSON格式,再將其解壓還原,并通過matplotlib進(jìn)行可視化。這一過程可應(yīng)用于字體設(shè)計(jì)、矢量圖形編輯或Web應(yīng)用中的路徑數(shù)據(jù)傳輸。

核心功能概述

1. 路徑命令解析

  • 輸入:包含moveTo、lineTo、qCurveTo(二次貝塞爾曲線)、closePath命令的路徑數(shù)據(jù)。
  • 輸出:轉(zhuǎn)換為matplotlib.path.Path對象,用于繪制矢量圖形。

2. 路徑數(shù)據(jù)壓縮

  • 將路徑命令序列轉(zhuǎn)換為緊湊的JSON格式,便于存儲或傳輸。
  • 示例:moveTo((100, 177)) → {"M":[100,177]}

3. 路徑數(shù)據(jù)解壓

  • 將JSON格式還原為原始路徑命令序列,確保數(shù)據(jù)完整性。

4. 可視化

  • 使用matplotlib渲染路徑,驗(yàn)證壓縮/解壓過程的正確性。

代碼實(shí)現(xiàn)詳解

1. 路徑命令解析(parse_commands函數(shù))

def parse_commands(data):
    codes = []
    vertices = []
    for cmd, params in data:
        if cmd == 'moveTo':
            codes.append(Path.MOVETO)
            vertices.append(params[0])
        elif cmd == 'lineTo':
            codes.append(Path.LINETO)
            vertices.append(params[0])
        elif cmd == 'qCurveTo':
            # 處理二次貝塞爾曲線(每段需要兩個控制點(diǎn)和一個終點(diǎn))
            for i in range(0, len(params), 2):
                control = params[i]
                end = params[i+1] if i+1 < len(params) else params[-1]
                codes.extend([Path.CURVE3, Path.CURVE3])
                vertices.extend([control, end])
        elif cmd == 'closePath':
            codes.append(Path.CLOSEPOLY)
            vertices.append(vertices[0])  # 閉合路徑回到起點(diǎn)
    return codes, vertices

關(guān)鍵點(diǎn):

  • 二次貝塞爾曲線qCurveTo命令需兩個控制點(diǎn)和一個終點(diǎn),通過Path.CURVE3實(shí)現(xiàn)。
  • 閉合路徑CLOSEPOLY命令自動連接最后一個點(diǎn)到起點(diǎn)。

2. 路徑數(shù)據(jù)壓縮(compress_path_to_json函數(shù))

def compress_path_to_json(data):
    command_map = {'moveTo': 'M', 'lineTo': 'L', 'qCurveTo': 'Q', 'closePath': 'Z'}
    compressed = []
    for cmd, params in data:
        cmd_short = command_map[cmd]
        points = []
        if cmd == 'closePath':
            compressed.append({cmd_short: []})
        else:
            # 將坐標(biāo)元組展平為一維列表(如 [(x,y), (a,b)] → [x,y,a,b])
            for coord in params:
                points.extend(list(coord))
            compressed.append({cmd_short: points})
    return json.dumps(compressed, separators=(',', ':'))

示例輸出:

[{"M":[100,177]},{"L":[107,169]},{"Q":[116,172,127,172]},...]

3. 路徑數(shù)據(jù)解壓(decompress_json_to_path函數(shù))

def decompress_json_to_path(compressed_json):
    command_map = {'M': 'moveTo', 'L': 'lineTo', 'Q': 'qCurveTo', 'Z': 'closePath'}
    data = json.loads(compressed_json)
    decompressed = []
    for item in data:
        cmd_short = next(iter(item))
        points = item[cmd_short]
        cmd = command_map[cmd_short]
        if not points:
            decompressed.append((cmd, ()))  # 閉合路徑無參數(shù)
        else:
            # 將一維列表轉(zhuǎn)換為坐標(biāo)元組(如 [x,y,a,b] → [(x,y), (a,b)])
            coords = []
            for i in range(0, len(points), 2):
                coords.append((points[i], points[i+1]))
            decompressed.append((cmd, tuple(coords)))
    return decompressed

4. 可視化渲染(show_ttf函數(shù))

def show_ttf(data):
    codes, vertices = parse_commands(data)
    path = Path(vertices, codes)
    fig, ax = plt.subplots()
    patch = patches.PathPatch(path, facecolor='orange', lw=2)
    ax.add_patch(patch)
    ax.set_xlim(0, 250)  # 根據(jù)數(shù)據(jù)范圍調(diào)整坐標(biāo)軸
    ax.set_ylim(-30, 220)
    plt.gca().set_aspect('equal')
    plt.show()

完整代碼與運(yùn)行結(jié)果

示例數(shù)據(jù)

data = [
    ('moveTo', ((100, 177),)),
    ('lineTo', ((107, 169),)),
    ('qCurveTo', ((116, 172), (127, 172))),
    # ... 其他路徑命令(如閉合路徑、復(fù)雜曲線)
]

執(zhí)行流程

# 壓縮數(shù)據(jù)
compressed_json = compress_path_to_json(data)
print("壓縮后的JSON:", compressed_json)

# 解壓數(shù)據(jù)
decompressed = decompress_json_to_path(compressed_json)
print("解壓后的路徑數(shù)據(jù):", decompressed)

# 可視化
show_ttf(decompressed)

結(jié)果展示

1. 壓縮后的JSON片段

[
  {"M":[100,177]},
  {"L":[107,169]},
  {"Q":[116,172,127,172]},
  {"Z":[]}
]

2. 解壓后的路徑數(shù)據(jù)

[
    ('moveTo', ((100, 177),)),
    ('lineTo', ((107, 169),)),
    ('qCurveTo', ((116, 172), (127, 172))),
    ('closePath', ())
]

技術(shù)要點(diǎn)總結(jié)

  1. 路徑命令映射

    • M → moveTo:移動到起點(diǎn)
    • L → lineTo:繪制直線
    • Q → qCurveTo:二次貝塞爾曲線
    • Z → closePath:閉合路徑
  2. JSON壓縮策略

    • 將坐標(biāo)元組展平為一維列表,減少冗余。
    • 閉合路徑(Z)的參數(shù)為空列表。
  3. matplotlib路徑渲染

    • 使用Path對象和PathPatch實(shí)現(xiàn)復(fù)雜曲線的繪制。
    • CURVE3命令需成對使用,適配二次貝塞爾曲線的參數(shù)。

應(yīng)用場景

  • Web開發(fā):將矢量路徑數(shù)據(jù)嵌入SVG或Canvas元素。
  • 字體設(shè)計(jì):存儲和傳輸字體輪廓路徑。
  • 數(shù)據(jù)可視化:動態(tài)生成并傳輸圖表路徑數(shù)據(jù)。
import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches


# 解析輸入數(shù)據(jù)


def parse_commands(data):
    codes = []
    vertices = []
    for command, params in data:
        if command == 'moveTo':
            codes.append(Path.MOVETO)
            vertices.append(params[0])
        elif command == 'lineTo':
            codes.append(Path.LINETO)
            vertices.append(params[0])
        elif command == 'qCurveTo':
            # Check if there are enough points to form a quadratic Bezier curve segment
            for i in range(0, len(params) - 1, 2):  # Ensure we don't go out of bounds
                control_point = params[i]
                end_point = params[i + 1]
                codes.extend([Path.CURVE3, Path.CURVE3])  # Two CURVE3 commands for the quad Bezier
                vertices.extend([control_point, end_point])
        elif command == 'closePath':
            codes.append(Path.CLOSEPOLY)
            vertices.append(vertices[0])  # Closing back to the start point
    return codes, vertices


def show_ttf():
    codes, vertices = parse_commands(data)

    path = Path(vertices, codes)

    fig, ax = plt.subplots()
    patch = patches.PathPatch(path, facecolor='orange', lw=2)
    ax.add_patch(patch)
    ax.set_xlim(0, 250)  # Adjust these limits based on your data's extent
    ax.set_ylim(-30, 220)  # Adjust these limits based on your data's extent
    plt.gca().set_aspect('equal', adjustable='box')  # Keep aspect ratio equal
    plt.show()


import json


def compress_path_to_json(data):
    command_map = {
        'moveTo': 'M',
        'lineTo': 'L',
        'qCurveTo': 'Q',
        'closePath': 'Z'
    }

    compressed = []
    for cmd, params in data:
        command_type = command_map[cmd]
        points = []
        if cmd == 'closePath':
            pass  # closePath無需坐標(biāo)
        else:
            # 確保params[0]是坐標(biāo)點(diǎn)列表(即使只有一個點(diǎn))
            for param in params:
                points += list(param)

        compressed.append({
            command_type: points
        })

    return json.dumps(compressed, separators=(',', ':'))


data = [('moveTo', ((100, 177),)), ('lineTo', ((107, 169),)), ('qCurveTo', ((116, 172), (127, 172))),
        ('lineTo', ((240, 172),)), ('lineTo', ((224, 190),)), ('lineTo', ((212, 177),)), ('lineTo', ((175, 177),)),
        ('qCurveTo', ((183, 186), (176, 200), (154, 210))), ('lineTo', ((152, 207),)),
        ('qCurveTo', ((164, 190), (166, 177))), ('closePath', ()), ('moveTo', ((204, 143),)), ('lineTo', ((211, 148),)),
        ('lineTo', ((198, 162),)), ('lineTo', ((189, 152),)), ('lineTo', ((143, 152),)), ('lineTo', ((128, 160),)),
        ('qCurveTo', ((129, 149), (129, 116), (128, 102))), ('lineTo', ((142, 106),)), ('lineTo', ((142, 114),)),
        ('lineTo', ((191, 114),)), ('lineTo', ((191, 105),)), ('lineTo', ((205, 111),)),
        ('qCurveTo', ((204, 119), (204, 135), (204, 143))), ('closePath', ()), ('moveTo', ((142, 147),)),
        ('lineTo', ((191, 147),)), ('lineTo', ((191, 119),)), ('lineTo', ((142, 119),)), ('closePath', ()),
        ('moveTo', ((119, 87),)), ('lineTo', ((218, 87),)), ('lineTo', ((218, 6),)),
        ('qCurveTo', ((218, -3), (210, -5), (181, -3))), ('lineTo', ((181, -8),)),
        ('qCurveTo', ((212, -13), (212, -26))), ('qCurveTo', ((221, -22), (231, -12), (231, 2))),
        ('lineTo', ((231, 80),)), ('lineTo', ((240, 87),)), ('lineTo', ((224, 102),)), ('lineTo', ((216, 92),)),
        ('lineTo', ((119, 92),)), ('lineTo', ((105, 100),)), ('qCurveTo', ((106, 84), (106, 5), (105, -26))),
        ('lineTo', ((119, -18),)), ('closePath', ()), ('moveTo', ((196, 58),)), ('lineTo', ((203, 63),)),
        ('lineTo', ((188, 76),)), ('lineTo', ((182, 67),)), ('lineTo', ((151, 67),)), ('lineTo', ((137, 76),)),
        ('qCurveTo', ((138, 59), (138, 30), (137, 5))), ('lineTo', ((150, 11),)), ('lineTo', ((150, 21),)),
        ('lineTo', ((184, 21),)), ('lineTo', ((184, 10),)), ('lineTo', ((197, 16),)),
        ('qCurveTo', ((196, 27), (196, 48), (196, 58))), ('closePath', ()), ('moveTo', ((150, 62),)),
        ('lineTo', ((184, 62),)), ('lineTo', ((184, 26),)), ('lineTo', ((150, 26),)), ('closePath', ()),
        ('moveTo', ((36, 63),)), ('qCurveTo', ((66, 100), (94, 148))), ('lineTo', ((103, 152),)),
        ('lineTo', ((83, 163),)), ('qCurveTo', ((74, 138), (66, 125))), ('lineTo', ((30, 123),)),
        ('qCurveTo', ((50, 154), (71, 193))), ('lineTo', ((82, 197),)), ('lineTo', ((59, 209),)),
        ('qCurveTo', ((51, 178), (23, 124), (14, 124))), ('lineTo', ((25, 106),)),
        ('qCurveTo', ((31, 111), (50, 117), (63, 119))), ('qCurveTo', ((44, 87), (24, 63), (18, 62))),
        ('lineTo', ((28, 44),)), ('qCurveTo', ((39, 51), (68, 60), (98, 66))), ('lineTo', ((97, 70),)),
        ('qCurveTo', ((67, 66), (36, 63))), ('closePath', ()), ('moveTo', ((11, 14),)), ('lineTo', ((21, -4),)),
        ('qCurveTo', ((30, 4), (65, 20), (95, 30))), ('lineTo', ((94, 34),)),
        ('qCurveTo', ((72, 28), (25, 16), (11, 14))), ('closePath', ())]


def decompress_json_to_path(compressed_json):
    command_map = {
        'M': 'moveTo',
        'L': 'lineTo',
        'Q': 'qCurveTo',
        'Z': 'closePath'
    }

    data = json.loads(compressed_json)
    decompressed = []

    for item in data:
        cmd_char = next(iter(item))  # 獲取命令字符
        points = item[cmd_char]
        original_cmd = command_map[cmd_char]

        if not points:
            # closePath,參數(shù)為空
            decompressed.append((original_cmd, ()))
        else:
            # 將points列表轉(zhuǎn)換為坐標(biāo)點(diǎn)元組的元組
            tuples = []
            for i in range(0, len(points), 2):
                x = points[i]
                y = points[i + 1]
                tuples.append((x, y))
            params = tuple(tuples)
            decompressed.append((original_cmd, params))

    return decompressed


compressed_json = compress_path_to_json(data)

# 解壓
decompressed = decompress_json_to_path(compressed_json)



以上就是使用Python實(shí)現(xiàn)矢量路徑的壓縮、解壓與可視化的詳細(xì)內(nèi)容,更多關(guān)于Python矢量路徑解壓縮與可視化的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Python?sentence-transformers庫示例詳解

    Python?sentence-transformers庫示例詳解

    Sentence?Transformer是一個Python框架,用于句子、文本和圖像嵌入Embedding,它基于Transformer架構(gòu)的預(yù)訓(xùn)練模型,并在大量語義相似性數(shù)據(jù)上進(jìn)行了微調(diào),能夠捕捉句子之間的深層語義關(guān)系,本文給大家介紹Python?sentence-transformers庫的相關(guān)知識,感興趣的朋友一起看看吧
    2025-08-08
  • Python腳本實(shí)現(xiàn)自動刪除C盤臨時文件夾

    Python腳本實(shí)現(xiàn)自動刪除C盤臨時文件夾

    在日常使用電腦的過程中,臨時文件夾往往會積累大量的無用數(shù)據(jù),占用寶貴的磁盤空間,下面我們就來看看Python如何通過腳本實(shí)現(xiàn)自動刪除C盤臨時文件夾吧
    2025-01-01
  • Python pip安裝依賴redis被自動降級的問題及解決

    Python pip安裝依賴redis被自動降級的問題及解決

    安裝Redis 7.1.0時因版本過舊與Python3.10不兼容,通過pip安裝依賴時遵循“版本約束”,導(dǎo)致Redis降級到<3.0,Booktype 項(xiàng)目依賴Redis <3.0,與Python3.10不兼容,解決方法是刪除Booktype依賴,以避免版本沖突
    2025-12-12
  • 用Python實(shí)現(xiàn)簡單的人臉識別功能步驟詳解

    用Python實(shí)現(xiàn)簡單的人臉識別功能步驟詳解

    這篇文章主要介紹了用Python實(shí)現(xiàn)簡單的人臉識別功能步驟詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • 如何利用Python 快速找到最大文件

    如何利用Python 快速找到最大文件

    現(xiàn)在的電腦差不多都是固態(tài)硬盤了,速度很快,但容量不會太大,經(jīng)常會出現(xiàn)磁盤空間不足的情況,怎么辦,刪除那些不重要的最大的文件是最有效的辦法,這篇文章我們就來介紹介紹了如何利用Python 快速找到最大文件,需要的朋友可以參考一下
    2021-11-11
  • Python使用描述符實(shí)現(xiàn)屬性類型檢查的案例解析

    Python使用描述符實(shí)現(xiàn)屬性類型檢查的案例解析

    這篇文章主要介紹了Python使用描述符實(shí)現(xiàn)屬性類型檢查,實(shí)例屬性就是在一個類中將另一個類的實(shí)例作為該類的一個數(shù)屬性,本文通過代碼演示給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-05-05
  • python之value_counts()的具體使用

    python之value_counts()的具體使用

    value_counts()?是一個用于統(tǒng)計(jì)某列中各個值的出現(xiàn)次數(shù)的函數(shù),本文主要介紹了python之value_counts()的具體使用,具有一定的參考價值,感興趣的可以了解一下
    2023-10-10
  • 回歸預(yù)測分析python數(shù)據(jù)化運(yùn)營線性回歸總結(jié)

    回歸預(yù)測分析python數(shù)據(jù)化運(yùn)營線性回歸總結(jié)

    本文主要介紹了python數(shù)據(jù)化運(yùn)營中的線性回歸一般應(yīng)用場景,常用方法,回歸實(shí)現(xiàn),回歸評估指標(biāo),效果可視化等,并采用了回歸預(yù)測分析的數(shù)據(jù)預(yù)測方法
    2021-08-08
  • Python實(shí)現(xiàn)的銀行系統(tǒng)模擬程序完整案例

    Python實(shí)現(xiàn)的銀行系統(tǒng)模擬程序完整案例

    這篇文章主要介紹了Python實(shí)現(xiàn)的銀行系統(tǒng)模擬程序,結(jié)合完整實(shí)例形式分析了Python基于面向?qū)ο蟪绦蛟O(shè)計(jì)模擬的銀行系統(tǒng)登錄驗(yàn)證、開戶、找回密碼、掛失、查詢、存取款、轉(zhuǎn)賬等功能相關(guān)操作技巧,需要的朋友可以參考下
    2019-04-04
  • 詳解如何減少python內(nèi)存的消耗

    詳解如何減少python內(nèi)存的消耗

    這篇文章主要介紹了詳解如何減少python內(nèi)存的消耗,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08

最新評論

东宁县| 藁城市| 蒲城县| 普洱| 合山市| 奉新县| 涿鹿县| 澎湖县| 平昌县| 响水县| 三台县| 西藏| 闽侯县| 皋兰县| 甘南县| 株洲县| 若尔盖县| 安福县| 米林县| 抚顺市| 凤阳县| 广丰县| 临颍县| 祁阳县| 桂阳县| 丰县| 瓦房店市| 黎城县| 玉田县| 乌鲁木齐市| 太和县| 潞城市| 马关县| 冕宁县| 广元市| 黑龙江省| 宿松县| 巴彦淖尔市| 丹巴县| 始兴县| 铜山县|