fix(inkscape): use headless-safe export syntax (--export-type/--export-filename)
Breaking change from Inkscape 1.0+: - Old syntax: inkscape input.png -o output.svg (triggers GTK init) - New syntax: inkscape input.png --export-type=svg --export-filename=output.svg This is the correct headless-safe approach, no need for xvfb. Ref: https://inkscape.org/doc/inkscape-man.html
This commit is contained in:
parent
b5992a84e0
commit
26304a295e
3 changed files with 52 additions and 80 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
import { extname } from "node:path";
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
|
@ -32,12 +33,16 @@ export const properties = {
|
|||
* Inkscape 轉換器
|
||||
*
|
||||
* ⚠️ Headless 環境注意事項:
|
||||
* Inkscape 需要 X11 顯示器連線。在 Docker/Server 環境中,
|
||||
* 必須使用 xvfb-run 建立虛擬顯示器。
|
||||
* Inkscape 1.0+ 的新版命令列語法支援 headless 執行,
|
||||
* 不需要 X11 或 xvfb。
|
||||
*
|
||||
* 🔧 解決方案:
|
||||
* 1. 優先使用 xvfb-run(虛擬 X11)
|
||||
* 2. 若 xvfb-run 失敗,嘗試 GDK_BACKEND=svg(純 SVG 後端)
|
||||
* 🔧 正確的 headless-safe 語法:
|
||||
* inkscape input.png --export-type=svg --export-filename=output.svg
|
||||
*
|
||||
* ❌ 舊版語法(會觸發 GTK 初始化):
|
||||
* inkscape input.png -o output.svg
|
||||
*
|
||||
* 參考:https://inkscape.org/doc/inkscape-man.html
|
||||
*/
|
||||
export function convert(
|
||||
filePath: string,
|
||||
|
|
@ -48,45 +53,18 @@ export function convert(
|
|||
execFile: ExecFileFn = execFileOriginal, // to make it mockable
|
||||
): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 使用 xvfb-run 執行 Inkscape(建立虛擬 X11 顯示器)
|
||||
// -a: 自動尋找可用的 display number
|
||||
// --server-args: 設定虛擬螢幕解析度
|
||||
const xvfbArgs = [
|
||||
"-a",
|
||||
"--server-args=-screen 0 1024x768x24",
|
||||
"inkscape",
|
||||
filePath,
|
||||
"-o",
|
||||
targetPath,
|
||||
];
|
||||
// 從目標路徑取得輸出格式(移除開頭的點)
|
||||
const exportType = extname(targetPath).slice(1).toLowerCase();
|
||||
|
||||
execFile("xvfb-run", xvfbArgs, (error: Error | null, stdout: string, stderr: string) => {
|
||||
// 使用 Inkscape 1.0+ 的 headless-safe 命令列語法
|
||||
// --export-type: 明確指定輸出格式
|
||||
// --export-filename: 指定輸出檔案路徑
|
||||
// 這種語法不會初始化 GTK,因此在無 DISPLAY 的環境也能運作
|
||||
const args = [filePath, `--export-type=${exportType}`, `--export-filename=${targetPath}`];
|
||||
|
||||
execFile("inkscape", args, (error: Error | null, stdout: string, stderr: string) => {
|
||||
if (error) {
|
||||
// xvfb-run 失敗,回退到直接執行 inkscape
|
||||
// 這可能在某些已有 DISPLAY 設定的環境中運作
|
||||
console.log("[Inkscape] xvfb-run failed, trying direct inkscape execution...");
|
||||
console.log(`[Inkscape] Original error: ${error.message}`);
|
||||
|
||||
execFile(
|
||||
"inkscape",
|
||||
[filePath, "-o", targetPath],
|
||||
(error2: Error | null, stdout2: string, stderr2: string) => {
|
||||
if (error2) {
|
||||
reject(`error: ${error2}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (stdout2) {
|
||||
console.log(`stdout: ${stdout2}`);
|
||||
}
|
||||
|
||||
if (stderr2) {
|
||||
console.error(`stderr: ${stderr2}`);
|
||||
}
|
||||
|
||||
resolve("Done");
|
||||
},
|
||||
);
|
||||
reject(`error: ${error}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue