mcpField
V
vecline

vecline

ローカル
vecline.xyzメディア・デザイン1710 週間前に更新

vecline について

Veclineは、開発者やクリエイター向けのローカル優先の画像・ドキュメントツールキットです。CLI、ライブラリ、ブラウザー版Studioを備え、形式変換とベクター化の精度を測定し、検証済みのビット単位で正確なモードも提供します。

主な機能

  1. 01ラスター形式とSVGの相互変換
  2. 02正確性を保証または測定するベクター化
  3. 03画像の類似度と変換精度の測定
  4. 04PDFとOffice文書のレンダリングと変換
  5. 05DXF、EPS、G-codeへの出力

活用シーン

  1. 01ロゴやアイコンを編集可能なベクターに変換
  2. 02異なる画像形式間でファイルを変換
  3. 03変換結果がピクセル単位で一致するか確認
  4. 04加工用に実寸のカットデザインを準備

設定

ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。

mcp.json · 共通設定
{
"mcpServers": {
"shunyagatha-vecline": {
"command": "npx",
"args": [
"-y",
"vecline"
],
"env": {
"VECLINE_SOFFICE": "<VECLINE_SOFFICE>"
}
}
}
}
起動コマンドnpx -y vecline
設定が必要な環境変数
VECLINE_SOFFICEOptional. Path to a LibreOffice `soffice` binary, used only by the Office conversion tools. Left unset, they are auto-detected; if LibreOffice is absent the affected tools report themselves as unavailable rather than failing.

ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。

パッケージ
npmvecline2.1.4

ツール

16

掲載時のツール一覧 · 2 週間前に更新

パラメーター型必須説明
modeenumいいえauto(デフォルト)は画像に応じて選択します。フラットな画像では pixel/lossless はビット単位で完全に一致します。trace はパスで近似し、embed は元のラスター画像をロスレスでラップします。auto | lossless | pixel | trace | embed
inputstringはいソースとなるラスター画像のパス
colorsnumberいいえトレースモードのパレットサイズ(2~256)
outputstringいいえ任意の .svg 出力パス
presetenumいいえトレースパスの調整設定。ピクセルモードと埋め込みモードでは無視されますauto | logo | lineart | poster | photo | detailed | pixelart | exact
verifybooleanいいえ結果をラスタライズして測定します。SVG テキストの代わりに、ssim、psnr、meanDeltaE、pixelIdentical、svgBytes を含む JSON を返します。追加で 1 回レンダリングします。

詳細

Vecline

Vecline

測定可能なラスター ⇄ SVG 変換 — さらに幅広い画像・ドキュメントツールキット。 10 種類のラスター形式を相互に変換でき、各変換の精度は主張ではなく実際に測定されています。さらに、PDF と Office(docx/xlsx/pptx)のレンダリングと変換、画像 → PDF、EPS や G-code と並ぶ、実際の物理的なカットサイズでの DXF 出力、メーカー向けの中心線トレースやコンテンツを考慮したトリミングにも対応しています。その多くを、ブラウザー向けのバンドルが CI で実証されている依存関係ゼロのコアで実現しています。

フラットなアートワーク(ロゴ、アイコン、UI、スクリーンショット、ピクセルアート)では、出力はビット単位で完全一致します。SSIM 1.0000、PSNR ∞、差分ピクセルはゼロです。実際のロゴでは、近似にとどまる imagetracerjs や vtracer よりもファイルサイズが小さく、それぞれ 60 KB と 64 KB に対して 24 KB です。これは、より優れた曲線フィッティングではなく、近似するより正確に符号化するほうが効率的な画像だと認識することで実現しています。トレースでは、デフォルトで実際の曲線を出力するようになりました。 サブピクセルのエッジ配置が有効になっており、これが曲線フィッターを動作させる唯一の方法です。以前のデフォルトでは、実際のアートワークに対して曲線コマンドがゼロの階段状の出力が返されていました。整数格子から座標を移動すると圧縮効率が下がるため、gzip 圧縮後のバイト数は約 2.35 倍になります。--no-subpixel を指定すれば、従来の小さな出力に戻せます。ピクセルモードと完全一致モードには変更がなく、引き続きビット単位で完全一致します。potrace は他のどのツールよりも小さい出力になりますが、精度は大幅に低くなります。これは実際のトレードオフであり、この README で隠すつもりはありません。実際の写真では、デフォルト設定での SSIM は 3 つのツールすべてを 0.05~0.18 上回っています。vtracer に特定のフラグを指定すると、その差の一部は縮まります。最速というわけではなく、測定したすべてのフィクスチャで imagetracerjs のほうが高速です。この README にある数値はすべて再現可能です。node scripts/fetch-corpus.mjs && npm run compare を実行してください。(コーパスはコミットせずに取得します。写真の再配布権がないためです。)

npm version npm downloads CI types license node

▶ Vecline Studio — vecline.xyz — ツールキット全体をブラウザーで利用できます。画像、PDF、またはブラウザーで読み込めない TGA/PNM/ICO をドロップして、調整し、SSIM / PSNR / CIEDE2000 の値をリアルタイムで確認できます。SVG、実際のカットサイズでの DXF、EPS、PDF、G-code、React/Vue/Svelte/Solid コンポーネント、色分解、スプライトシート、ファビコン、BlurHash のほか、10 種類のラスター形式間での再エンコードにも対応しています。無料、無制限、登録不要、オフラインでも動作し、何もアップロードされません。すべての変換はサーバーではなく、ブラウザーのタブ内で実行されます。(比較 · 開発者向けプレイグラウンド)

vecline vectorize logo.png --verify
✓ logo.svg  400×300  pixel mode  4 shapes  2.1 KB → 7.5 KB  228 ms
  · Auto-selected pixel mode: 4 distinct colours, 1.0% run density. Output is bit-exact.

Accuracy  bit-exact (lossless)
  PSNR        ∞
  SSIM        1.000000 (luma 1.000000)
  RMSE        0.0000

ロスレスの保証

vecline vectorize anything.png --lossless

--lossless はビット単位で完全一致する SVG を返すか、失敗します。近似した結果を黙って返すことはありません。

これは構築方法ではなく、測定によって保証されます。すべての候補エンコードをピクセルにレンダリングし直してソースと比較します。ビット単位で完全一致しないものはすべて破棄され、残る候補がなければコマンドはエラーになります。候補は、結果の有用性が高い順に試されます。

  1. 正確なジオメトリ — 編集可能で、無限に拡大縮小できる本物のパスです。より小さくエンコードできる方に応じて、矩形または輪郭を使います。
  2. 埋め込み、元のバイト列を保持 — ピクセルだけでなく、ソースファイルのバイト単位で完全一致する往復変換です。
  3. 埋め込み、PNG として再エンコード — 常に正確にレンダリングされますが、元のファイルは保持されません。

テストスイートのすべてのフィクスチャ(フラットなアートワーク、ピクセルアート、ソフトアルファ、写真、JPEG ソース、1 ピクセル)で測定した結果、いずれも PSNR ∞、maxChannelDiff 0 で復元されます。

バイト単位の一致と検証

元のファイルを保持する場合、SVG にはその SHA-256 が記録されます。extract はファイルを返し、ダイジェストを検証します。

vecline vectorize logo.png -o keep.svg --mode embed --embed-strategy preserve
vecline extract keep.svg -o recovered.png --against logo.png
✓ recovered.png  image/png  2.1 KB
  sha256   1c4f95f66b28a40a75672614796de762f6ef8a6afec3191b460dbbd556f10366
  digest   matches the value recorded when the SVG was written
  payload  the original file, preserved byte for byte
  vs source byte-identical to logo.png

不一致があると extract はゼロ以外の終了コードを返すため、CI のゲートとして使用できます。正直に補足すると、埋め込み JPEG はバイト単位ではそのまま保持されますが、ビット単位では完全一致してレンダリングされません。これは resvg のデコーダーが逆 DCT を異なる方法で丸めるためです。厳密な --lossless はこれを検出して候補を破棄し、その旨を通知します。

どの結果になるか
入力結果サイズ正確か?
フラットなアートワーク 400×300本物のジオメトリ(輪郭)3.9 KB✅
ピクセルアート 128×128本物のジオメトリ(矩形)0.6 KB✅
favicon.ico 64×64本物のジオメトリ(矩形)0.5 KB✅
BMP 400×300本物のジオメトリ(輪郭)3.9 KB✅
写真 320×240埋め込み PNG230 KB✅

写真を正確なジオメトリとして出力することもでき、--prefer geometry を指定すれば実行できます。ただし、ピクセルごとに矩形が 1 つ必要になるため、同じ写真が 42,933 個のシェイプを含む 1.99 MB のファイルになります。名前だけのベクターなので、auto はビットマップを使い、測定した比率を通知します。隠し立てはありません。

「精度 100%」の正直な説明

多くのベクター化ツールは完全な精度をうたっています。どのツールを使うべきかを決めるうえで重要な、実際に正しいことを説明します。

変換方向正確に変換できるか?理由
SVG → ラスターできます。指定した任意の解像度で変換できますレンダリングは明確に定義された計算です。幅 4000px を指定すれば、レンダラーのラスタライズ規則に従って、正確にそのサイズが得られます。
ラスター → SVG、ロスレスできますどちらもビット単位で完全一致する、2 つの異なる方法があります。以下の pixel と embed を参照してください。
ラスター → SVG、曲線としてトレースできませんし、今後もできません写真には、コンパクトなベジェ曲線の集合では表現できないほど多くの独立した情報が含まれています。トレースは、定義上、近似です。

写真を曲線に正確にベクター化できるとうたうものは、ビットマップを埋め込んでベクターと呼んでいるか、誤りを述べています。Vecline は 2 つの正確な変換を適切に行い、近似変換も高品質に行います。また、どの方法で変換されたか、その結果がどの程度正確かを常に通知します。

3つの方式と、それぞれの使いどころ

方式出力正確性用途
lossless実際のジオメトリ、または埋め込みビットマップビット単位で完全一致、検証済み正確さが絶対条件となる場合
pixel実際のベクタージオメトリ(矩形または輪郭)ビット単位で完全一致ロゴ、アイコン、ピクセルアート、スクリーンショット、図、単色のアート
trace実際のベジェ曲線近似、測定済み写真、複雑なアート、拡大または編集したいもの
embedSVG ラッパー内のビットマップビット単位で完全一致この画像をそのまま SVG コンテナーに入れる必要がある場合

auto(デフォルト)は画像を調べ、pixel と trace のどちらかを選びます。--lossless は、上記の保証を適用してすべての設定を上書きします。

pixel モードは、意外に思われることが多いモードです。 入力画像と再ラスタライズした結果の間に異なるピクセルが一つもない、実際に編集可能で、無限に拡大できるベクターパスを生成します。「見た目が同じ」ではなく、文字どおり完全に一致します。フラットなアートでは、通常これがまさに必要なものです。

インストール

npm install -g vecline        # the CLI
npm install vecline           # the library

Node.js 18.17 以上が必要です。ネイティブ依存パッケージ(sharp、resvg)には、Linux、macOS、Windows 用のビルド済みバイナリが含まれています。

あらゆるプロジェクト構成に対応
必要なものインポートネイティブ依存関係
Node ツールキット一式import { vectorize } from 'vecline'あり
… CommonJS からconst { vectorize } = require('vecline')あり
ベクター化機能のみimport { trace } from 'vecline/vectorize'なし
メトリクスのみimport { compareImages } from 'vecline/metrics'なし
純粋な TypeScript コーデックのみimport { encodeBmp } from 'vecline/formats'なし
すべてポータブルに利用import { vectorizeExact } from 'vecline/core'なし
画像編集(リサイズ、回転など)import { editImage } from 'vecline/ops'sharp のみ
カスタムコーデックの登録import { registerDecoder } from 'vecline/codecs'なし

使うものだけをインストールしてください。none と記載されたサブパスはそれぞれ独立してインポートでき、ネイティブコーデックを省いても動作します(npm install vecline --omit=optional)。また、パッケージは "sideEffects": false なので、バンドラーはインポートしないものをすべて除外します。vecline/core は、依存関係がゼロで Node 組み込みモジュールを使わないベクター化・測定エンジンです。ブラウザーの ImageData とバイト単位で同じレイアウトの単純な { width, height, data } を受け取るため、キャンバスのピクセルをそのまま渡せます。

import { vectorizeExact } from 'vecline/core';

const { data, width, height } = ctx.getImageData(0, 0, canvas.width, canvas.height);
const { svg } = vectorizeExact({ width, height, data });   // bit-exact, no codec needed

依存関係ゼロという主張は、単に述べているのではなく CI で検証しています。 すべてのコミットで、esbuild を使って vecline/core をブラウザー向けにバンドルします。Node プラットフォームも外部モジュールも指定せず、出力に node: 指定子や Node グローバルが一つでも残っていれば失敗します。圧縮後のサイズは 96 KB で、サイズが大幅に増えても見逃さないよう、上限と下限の両方にしきい値を設けています。インポートグラフを読むだけでは、目に見えるインポートがクリーンであることしか確認できません。バンドルすれば、ユーザーが実際に行う操作が機能することを証明できます。

オプションのネイティブパッケージを省いてインストールしても(npm install vecline --omit=optional)、core は約 100 MB ではなく 2 MB で引き続き動作します。画像ファイルの読み込み、SVG のピクセルへのレンダリング、検証済みのロスレス保証には、実際のコーデックが必要です。そのため、これらはメインエントリーポイントに含まれています。

BMP、ICO、PNM、TGA のコーデックはこのパッケージ内で一から実装されているため、ネイティブパッケージを省いても動作します。これらの読み書きに libvips は必要ありません。一点、後から知ることにならないように注意してください。ICO エントリーには、生のピクセルではなく完全な PNG が格納されている場合があります(256×256 のアイコンの多くがそうです)。その場合、デコードには実際の PNG コーデックが必要です。ICO コンテナー自体はこちらで解析できますが、内部のデータはどこかで処理する必要があります。小さいアイコンで通常使われる、生の DIB を格納したエントリーなら、何もインストールせずに読み込めます。

対応形式

読み込み書き出し
PNG✅✅
JPEG✅✅
WebP✅✅ 非可逆+可逆
AVIF✅✅ 非可逆+可逆
TIFF✅✅
GIF✅ 先頭フレーム✅
BMP✅ すべての色深度、RLE、BITFIELDS✅ 24/32-bit
ICO / CUR✅ 最大のエントリー✅ PNG または DIB ペイロード
PNM(PBM/PGM/PPM)✅ P1–P6✅ P4/P5/P6
TGA✅ RLE、カラーマップ✅ RLE は任意
SVG✅✅

読み込める形式はすべて書き出せます。 これは 11 × 11 = 121 通りの変換にあたり、テストスイートではコミットごとにすべての変換を実行します。PNG→TGA、ICO→WebP、TGA→SVG、SVG→BMPなど、必要な変換を実行できます。すべての組み合わせを1つのコマンドで利用できます。

vecline convert photo.png thumb.webp   # raster → raster
vecline convert logo.png logo.svg      # raster → vector
vecline convert logo.svg [email protected]   # vector → raster

convert は拡張子だけでなく、入力バイトと出力拡張子の両方から形式を判定します。たとえば、.txt という名前でも <svg> を含むファイルは SVG として扱われ、PNG バイトを含む .svg ファイルは SVG として扱われません。

BMP、ICO、PNM、TGA は純粋な TypeScript でデコードされます。libvips にはこれらの形式が組み込まれておらず、いずれも完全に実装できるほどシンプルで安定しているため、新たなネイティブ依存関係を追加していません。これら4形式はすべて可逆形式なので、テストスイートでは近似的な一致ではなく、ビット単位で完全に一致するデコードを検証します。

標準ではサポートされていません: HEIC、JPEG XL、JPEG 2000、PSD、PDF、カメラ RAW。sharp に同梱されるビルド済みの libvips では、これらの読み書きはできません。HEIC は HEVC が特許で保護されているため、JXL と JP2 は単にコンパイルに含まれていないためです(確認済みのエラー:heifsave: Unsupported compression、jxlsave_buffer not found、JP2 output requires OpenJPEG)。それぞれの形式に WASM コーデックを同梱すると、ほとんどのユーザーが使わない形式のために、インストールのたびに数十メガバイトが追加されます。

ただし、プラグインとして追加できます。 コーデックを同梱する代わりに、Vecline は接続口を用意しています。WASM デコーダーを自分でインストールして登録すれば、その形式を、組み込み形式と同じようにあらゆる場所で読み書きできるようになります。

import decodeJxl from '@jsquash/jxl/decode.js';
import { registerDecoder } from 'vecline/codecs';

registerDecoder({
  format: 'jxl',
  canDecode: (b) => b.length > 2 && b[0] === 0xff && b[1] === 0x0a, // JXL signature
  decode: async (bytes) => {
    const { data, width, height } = await decodeJxl(bytes);
    return { width, height, data: new Uint8ClampedArray(data.buffer) };
  },
});
// vecline can now vectorize, convert, and edit .jxl files.

この機能を必要としないユーザーには、何も追加されません。単発の変換であれば、まず ImageMagick または libheif を使うのが、引き続き最も簡単な方法です。

クイックスタート

# Convert, letting vecline choose the strategy
vecline vectorize logo.png

# Prove the result is what it claims
vecline vectorize logo.png --verify

# Guarantee a bit-exact result whatever the input, or fail
vecline vectorize photo.jpg --lossless

# Trace to curves, escalating settings until it hits a quality target
vecline vectorize portrait.jpg --target-ssim 0.95

# SVG back to raster at any size
vecline rasterize logo.svg -o [email protected] --scale 4
vecline rasterize logo.svg -o hero.webp --width 2400 --lossless

# Ask what a file is and what to do with it
vecline info photo.jpg

# Measure any two images against each other — raster or SVG, in any combination
vecline verify original.png result.svg

# Whole directories
vecline batch 'assets/**/*.png' -o dist/ --to svg

透明な出力

--transparent を指定すると、単色の背景が取り除かれ、本物の透明部分が残ります。

vecline vectorize logo.png --transparent             # detect the background colour
vecline vectorize logo.png --transparent '#ffffff'   # or name it
vecline rasterize icon.svg -o icon.png --transparent

破壊的な処理ではなく安全に使えるのは、次の2つの工夫によるものです。

  • 端から塗りつぶします。 「すべての白いピクセル」を取り除くと、ロゴ内部の白い部分にも穴が開きます。目の輝きや、o の内側の空間などがその例です。境界から到達できる色だけが背景として扱われます。--bg-everywhere を指定すると、すべての箇所に適用する大まかな処理になります。
  • 許容範囲は知覚に基づきます。 JPEG の白は厳密には #ffffff ではなく、RGB しきい値を緩めてそれを捉えようとすると、薄い黄色まで消えてしまいます。--bg-tolerance は Oklab の距離を使うため、「わずかにオフホワイトの色」と「明らかに異なる色」がしきい値の両側に分かれます。--feather を使うと、切り抜きの境界が滑らかになります。

コア機能でも利用できるため、ブラウザーでも動作します:removeBackground(image, { tolerance: 0.02 })。

精度の測定結果

以下の数値はすべて --verify で生成されます。生成された SVG をピクセルにレンダリングし、元データと比較します。npm run bench で再現できます。

入力モード入力出力ピクセル完全一致PSNRSSIM平均 ΔE₀₀
フラットなアートワーク、400×300pixel2.1 KB7.5 KB100.00%∞1.00000.000
ピクセルアートのスプライト、128×128pixel0.5 KB0.6 KB100.00%∞1.00000.000
フラットなアートワーク、400×300embed2.1 KB3.2 KB100.00%∞1.00000.000
写真、320×240embed14.5 KB19.7 KB87.94%58.04 dB0.99820.060
写真、320×240trace(auto と --preset photo は同じ)14.5 KB49.3 KB0.01%31.31 dB0.84762.931
フラットなアートワーク、400×300lossless → pixel2.1 KB3.9 KB100.00%∞1.00000.000
ピクセルアートのスプライト、128×128lossless → pixel0.5 KB0.6 KB100.00%∞1.00000.000
写真、320×240lossless → embed14.5 KB230.5 KB100.00%∞1.00000.000

トレースした写真の行がまた変わりました。49.3 KB から 93.8 KB、31.31 から 30.82 dB、 SSIM は 0.8476 から 0.8116 です。その意味は正確に理解しておく価値があります。 サブピクセルでのエッジ配置がデフォルトで有効になったことで、カーブフィッターが実行できるようになりました。これがなければ、トレース結果にはカーブコマンドが一つも含まれず、SVG でラップされたビットマップになります。

この列では、SVG を元画像と同じサイズで比較します。1 倍ではピクセル格子が劣化することはありません。再サンプリングされた元画像そのものだからです。そのため、出力がベクターに近づき、コピーから遠ざかるほど、この行の数値は悪化します。これは隠れたコストを取り繕っているのではありません。トレーサーには不適切な評価基準であり、ビット単位で完全一致し、その精度を保つ上の 3 つのモードには適切な基準です。

循環しない評価方法である npm run bench:scale では、トレーサーが参照することのない実際のベクター形式の元データを、入力には含まれていない倍率で評価します。この方法で評価すると、300 個の実在するロゴ全体で、リファインメントにより +3.01 dB の改善が得られます。形状として復元するのではなく、入力をそのまま再現したい場合は、pixel、embed、lossless がそれを正確に行います。また、--no-subpixel を指定すると、以前のピクセル格子によるトレースに戻り、gzip 圧縮後のバイト数をおよそ 3 分の 1 にできます。

トレースした写真の行は 52.9 KB から 49.3 KB に変わりましたが、精度の数値はすべて桁まで同じです。閉じたポリゴンでは、すでに描画される閉じ辺を z の前に繰り返し指定していました。z は定義上、サブパスの始点に戻るため、明示的な戻り辺があると、埋める対象のない長さゼロの隙間ができるだけでした。これを削除した結果、ストロークの有無を問わず、2 つの倍率で約 4,000 万個のチャンネルのうちサブピクセル単位で異なるチャンネルは 0 個のまま、コーパス全体のパスコマンドを 16.9% 削減できました。

見過ごすとツールに誤解させられるため、説明が必要な行が 2 つあります。

  • 写真 + embed は 100% 完全一致ではありません。元の JPEG バイト列は SVG 内にそのまま保持されています。それでも残差(チャンネルごとに最大 3/255)が生じるのは、SVG レンダラーの JPEG デコーダーが、逆 DCT の丸め処理を参照デコーダーとは異なる方法で行うためです。データは失われていません。2 つのデコーダーが最下位ビットで食い違っているだけです。Vecline は主張ではなく、測定結果を報告します。
  • 写真 + trace は実際に近似です。ピクセル完全一致が 0.01% なのはバグではなく、写真をトレースするとはそういうことです。この数値が重要なら、embed を使ってください。

他のベクター化ツールとの比較

速度について、そしてこの表に時間の列がない理由。 scripts/compare.mjs はツールごとの ms を記録して出力しますが、これらの表では省略しており、その省略は私たちに都合のよい結果となっていました。PNG を入力して SVG をディスクに出力する、コールドプロセスを5回実行した最小値で測定すると、vecline はすべてのテスト画像で imagetracerjs より遅く、その差は1.10倍から1.55倍です。また、小さなロゴでは vtracer より4.08倍遅く(280 ms 対 69 ms)、そのうち約83 msは処理開始前に Node がモジュールグラフを読み込む時間です。より負荷の高い2枚の写真では、vecline は壁時計時間で vtracer より高速(ポートレートは1001 ms 対 1386 ms、バイクは1160 ms 対 1970 ms)で、スコアも高くなっています。

ms 列は、誤解を招く形で公開しないよう、意図的に表から省いています。ハーネスは produce() の処理時間を計測しますが、各ツールの内部で行う処理は異なります。vecline は計測区間内で PNG のエンコードとデコードの両方を行い、imagetracerjs は生ピクセルを受け取るためコーデック処理がなく、vtracer はプロセスの起動に時間がかかります。この計測方法の修正は追跡中です。それまでは、上記の数値が誠実な要約です。生の列を確認したい場合は、npm run compare を実行してください。

npm run compare を実行して、自分で試すことができます。すべてのツールの SVG を同じレンダラーでレンダリングし、同じ指標で、同じ白い背景上でスコアを算出するため、ここに示す内容は Vecline 独自の品質評価に左右されません。対象は potrace、imagetracerjs、そして最も有力な現代のオープンソース競合ツールである vtracer(VisionCortex、Rust)です。ツールの作者が実際に配布しているバイナリを評価するには、VECLINE_VTRACER に vtracer のリリース済みバイナリを指定してください。利用できない場合、ハーネスは @neplex/vectorizer のバインディングにフォールバックします。どちらも存在しない場合は、推測で補わず、その行自体を表示しません。

合成テスト画像 — 誰かの写真のライセンスを取得しなくても再現できます。

テスト画像ツールサイズPSNRSSIM平均 ΔE₀₀
二値画像potrace1.5 KB24.67 dB0.95110.702
imagetracerjs1.7 KB19.75 dB0.86071.667
vecline (auto)1.4 KB∞1.00000.000
カラーアートpotrace posterize1.9 KB14.61 dB0.801021.302
imagetracerjs1.6 KB26.56 dB0.93630.662
vtracer1.2 KB27.88 dB0.94900.582
vecline (auto)1.8 KB∞1.00000.000
写真(グラデーション+ノイズ)potrace posterize11.5 KB13.19 dB0.602423.911
imagetracerjs11.8 KB26.85 dB0.71435.623
vtracer42.7 KB32.53 dB0.79793.049
vecline (auto / photo)19 KB31.12 dB0.77502.940
vecline lossless43.7 KB∞1.00000.000

実際の写真 — 480px の Kodak セットで、実際に重要となるテストです。vecline (auto) は設定不要のデフォルトです。vecline convert photo.png out.svg を実行すると、コンテンツに合わせてパレットが自動調整されます。

写真ツールサイズPSNRSSIM平均 ΔE₀₀
ポートレート(肌、柔らかい質感)imagetracerjs1621 KB25.47 dB0.70935.957
vtracer987 KB25.88 dB0.76524.743
vecline (auto)1338 KB34.80 dB0.91402.663
灯台(空)imagetracerjs2010 KB24.58 dB0.74654.900
vtracer1032 KB24.25 dB0.76245.665
vecline (auto)1743 KB36.26 dB0.94532.575
オウム(細部)imagetracerjs301 KB25.81 dB0.76156.317
vtracer344 KB23.17 dB0.79497.728
vecline (auto)309 KB31.18 dB0.84603.686

二値画像とカラーアートでは、vecline はビット単位で完全一致します(SSIM 1.0000)。potrace と imagetracerjs は近似であり、カラーアートでは vtracer も 0.9490 ですが、vecline のファイルサイズはそれらより小さいか同程度です。

これらのテスト画像はどちらも合成画像です。長い間、このセクションはそれらだけに基づいていました。実際のフラットアートワークは以下に追加しました。実際には状況が大きく異なり、こちらにとっては一方向でより厳しい結果になっています。

実際のフラットアートワーク — このプロジェクト独自のコーパス画像です。今回から npm run compare に含まれ、ここに示す他のすべての表と同じハーネス、レンダラー、メトリクスによって行が生成されます。

テスト画像ツールサイズPSNRSSIM平均 ΔE₀₀
logo-tux(実際のロゴ)potrace posterize7.7 KB14.41 dB0.76496.146
imagetracerjs59.8 KB24.17 dB0.88611.975
vtracer (cli)64.0 KB23.51 dB0.89071.517
vecline --preset logo53.4 KB26.43 dB0.90321.073
vecline (auto)25.8 KB∞1.00000.000
vecline lossless24.0 KB∞1.00000.000
alpha-dice(実画像、アルファ付き)potrace posterize11.1 KB11.69 dB0.685714.690
imagetracerjs72.1 KB26.05 dB0.86852.108
vtracer (cli)167.8 KB20.90 dB0.85773.213
vecline --preset logo139.9 KB28.39 dB0.88231.682
vecline (auto)189.1 KB35.85 dB0.95370.862
vecline lossless209.6 KB∞1.00000.000

正直な見方は3つありますが、すべてが同じ結論を示すわけではありません。

実際のロゴでは、ビット単位で完全一致する方法が最小サイズでもあります。 lossless は SSIM 1.0000 で24.0 KBを実現します。近似表現のために imagetracerjs と vtracer が使うサイズの3分の1です。これがフラットアートワークの要点であり、この結果は変わりません。ただし、これは画像を近似するより正確にエンコードするほうが効率的で、vecline がそれを認識して完全なコピーを出力するためです。曲線フィッティングが優れているからではありません。曲線を求めると、そのすぐ上の行の結果になります。

品質では --preset logo が優位ですが、その差は合成テスト画像が示すほど大きくありません。 logo-tux では vtracer に対して +2.9 dB、SSIM +0.013 で、色誤差は3分の1、ファイルサイズも小さくなっています(53.4 KB 対 64.0 KB)。alpha-dice では、vtracer より17%小さいサイズで、品質の3つの指標すべてで優位です。良い結果ですが、合成テスト画像が示唆する15~19 dBの差ではありません。logo は16色に量子化するため、実際のアートワークでは4色のテストパターンよりもその代償が大きくなります。

potrace は他よりはるかに小さく、これは実際にトレードオフです。 当社の24~53 KBに対し、7.7 KBです。設計上、二値画像であり、色の数値は劣ります(SSIM 0.7649、ΔE 6.1)。しかし、色の忠実度より数キロバイトの節約を重視するなら、サイズではこれが勝っており、この表にもその事実を示す必要があります。

合成写真 — 純粋なグラデーションにノイズを加えた画像 — は vtracer が最も得意とするケースであり、細かな色精度でトレースして SSIM で勝っています。vecline はファイルサイズを半分未満(19 KB 対 42.7 KB)に抑えながら0.7750に達し、imagetracerjs(0.7143)も余裕をもって上回ります。色数を増やせば最後の差を縮められますが、合成画像の最悪ケースでバイト数を2.2倍にする価値はありません。

この行は v1.33.1 で下方に変更されました。その理由を説明しておきます。以前、photo プリセットはここで0.7923を記録していました。しかし、npm run compare では、実際の写真すべてで同じプリセットが通常の auto を下回り、処理に最大136秒かかることが分かりました。写真を形作る細部を消してしまう、強制的なノイズ除去のしきい値が原因です。この修正により、この合成テスト画像では SSIM が約0.017低下しましたが、下記の Kodak セットでは約75倍の速度で SSIM が+0.25向上しました。グラデーションとノイズのパターンは写真ではありません。両者の結果が食い違う場合は、実際の写真を優先します。現在、photo と auto は測定上最良の同じ構成を使用するため、1つの行にまとめて報告しています。 実際の写真では、すべての品質指標で vecline が他のどのツールのデフォルト設定よりも優れています。 自動モードはコンテンツに合わせてパレットを調整するため、設定不要のデフォルトですべての写真において SSIM が 0.05~0.18 上回ります。vtracer の 0.7652 / 0.7624 / 0.7949、imagetracerjs の 0.7093 / 0.7465 / 0.7615 に対して 0.9140 / 0.9453 / 0.8460 です。PSNR も大幅に高く(25.9 / 24.3 / 23.2 dB に対して 34.8 / 36.3 / 31.2 dB)、色差はおよそ半分です。合成画像の最悪ケースについての話は、実際の写真を相手にすると成り立ちません。

上記の比較はデフォルト設定同士であり、こちらに有利な条件です。 vtracer には指定可能なフラグがあり、ドキュメントに記載されたプリセットを使うと、表の一部では評価が変わります。同じバイナリ、同じハーネス、同じレンダラー、同じ指標での結果です。

フィクスチャvtracer の設定サイズPSNRSSIM平均 ΔE₀₀
kodak-parrots--preset poster534 KB29.86 dB0.86432.560
vecline(自動)309 KB31.18 dB0.84603.686
synthetic photo--preset poster58 KB36.57 dB0.86201.935
vecline(自動)19 KB31.12 dB0.77502.940
4 つすべてのカラー画像-p 8 -g 4 --filter-speckle 0バイト数が 4~5 倍——すべてで vecline を上回る

つまり、--preset poster は kodak-parrots の SSIM でこちらを上回り(0.8643 対 0.8460)、synthetic photo では 3 つすべての品質指標で勝っています。また、--color-precision 8 --gradient-step 4 --filter-speckle 0 は 4 つすべてのカラー画像で色差をこちらより小さくします。ただし、バイト数は 4~5 倍、処理時間は約 2.4 倍です。これはトレードオフです。こちらの SSIM の優位性はポートレートと灯台では維持され、最後の設定に対してはわずかな差です(0.9140 対 0.9099、0.9453 対 0.9074)。

これらの調整は、こちらにもできないものではありません。重要なのは、「すべてで上回る」という主張は、誰も調整していないツールを相手に測定した結果であり、公平に比較する読者は各ツールを調整するということです。

そして、正直に言えば、3 枚中 2 枚では vtracer のファイルのほうが小さくなります。 ポートレートでは vecline の 1338 KB に対して 987 KB、灯台では 1743 KB に対して 1032 KB です。vecline のほうが小さいのはオウムの画像だけです(309 対 344)。このバイト数で上記の品質が得られます。PSNR が約 10 dB 高いのは丸め誤差ではありません。しかし、サイズを最優先し、SSIM 0.76 で十分なら、このトレードオフでは vtracer が勝ちます。この表でその事実を隠すべきではありません。

v1.38.1 では、こちらに不利な方向に数値が変わりました。 以前の vtracer の結果は、サードパーティ製の napi バインディングである @neplex/vectorizer を介して測定していました。現在は vtracer 自身がリリースしたバイナリ(1.0.0-alpha.3、デフォルト設定、調整なし)で測定しています。このバイナリは、同じ品質で大幅に小さいファイルを生成します。バインディングでは 1661 KB だったところが 987 KB です。そのため、以前の表では「毎回、同等以下のサイズのファイルを vecline が生成する」と主張していましたが、vtracer が実際に配布しているツールとの比較では、これは誤りでした。VECLINE_VTRACER=/path/to/vtracer npm run compare を実行すると再現できます。

グラデーション出力(--gradients。写真では自動モードでデフォルト有効)は、滑らかな色の移り変わり(空や肌など)を単色の帯ではなく SVG グラデーションとして再構築します。<linearGradient>(方向性のあるグラデーション)と <radialGradient>(ビネット、円形のハイライト、スポットライト)の両方を領域ごとに当てはめ、より近い結果をレンダリングするほうを採用します。放射対称のグラデーションには線形の方向がないため、領域の重心から外側へ距離に基づいて当てはめます。合成ビネット画像では、約 350 バイトで SSIM 0.998 の再構築を実現します。一方、単色の帯では 3~8 KB を使って SSIM 0.73~0.88 です。品質が悪化することはありません。 グラデーションが単色の帯を置き換えるのは、グラデーションの実際のレンダリング結果(レンダラーによる sRGB のストップ間補間を再現し、ピクセル単位で Oklab により評価)が置き換え対象の単色の帯を上回る場合だけです。そのため、フラットな画像はバイト単位で完全に同一のままで、はっきりしたエッジにも変更は加わりません。バンディングの軽減に特化した改善であり、品質が後退することはありません。 幾何プリミティブ(--primitives)は、逆方向のクリーンアップを行います。領域が実際に円、楕円、長方形、角丸長方形(UI/アイコンで定番の形状 — <rect rx>)、または扇形(パイの一切れやドーナツの一区画 — あらゆるグラフを構成する形状)である場合、vecline は4つの曲線からなるベジェ近似ではなく、本物のプリミティブを出力します。単純な円盤ならファイルサイズが68%小さくなります(42 pxの円はパスではなく、<circle cx="60" cy="60" r="42">です)。4分割の円グラフは、ベジェ曲線の2323バイトから、本物の円弧の488バイトになります。他のどのJSトレーサーとも異なり、形状はIllustrator/Inkscapeで形状として編集可能なまま保たれ、CAD/DXFエクスポートでは本物の円弧になります。この置き換えは残差で判定されます。領域の境界がフィットした形状から--primitive-errorピクセル以内(デフォルトは1.0)に収まる場合にのみ置き換え、自然な形状の塊が円に丸められることはありません。detectPrimitive()は純粋関数で、vecline/coreにあります。

<rect>は実際にレンダリング結果が完全に一致します。曲線プリミティブである<circle>、<ellipse>、扇形は、レンダリング結果を維持するものではなく、測定されたトレードオフです。理想的な円弧ではピクセルの階段状の輪郭に完全には沿えないため、ソースラスターに対してSSIMが約0.02低下する代わりに、ファイルサイズがわずかな割合になり、CADツールで実際の円弧として読み取れるジオメトリが得られます。扇形は色ごとではなく領域ごとに認識されるため、凡例でスライスの色を再利用している円グラフも円弧としてトレースされます。スイープが約0.6ラジアン未満、または半径が約15 px未満の場合はフィッターが採用を見送り、ベジェパスにフォールバックするため、安全に失敗します。

数値(npm run bench:featuresで再現できます — すべての数値はSVGをピクセルに再レンダリングしてスコアを算出したもので、アサーションではありません):

ケースベースライン(SSIM/サイズ)veclineの機能(SSIM/サイズ)
放射状グラデーション · ビネット · 8色0.7887 / 4.5 KB0.9646 / 759 B
放射状グラデーション · ビネット · 12色0.8745 / 7.9 KB0.9977 / 356 B
放射状グラデーション · ビネット · 16色0.9193 / 10.2 KB0.9977 / 356 B
プリミティブ · 円盤 → <circle>1.0000 / 681 B0.9897 / 182 B

グラデーションの行は、置き換えるフラットな帯よりもはるかに高精度で、なおかつ桁違いに小さくなっています。プリミティブの行は、レンダリング結果の差を2%未満に抑える代わりに、ファイルサイズを73%削減し、形状として編集可能にします。

写真の結果に至った経緯。 以前のバージョンは合成写真でimagetracerjsに及ばず、正直なところ原因は不明でした。scripts/diagnose-photo.mjsでパイプラインを分解したところ、原因が判明しました。主な損失要因は量子化ではなくカーブフィッター(SSIMが0.11~0.24低下)であり、フィッティング許容誤差1 pxは、精度とファイルサイズの両方で0.4よりも明確に劣っていました。デフォルトを調整することで、差の大部分を縮めました。次に同様の主張をする際に推測ではなく測定できるよう、診断スクリプトは残してあります。

注意点が2つあります。potraceは設計上、二値画像用です。カラーに関する行では後付けのposterizeを使っており、それを明記せずに報告すれば、公平な比較にはなりません。また、最も高性能な商用トレーサー(Illustrator Image Trace)やAIベクタライザーとの比較はまだ測定していません。ここでのveclineは、インストール可能なオープンソース製品の中で最高クラスですが、あらゆる製品に対して実証されているわけではありません。 精度だけでなく、調整用ノブも。 数値だけではありません。vecline は、各ツールでおなじみの制御機能も備えるようになりました。potrace の --threshold/--black-on-white による二値モードと大津の自動しきい値設定、対角方向で自己接触する形状に対応する 6 種類の --turn-policy モード、そして --fill-strategy(mean/dominant/median)です。imagetracerjs のエッジを保持する --blur、境界を塗り直す --stroke-width(ここでは精度を測定していますが、上流版とは異なり、不透明な画像では精度が向上し、透明な画像ではハローが生じます)、そして --right-angle による角のスナップ(ここでは厳密なテストを許容差に一般化しているため、量子化の結果、角度が 1、2 度ずれた角も補正します)です。さらに、potrace にも imagetracerjs にもない --gradients 出力や、vecline edit と vecline/ops エントリーポイントを支える sharp の編集パイプラインも備えています。意図的に取り入れていないのは、グレースケールのポスタライズに使う potrace のヒストグラム rangeDistribution だけです。vecline の Wu + Oklab-Lloyd 量子化器のほうが、デフォルトとして明らかに優れており、代表色を選びたい呼び出し側には --fill-strategy で選択肢を用意しています。

メトリクス

--verify は、標準的な全参照指標を報告します。値を他のツールのものと比較できるよう、各指標の文献上の定義に従って計算しています。

  • PSNR — dB 単位のピーク信号対雑音比です。画像がビット単位で同一の場合に限り、∞ になります。
  • SSIM — Wang et al. 2004 に基づきます。ガウス重み付き 11×11 ウィンドウ、σ=1.5、valid 畳み込みを使用します(参照実装および scikit-image に合わせ、境界のピクセルはパディングせず除外します)。
  • CIEDE2000 — 色差の平均、p95、最大値です。実装の多くが誤りやすい色相角の不連続を検出するために作られた、Sharma, Wu & Dalal のテストセットに含まれる 34 組すべてで検証済みです。
  • ピクセル完全一致率 — 4 チャンネルすべてが一致する割合です。

比較では、デフォルトでアルファ事前乗算を使用します。完全に透明なピクセルの下に保存された色は見えないため、同じように描画される 2 枚の画像は、同じ値で評価されるべきです。保存された生バイトを比較するには、--alpha-mode straight を使用してください。

他者のトレーサーを含む、あらゆるトレーサーを評価する

verify と diff は vecline 専用ではありません。あらゆる作成元の SVG を受け取り、元のラスター画像と比較して評価します。ファイルを書き出したツールが何であれ、処理には影響しません。

# Score another tool's output. Most tracers emit a transparent ground, so give
# it the colour the artwork was meant to sit on, or every transparent pixel
# counts as a difference.
vecline verify source.png their-output.svg --render-background '#ffffff'

# As a CI gate: exit code 2 if it misses the bar.
vecline verify source.png their-output.svg --render-background '#ffffff' --fail-under 0.98

このフラグは些細なものではありません。200×200 の円盤 1 つで、同じ画像が白い背景ありでは 29.92 dB、背景なしでは 2.12 dB になります。そのため、このフラグなしで比較を実行しても、競合するトレーサーの性能を測ることにはなりません。背景の矩形を書き出したかどうかを測ることになります。vecline は、この不一致を検出すると、数値をそのまま通すのではなく警告します。

--json は、psnr、ssim、ssimLuma、rmse、exactRatio、deltaE{mean,p95,max}、maxChannelDiff、lossless に加えて寸法を含む、安定したオブジェクトを出力します。スクリプトからこれらの値を使って判定できます。終了コードは --help に記載のとおり 0、1、2 です。

共通のコーパスを使って potrace、imagetracerjs、vtracer と徹底比較するには、このリポジトリをクローンして npm run compare を実行すると、すべての比較が行われます。node scripts/fetch-corpus.mjs を実行すると、来歴とライセンスを記録した画像を取得できます。

自分のトレーサーも参加できます。 評価方法はもともとツールに依存しませんでしたが、参加できるツールの一覧はそうではありませんでした。コマンドを渡すと、ほかのツールとまったく同じ方法で評価され、すべての比較対象に加わります。

npm run compare -- --tool "mytracer=/path/to/bin --input {in} --output {out}"

{in} には PNG が渡され、{out} は SVG の出力先です。このフラグは繰り返し指定できます。比較は他者のソフトウェアについて主張するものなので、どのように実行したかを読者が確認できるよう、表の上に正確なコマンドを表示します。

仕組み

pixel — フラットなアートワークから正確なジオメトリを生成

貪欲メッシュ化では、各色の領域を最大の長方形に分解します。色が続く限り右へ広げ、次に、幅全体で色が続く限り下へ広げます。同じ色の長方形はすべて、1 つの <path> にまとめます。

この 2 つの詳細は、正確性を保証するうえで重要です。

  • すべての長方形の角はピクセルグリッド上の整数座標にあるため、アンチエイリアス処理を行うラスタライザーは、内部のカバー率を正確に 1.0、外部を正確に 0.0 と計算します。丸めが必要な中間的なカバー率はありません。
  • パス内のカバー率は、合成の前に累積されるため、1 つのパス内で隣接する長方形が、別々の要素を使った場合に生じる細い継ぎ目を作ることはありません。
trace — あらゆる画像から曲線を生成
quantise → segment → trace contours → fit curves
  1. 色の量子化。 Wu のアルゴリズムは、32³ のグリッド上に 3 次元の色モーメントを構築し、分割による分散の減少量が最大となるボックスを分割します。ランダムなシードを使わず、結果は決定的です。その後、Oklab で Lloyd 法による緩和を行ってパレットを仕上げます。これは、Wu のアルゴリズムが sRGB 上で分散を最小化するためです。sRGB では、数値上の距離が同じでも、視覚上の差は同じとは限りません。アルファ値は別途 1 次元でクラスタリングするため、なめらかなエッジのために色数を消費することはありません。
  2. セグメンテーション。 2 パスの union-find による連結成分抽出を行い、4 近傍で連結性を判定します。
  3. クラック追跡による輪郭抽出。ピクセルの中心ではなく、ピクセル間の境界をたどります。すべての頂点は整数格子点上に置かれるため、単純化前のポリゴンをラスタライズすると、半ピクセルのずれなく、元のマスクとビット単位で一致します。
  4. 曲線フィッティング。 Douglas–Peucker 法で構造上重要な頂点を見つけ、角検出で本当の鋭い特徴と緩やかな曲がりを区別します。そして、Schneider の最小二乗アルゴリズムで、角と角の間にある元の格子点に三次ベジェ曲線をフィッティングします。単純化した輪郭は分割位置を決めるためだけに使い、フィッティングのデータには使いません。

同じ色の領域は、fill-rule="evenodd" を指定した 1 つの <path> を共有します。各領域のパスには、その内部に含まれる領域の境界が含まれるため、領域が自身の穴を塗りつぶすことはなく、描画順に関係なく入れ子構造が正しく処理されます。

サイズ上限と、その根拠

「トレースした SVG は大きすぎる」というのは、あらゆるベクター化ツールが最もよく受ける不満です。よくある対処法は、処理にどれだけ影響するのかをまったく示さない、不透明な単純化スライダーです。Vecline は出力を自らレンダリングして評価するため、サイズ上限には根拠を添えられます。

vecline vectorize logo.png --max-bytes 40KB
Budget  met  in 3 steps
  size        92.0 KB → 38.4 KB (-58%)  target 39.1 KB
  accuracy    0.9994 → 0.9971  −0.0023 SSIM paid

探索は、最もコストの低い調整から段階的に制約を緩めます。まず曲線フィッティングを粗くし、次に座標を丸めます。連続的に調整できる手段を使い切ってから、特徴全体やパレットの色を削減します。この順序が重要なのは、精度だけが理由ではありません。構造的な調整は不連続です(色を 1 つ減らすだけで、ファイルサイズが一気に半分になることもあります)。そのため、なめらかに調整できる手段から始めることで、通常の二分探索でも目標を飛び越えて次の急な変化点に落ちることなく、目標に到達できます。得られるのは、たまたま条件を満たした最初の結果ではなく、上限に収まる最も正確な結果です。--max-nodes は代わりにアンカーポイント数を目標とします。これは、イラストレーターが編集時に実感する要素だからです。両者は連動して変化するとは限らないため、別々に扱います(座標を丸めれば、ノード数を減らさずにバイト数を削減できます)。上限が調整手段で達成できる範囲を下回る場合は、その旨を伝え、達成したふりをせず、実際に得られる中で最も近い結果を返します。

--extend-under — 2 つではなく 1 つの境界

領域は大きいものから順に描画されるため、小さな形状を描くころには、その下にある大きな形状はすでに描画されています。つまり、領域の塗りつぶしは共有境界で止める必要はなく、その下まで延ばせます。後から描画される領域がそのピクセルを塗り直すため、レンダリング結果は変わりません。

vecline vectorize chart.png --extend-under

ここから 2 つのことがわかります。2 つの領域で共有される境界は、通常、それぞれの領域の端として 2 回トレースされますが、ここでは 1 回だけトレースされます。また、隣り合う 2 つの形状の間にアンチエイリアス処理で生じる細い継ぎ目も現れません。継ぎ目が開く接合部がなくなるためです。これは --stroke-width で塗りつぶす目的のものですが、実測では、隙間を覆う以上の効果があります。境界の半分だけ覆われたピクセルを塗り直すことで、バイト数の増加を 3% 未満に抑えながら、コーパス全体で SSIM が最大 +0.085 向上します。透明なアートワークを暗い背景に置いたときに輪郭の外側にも塗られてハローが生じるため、--preset clean 以外ではすべてデフォルトでオフです。この値を決めるのは、ジオメトリがピクセル格子に沿っているかどうかです。格子に沿ったポリゴンの接合部ではアンチエイリアスが生じないため、ストロークは太くするだけですが、clean の曲線では実際に細い継ぎ目ができます。下に何も描画されていない状態でレンダリングすると、logo-tux では 2.7 倍に拡大したときに 943 ピクセルに漏れが生じますが、ストロークによって 66 ピクセルまで減少します。

デフォルトではオフです。その理由は推測ではなく、実測に基づいています。

フィクスチャサイズの変化レンダリング
フラットなアートワーク−28.3%同一
小さなロゴ+100.6%同一
オウム(写真)+125.8%同一
灯台(写真)+128.9%同一

レンダリング結果は毎回ビット単位で完全に一致するため、vecline verify a.svg b.svg は PSNR ∞、SSIM 1.000000 を報告します。つまり、これはサイズと継ぎ目のトレードオフだけの問題です。色の面が少なく大きなフラットアートワークでは明らかに効果がありますが、後から描画される色が散在している場合は、置き換える領域よりもトレースする領域のほうが複雑になるため、大きく不利になります。全体に適用するのではなく、独自の画像で効果を測定してください。

--target-ssim / --target-psnr

トレース、レンダリング、測定を行い、目標を達成するまで段階的に処理を進めます。失敗の原因はそれぞれ異なるため、各段階でパレットを 2 倍にし、幾何学的な許容誤差も厳しくします。色数が少なすぎると階調の縞が現れ、許容誤差が大きすぎると細部が丸められます。最良の結果は保持されるため、達成できない目標に対しても、最も近い結果と未達であることを示す注記が返されます。

CLI

vecline vectorize <input>
オプション説明
-o, --output <file>出力先(デフォルトは<input>.svg)
-l, --losslessビット単位で完全に一致する結果を保証します。一致できない場合は失敗します
-t, --transparent [color]背景を削除します。色を省略すると自動検出します
--bg-tolerance <n>ピクセルと背景色との許容距離(Oklab 距離)
--bg-everywhere端から内側に向かって削除するのではなく、一致するピクセルを場所を問わず削除します
--featherエッジをくっきり切り抜かず、徐々にフェードさせます
--prefer <what>auto(デフォルト)、geometry、size — ロスレス処理で何を優先するか
--max-geometry-ratio <n>--prefer autoで実際のジオメトリに許容する拡大率(デフォルトは4)
-m, --mode <mode>auto、lossless、pixel、trace、embed
-p, --preset <preset>logo、lineart、poster、photo、detailed、pixelart、exact
-c, --colors <n>パレットサイズ(1~256)
--alpha-levels <n>保持する異なるアルファ値の数
--min-area <px>これより小さい領域を隣接領域に吸収します
--tolerance <px>輪郭の簡略化許容値
--fit-error <px>曲線フィッティングの最大誤差
--corner-angle <deg>鋭角の角として扱う折れ曲がり角度
--polygon曲線ではなくポリゴンを出力します
--threshold <cutoff|auto>トレース前に輝度で2色に減色します(potrace 形式の二値化。auto = Otsu)
--black-on-white <bool>--threshold使用時、暗いピクセルを図形として扱います(デフォルトはtrue)
--speckle-scope <all|isolated>--min-areaで吸収できる小領域を指定します。all(デフォルト)はカットオフ未満の領域をすべて対象にします。isolatedは単一色に囲まれた点状領域だけを対象にし、アンチエイリアスの縁は残します。logo-tuxでの測定では、8px未満の成分のうち孤立領域は40.2%だけで、残りは縁です。そのため、isolatedは忠実度あたりのサイズ削減効率が2倍になり(0.00041 SSIM/KB 対 0.00086)、JPEG アーティファクトのある写真では、allの0.5488に対してSSIM 0.8657を達成します
--severity--verify使用時に、誤差がある場所も報告します。SSIM、PSNR、平均ΔEは全体の集計値であり、すべてのエッジに沿った無害なアンチエイリアスのざらつきと、まとまった誤った領域1つを区別できません。メガピクセル画像では、平均すると同じスコアになります。差分ピクセルから1ピクセル幅の線を除去してクラスタリングし、面積の二乗和で評価するため、まとまった塊は散在するノイズより重く評価されます。さらに、精度、構造、一貫性の幾何平均であるCompositeを追加し、いずれかの強い軸が崩れた軸を覆い隠さないようにします
--adaptiveフレーム全体に1つのカットオフを使うのではなく、各ピクセルの近傍に応じて二値化します(Bradley–Roth)。紙の写真のように、片隅が影になり、全体に共通する数値では明るい側と暗い側の両方に対応できない場合に有効です。インクが局所的な紙の明るさより常に35%暗いページでは、OtsuのF1スコアは26.4%(影の部分が塗りつぶされます)ですが、この方式では100%です。特に効果が大きいcenterlineとgcodeにも有効です。デフォルトではオフです。均一に照明された画像では、Otsuのほうが適切な推定方法です
--adaptive-window <px>--adaptiveで使う近傍の一辺の長さ。0(デフォルト)は短辺の8分の1です
--adaptive-t <pct>インクとして扱う局所平均からの差(デフォルトは15)
--blur <1-5>量子化前に、エッジを保持する選択的なぼかしを適用します。エッジをぼかさずに粒状感を取り除きます
--blur-delta <n>--blurのエッジ保持しきい値(デフォルトは20)
--stroke-width <n>各パスをそれぞれの塗りつぶし色でストロークし、境界に沿った半透明のピクセルを塗り直します。不透明なアートワークでは精度の向上を測定できており(コーパスの6件中6件で0.5により改善し、バイト数の増加は3%未満)、シルエットの外側にも描画するため、暗い背景では透明なアートワークにハローが生じます
--underpaint / --no-underpaint不透明なシルエットを単一パスとしてすべての下に一度描画し、内側の継ぎ目から透けないようにします。隣接する2つの塗りつぶしは別々の要素であり、共有する境界では両方を合わせてもピクセルが最大4分の1透明になります。これを隠す背景の矩形がない場合、つまり透明部分のあるアートワークでは、その隙間がすべての内側の境界に沿って現れます。--preset cleanでは有効で、logo-tuxでは、漏れのあるピクセルが3,621個(そのうち3,171個はシルエットから遠く離れた位置)から319個、さらに0個へと減少します。また、alpha-diceでは1,350/725個から243/16個へと減少し、両方で有料の競合製品を上回ります。logo-tuxではgzipサイズが4%、alpha-diceでは12%増加しますが、ファイルにすでに存在しない座標は追加されず、透明ピクセルのないアートワークでは何も変更せず、バイト単位で同一の出力になります
--turn-policy <p>対角線上で自己接触する箇所を解決します。left(デフォルト)、right、black、white、minority、majority(potraceのturnPolicy)
--fill-strategy <how>パレット色をクラスタから選ぶ方法:mean(デフォルト)、dominant、median(potraceのfillStrategy)
--right-angle軸に近い直角の角を正確な90°にスナップします。UI、スクリーンショット、ピクセルアートをより鮮明にします(imagetracerjsのrightangleenhance)
--right-angle-threshold <deg>--right-angleで許容する角度のずれ(デフォルトは12)
--gradients滑らかな色のグラデーション(空、肌、ブランドアートワーク)をSVGグラデーションとして再構成します。測定可能な精度で適合し、かつそのコストを上回る数の帯を置き換える場合にのみ採用します。単純なモデルが勝てない生の誤差比較ではなく、複数の帯によるフラットな代替表現と公平に比較します
--primitives円、楕円、長方形、角丸長方形、扇形(パイ/ドーナツ)を認識して実際の図形として出力します。ファイルが小さく、編集しやすく、CADで使える実際の円弧になります
--primitive-error <px>--primitivesの頂点ごとの残差許容値(デフォルトは1.0)
--layers色ごとに名前付きのInkscape/Illustrator レイヤーを出力します。編集可能で、スクリーン印刷やビニールの色分解に対応します
--palette <colors>指定したカンマ区切りの色だけでトレースします(ブランドカラー/特色)。例:"#fff,#e4002b,#000"
--no-optimize1本の曲線で表現できる隣接曲線を結合しません
--opt-tolerance <n>曲線を結合する際の誤差許容値
--quadratics三次曲線がすでに満たす必要のある誤差許容値以内で同じ区間を表せる場合、三次曲線(c)の代わりに二次曲線(q)を出力します。数値は6個ではなく4個です。置き換えはすべて、置き換え元の三次曲線ではなくトレースされた点に対して測定されるため、保証される許容誤差は変わりません。デフォルトではオフです。--preset cleanでは曲線の約90%が変換され、非圧縮で25%、gzip圧縮後で23%削減されます
--refine-iterations <n>パレット構築時のLloyd緩和パス数
--precision <n>パス座標に保持する小数桁数
--no-background最頻色を1つの長方形にまとめません
--target-ssim <v> / --target-psnr <db>目標に達するまで品質を段階的に上げます
--max-bytes <size>サイズ上限 — SVGが収まるまで許容値を緩和します(40KB、1.5MB、またはバイト数のみ)。その結果生じる精度も報告します
--max-nodes <n>複雑さの上限 — ジオメトリのアンカーポイントが指定数以下になるまで許容値を緩和します
--verify結果をレンダリングし、入力と比較して測定します
--embed-strategy <s>auto、preserve、png、webp
--xlinkSVG 1.1の利用側にxlink:hrefを使用します
--json標準出力に機械可読な形式で出力します
vecline rasterize <input.svg>
オプション説明
-o, --output <file>出力パス(デフォルトは <input>.png)
-w, --width / -h, --height / -s, --scale出力サイズ
--dpi <n>物理単位(mm、pt、in)の解像度
-b, --background <color>アートワークの背面に塗りつぶす色。#rgb、#rrggbbaa、rgb()、または色名
-f, --format <fmt>png、jpeg、webp、avif、tiff、gif
-q, --quality <n>非可逆エンコーダーの品質
--lossless可逆 WebP/AVIF
--shape-rendering <mode>geometricPrecision(デフォルト)、crispEdges、optimizeSpeed
--font-dir <dir...> / --default-font <family><text> のフォント解決
--verifyエンコード済みファイルを再デコードし、エンコーダーによる劣化を報告

rasterize の --verify は、実際に問題となる エンコーダー を測定します。JPEG を指定した結果、アルファチャンネルが気づかないうちに失われたり、品質設定によって想定以上に劣化したりするケースです。

その他のコマンド
vecline edit photo.jpg -o small.png --resize 800x --grayscale  # resize, rotate, crop, tone
vecline crop photo.jpg -a 1:1 -o avatar.jpg    # content-aware crop — keeps the subject
vecline component logo.png -o Logo.tsx -f react --current-color # raster → typed component
vecline favicon logo.png -o public/    # full favicon/PWA set + manifest + <head> HTML
vecline responsive hero.jpg -o img/    # AVIF/WebP/fallback ladder + <picture> markup
vecline placeholder hero.jpg -f blurhash   # BlurHash string (or -f svg for a tiny LQIP-SVG)
vecline palette art.png --css          # perceptual palette as CSS custom properties
vecline extract keep.svg -o out.png --against original.png   # byte-identical recovery
vecline convert in.png out.svg      # direction inferred from input + extension
vecline convert photo.png thumb.webp   # …including plain raster → raster
vecline doc report.pdf -o pages/ --dpi 150   # PDF (or SVG) → one image per page
vecline office report.docx -o report.pdf     # Word/Excel/PPT ⇄ PDF (uses your LibreOffice)
vecline pdf page1.png page2.jpg -o album.pdf # combine images into one multi-page PDF
vecline centerline drawing.png -o strokes.svg  # single-stroke medial-axis paths
vecline gcode drawing.png --tool laser --feed 800   # ready-to-run laser/plotter G-code
vecline convert logo.png out.dxf --units mm --physical-width 80   # cuts at exactly 80 mm
vecline convert logo.png out.dxf    # CAD/CNC/laser vector export (also .eps, .pdf --cmyk)
vecline optimize icon.svg -o icon.min.svg   # render-preserving SVG minify
vecline sprite icons/*.svg -o sprite.svg    # pack many icons into one <symbol> sheet
vecline animate loading.gif -o loading.svg  # animated GIF/APNG/WebP → one CSS-animated SVG
vecline verify a.png b.svg          # measure any two images
vecline diff before.png after.png -o diff.png  # perceptual visual-regression heatmap
vecline batch 'src/**/*.png' -o out/ --to svg --summary "$GITHUB_STEP_SUMMARY"
vecline mcp                         # MCP server: expose vecline as tools to AI agents/IDEs
vecline serve                       # local bridge: let Vecline Studio use your LibreOffice

vecline serve — アップロード不要で、ブラウザー上で Office 変換できます。 ブラウザーのタブには Office エンジンがなく、通常、それを利用可能にする方法は 2 つしかありません。約 300 MB の LibreOffice-WASM をバンドルするか、ドキュメントを誰かのサーバーにアップロードする方法です。前者では読み込みが即時でなくなり、後者ではプライバシーに関する主張が成り立たなくなります。どちらも採用しません。vecline serve を実行すると、Vecline Studio がドキュメントをお使いのマシンに渡し、変換後に受け取ります。

npm install -g vecline && vecline serve

処理のすべての段階がローカルで完結します。.docx → お使いの LibreOffice → PDF → タブ内の mupdf → ピクセル → そのピクセルと照合して採点されたトレース済み SVG。

攻撃を想定して構築し、実際に攻撃を受けました。 ブリッジは 127.0.0.1 のみにバインドされ、vecline.xyz または --allow-origin で指定したオリジンからのリクエストのみを受け付けます。Chrome の Private Network Access プリフライトには、これらのオリジンに対してのみ応答します。再バインドされた Host は拒否し、1 つのリクエストボディを 64 MB、同時変換数を 2 件に制限します。また、バイト列を受け取り、バイト列を返す 2 つのエンドポイントのみを公開します。リクエストのどのフィールドにもファイル名が含まれないため、パスをたどる手段はありません。起動したときにのみ動作します。

4 つのエージェントによる敵対的レビューを実施し、各指摘を稼働中のサーバーに対して独立に再テストした結果、侵害された境界は見つからず、4 件の強化すべき点が判明しました。いずれも修正済みです。

  • 変換に失敗すると、以前は LibreOffice の生のエラーが返されており、一時パス、ホームディレクトリ、アカウント名が漏れていました。現在は利用者向けに書かれたメッセージのみを送信し、詳細はコンソールに出力します。
  • 以前は、任意のポート上のすべてのループバックオリジンが許可されていたため、localhost で配信されるすべてのページがブリッジに完全にアクセスできました。現在は、指定したオリジンのみが許可されます。
  • 同時実行数に上限がなく、64 MB のリクエストボディ 6 件を同時に処理すると、メモリ使用量が 100 MB から 722 MB に増加していました。
  • --token= を指定すると、認証がオフのまま気づかずに起動していました。現在は起動を拒否します。

--token よりも --token-file <path> または VECLINE_TOKEN をお使いください。引数は、トークンで締め出そうとしている唯一の主体であるローカルアカウントから、プロセステーブルを通じて読み取れるためです。

Studio をローカルで実行していますか?開発用オリジンを指定してください:vecline serve --allow-origin http://localhost:5173。

ビルド時。 Vite/Rollup プラグインを使うと、ビルド時にアセットをベクター化できます。クエリ接尾辞を付けて画像をインポートすると、CLI の手順なしでベクター画像が返されます。

// vite.config.ts
import vecline from 'vecline/vite';
export default { plugins: [vecline()] };
import logo from './logo.png?svg';        // the traced SVG string
import Logo from './logo.png?component';  // a React/Vue/Svelte/Solid component

通常の Vite/Rollup プラグインオブジェクトを返すため(unplugin への依存はありません)、純粋な TS コアにより、sharp ベースのプラグインで発生するネイティブバイナリー関連の CI の問題を回避できます。

CI ネイティブ。 GitHub Action を使うと、プッシュのたびに画像アセットをベクター化/最適化し、サイズ削減の表をジョブのサマリーに直接書き込めます。

- uses: shunyagatha/Vecline@v1
  with:
    files: 'assets/**/*.png'
    to: svg

これは vecline batch … --summary "$GITHUB_STEP_SUMMARY" を実行する薄いコンポジットアクションなので、純粋な TS コアによるネイティブバイナリー不要のインストールをそのまま利用できます。CI で libvips をコンパイルする必要はありません。同じ Markdown レポート(ファイルごとの入出力サイズと符号付きの削減量)は、どこでも vecline batch … --summary <file> を実行すれば得られます。 AI ネイティブ。 vecline mcp は Model Context Protocol サーバー(stdio)を起動するため、AI エージェントや IDE(Claude、Codex、VS Code、Cursor、Continue)から vecline を直接呼び出せます。「このロゴをベクター化して」「この図面をレーザー用の G-code に変換して」「この SVG は PNG とどのくらい近い?」といった指示に対応します。12 個のツール(vectorize、convert、centerline、measure、diff、crop、doc_to_images、office_convert、images_to_pdf、palette、placeholder、image_info)を備え、依存関係なしの JSON-RPC 実装なのでインストールに何も追加しません。クライアントの MCP 設定で { "command": "npx", "args": ["vecline", "mcp"] } を指定してください。

// Claude Desktop: claude_desktop_config.json — Cursor, Windsurf and Continue take the same shape
{
  "mcpServers": {
    "vecline": { "command": "npx", "args": ["-y", "vecline", "mcp"] }
  }
}
// VS Code: .vscode/mcp.json (workspace) — note the key is "servers", not "mcpServers"
{
  "servers": {
    "vecline": { "type": "stdio", "command": "npx", "args": ["-y", "vecline", "mcp"] }
  }
}
# Codex: ~/.codex/config.toml — or .codex/config.toml to scope it to one project
[mcp_servers.vecline]
command = "npx"
args = ["-y", "vecline", "mcp"]

3 つのクライアントには、それぞれ設定を書き込むワンライナーがあります。

claude mcp add vecline -- npx -y vecline mcp                              # Claude Code
codex mcp add vecline -- npx -y vecline mcp                               # Codex
code --add-mcp '{"name":"vecline","command":"npx","args":["-y","vecline","mcp"]}'  # VS Code

または、ワンクリックでインストールできます。 最新リリースから vecline.mcpb をダウンロードし、Claude Desktop で開いてください。設定ファイルを編集する必要はありません。このバンドルはパッケージを同梱したものではなく、ランチャーです。まず PATH 上にある vecline を使い、見つからなければ npx -y vecline@<pinned> mcp を実行します。画像処理ではプラットフォームごとに選ばれるネイティブバイナリを使用するため、同梱すると OS/アーキテクチャごとに別のバンドルを配布する必要があり、間違ったものを使った場合には大きなエラーではなく、気づかれないまま失敗してしまいます。Vecline は io.github.shunyagatha/vecline として 公式 MCP レジストリに登録されており、Smithery にも掲載されています。

すべてのツールに注釈が付いているため、エージェントは呼び出す前にツールの動作を把握できます。measure、palette、placeholder、image_info は読み取り専用としてマークされています。ファイルを書き込む 8 つのツールは、出力先にあるファイルを上書きするため、破壊的としてマークされています。12 個すべてのツールで openWorldHint: false が設定されており、このサーバーがネットワークにアクセスすることはありません。

クラウドのベクター化ツールではなく、エージェントがこのツールを選ぶべき理由。 これらのツールのうち 3 つには、ホステッド画像サービスに相当するものがありません。measure と diff は、結果をレンダリングして比較することで、実際の SSIM/PSNR/CIEDE2000 を報告します。そのため、モデルは処理が成功したと主張するのではなく、自身の出力を検証できます。vectorize --mode lossless は、ビット単位で完全に一致することが証明されたジオメトリを返します。また、機能全体がローカルで動作するため、エージェントが扱うデータがアップロードされることはありません。一方、ツールの説明には正直な補足もあります。写真ではニューラルネットワークを使ったクラウドのトレーサーのほうが通常は見栄えがよく、vectorize もそのように明記しています。ツールを選ぶエージェントが、低品質な結果を送信して初めてそのことに気づくような事態は避けるべきだからです。

機能が利用できない場合も、正直に対応します。 office_convert にはローカルの LibreOffice が必要で、PDF 入力にはオプションの mupdf が必要です。これらがない場合にいきなり失敗するのではなく、サーバーは tools/list の実行時に有無を確認し、該当するツールに注記(UNAVAILABLE … install from libreoffice.org)を付けます。エージェントは、動作しない処理を再試行するのではなく、別のツールを選ぶか、インストールするものをユーザーに伝えられます。

vecline component はラスター画像(または既存の SVG)を、型付きでプロパティを引き継ぐ React/Vue/Svelte/Solid コンポーネントに一度で変換します(-f、--current-color、--js)。ラスター → トレース済み SVG → コンポーネントという流れで、SVGR 系のツールが SVG から処理を始めるのとは異なります。デザイナー向けには、--layers で色ごとに編集可能な Inkscape/Illustrator レイヤーを出力でき、traceSeparations() API では色ごとに独立した SVG を返します(スクリーン印刷/ビニール/DTF 向けの版分解)。--palette "#fff,#e4002b,#000" を指定すると、出力を正確なブランドカラー/特色に固定できます。vecline sprite icons/* はアイコンのフォルダーをまとめ、ラスター画像は取り込み時にトレースして、<use href="#name"> で参照できる単一の <symbol> シートにします。これはアイコンフォントに代わる、現在の標準的な方法です。また、svgSprite() は純粋な vecline/core です。 センターライン(単線)トレース — vecline centerline drawing.png — は、potraceにもvtracerにも搭載されていない、最も要望の多いトレーサー機能です。ストロークの両方のエッジを輪郭化する(ジオメトリが倍になり、ペンやレーザーが各線を2回なぞることになる)のではなく、Zhang–Suenの細線化 → スケルトングラフの走査 → Douglas–Peuckerによって中軸を抽出します。各ストロークの中央を通る、開いた<path fill="none">を1本生成します。プロッター、レーザー彫刻機、CNCルーター、ビニールカッター、署名のベクター化にぴったりです。centerlineTrace()は純粋関数で、vecline/coreにあります。また、vecline gcode drawing.png --tool laser|penを使えば、最後の工程まで実行できます。そのまま実行できるGRBLスタイルのGコードツールパス(送り速度/出力/単位/スケールを指定でき、Y軸は加工領域に合わせて反転)を生成します。ほかのツールがSVGの生成までで止まり、別のsvg2gcodeを探さなければならない中、JSでは珍しい、画像から機械までを一貫して処理するパイプラインです。

SVG以外へのベクター出力は、ほかのJSトレーサーでは対応していない、メイカー/CAD向けの機能です。vecline convert in.png out.dxfは、LightBurn、LibreCAD、Fusion、あらゆるレーザー/ルーター/ビニールカッターで読み込めるDXF(実際の色を持つ閉じたLWPOLYLINE、Y軸は上向き)を書き出します。out.epsはEPS/PostScriptを書き出し、out.pdfは印刷に対応したPDFを書き出します。プリプレス向けには--cmykを指定できます(無料のJSツールはすべてsRGBに変換してしまいますが、veclineは違います)。単なる図面ではなく、部品です。--units mm --physical-width 80を指定すると、DXF自体にスケール($INSUNITSと、それではなくこちらを読み取るインポーター向けの$MEASUREMENT)が記録され、座標が実寸で出力されます。指定しない場合、DXFには単位がまったく記録されません。LightBurn、LibreCAD、Fusionはそれぞれ異なる既定値を適用するため、同じファイルでも、どのアプリで開いたかによって3種類の異なるサイズで切断されます。それに気づくのは切断後、材料を使ってしまったあとです。テストスイートは出力された座標を読み戻し、ジオメトリが指定された距離に実際に収まることを検証します。ピクセル座標のままヘッダーにミリメートルと記録しただけでは、ほかの検査をすべて通過してしまうためです。

さらにDXFは円弧に対応しています。丸い穴や円形のボスは、実際のCIRCLE/ELLIPSEエンティティとして書き出されます。機械は滑らかな1回の動作で円弧を切削でき、ポリラインで強制される短い弦の連なりにはなりません。(プリミティブ認識はエクスポーターで既定で実行されます。生のポリラインを出力するにはprimitives: falseを指定してください。)traceGeometry()/toDxf/toEps/toPdf API(すべて純粋関数で、vecline/coreにあります)を使うと、同じ構造化されたベジェジオメトリをカスタムパイプラインで利用できます。各サブパスにはprimitivesアノテーションも付与されます。

アセットパイプラインは、ウェブ開発者がデプロイするものまで一貫して対応します。vecline faviconは、単一のソースから、完全なファビコン/PWAアイコンセット(複数サイズの.ico、Appleタッチアイコン、192/512サイズおよびマスカブルPNG)、manifest.webmanifest、<head>マークアップを書き出します。vecline responsiveは、すぐに使える<picture>/srcsetマークアップとともに、AVIF/WebP/フォールバック画像の幅別セットを書き出します。vecline placeholderは、ぼかし表示用にBlurHash文字列または小さなLQIP-SVG(バイナリを使わないSQIPの後継)を生成します。vecline paletteは、知覚的に調整されたドミナントカラーのパレットをJSONまたはCSSカスタムプロパティとして抽出します。可能なものはすべて純粋なTypeScriptで実装されています(blurHash、lqipSvg、extractPaletteはvecline/coreにあります)。

ラスターアニメーション → SVGアニメーション — vecline animate loading.gifは、すべてのフレームをトレースし、単体で完結するCSSアニメーションSVG(負のanimation-delayを使ったフリップブックで、JavaScriptは不要)にまとめます。すべてのフレームで同じパレットを共有するため、フレームごとに色がちらつかず、拡大してもGIFのようなぼやけやバンディングが発生しません。フレーム0は、アニメーションに対応していないレンダラーやprefers-reduced-motion向けの静止ポスターになります。framesToAnimatedSvg()は純粋関数(vecline/core)で、traceAnimation()がフレームを読み込みます(Node)。ラスターアニメーションからアニメーションベクターへの変換に対応するJSツールは、ほとんどありません。 アニメーション GIF、APNG、アニメーション WebP はすべて動作します。 GIF と WebP のフレームは libvips から取得します。APNG は libvips から取得できず、今も取得できません。プリビルドされた sharp バイナリはページ数をまったく報告しません。つまり、metadata().pages は 20 ではなく undefined です。そのため、以前は APNG が静止画として読み込まれ、animate は、ほかのフレームが破棄されたことを示すものが何もない、1 フレームの SVG を返していました。

そのため、ここでは APNG を直接読み込みます。APNG の各フレームは、ヘッダーを取り除いたうえで fdAT チャンクに分割された通常の PNG 画像データです。そこで src/io/formats/apng.ts でヘッダーを戻し、本物の PNG を本物のコーデックに渡します。また、src/io/apng-compose.ts でフレームを合成します。SOURCE/OVER に従って各フレームをオフセット位置に描画し、その後 NONE/BACKGROUND/PREVIOUS に従って破棄します。

9 つの適合性テストファイルを使い、すべての破棄・ブレンド演算子、パレット、グレースケール+アルファ、16 ビット、実際の 20 フレームアニメーションについて、Pillow とフレーム単位で照合しました。7 つは差異のあるサブピクセルがゼロで一致します。異なる 2 つも、アルファにのみ差があります。これは Pillow 側の問題です。アルファ 50%の青を不透明なキャンバスに合成すると、a = aₛ + a_d(1 − aₛ) は a_d が 1 のとき必ず 1 になるため、不透明でなければなりません。Pillow は 191 を返します。これは aₛ + aₛ(1 − aₛ) に相当し、生成したばかりのキャンバスではなく、ソース自身のアルファに対してブレンドしています。

ドキュメントから画像へ — vecline doc report.pdf -o pages/ --dpi 150 は、PDF、SVG、またはOffice ドキュメント(.docx/.xlsx/.pptx/ODF。ご利用の LibreOffice 経由)を、任意の DPI またはスケールで、ページごとに 1 枚のラスター画像にレンダリングします。出力形式も任意に指定できます(--format png|jpeg|webp|avif、--pages "1,3-5")。--format svg を指定すると、各ページをベクター化できます。スキャン画像やラスター画像のページを、1 ステップで本物のスケーラブルな SVG に変換します。たとえば vecline doc slides.pptx -o thumbs/ -f webp を実行すると、スライドごとに WebP サムネイルが作成されます。SVG のレンダリングには同梱の resvg を使用します。PDF のレンダリングは vecline の「コーデックは利用者が用意する」方針に従い、オプションの純粋な WASM パッケージ mupdf を動的に読み込みます(コンパイルが必要なネイティブバイナリはありません)。パッケージがインストールされていない場合は、1 行のインストール案内を表示するため、基本インストールは軽量なままです。renderPdfPages()/isPdf() はプログラムから使用できるようにエクスポートされています。

画像 → 1 つの PDF — vecline pdf scan1.png scan2.jpg -o album.pdf は、写真やスキャン画像のセットを、1 ページにつき 1 枚の画像を配置した複数ページの PDF にまとめます。ページサイズは任意の --dpi で指定できます。PDF は正しい相互参照テーブルを使い、バイト列から直接構築されます(各ページは DCTDecode JPEG として埋め込まれます)。そのため、ファイルサイズが小さく、どこでも開けます。これは vecline doc(PDF → 画像)を自然に補完する機能です。imagesToPdf()/assembleImagePdf() はエクスポートされています。

Office ドキュメント ⇄ PDF — vecline office report.docx -o report.pdf(逆方向の scan.pdf -o out.docx に加え、Excel、PowerPoint、ODF、RTF、HTML、CSV など、LibreOffice が相互変換できる任意の形式ペアに対応)。Word/Excel/PowerPoint を忠実にレンダリングするには完全なオフィスエンジンが必要です。そのため、PDF の場合とまったく同じように、vecline は何も同梱せず、通常の子プロセス経由でローカルの LibreOffice を実行します。これにより、追加の依存関係はゼロで、インストールは軽量なまま、ドキュメントがマシンの外部に送信されることもありません(多くのコンバーターとは異なり、クラウドへのアップロードはありません)。出力拡張子から出力形式を推測します。LibreOffice が見つからない場合は、インストール方法を案内するか、バイナリへのパスとして VECLINE_SOFFICE を指定するようエラーメッセージに表示します。glob と --to を使うと、フォルダー全体を一度に変換できます。vecline office "docs/**/*.docx" --to pdf -o out/ を実行すると、ドキュメントごとに PDF が 1 つ作成されます(異なるフォルダーにある同名ファイルは区別され、上書きされません)。convertOffice()/convertOfficeBatch() はプログラムから使用できるようにエクスポートされています。 コンテンツに応じた切り抜き — vecline crop photo.jpg -a 1:1(または 16:9、4:5、-w 512 --height 512)を実行すると、中央ではなく、重要な被写体を残して指定したアスペクト比に合わせて構図を調整します。一般的な smartcrop.js と同じように、エッジの強さと色の彩度をもとに候補となるすべてのウィンドウを評価します(Sobel 重要度マップを積分画像に集約するため、各ウィンドウを O(1) で評価できます)。ただし、依存関係のない純粋な TypeScript で実装しているため、ブラウザーでも smartCrop() と cropImage() を vecline/core から実行できます。被写体が片側に寄った広角写真では、単純な中央切り抜きだと被写体が外れてしまいますが、この処理なら被写体を追います。

vecline edit は、sharp のパイプラインを 1 つのコマンドで実行できるようにし、適切な順序(ジオメトリ → トーン → 色 → モルフォロジー → 合成 → 仕上げ)で処理します。--resize/--fit、--rotate、--flip/--flop、--crop、--trim、--blur、--sharpen、--median、--clahe <WxH>、--gamma、--normalize、--grayscale、--negate、--sepia、--tint <color>、--threshold <0-255>、--brightness/--saturation/--hue/--lightness、--dilate/--erode、--unflatten、およびフラット化するための -b, --background を利用できます。任意のアフィン変換、エッジのパディング(extend)、チャンネルごとの linear レベル、カスタム convolve カーネル、3×3 の recomb、複数画像の composite は、vecline/ops ライブラリーのエントリーポイントから利用できます。Node.js 専用(sharp が必要)で、独立したサブパスとして提供されるため、ブラウザー用およびエッジ向けのバンドルに取り込まれることはありません。

vecline verify --fail-under 0.98 は、SSIM がしきい値を下回ると 0 以外の終了コードを返すため、アセットのパイプラインで CI のゲートとして利用できます。verify で数値を確認できるのに対し、vecline diff before.png after.png では 差異の場所 を確認できます。ベース画像を淡い背景として表示し、CIEDE2000 のしきい値を超えて変化した各ピクセルを赤く示す、pixelmatch 風のヒートマップです。知覚に基づく比較のため、1 ビットの丸め誤差では画像全体が強調表示されず、実際の色相の変化は検出されます。--fail-over 0.01 を指定すると、変更されたピクセルの割合を基準に CI のゲートを設定できます。また、diffImages() は純粋関数(vecline/core)なので、同じヒートマップをプレイグラウンドやブラウザーテストランナーでクライアント側に描画できます。

ライブラリー

import { loadRaster, vectorize, rasterize, compareImages } from 'vecline';
import { readFile, writeFile } from 'node:fs/promises';

const source = await loadRaster(await readFile('logo.png'));

const result = await vectorize(source, {
  mode: 'auto',
  verify: true,
  targetSsim: 0.98,
});

console.log(result.mode);              // 'pixel'
console.log(result.lossless);          // true — measured, not asserted
console.log(result.quality?.psnr);     // Infinity
await writeFile('logo.svg', result.svg);
// SVG → raster
const png = await rasterize(await readFile('logo.svg'), {
  width: 2400,
  encode: { format: 'png' },
});
await writeFile('[email protected]', png.buffer);

すべての変換関数はファイルシステムに対して純粋です。ファイルを読み込むのは loadRaster だけで、書き込みは一切行わないため、既存のパイプラインに自由に組み込めます。低レベルの構成要素(quantize、connectedComponents、traceComponents、fitLoop、PathBuilder、ssimPlane、deltaE2000)もエクスポートされています。

制限事項

投資する前に知っておいていただきたいことを、率直に述べます。

  • 写真をトレースしても、写真のようにはなりません。 これは本質的な制約であり、設定の調整で解決する問題ではありません。忠実度が重要なら embed を、スケーラビリティと編集のしやすさを重視するなら trace を使用してください。
  • 写真を入力した場合の pixel モードでは、ピクセルごとにおよそ1つの長方形が必要になります。Vecline はこれを拒否し、代わりに embed または trace を使用するよう通知します。
  • embed モードの WebP ペイロードはブラウザー専用です。 WebP に対応していない resvg と librsvg のビルドでは、WebP の <image> が警告なしに 空白 として描画されます。そのため、auto が WebP を選択することはありません。--embed-strategy webp を指定するとオプトインされ、警告が表示されます。
  • 16 ビットのソースは、 SVG のペイントサーバーではそれ以上のビット深度を表現できないため、pixel と trace では 8 ビットに変換されます。--embed-strategy preserve を指定した embed では、元のビット深度がそのまま保持されます。
  • アニメーションには対応していません。 複数フレームの入力では、最初のフレームが使われます。
  • trace のメモリー使用量は画像の面積に応じて増加します。非常に大きな写真は、先に縮小することをおすすめします。
  • HEIC、JPEG XL、JPEG 2000、PSD、PDF、カメラ RAW は組み込みでは対応していません — プリビルドの libvips にコーデックが含まれていないためです。独自のコーデックを vecline/codecs 経由で登録できます。フォーマットを参照してください。
  • vecline/core は圧縮された画像ファイルの読み書きに対応していません。 PNG、JPEG、WebP などには実際のコーデックが必要です。core が BMP、ICO、PNM、TGA を扱えるのは、このパッケージがそれらを独自に実装しているためです。ブラウザーでは、デコードに createImageBitmap / canvas を、エンコードに canvas.toBlob を使用してください。
  • 許容誤差を小さくしたトレースでは、滑らかな曲線の数より正確さが優先されます。 調整済みのデフォルト(0.4px)では、大きく滑らかな弧は少数のベジェ曲線ではなく、ピクセル精度の細かなポリゴンになります。写真やピクセル単位の忠実度には適切ですが、編集可能な少数の曲線でロゴを表現したい場合は、--preset logo(許容誤差 0.65)を使用するか、--tolerance を自分で大きくしてください。この2つの目標には実際にトレードオフがあり、デフォルトでは正確さを優先します。
  • 商用トレーサーとの比較は行っていません。 比較では、インストールしてスクリプトから実行できる potrace、imagetracerjs、vtracer を取り上げています。Illustrator、Vector Magic、Vectorizer.AI は未評価のため、それらについては何も主張していません。

変更履歴

すべてのリリースはタグ付けされ、CHANGELOG.md に記録されています。そこには、以前の主張を訂正したリリースも含む、GitHub 上の完全なリリースノートへの索引があります。

コントリビューション

コントリビューションを歓迎します — CONTRIBUTING.md を参照してください。

git clone https://github.com/shunyagatha/Vecline.git
cd Vecline
npm install
npm run build
npm test

テスト用フィクスチャはバイナリとしてコミットするのではなく、コードから生成されます。差分で誰もレビューできない画像データはリスクになります。また、画像ライブラリのリサンプリング処理が変更されると、それに基づくすべての期待値が気付かないうちに無効になるためです。

謝辞

以下の方々の功績を基盤としています:Xiaolin Wu(色の量子化)、Philip J. Schneider(曲線フィッティング)、Peter Selinger(potrace。境界トレースの手法から着想を得ています)、Björn Ottosson(Oklab)、Wang, Bovik, Sheikh & Simoncelli(SSIM)、Sharma, Wu & Dalal(CIEDE2000)。sharp 経由で libvips を、また resvg を使用しています。

プライバシーポリシー

Vecline は何も収集しません。 データの送信先となるサーバーはありません。トレース、測定、トリミング、PDF と Office のレンダリングを含むすべての変換はお使いのマシン上で行われ、画像やドキュメントがアップロードされることはありません。

  • 収集するデータ: ありません。ファイル、アカウント、分析データ、テレメトリー、Cookie は一切ありません。
  • 保存: ファイルはメモリ上で処理され、指定した場所にのみ書き込まれます。
  • サードパーティ: 収集するデータがないため、共有される情報もありません。MCP デスクトップ拡張機能は初回実行時に npm から vecline パッケージを取得する場合があり、Office の変換ではお使いのマシンにすでにインストールされている LibreOffice を呼び出しますが、どちらもドキュメントを送信することはありません。
  • 保持期間: 保存されたデータがないため、請求や削除の対象となるデータもありません。
  • ご確認ください: 変換中にブラウザーのネットワークタブを確認するか、インターネットから切断して作業を続けてください。

ポリシー全文:https://vecline.xyz/privacy.html · お問い合わせ:issue を作成

Vecline を支援する

Vecline は無料で、今後も無料です。ライブラリ、CLI、MCP サーバーは MIT ライセンスです。Studio は永久に無料で、利用回数の制限も登録も不要です。別のサービスの試用版ではありません。また、画像がアップロードされないことを誰でも確認できるよう、ソースコードを公開しています。ただし、ソースコードは公開されていますが、オープンソースではありません。自由に読んだり、ビルドしたり、監査したりできますが、再配布またはホスティングを行う前にライセンスをご確認ください。料金を支払わない人に提供されない機能はなく、有料プランへ誘導することもありません。

午後の時間を節約できて、感謝の気持ちを伝えたいと思ったら:

tiptopjar.com/vecline にリンクする QR コード

tiptopjar.com/vecline — 単発の寄付で、アカウントは不要です。QR コードも同じリンク先です。スマートフォンでご利用ください。

同じくらい、あるいはそれ以上に役立ち、費用もかからないことがあります。問題の原因となった画像を添えたバグ報告、Vecline がほかのものより劣ることを示す測定結果、またはスターです。最初の 2 つは寄付よりも価値があります。このプロジェクトの主張は、出力が測定されているということです。それが成り立つのは、人々が検証し続けてくれる間だけです。


ライセンス

MIT

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。