@cadit-app/image-extrude 0.1.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Parameter schema for the Image Extrude generator.
3
3
  */
4
- // Default SVG - a simple star shape
5
- const defaultSvgDataUrl = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cG9seWdvbiBwb2ludHM9IjUwLDUgNjEsMzkgOTcsMzkgNjgsMjIgNzksOTUgNTAsNzAgMjEsOTUgMzIsNjIgMywzOSAzOSwzOSIgZmlsbD0iYmxhY2siLz48L3N2Zz4=';
4
+ // Default image - CookieCAD logo from GitHub via jsdelivr CDN
5
+ const defaultImageUrl = 'https://cdn.jsdelivr.net/gh/CADit-app/image-extrude@master/images/cookiecad-logo-dark.svg';
6
6
  export const imageExtrudeParamsSchema = {
7
7
  mode: {
8
8
  type: 'choice',
@@ -17,10 +17,10 @@ export const imageExtrudeParamsSchema = {
17
17
  type: 'image',
18
18
  label: 'Image File',
19
19
  default: {
20
- imageUrl: '',
21
- dataUrl: defaultSvgDataUrl,
20
+ imageUrl: defaultImageUrl,
21
+ dataUrl: '',
22
22
  fileType: 'image/svg+xml',
23
- fileName: 'star.svg'
23
+ fileName: 'cookiecad-logo-dark.svg'
24
24
  },
25
25
  },
26
26
  height: {
@@ -1,5 +1,8 @@
1
1
  /**
2
2
  * SVG to bitmap rendering using resvg-wasm
3
+ *
4
+ * Note: When running as a dynamically loaded script in CADit, the WASM module
5
+ * is loaded from esm.sh CDN since Vite's ?url import syntax isn't available.
3
6
  */
4
7
  /**
5
8
  * Renders an SVG Data URL to a PNG Data URL using resvg-wasm.
@@ -1 +1 @@
1
- {"version":3,"file":"resvg.d.ts","sourceRoot":"","sources":["../../src/resvg.ts"],"names":[],"mappings":"AAAA;;GAEG;AA+BH;;GAEG;AACH,eAAO,MAAM,wBAAwB,GACnC,YAAY,MAAM,EAClB,UAAU;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,KAC9B,OAAO,CAAC,MAAM,CAuBhB,CAAC"}
1
+ {"version":3,"file":"resvg.d.ts","sourceRoot":"","sources":["../../src/resvg.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAsCH;;GAEG;AACH,eAAO,MAAM,wBAAwB,GACnC,YAAY,MAAM,EAClB,UAAU;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,KAC9B,OAAO,CAAC,MAAM,CA6BhB,CAAC"}
package/dist/src/resvg.js CHANGED
@@ -1,26 +1,41 @@
1
1
  /**
2
2
  * SVG to bitmap rendering using resvg-wasm
3
+ *
4
+ * Note: When running as a dynamically loaded script in CADit, the WASM module
5
+ * is loaded from esm.sh CDN since Vite's ?url import syntax isn't available.
3
6
  */
4
7
  import * as resvg from '@resvg/resvg-wasm';
5
8
  import { svgDataUrlToString } from './utils';
9
+ // Hardcoded version for WASM URL - update when upgrading @resvg/resvg-wasm dependency
10
+ const RESVG_VERSION = '2.6.2';
6
11
  let wasmInitialized = false;
12
+ let wasmInitPromise = null;
7
13
  /**
8
- * Initialize resvg WASM module
9
- * In CLI context, we need to load from file system
10
- * In browser context (via bundler), the WASM is loaded differently
14
+ * Initialize resvg WASM module.
15
+ * Fetches the WASM binary from esm.sh CDN to work in dynamically loaded scripts.
16
+ *
17
+ * Safe to call multiple times - subsequent calls return immediately.
18
+ * If initialization fails, subsequent calls will retry.
11
19
  */
12
20
  async function initializeResvgWasm() {
13
21
  if (wasmInitialized)
14
22
  return;
15
- // For CLI usage, load WASM from node_modules
16
- const { readFile } = await import('fs/promises');
17
- const { resolve, dirname } = await import('path');
18
- const { fileURLToPath } = await import('url');
19
- // Find the wasm file in node_modules
20
- const wasmPath = resolve(dirname(fileURLToPath(import.meta.url)), '../node_modules/@resvg/resvg-wasm/index_bg.wasm');
21
- const wasmBuffer = await readFile(wasmPath);
22
- await resvg.initWasm(wasmBuffer);
23
- wasmInitialized = true;
23
+ if (wasmInitPromise)
24
+ return wasmInitPromise;
25
+ wasmInitPromise = (async () => {
26
+ try {
27
+ // Fetch WASM from esm.sh CDN
28
+ const wasmUrl = `https://esm.sh/@resvg/resvg-wasm@${RESVG_VERSION}/index_bg.wasm`;
29
+ await resvg.initWasm(fetch(wasmUrl));
30
+ wasmInitialized = true;
31
+ }
32
+ catch (error) {
33
+ // Reset promise so retry is possible
34
+ wasmInitPromise = null;
35
+ throw error;
36
+ }
37
+ })();
38
+ return wasmInitPromise;
24
39
  }
25
40
  /**
26
41
  * Renders an SVG Data URL to a PNG Data URL using resvg-wasm.
@@ -40,8 +55,10 @@ export const renderSvgToBitmapDataUrl = async (svgDataUrl, options) => {
40
55
  }
41
56
  const resvgInstance = new resvg.Resvg(svgString, opts);
42
57
  const pngData = resvgInstance.render();
43
- const pngBuffer = pngData.asPng();
44
- // Convert to data URL
45
- const base64 = Buffer.from(pngBuffer).toString('base64');
46
- return `data:image/png;base64,${base64}`;
58
+ const pngBuffer = pngData.asPng(); // Uint8Array
59
+ // Convert Uint8Array to proper ArrayBuffer for Blob
60
+ const arrayBuffer = pngBuffer.buffer.slice(pngBuffer.byteOffset, pngBuffer.byteOffset + pngBuffer.byteLength);
61
+ // Return blob URL (browser-compatible and more efficient)
62
+ const blob = new Blob([arrayBuffer], { type: 'image/png' });
63
+ return URL.createObjectURL(blob);
47
64
  };
@@ -1,5 +1,8 @@
1
1
  /**
2
2
  * Image tracing and SVG sampling utilities
3
+ *
4
+ * Uses potrace for bitmap tracing. When running in CADit, potrace is exposed
5
+ * as an importable library by the code.worker, which handles the jimp dependency.
3
6
  */
4
7
  import { CrossSection } from '@cadit-app/manifold-3d/manifoldCAD';
5
8
  /**
@@ -16,6 +19,7 @@ export declare const svgStringToCrossSection: (svgContent: string, maxWidth?: nu
16
19
  export declare const sampleSvg: (svgDataUrl: string, maxWidth?: number) => Promise<CrossSection>;
17
20
  /**
18
21
  * Traces a bitmap image and returns a centered CrossSection
22
+ * Uses potrace with jimp for image loading (works in web workers).
19
23
  */
20
24
  export declare const traceImage: (imageDataUrl: string, options: {
21
25
  maxWidth?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../../src/tracing.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAKlE;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAC/B,YAAY,MAAM,EAClB,UAAU,MAAM,kCAWjB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAClC,YAAY,MAAM,EAClB,WAAW,MAAM,EACjB,WAAU,MAAa,KACtB,OAAO,CAAC,YAAY,CAgBtB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS,GAAU,YAAY,MAAM,EAAE,WAAW,MAAM,KAAG,OAAO,CAAC,YAAY,CAO3F,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,UAAU,GACrB,cAAc,MAAM,EACpB,SAAS;IACP,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,KACA,OAAO,CAAC,YAAY,CAmBtB,CAAC"}
1
+ {"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../../src/tracing.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAKlE;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAC/B,YAAY,MAAM,EAClB,UAAU,MAAM,kCAWjB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAClC,YAAY,MAAM,EAClB,WAAW,MAAM,EACjB,WAAU,MAAa,KACtB,OAAO,CAAC,YAAY,CAgBtB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS,GAAU,YAAY,MAAM,EAAE,WAAW,MAAM,KAAG,OAAO,CAAC,YAAY,CAO3F,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,UAAU,GACrB,cAAc,MAAM,EACpB,SAAS;IACP,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,KACA,OAAO,CAAC,YAAY,CAmBtB,CAAC"}
@@ -1,5 +1,8 @@
1
1
  /**
2
2
  * Image tracing and SVG sampling utilities
3
+ *
4
+ * Uses potrace for bitmap tracing. When running in CADit, potrace is exposed
5
+ * as an importable library by the code.worker, which handles the jimp dependency.
3
6
  */
4
7
  import { svgToPolygons } from '@cadit-app/svg-sampler';
5
8
  import { CrossSection } from '@cadit-app/manifold-3d/manifoldCAD';
@@ -49,6 +52,7 @@ export const sampleSvg = async (svgDataUrl, maxWidth) => {
49
52
  };
50
53
  /**
51
54
  * Traces a bitmap image and returns a centered CrossSection
55
+ * Uses potrace with jimp for image loading (works in web workers).
52
56
  */
53
57
  export const traceImage = async (imageDataUrl, options) => {
54
58
  const tracer = new Potrace({
@@ -56,7 +60,7 @@ export const traceImage = async (imageDataUrl, options) => {
56
60
  });
57
61
  // Promisify tracer.loadImage
58
62
  await new Promise((resolve, reject) => {
59
- tracer.loadImage(imageDataUrl, (err) => {
63
+ tracer.loadImage(imageDataUrl, (_potrace, err) => {
60
64
  if (err) {
61
65
  reject(err);
62
66
  }
package/package.json CHANGED
@@ -1,13 +1,25 @@
1
1
  {
2
2
  "name": "@cadit-app/image-extrude",
3
- "version": "0.1.0",
3
+ "version": "0.3.1",
4
4
  "description": "Image Extrude for CADit - Extrude shapes from SVG or bitmap images",
5
5
  "type": "module",
6
- "main": "dist/main.js",
7
- "types": "dist/main.d.ts",
6
+ "main": "dist/bundle.js",
7
+ "types": "dist/src/main.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/bundle.js",
11
+ "types": "./dist/src/main.d.ts"
12
+ },
13
+ "./unbundled": {
14
+ "import": "./dist/src/main.js",
15
+ "types": "./dist/src/main.d.ts"
16
+ }
17
+ },
8
18
  "scripts": {
9
19
  "typecheck": "tsc --noEmit",
10
- "build": "tsc",
20
+ "build:types": "tsc",
21
+ "build:bundle": "vite build",
22
+ "build": "npm run build:types && npm run build:bundle",
11
23
  "prepublishOnly": "npm run build",
12
24
  "generate": "npx tsx cli.ts",
13
25
  "build:glb": "npx tsx cli.ts output.glb",
@@ -17,7 +29,6 @@
17
29
  "@cadit-app/script-params": "0.4.1",
18
30
  "@cadit-app/svg-sampler": "^0.1.0",
19
31
  "@resvg/resvg-wasm": "^2.6.2",
20
- "@types/potrace": "^2.1.5",
21
32
  "potrace": "^2.1.8"
22
33
  },
23
34
  "peerDependencies": {
@@ -28,9 +39,12 @@
28
39
  "@gltf-transform/core": "^4.1.1",
29
40
  "@jscadui/3mf-export": "^0.5.0",
30
41
  "@types/node": "^25.0.3",
42
+ "@types/potrace": "^2.1.5",
43
+ "esbuild": "^0.24.0",
31
44
  "fflate": "^0.8.2",
32
45
  "tsx": "^4.0.0",
33
- "typescript": "^5.0.0"
46
+ "typescript": "^5.0.0",
47
+ "vite": "^7.3.1"
34
48
  },
35
49
  "keywords": [
36
50
  "cadit",
package/src/params.ts CHANGED
@@ -18,8 +18,8 @@ export interface ImageFileValue {
18
18
  fileName?: string;
19
19
  }
20
20
 
21
- // Default SVG - a simple star shape
22
- const defaultSvgDataUrl = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cG9seWdvbiBwb2ludHM9IjUwLDUgNjEsMzkgOTcsMzkgNjgsMjIgNzksOTUgNTAsNzAgMjEsOTUgMzIsNjIgMywzOSAzOSwzOSIgZmlsbD0iYmxhY2siLz48L3N2Zz4=';
21
+ // Default image - CookieCAD logo from GitHub via jsdelivr CDN
22
+ const defaultImageUrl = 'https://cdn.jsdelivr.net/gh/CADit-app/image-extrude@master/images/cookiecad-logo-dark.svg';
23
23
 
24
24
  export const imageExtrudeParamsSchema = {
25
25
  mode: {
@@ -35,10 +35,10 @@ export const imageExtrudeParamsSchema = {
35
35
  type: 'image' as const,
36
36
  label: 'Image File',
37
37
  default: {
38
- imageUrl: '',
39
- dataUrl: defaultSvgDataUrl,
38
+ imageUrl: defaultImageUrl,
39
+ dataUrl: '',
40
40
  fileType: 'image/svg+xml',
41
- fileName: 'star.svg'
41
+ fileName: 'cookiecad-logo-dark.svg'
42
42
  } as ImageFileValue,
43
43
  },
44
44
  height: {
package/src/resvg.ts CHANGED
@@ -1,34 +1,44 @@
1
1
  /**
2
2
  * SVG to bitmap rendering using resvg-wasm
3
+ *
4
+ * Note: When running as a dynamically loaded script in CADit, the WASM module
5
+ * is loaded from esm.sh CDN since Vite's ?url import syntax isn't available.
3
6
  */
4
7
 
5
8
  import * as resvg from '@resvg/resvg-wasm';
6
9
  import { svgDataUrlToString } from './utils';
7
10
 
11
+ // Hardcoded version for WASM URL - update when upgrading @resvg/resvg-wasm dependency
12
+ const RESVG_VERSION = '2.6.2';
13
+
8
14
  let wasmInitialized = false;
15
+ let wasmInitPromise: Promise<void> | null = null;
9
16
 
10
17
  /**
11
- * Initialize resvg WASM module
12
- * In CLI context, we need to load from file system
13
- * In browser context (via bundler), the WASM is loaded differently
18
+ * Initialize resvg WASM module.
19
+ * Fetches the WASM binary from esm.sh CDN to work in dynamically loaded scripts.
20
+ *
21
+ * Safe to call multiple times - subsequent calls return immediately.
22
+ * If initialization fails, subsequent calls will retry.
14
23
  */
15
- async function initializeResvgWasm() {
24
+ async function initializeResvgWasm(): Promise<void> {
16
25
  if (wasmInitialized) return;
17
-
18
- // For CLI usage, load WASM from node_modules
19
- const { readFile } = await import('fs/promises');
20
- const { resolve, dirname } = await import('path');
21
- const { fileURLToPath } = await import('url');
22
-
23
- // Find the wasm file in node_modules
24
- const wasmPath = resolve(
25
- dirname(fileURLToPath(import.meta.url)),
26
- '../node_modules/@resvg/resvg-wasm/index_bg.wasm'
27
- );
28
-
29
- const wasmBuffer = await readFile(wasmPath);
30
- await resvg.initWasm(wasmBuffer);
31
- wasmInitialized = true;
26
+ if (wasmInitPromise) return wasmInitPromise;
27
+
28
+ wasmInitPromise = (async () => {
29
+ try {
30
+ // Fetch WASM from esm.sh CDN
31
+ const wasmUrl = `https://esm.sh/@resvg/resvg-wasm@${RESVG_VERSION}/index_bg.wasm`;
32
+ await resvg.initWasm(fetch(wasmUrl));
33
+ wasmInitialized = true;
34
+ } catch (error) {
35
+ // Reset promise so retry is possible
36
+ wasmInitPromise = null;
37
+ throw error;
38
+ }
39
+ })();
40
+
41
+ return wasmInitPromise;
32
42
  }
33
43
 
34
44
  /**
@@ -55,9 +65,15 @@ export const renderSvgToBitmapDataUrl = async (
55
65
 
56
66
  const resvgInstance = new resvg.Resvg(svgString, opts);
57
67
  const pngData = resvgInstance.render();
58
- const pngBuffer = pngData.asPng();
68
+ const pngBuffer = pngData.asPng(); // Uint8Array
69
+
70
+ // Convert Uint8Array to proper ArrayBuffer for Blob
71
+ const arrayBuffer = pngBuffer.buffer.slice(
72
+ pngBuffer.byteOffset,
73
+ pngBuffer.byteOffset + pngBuffer.byteLength
74
+ ) as ArrayBuffer;
59
75
 
60
- // Convert to data URL
61
- const base64 = Buffer.from(pngBuffer).toString('base64');
62
- return `data:image/png;base64,${base64}`;
76
+ // Return blob URL (browser-compatible and more efficient)
77
+ const blob = new Blob([arrayBuffer], { type: 'image/png' });
78
+ return URL.createObjectURL(blob);
63
79
  };
package/src/tracing.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  /**
2
2
  * Image tracing and SVG sampling utilities
3
+ *
4
+ * Uses potrace for bitmap tracing. When running in CADit, potrace is exposed
5
+ * as an importable library by the code.worker, which handles the jimp dependency.
3
6
  */
4
7
 
5
8
  import { svgToPolygons } from '@cadit-app/svg-sampler';
@@ -65,6 +68,7 @@ export const sampleSvg = async (svgDataUrl: string, maxWidth?: number): Promise<
65
68
 
66
69
  /**
67
70
  * Traces a bitmap image and returns a centered CrossSection
71
+ * Uses potrace with jimp for image loading (works in web workers).
68
72
  */
69
73
  export const traceImage = async (
70
74
  imageDataUrl: string,
@@ -79,7 +83,7 @@ export const traceImage = async (
79
83
 
80
84
  // Promisify tracer.loadImage
81
85
  await new Promise<void>((resolve, reject) => {
82
- tracer.loadImage(imageDataUrl, (err: Error | null) => {
86
+ tracer.loadImage(imageDataUrl, (_potrace, err) => {
83
87
  if (err) {
84
88
  reject(err);
85
89
  } else {
package/src/types.d.ts DELETED
@@ -1,40 +0,0 @@
1
- declare module 'potrace' {
2
- interface PotraceOptions {
3
- turdSize?: number;
4
- turnPolicy?: string;
5
- alphaMax?: number;
6
- optCurve?: boolean;
7
- optTolerance?: number;
8
- threshold?: number;
9
- blackOnWhite?: boolean;
10
- color?: string;
11
- background?: string;
12
- }
13
-
14
- class Potrace {
15
- constructor(options?: PotraceOptions);
16
- loadImage(source: string | Buffer, callback: (err: Error | null) => void): void;
17
- getSVG(): string;
18
- getPathTag(): string;
19
- }
20
-
21
- function trace(source: string | Buffer, options?: PotraceOptions, callback?: (err: Error | null, svg: string) => void): void;
22
- function posterize(source: string | Buffer, options?: PotraceOptions, callback?: (err: Error | null, svg: string) => void): void;
23
-
24
- export { Potrace, trace, posterize, PotraceOptions };
25
- }
26
-
27
- declare module '@jscadui/3mf-export' {
28
- export interface ZipWriter {
29
- files: Record<string, Uint8Array>;
30
- add(path: string, data: string): void;
31
- }
32
-
33
- export interface Mesh3MF {
34
- id: string;
35
- vertices: number[];
36
- indices: number[];
37
- }
38
-
39
- export function create3mf(zipWriter: ZipWriter, meshes: Mesh3MF[]): void;
40
- }