@cadit-app/image-extrude 0.1.1 → 0.3.2

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.
package/src/tracing.ts DELETED
@@ -1,94 +0,0 @@
1
- /**
2
- * Image tracing and SVG sampling utilities
3
- */
4
-
5
- import { svgToPolygons } from '@cadit-app/svg-sampler';
6
- import { CrossSection } from '@cadit-app/manifold-3d/manifoldCAD';
7
- import { Potrace } from 'potrace';
8
- import { svgDataUrlToString } from './utils';
9
- import { centerCrossSection } from './crossSectionUtils';
10
-
11
- /**
12
- * Converts SVG content to polygons
13
- */
14
- export const svgContentToPolygons = async (
15
- svgContent: string,
16
- maxError: number
17
- ) => {
18
- // Sample the SVG into polygons
19
- const polygons = await svgToPolygons(svgContent, { maxError });
20
-
21
- // Flip the Y-axis for SVG paths (SVG uses Y-down, but 3D modeling uses Y-up)
22
- const flippedPolygons = polygons.map((polygon) => {
23
- return polygon.points.map(([x, y]) => [x, -y]) as [number, number][];
24
- });
25
-
26
- return flippedPolygons;
27
- };
28
-
29
- /**
30
- * Converts an SVG string to a CrossSection with optional scaling
31
- */
32
- export const svgStringToCrossSection = async (
33
- svgContent: string,
34
- maxWidth?: number,
35
- maxError: number = 0.01
36
- ): Promise<CrossSection> => {
37
- const polygons = await svgContentToPolygons(svgContent, maxError);
38
-
39
- const crossSection = new CrossSection(polygons, 'EvenOdd').simplify(maxError);
40
- if (!maxWidth) return crossSection;
41
-
42
- // Check the width of the resulting CrossSection
43
- const boundingBox = crossSection.bounds();
44
- const width = boundingBox.max[0] - boundingBox.min[0];
45
- const scaleFactor = maxWidth / width;
46
- const scaledError = maxError / scaleFactor;
47
-
48
- // Sample again with new error
49
- const newPolygons = await svgContentToPolygons(svgContent, scaledError);
50
- const newCrossSection = new CrossSection(newPolygons, 'EvenOdd').simplify(scaledError);
51
- return newCrossSection.scale([scaleFactor, scaleFactor]);
52
- };
53
-
54
- /**
55
- * Samples an SVG data URL and returns a centered CrossSection
56
- */
57
- export const sampleSvg = async (svgDataUrl: string, maxWidth?: number): Promise<CrossSection> => {
58
- const svgContent = svgDataUrlToString(svgDataUrl);
59
- if (!svgContent) {
60
- throw new Error('Failed to parse SVG data URL');
61
- }
62
- const crossSection = await svgStringToCrossSection(svgContent, maxWidth);
63
- return centerCrossSection(crossSection);
64
- };
65
-
66
- /**
67
- * Traces a bitmap image and returns a centered CrossSection
68
- */
69
- export const traceImage = async (
70
- imageDataUrl: string,
71
- options: {
72
- maxWidth?: number;
73
- despeckleSize?: number;
74
- }
75
- ): Promise<CrossSection> => {
76
- const tracer = new Potrace({
77
- turdSize: options.despeckleSize || 2,
78
- });
79
-
80
- // Promisify tracer.loadImage
81
- await new Promise<void>((resolve, reject) => {
82
- tracer.loadImage(imageDataUrl, (err: Error | null) => {
83
- if (err) {
84
- reject(err);
85
- } else {
86
- resolve();
87
- }
88
- });
89
- });
90
-
91
- const svgContent = tracer.getSVG();
92
- const crossSection = await svgStringToCrossSection(svgContent, options.maxWidth);
93
- return centerCrossSection(crossSection);
94
- };
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
- }
package/src/utils.ts DELETED
@@ -1,55 +0,0 @@
1
- /**
2
- * Utility functions for image processing
3
- */
4
-
5
- /**
6
- * Extracts the plain SVG XML string from a Data URL.
7
- * Handles both Base64 encoded and URL-encoded SVG data URLs.
8
- */
9
- export function svgDataUrlToString(dataUrl: string): string | null {
10
- if (!dataUrl || !dataUrl.startsWith('data:image/svg+xml')) {
11
- console.error("Invalid SVG Data URL format.");
12
- return null;
13
- }
14
-
15
- const commaIndex = dataUrl.indexOf(',');
16
- if (commaIndex === -1) {
17
- console.error("Invalid Data URL: Missing comma separator.");
18
- return null;
19
- }
20
-
21
- const header = dataUrl.substring(0, commaIndex);
22
- const encodedData = dataUrl.substring(commaIndex + 1);
23
-
24
- if (header.includes(';base64')) {
25
- try {
26
- // Decode Base64
27
- return atob(encodedData);
28
- } catch (e) {
29
- console.error("Error decoding Base64 SVG data:", e);
30
- return null;
31
- }
32
- } else {
33
- try {
34
- // Decode URL-encoded string
35
- return decodeURIComponent(encodedData);
36
- } catch (e) {
37
- console.error("Error decoding URL-encoded SVG data:", e);
38
- return null;
39
- }
40
- }
41
- }
42
-
43
- /**
44
- * Fetches an image URL and converts it to a data URL
45
- */
46
- export async function fetchImageAsDataUrl(imageUrl: string): Promise<string> {
47
- const response = await fetch(imageUrl);
48
- const blob = await response.blob();
49
- return new Promise<string>((resolve, reject) => {
50
- const reader = new FileReader();
51
- reader.onloadend = () => resolve(reader.result as string);
52
- reader.onerror = reject;
53
- reader.readAsDataURL(blob);
54
- });
55
- }