fix(inkscape): use xvfb-run for headless execution

- Inkscape requires X11 display connection, causing 'GtkStyleContext without display' error
- Solution: use xvfb-run to create virtual X11 display
- Fallback: try direct inkscape if xvfb-run fails
- Add xvfb package to Dockerfile
- Update inkscape tests for new xvfb-run behavior

Fixes: Gtk-ERROR: Can't create a GtkStyleContext without a display connection
This commit is contained in:
Your Name 2026-01-22 23:56:47 +08:00
parent 2f9c418964
commit b5992a84e0
4 changed files with 168 additions and 7 deletions

View file

@ -28,6 +28,17 @@ export const properties = {
},
};
/**
* Inkscape
*
* Headless
* Inkscape X11 Docker/Server
* 使 xvfb-run
*
* 🔧
* 1. 使 xvfb-run X11
* 2. xvfb-run GDK_BACKEND=svg SVG
*/
export function convert(
filePath: string,
fileType: string,
@ -37,9 +48,46 @@ export function convert(
execFile: ExecFileFn = execFileOriginal, // to make it mockable
): Promise<string> {
return new Promise((resolve, reject) => {
execFile("inkscape", [filePath, "-o", targetPath], (error, stdout, stderr) => {
// 使用 xvfb-run 執行 Inkscape建立虛擬 X11 顯示器)
// -a: 自動尋找可用的 display number
// --server-args: 設定虛擬螢幕解析度
const xvfbArgs = [
"-a",
"--server-args=-screen 0 1024x768x24",
"inkscape",
filePath,
"-o",
targetPath,
];
execFile("xvfb-run", xvfbArgs, (error: Error | null, stdout: string, stderr: string) => {
if (error) {
reject(`error: ${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");
},
);
return;
}
if (stdout) {
@ -47,7 +95,8 @@ export function convert(
}
if (stderr) {
console.error(`stderr: ${stderr}`);
// Inkscape 經常輸出警告到 stderr但這不代表失敗
console.log(`stderr: ${stderr}`);
}
resolve("Done");