Pythonと画像ベクター化APIでSVGを保存する方法:テストと変換の復旧
PythonからPNG、JPEG、WebPをベクター化APIに送信してSVGを保存します。テスト応答の確認と、接続切れ後に既存の変換を取り直す方法も解説します。
目次
Pythonスクリプトでラスター画像をPerfectVectorのベクター化APIに送り、返されたSVGを元画像と同じ場所に保存できます。次の例では、ダウンロード前に変換IDを表示します。接続が途切れたら、そのIDまたは自分で決めたリクエストキーから結果を取り直せます。
テストキーと画像を1枚用意する
Developer APIのページでテストキーを作成します。ターミナルで環境変数 PERFECTVECTOR_API_KEY に設定し、スクリプトやバージョン管理には入れないでください。プロジェクトのPython環境で python -m pip install requests を実行します。
最初は logo.png という512 × 512ピクセルのロゴなど、単一フレームのPNG、JPEG、WebPを使います。APIは5 MiB以下で、各辺が100~4,096ピクセルの画像を受け付けます。テストモードはアップロードを検証し、「TEST MODE」と記された固定のSVGを無料で返します。このファイルでリクエストとダウンロードを確認できます。トレースの品質は、自分の画像を本番変換して評価します。PerfectVector APIのテストモード
テストキーでPythonスクリプトを実行すると、ダウンロードしたSVGを正常に解析できました。同じリクエストキーで同じアップロードを再送すると、どちらも同じ変換IDが返りました。

Pythonで画像を送信してSVGを保存する
次のコードを vectorize.py として保存します。Requestsの files 引数でマルチパートのアップロードを作成し、元画像のデータを image フォームフィールドに入れます。Requestsのマルチパートアップロード
import os
import sys
import time
from pathlib import Path
import requests
API = "https://api.perfectvector.com/v1"
AUTH = {"Authorization": f"Bearer {os.environ['PERFECTVECTOR_API_KEY']}"}
def checked(response):
content_type = response.headers.get("Content-Type", "").split(";")[0]
if response.status_code >= 400 and content_type == "application/problem+json":
problem = response.json()
raise RuntimeError(f"{problem['code']} (request {problem['request_id']})")
response.raise_for_status()
return response
def vectorize(source, destination, operation_id):
with source.open("rb") as image:
response = checked(requests.post(
f"{API}/vectorizations",
headers={**AUTH, "Idempotency-Key": operation_id, "Prefer": "wait=10"},
files={"image": (source.name, image)},
timeout=30,
))
conversion = response.json()
conversion_id = conversion["id"]
print(f"Conversion ID: {conversion_id}", flush=True)
deadline = time.monotonic() + 720
while conversion["status"] in {"queued", "processing"}:
if time.monotonic() >= deadline:
raise TimeoutError(f"Stopped polling {conversion_id}")
time.sleep(2)
conversion = checked(requests.get(
f"{API}/vectorizations/{conversion_id}", headers=AUTH, timeout=30,
)).json()
if conversion["status"] != "succeeded":
error = conversion["results"][0].get("error") or {}
raise RuntimeError(f"{conversion_id}: {error.get('code', conversion['status'])}")
svg = checked(requests.get(
f"{API}/vectorizations/{conversion_id}/result", headers=AUTH, timeout=30,
))
if svg.headers.get("Content-Type", "").split(";")[0] != "image/svg+xml":
raise ValueError("Expected an SVG response")
partial = destination.with_suffix(".svg.part")
partial.write_bytes(svg.content)
partial.replace(destination)
print(f"{destination} saved ({len(svg.content)} bytes)")
if __name__ == "__main__":
source = Path(sys.argv[1])
if source.suffix.lower() not in {".png", ".jpg", ".jpeg", ".webp"}:
raise SystemExit("Choose a PNG, JPEG or WebP file")
if source.stat().st_size > 5 * 1024 * 1024:
raise SystemExit("Choose a file no larger than 5 MiB")
vectorize(source, source.with_suffix(".svg"), sys.argv[2])logo.png があるディレクトリから実行します。コマンドを実行する前に、変換用のIDを決めて記録します。APIではこれを冪等性キーと呼び、同じアップロードの再送を1つの変換にひも付けます。例では logo-asset-0001 を使います。画像や操作が異なる場合は、別の値を使います。PerfectVectorの安全な再試行
python vectorize.py logo.png logo-asset-0001テストが成功すると変換IDとバイト数が表示され、logo.png の隣に logo.svg が保存されます。logo.svg を開いて、サンプルが表示されるか確認します。スクリプトは新しいSVGのダウンロードが終わると、同名の既存SVGを置き換えます。初回は作業用フォルダーで試してください。
スクリプトはサーバーに、未完了の変換を返すまで最大10秒待つよう求めます。queued と processing の変換は約2秒間隔で確認し、succeeded になってからダウンロードします。テスト変換はすぐに終わります。本番ワーカーに組み込む前に、ローカルのテストデータで未完了の応答を再現して、ポーリングの分岐を確認します。PerfectVectorの待機と非同期処理
タイムアウト後に既存の変換を取り直す
Pythonが変換IDを表示していれば、GET /v1/vectorizations/{id} でそのIDの状態を調べます。成功後、同じアカウントとモードで GET /v1/vectorizations/{id}/result を呼び、SVGをダウンロードします。結果のリンクは完了から24時間で期限が切れるため、後から使うなら自分のストレージにコピーしてください。PerfectVectorの結果ダウンロード
IDが表示される前にPythonが止まったら、最初のリクエストから24時間以内に、同じファイルのデータと同じ冪等性キーを使ってコマンドを実行し直します。最初の送信が受理されていれば、APIは既存の変換を返します。この期間を過ぎると、同じキーで送っても新しい変換が始まる場合があります。PerfectVectorの安全な再試行
| 表示された内容 | 確認すること |
|---|---|
401 invalid_api_key | Pythonが使う環境に有効なテストキーを設定します。キーを失効させた場合は、同じモードで作り直します。 |
415 unsupported_media_type または 422 invalid_image | 元ファイルを開き、実際の形式とピクセル寸法を確認します。修正した画像を保存し、そのアップロードには別のキーを使います。 |
変換IDの後に processing_failed | APIは変換の記録を作成しましたが、画像をトレースできませんでした。元画像を調べ、修正したファイルを別の操作として送ります。 |
409 idempotency_conflict | 同じキーで異なる画像データまたはオプションを使っています。元ファイルで復旧するか、新しい入力に新しいキーを割り当てます。 |
サポートに連絡する場合は、例外に表示されたリクエストIDか、スクリプトが表示した変換IDを控えます。APIエラーのリファレンスで安全に再試行できるエラーを確認できます。
よくある質問
同じPythonスクリプトでJPEGやWebPもベクター化できますか?
はい。最初の引数にJPEGまたはWebPのファイルを指定します。ファイルサイズ、寸法、単一フレームの条件は同じで、出力の拡張子はSVGです。
このPythonの例でフォルダー全体を処理できますか?
まず1件のアップロードとダウンロードを確認してください。フォルダーを処理する場合は、各ファイルのキー、変換ID、出力パスを永続的なキューに記録します。PerfectVectorは既定で1アカウントにつき同時に1件の本番変換を許可するので、次を送る前に前の変換が終わるまで待ちます。PerfectVector APIの制限
参考資料
- Requests — クイックスタート — マルチパートのファイル、タイムアウト、バイト応答。
- PerfectVector — テストモード — アップロードの制限、固定のテストSVG、クレジットの扱い。
- PerfectVector — 待機と非同期処理 — サーバーの待機指定、ポーリング、テストリクエストの完了時点。
- PerfectVector — 冪等性 — キーの有効期間、適用範囲、競合、再送条件。
- PerfectVector — 結果 — 結果のエンドポイント、認証、有効期限。
- PerfectVector — エラー — HTTPの問題コードと復旧方法。
- PerfectVector — 制限 — 本番の既定同時実行数とファイル制限。
PerfectVector APIのページでテストキーを取得し、手元の画像1枚でスクリプトを実行します。保存されたSVGが開けることと、ターミナルに変換IDが表示されることを確認してください。


