Skip to content

Commit 082dd8c

Browse files
authored
Merge pull request #388 from SAHIL-Sharma21/feat/Vtracer_implementation
Feat: add VTracer converter for raster to vector conversion
2 parents 554edf5 + 43524dc commit 082dd8c

File tree

4 files changed

+117
-18
lines changed

4 files changed

+117
-18
lines changed

Dockerfile

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ RUN bun run build
4343
# copy production dependencies and source code into final image
4444
FROM base AS release
4545

46-
# install additional dependencies
46+
# install additional dependencies
4747
RUN apt-get update && apt-get install -y \
4848
assimp-utils \
4949
calibre \
@@ -75,6 +75,19 @@ RUN apt-get update && apt-get install -y \
7575
--no-install-recommends \
7676
&& rm -rf /var/lib/apt/lists/*
7777

78+
# Install VTracer binary
79+
RUN ARCH=$(uname -m) && \
80+
if [ "$ARCH" = "aarch64" ]; then \
81+
VTRACER_ASSET="vtracer-aarch64-unknown-linux-musl.tar.gz"; \
82+
else \
83+
VTRACER_ASSET="vtracer-x86_64-unknown-linux-musl.tar.gz"; \
84+
fi && \
85+
curl -L -o /tmp/vtracer.tar.gz "https://github.com/visioncortex/vtracer/releases/download/0.6.4/${VTRACER_ASSET}" && \
86+
tar -xzf /tmp/vtracer.tar.gz -C /tmp/ && \
87+
mv /tmp/vtracer /usr/local/bin/vtracer && \
88+
chmod +x /usr/local/bin/vtracer && \
89+
rm /tmp/vtracer.tar.gz
90+
7891
COPY --from=install /temp/prod/node_modules node_modules
7992
COPY --from=prerelease /app/public/generated.css /app/public/
8093
COPY --from=prerelease /app/dist /app/dist
@@ -86,4 +99,4 @@ EXPOSE 3000/tcp
8699
# used for calibre
87100
ENV QTWEBENGINE_CHROMIUM_FLAGS="--no-sandbox"
88101
ENV NODE_ENV=production
89-
ENTRYPOINT [ "bun", "run", "dist/src/index.js" ]
102+
ENTRYPOINT [ "bun", "run", "dist/src/index.js" ]

README.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,23 @@ A self-hosted online file converter. Supports over a thousand different formats.
2525

2626
## Converters supported
2727

28-
| Converter | Use case | Converts from | Converts to |
29-
| ------------------------------------------------ | ---------------- | ------------- | ----------- |
30-
| [libjxl](https://github.com/libjxl/libjxl) | JPEG XL | 11 | 11 |
31-
| [resvg](https://github.com/RazrFalcon/resvg) | SVG | 1 | 1 |
32-
| [Vips](https://github.com/libvips/libvips) | Images | 45 | 23 |
33-
| [libheif](https://github.com/strukturag/libheif) | HEIF | 2 | 4 |
34-
| [XeLaTeX](https://tug.org/xetex/) | LaTeX | 1 | 1 |
35-
| [Calibre](https://calibre-ebook.com/) | E-books | 26 | 19 |
36-
| [Pandoc](https://pandoc.org/) | Documents | 43 | 65 |
37-
| [dvisvgm](https://dvisvgm.de/) | Vector images | 4 | 2 |
38-
| [ImageMagick](https://imagemagick.org/) | Images | 245 | 183 |
39-
| [GraphicsMagick](http://www.graphicsmagick.org/) | Images | 167 | 130 |
40-
| [Inkscape](https://inkscape.org/) | Vector images | 7 | 17 |
41-
| [Assimp](https://github.com/assimp/assimp) | 3D Assets | 77 | 23 |
42-
| [FFmpeg](https://ffmpeg.org/) | Video | ~472 | ~199 |
43-
| [Potrace](https://potrace.sourceforge.net/) | Raster to vector | 4 | 11 |
28+
| Converter | Use case | Converts from | Converts to |
29+
| -------------------------------------------------- | ---------------- | ------------- | ----------- |
30+
| [libjxl](https://github.com/libjxl/libjxl) | JPEG XL | 11 | 11 |
31+
| [resvg](https://github.com/RazrFalcon/resvg) | SVG | 1 | 1 |
32+
| [Vips](https://github.com/libvips/libvips) | Images | 45 | 23 |
33+
| [libheif](https://github.com/strukturag/libheif) | HEIF | 2 | 4 |
34+
| [XeLaTeX](https://tug.org/xetex/) | LaTeX | 1 | 1 |
35+
| [Calibre](https://calibre-ebook.com/) | E-books | 26 | 19 |
36+
| [Pandoc](https://pandoc.org/) | Documents | 43 | 65 |
37+
| [dvisvgm](https://dvisvgm.de/) | Vector images | 4 | 2 |
38+
| [ImageMagick](https://imagemagick.org/) | Images | 245 | 183 |
39+
| [GraphicsMagick](http://www.graphicsmagick.org/) | Images | 167 | 130 |
40+
| [Inkscape](https://inkscape.org/) | Vector images | 7 | 17 |
41+
| [Assimp](https://github.com/assimp/assimp) | 3D Assets | 77 | 23 |
42+
| [FFmpeg](https://ffmpeg.org/) | Video | ~472 | ~199 |
43+
| [Potrace](https://potrace.sourceforge.net/) | Raster to vector | 4 | 11 |
44+
| [VTracer](https://github.com/visioncortex/vtracer) | Raster to vector | 8 | 1 |
4445

4546
<!-- many ffmpeg fileformats are duplicates -->
4647

src/converters/main.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { convert as convertPandoc, properties as propertiesPandoc } from "./pand
2020
import { convert as convertPotrace, properties as propertiesPotrace } from "./potrace";
2121
import { convert as convertresvg, properties as propertiesresvg } from "./resvg";
2222
import { convert as convertImage, properties as propertiesImage } from "./vips";
23+
import { convert as convertVtracer, properties as propertiesVtracer } from "./vtracer";
2324
import { convert as convertxelatex, properties as propertiesxelatex } from "./xelatex";
2425

2526
// This should probably be reconstructed so that the functions are not imported instead the functions hook into this to make the converters more modular
@@ -117,6 +118,10 @@ const properties: Record<
117118
properties: propertiesPotrace,
118119
converter: convertPotrace,
119120
},
121+
vtracer: {
122+
properties: propertiesVtracer,
123+
converter: convertVtracer,
124+
},
120125
};
121126

122127
function chunks<T>(arr: T[], size: number): T[][] {

src/converters/vtracer.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { execFile as execFileOriginal } from "node:child_process";
2+
import { ExecFileFn } from "./types";
3+
4+
export const properties = {
5+
from: {
6+
images: ["jpg", "jpeg", "png", "bmp", "gif", "tiff", "tif", "webp"],
7+
},
8+
to: {
9+
images: ["svg"],
10+
},
11+
};
12+
13+
interface VTracerOptions {
14+
colormode?: string;
15+
hierarchical?: string;
16+
mode?: string;
17+
filter_speckle?: string | number;
18+
color_precision?: string | number;
19+
layer_difference?: string | number;
20+
corner_threshold?: string | number;
21+
length_threshold?: string | number;
22+
max_iterations?: string | number;
23+
splice_threshold?: string | number;
24+
path_precision?: string | number;
25+
}
26+
27+
export function convert(
28+
filePath: string,
29+
fileType: string,
30+
convertTo: string,
31+
targetPath: string,
32+
options?: unknown,
33+
execFile: ExecFileFn = execFileOriginal, // to make it mockable
34+
): Promise<string> {
35+
return new Promise((resolve, reject) => {
36+
// Build vtracer arguments
37+
const args = ["--input", filePath, "--output", targetPath];
38+
39+
// Add optional parameter if provided
40+
if (options && typeof options === "object") {
41+
const opts = options as VTracerOptions;
42+
const validOptions: Array<keyof VTracerOptions> = [
43+
"colormode",
44+
"hierarchical",
45+
"mode",
46+
"filter_speckle",
47+
"color_precision",
48+
"layer_difference",
49+
"corner_threshold",
50+
"length_threshold",
51+
"max_iterations",
52+
"splice_threshold",
53+
"path_precision",
54+
];
55+
56+
for (const option of validOptions) {
57+
if (opts[option] !== undefined) {
58+
args.push(`--${option}`, String(opts[option]));
59+
}
60+
}
61+
}
62+
63+
execFile("vtracer", args, (error, stdout, stderr) => {
64+
if (error) {
65+
reject(`error: ${error}${stderr ? `\nstderr: ${stderr}` : ""}`);
66+
return;
67+
}
68+
69+
if (stdout) {
70+
console.log(`stdout: ${stdout}`);
71+
}
72+
73+
if (stderr) {
74+
console.log(`stderr: ${stderr}`);
75+
}
76+
77+
resolve("Done");
78+
});
79+
});
80+
}

0 commit comments

Comments
 (0)