abstract-image 13.0.61 → 13.1.0
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/CHANGELOG.md +4 -0
- package/README.md +1 -6
- package/lib/__stories__/react-svg-export/example-1.stories.d.ts +2 -2
- package/lib/__stories__/react-svg-export/example-1.stories.d.ts.map +1 -1
- package/lib/__stories__/react-svg-export/example-1.stories.js.map +1 -1
- package/lib/__stories__/svg-export/example-1.stories.d.ts +2 -2
- package/lib/__stories__/svg-export/example-1.stories.d.ts.map +1 -1
- package/lib/__stories__/svg-export/example-1.stories.js.map +1 -1
- package/lib/abstract-image-jsx/index.d.ts +2 -3
- package/lib/abstract-image-jsx/index.d.ts.map +1 -1
- package/lib/abstract-image-jsx/index.js +11 -8
- package/lib/abstract-image-jsx/index.js.map +1 -1
- package/lib/dynamic-image/components.d.ts +1 -1
- package/lib/dynamic-image/components.d.ts.map +1 -1
- package/lib/dynamic-image/components.js +3 -4
- package/lib/dynamic-image/components.js.map +1 -1
- package/lib/dynamic-image/dynamic-image.d.ts.map +1 -1
- package/lib/dynamic-image/dynamic-image.js +2 -4
- package/lib/dynamic-image/dynamic-image.js.map +1 -1
- package/lib/dynamic-image/utils.d.ts +2 -1
- package/lib/dynamic-image/utils.d.ts.map +1 -1
- package/lib/dynamic-image/utils.js.map +1 -1
- package/lib/exporters/dxf2d-export-image.d.ts +3 -2
- package/lib/exporters/dxf2d-export-image.d.ts.map +1 -1
- package/lib/exporters/dxf2d-export-image.js +13 -23
- package/lib/exporters/dxf2d-export-image.js.map +1 -1
- package/lib/exporters/eps-export-image.d.ts +1 -2
- package/lib/exporters/eps-export-image.d.ts.map +1 -1
- package/lib/exporters/eps-export-image.js +5 -16
- package/lib/exporters/eps-export-image.js.map +1 -1
- package/lib/exporters/react-svg-export-image.d.ts.map +1 -1
- package/lib/exporters/react-svg-export-image.js +10 -10
- package/lib/exporters/react-svg-export-image.js.map +1 -1
- package/lib/exporters/svg-export-image.d.ts.map +1 -1
- package/lib/exporters/svg-export-image.js +7 -5
- package/lib/exporters/svg-export-image.js.map +1 -1
- package/lib/model/abstract-image.d.ts +1 -1
- package/lib/model/abstract-image.d.ts.map +1 -1
- package/lib/model/abstract-image.js.map +1 -1
- package/lib/model/color.d.ts.map +1 -1
- package/lib/model/color.js +3 -5
- package/lib/model/color.js.map +1 -1
- package/lib/model/component.d.ts +3 -5
- package/lib/model/component.d.ts.map +1 -1
- package/lib/model/component.js +1 -1
- package/lib/model/component.js.map +1 -1
- package/package.json +17 -17
- package/src/__stories__/react-svg-export/example-1.stories.tsx +4 -14
- package/src/__stories__/svg-export/example-1.stories.tsx +4 -15
- package/src/abstract-image-jsx/index.ts +27 -32
- package/src/dynamic-image/components.ts +6 -19
- package/src/dynamic-image/dynamic-image.ts +6 -23
- package/src/dynamic-image/utils.ts +7 -5
- package/src/exporters/dxf2d-export-image.ts +22 -65
- package/src/exporters/eps-export-image.ts +8 -18
- package/src/exporters/react-svg-export-image.tsx +24 -49
- package/src/exporters/svg-export-image.ts +10 -15
- package/src/model/abstract-image.ts +2 -7
- package/src/model/color.ts +4 -13
- package/src/model/component.ts +5 -13
|
@@ -8,7 +8,7 @@ import type { Size } from "../model/size.js";
|
|
|
8
8
|
|
|
9
9
|
export const DXF_STANDARD = "AC1015";
|
|
10
10
|
export const DXF_DATA_URL = "data:application/dxf,";
|
|
11
|
-
export const DXF_ENTITIES: string
|
|
11
|
+
export const DXF_ENTITIES: Array<string> = [
|
|
12
12
|
"3DFACE",
|
|
13
13
|
"3DSOLID",
|
|
14
14
|
"ACAD_PROXY_ENTITY",
|
|
@@ -87,11 +87,13 @@ export function dxf2dExportImageEncoded(root: AbstractImage, options?: Optional<
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
function encodeWindows1252(str: string): Uint8Array {
|
|
90
|
+
// oxlint-disable-next-line no-bitwise
|
|
90
91
|
return Uint8Array.from(str, (c) => c.charCodeAt(0) & 0xff);
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
/**
|
|
94
|
-
* @deprecated Use `dxf2dExportImageEncoded()` instead. Otherwise the text might not be correctly encoded in some
|
|
95
|
+
* @deprecated Use `dxf2dExportImageEncoded()` instead. Otherwise the text might not be correctly encoded in some
|
|
96
|
+
* languages.
|
|
95
97
|
*/
|
|
96
98
|
export function dxf2dExportImage(root: AbstractImage, options?: Optional<DxfOptions>): string {
|
|
97
99
|
const externalCache = new Map<string, DxfInsert>();
|
|
@@ -115,15 +117,7 @@ export function dxf2dExportImage(root: AbstractImage, options?: Optional<DxfOpti
|
|
|
115
117
|
blocks += createSpaceBlock("*Model_Space", modelSpaceHandle, newHandle);
|
|
116
118
|
blocks += createSpaceBlock("*Paper_Space", paperSpaceHandle, newHandle);
|
|
117
119
|
for (const component of root.components) {
|
|
118
|
-
const [newEntities, newBlocks, newBlockRecords] = componentDxf(
|
|
119
|
-
component,
|
|
120
|
-
layer,
|
|
121
|
-
root.size,
|
|
122
|
-
modelSpaceHandle,
|
|
123
|
-
externalCache,
|
|
124
|
-
opts,
|
|
125
|
-
newHandle
|
|
126
|
-
);
|
|
120
|
+
const [newEntities, newBlocks, newBlockRecords] = componentDxf(component, layer, root.size, modelSpaceHandle, externalCache, opts, newHandle);
|
|
127
121
|
entities += newEntities;
|
|
128
122
|
blocks += newBlocks;
|
|
129
123
|
blockRecords.push(...newBlockRecords);
|
|
@@ -192,15 +186,7 @@ function componentDxf(
|
|
|
192
186
|
|
|
193
187
|
if (c.type === "group") {
|
|
194
188
|
for (const child of c.children) {
|
|
195
|
-
const [newEntities, newBlocks, newBlockRecords] = componentDxf(
|
|
196
|
-
child,
|
|
197
|
-
layer,
|
|
198
|
-
size,
|
|
199
|
-
modelSpaceHandle,
|
|
200
|
-
externalCache,
|
|
201
|
-
options,
|
|
202
|
-
newHandle
|
|
203
|
-
);
|
|
189
|
+
const [newEntities, newBlocks, newBlockRecords] = componentDxf(child, layer, size, modelSpaceHandle, externalCache, options, newHandle);
|
|
204
190
|
entities += newEntities;
|
|
205
191
|
blocks += newBlocks;
|
|
206
192
|
blockRecords.push(...newBlockRecords);
|
|
@@ -214,11 +200,7 @@ function componentDxf(
|
|
|
214
200
|
}
|
|
215
201
|
const imageData = options.imageDataByUrl[c.data.url];
|
|
216
202
|
const url =
|
|
217
|
-
imageData === undefined
|
|
218
|
-
? c.data.url
|
|
219
|
-
: typeof imageData === "string"
|
|
220
|
-
? imageData
|
|
221
|
-
: DXF_DATA_URL + dxf2dExportImage(imageData, options);
|
|
203
|
+
imageData === undefined ? c.data.url : typeof imageData === "string" ? imageData : DXF_DATA_URL + dxf2dExportImage(imageData, options);
|
|
222
204
|
if (url === undefined || typeof url !== "string" || !url.startsWith(DXF_DATA_URL)) {
|
|
223
205
|
return [entities, blocks, blockRecords];
|
|
224
206
|
}
|
|
@@ -253,9 +235,7 @@ function componentDxf(
|
|
|
253
235
|
const externalBlockRecords = extractBlockRecords(dxfString);
|
|
254
236
|
|
|
255
237
|
const newBlockRecordHandle = newHandle();
|
|
256
|
-
const newName = `EMBEDED_IMAGE_${randomID()}_${scale.x.toPrecision(4).replace(".", "_")}X${scale.y
|
|
257
|
-
.toPrecision(4)
|
|
258
|
-
.replace(".", "_")}`;
|
|
238
|
+
const newName = `EMBEDED_IMAGE_${randomID()}_${scale.x.toPrecision(4).replace(".", "_")}X${scale.y.toPrecision(4).replace(".", "_")}`;
|
|
259
239
|
|
|
260
240
|
const initOldHandlesMap = new Map<string, string>();
|
|
261
241
|
|
|
@@ -373,8 +353,8 @@ function componentDxf(
|
|
|
373
353
|
entities += "70\n0\n";
|
|
374
354
|
|
|
375
355
|
if (options.useStrokeThickness) {
|
|
376
|
-
entities += "40\n" +
|
|
377
|
-
entities += "41\n" +
|
|
356
|
+
entities += "40\n" + c.strokeThickness + "\n";
|
|
357
|
+
entities += "41\n" + c.strokeThickness + "\n";
|
|
378
358
|
}
|
|
379
359
|
|
|
380
360
|
const points: ReadonlyArray<Point> = [
|
|
@@ -422,8 +402,8 @@ function componentDxf(
|
|
|
422
402
|
entities += "70\n0\n";
|
|
423
403
|
|
|
424
404
|
if (options.useStrokeThickness) {
|
|
425
|
-
entities += "40\n" +
|
|
426
|
-
entities += "41\n" +
|
|
405
|
+
entities += "40\n" + c.strokeThickness + "\n";
|
|
406
|
+
entities += "41\n" + c.strokeThickness + "\n";
|
|
427
407
|
}
|
|
428
408
|
|
|
429
409
|
for (const point of c.points) {
|
|
@@ -448,8 +428,7 @@ function componentDxf(
|
|
|
448
428
|
}
|
|
449
429
|
|
|
450
430
|
if (c.type === "text") {
|
|
451
|
-
const horizontalAlignment =
|
|
452
|
-
c.horizontalGrowthDirection === "left" ? 2 : c.horizontalGrowthDirection === "uniform" ? 1 : 0;
|
|
431
|
+
const horizontalAlignment = c.horizontalGrowthDirection === "left" ? 2 : c.horizontalGrowthDirection === "uniform" ? 1 : 0;
|
|
453
432
|
const verticalAlignment = c.verticalGrowthDirection === "up" ? 0 : c.verticalGrowthDirection === "uniform" ? 2 : 3;
|
|
454
433
|
const fontSize = c.fontSize - 2;
|
|
455
434
|
|
|
@@ -618,9 +597,7 @@ function extractEntities(dxf: string): string | undefined {
|
|
|
618
597
|
}
|
|
619
598
|
|
|
620
599
|
function extractBlockRecords(dxf: string): ReadonlyArray<BlockRecord> {
|
|
621
|
-
return [
|
|
622
|
-
...dxf.matchAll(/^\s*0\s*\n\s*BLOCK_RECORD[\s\S]*?\n\s*5\s*\n\s*([0-9A-Fa-f]+)[\s\S]*?\n\s*2\s*\n\s*([^\r\n]+)/gm),
|
|
623
|
-
].map((match) => ({
|
|
600
|
+
return [...dxf.matchAll(/^\s*0\s*\n\s*BLOCK_RECORD[\s\S]*?\n\s*5\s*\n\s*([0-9A-Fa-f]+)[\s\S]*?\n\s*2\s*\n\s*([^\r\n]+)/gm)].map((match) => ({
|
|
624
601
|
name: match[2],
|
|
625
602
|
id: match[1],
|
|
626
603
|
}));
|
|
@@ -676,7 +653,7 @@ function remapHandleIds(
|
|
|
676
653
|
|
|
677
654
|
function collectAndRemap(src: string): string {
|
|
678
655
|
const lines = src.split("\n");
|
|
679
|
-
const out: string
|
|
656
|
+
const out: Array<string> = [];
|
|
680
657
|
let i = 0;
|
|
681
658
|
let inEntityHeader = false;
|
|
682
659
|
while (i < lines.length) {
|
|
@@ -727,7 +704,7 @@ function scaleDxf(dxfString: string | undefined, sx: number, sy: number, _height
|
|
|
727
704
|
const yCoordinateCodes = new Set([20, 21, 22, 23, 24, 25, 26, 27, 28]);
|
|
728
705
|
|
|
729
706
|
const lines = dxfString.split(/\r?\n/);
|
|
730
|
-
const scaledLines: string
|
|
707
|
+
const scaledLines: Array<string> = [];
|
|
731
708
|
|
|
732
709
|
let currentAcDbEntity = "";
|
|
733
710
|
for (let i = 0; i < lines.length; i += 2) {
|
|
@@ -739,9 +716,6 @@ function scaleDxf(dxfString: string | undefined, sx: number, sy: number, _height
|
|
|
739
716
|
}
|
|
740
717
|
|
|
741
718
|
scaledLines.push(codeLine);
|
|
742
|
-
if (valueLine === undefined) {
|
|
743
|
-
continue;
|
|
744
|
-
}
|
|
745
719
|
|
|
746
720
|
const code = parseInt(codeLine.trim(), 10);
|
|
747
721
|
let value = valueLine;
|
|
@@ -816,13 +790,7 @@ function getScale(extents: DxfExtents, c: BinaryImage): { readonly x: number; re
|
|
|
816
790
|
};
|
|
817
791
|
}
|
|
818
792
|
|
|
819
|
-
function createExternalInsert(
|
|
820
|
-
ins: DxfInsert,
|
|
821
|
-
c: BinaryImage,
|
|
822
|
-
size: Size,
|
|
823
|
-
modelSpaceHandle: string,
|
|
824
|
-
newHandle: () => string
|
|
825
|
-
): string {
|
|
793
|
+
function createExternalInsert(ins: DxfInsert, c: BinaryImage, size: Size, modelSpaceHandle: string, newHandle: () => string): string {
|
|
826
794
|
const srcH = ins.extents.maxY - ins.extents.minY;
|
|
827
795
|
const srcW = ins.extents.maxX - ins.extents.minX;
|
|
828
796
|
const destW = c.bottomRight.x - c.topLeft.x;
|
|
@@ -1006,12 +974,7 @@ function createStyleTable(newHandle: () => string): string {
|
|
|
1006
974
|
return table;
|
|
1007
975
|
}
|
|
1008
976
|
|
|
1009
|
-
function createDimStyleTable(
|
|
1010
|
-
newHandle: () => string,
|
|
1011
|
-
dimArrowSize: number = 1.0,
|
|
1012
|
-
dimGlobalScale: number = 1.0,
|
|
1013
|
-
dimFontSize: number = 1.0
|
|
1014
|
-
): string {
|
|
977
|
+
function createDimStyleTable(newHandle: () => string, dimArrowSize: number = 1.0, dimGlobalScale: number = 1.0, dimFontSize: number = 1.0): string {
|
|
1015
978
|
const rootId = newHandle();
|
|
1016
979
|
let table = "";
|
|
1017
980
|
table += "0\nTABLE\n";
|
|
@@ -1129,12 +1092,7 @@ function createBlockRecordsTable(
|
|
|
1129
1092
|
return table;
|
|
1130
1093
|
}
|
|
1131
1094
|
|
|
1132
|
-
function createObjects(
|
|
1133
|
-
modelSpaceHandle: string,
|
|
1134
|
-
paperSpaceHandle: string,
|
|
1135
|
-
root: AbstractImage,
|
|
1136
|
-
newHandle: () => string
|
|
1137
|
-
): string {
|
|
1095
|
+
function createObjects(modelSpaceHandle: string, paperSpaceHandle: string, root: AbstractImage, newHandle: () => string): string {
|
|
1138
1096
|
let objects = "";
|
|
1139
1097
|
const rootDictId = newHandle();
|
|
1140
1098
|
const groupDictId = newHandle();
|
|
@@ -1161,8 +1119,7 @@ function createObjects(
|
|
|
1161
1119
|
objects += "0\nLAYOUT\n5\n" + layoutModelId + "\n102\n{ACAD_REACTORS\n330\n" + layoutDictId + "\n102\n}\n";
|
|
1162
1120
|
objects += "330\n" + layoutDictId + "\n100\nAcDbPlotSettings\n1\n\n2\nnone_device\n4\n\n6\n\n";
|
|
1163
1121
|
objects += "40\n0.0\n41\n0.0\n42\n0.0\n43\n0.0\n44\n0.0\n45\n0.0\n46\n0.0\n47\n0.0\n48\n0.0\n49\n0.0\n";
|
|
1164
|
-
objects +=
|
|
1165
|
-
"140\n0.0\n141\n0.0\n142\n1.0\n143\n1.0\n70\n1712\n72\n0\n73\n0\n74\n0\n7\n\n75\n0\n147\n1.0\n148\n0.0\n149\n0.0\n";
|
|
1122
|
+
objects += "140\n0.0\n141\n0.0\n142\n1.0\n143\n1.0\n70\n1712\n72\n0\n73\n0\n74\n0\n7\n\n75\n0\n147\n1.0\n148\n0.0\n149\n0.0\n";
|
|
1166
1123
|
objects += "100\nAcDbLayout\n1\nModel\n70\n1\n71\n0\n";
|
|
1167
1124
|
objects += "10\n0.0\n20\n0.0\n11\n" + root.size.width + "\n21\n" + root.size.height + "\n";
|
|
1168
1125
|
objects += "12\n0.0\n22\n0.0\n32\n0.0\n14\n0.0\n24\n0.0\n34\n0.0\n";
|
|
@@ -1174,8 +1131,7 @@ function createObjects(
|
|
|
1174
1131
|
objects += "0\nLAYOUT\n5\n" + layoutPaperId + "\n102\n{ACAD_REACTORS\n330\n" + layoutDictId + "\n102\n}\n";
|
|
1175
1132
|
objects += "330\n" + layoutDictId + "\n100\nAcDbPlotSettings\n1\n\n2\nnone_device\n4\n\n6\n\n";
|
|
1176
1133
|
objects += "40\n0.0\n41\n0.0\n42\n0.0\n43\n0.0\n44\n0.0\n45\n0.0\n46\n0.0\n47\n0.0\n48\n0.0\n49\n0.0\n";
|
|
1177
|
-
objects +=
|
|
1178
|
-
"140\n0.0\n141\n0.0\n142\n1.0\n143\n1.0\n70\n688\n72\n0\n73\n0\n74\n5\n7\n\n75\n16\n147\n1.0\n148\n0.0\n149\n0.0\n";
|
|
1134
|
+
objects += "140\n0.0\n141\n0.0\n142\n1.0\n143\n1.0\n70\n688\n72\n0\n73\n0\n74\n5\n7\n\n75\n16\n147\n1.0\n148\n0.0\n149\n0.0\n";
|
|
1179
1135
|
objects += "100\nAcDbLayout\n1\nLayout1\n70\n1\n71\n1\n";
|
|
1180
1136
|
objects += "10\n0.0\n20\n0.0\n11\n" + root.size.width + "\n21\n" + root.size.height + "\n";
|
|
1181
1137
|
objects += "12\n0.0\n22\n0.0\n32\n0.0\n14\n1.0E+20\n24\n1.0E+20\n34\n1.0E+20\n";
|
|
@@ -1339,6 +1295,7 @@ function isBlack(color: Color): boolean {
|
|
|
1339
1295
|
}
|
|
1340
1296
|
|
|
1341
1297
|
function colorToInteger(color: Color): number {
|
|
1298
|
+
// oxlint-disable-next-line no-bitwise
|
|
1342
1299
|
const colorAsInt = (color.r << 16) + (color.g << 8) + color.b;
|
|
1343
1300
|
if (Number.isNaN(colorAsInt)) {
|
|
1344
1301
|
return 0;
|
|
@@ -4,8 +4,7 @@ import type { Component, Text } from "../model/component.js";
|
|
|
4
4
|
|
|
5
5
|
type CharacterEncoding = "standard-encoding" | "iso-latin-1-encoding";
|
|
6
6
|
|
|
7
|
-
export function epsExportImage(root: AbstractImage): string;
|
|
8
|
-
export function epsExportImage(root: AbstractImage, characterEncoding: "standard-encoding"): string;
|
|
7
|
+
export function epsExportImage(root: AbstractImage, characterEncoding?: "standard-encoding"): string;
|
|
9
8
|
export function epsExportImage(root: AbstractImage, characterEncoding: "iso-latin-1-encoding"): Uint8Array;
|
|
10
9
|
export function epsExportImage(root: AbstractImage, characterEncoding?: CharacterEncoding): string | Uint8Array {
|
|
11
10
|
if (characterEncoding === "iso-latin-1-encoding") {
|
|
@@ -16,10 +15,9 @@ export function epsExportImage(root: AbstractImage, characterEncoding?: Characte
|
|
|
16
15
|
].join("\n");
|
|
17
16
|
return encodeLatin1Encoding(eps);
|
|
18
17
|
} else {
|
|
19
|
-
return [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
].join("\n");
|
|
18
|
+
return [...createEpsHeaderLines(root), ...root.components.flatMap((c) => epsExportComponent(c, root.size.height, "standard-encoding"))].join(
|
|
19
|
+
"\n"
|
|
20
|
+
);
|
|
23
21
|
}
|
|
24
22
|
}
|
|
25
23
|
|
|
@@ -53,12 +51,7 @@ function epsExportComponent(c: Component, height: number, characterEncoding: Cha
|
|
|
53
51
|
const ry = 0.5 * (c.bottomRight.y - c.topLeft.y);
|
|
54
52
|
return [
|
|
55
53
|
...getColored(c.fillColor, [`${cx} ${cy} ${rx} ${ry} 0 360 ellipse`, "closepath", "fill"]),
|
|
56
|
-
...getColored(c.strokeColor, [
|
|
57
|
-
`${cx} ${cy} ${rx} ${ry} 0 360 ellipse`,
|
|
58
|
-
"closepath",
|
|
59
|
-
`${c.strokeThickness} setlinewidth`,
|
|
60
|
-
"stroke",
|
|
61
|
-
]),
|
|
54
|
+
...getColored(c.strokeColor, [`${cx} ${cy} ${rx} ${ry} 0 360 ellipse`, "closepath", `${c.strokeThickness} setlinewidth`, "stroke"]),
|
|
62
55
|
];
|
|
63
56
|
}
|
|
64
57
|
case "group": {
|
|
@@ -102,10 +95,7 @@ function epsExportComponent(c: Component, height: number, characterEncoding: Cha
|
|
|
102
95
|
const h = c.bottomRight.y - c.topLeft.y;
|
|
103
96
|
return [
|
|
104
97
|
...getColored(c.fillColor, [`${c.topLeft.x} ${height - c.bottomRight.y} ${w} ${h} rectfill`]),
|
|
105
|
-
...getColored(c.strokeColor, [
|
|
106
|
-
`${c.strokeThickness} setlinewidth`,
|
|
107
|
-
`${c.topLeft.x} ${height - c.bottomRight.y} ${w} ${h} rectstroke`,
|
|
108
|
-
]),
|
|
98
|
+
...getColored(c.strokeColor, [`${c.strokeThickness} setlinewidth`, `${c.topLeft.x} ${height - c.bottomRight.y} ${w} ${h} rectstroke`]),
|
|
109
99
|
];
|
|
110
100
|
}
|
|
111
101
|
case "text": {
|
|
@@ -165,14 +155,14 @@ function createFontName(characterEncoding: CharacterEncoding, fontFamily: string
|
|
|
165
155
|
function encodeLatin1Encoding(text: string): Uint8Array {
|
|
166
156
|
// ISOLatin1Encoding is close to iso-8859-1 encoding (https://en.wikipedia.org/wiki/PostScript_Latin_1_Encoding)
|
|
167
157
|
// Code points 0-256 returned by codePointAt() maps to iso-8859-1
|
|
168
|
-
const unknownCharacter = "?".codePointAt(0)
|
|
158
|
+
const unknownCharacter = "?".codePointAt(0) ?? 32;
|
|
169
159
|
const output: Array<number> = [];
|
|
170
160
|
// Array.from() to handle characters consisting of multiple code points
|
|
171
161
|
for (const c of Array.from(text)) {
|
|
172
162
|
if (c.length > 1) {
|
|
173
163
|
output.push(unknownCharacter);
|
|
174
164
|
} else {
|
|
175
|
-
const cp = c.codePointAt(0)
|
|
165
|
+
const cp = c.codePointAt(0) ?? 32;
|
|
176
166
|
if (cp > 255) {
|
|
177
167
|
output.push(unknownCharacter);
|
|
178
168
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { fromByteArray } from "base64-js";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import type { AbstractImage } from "../model/abstract-image.js";
|
|
4
|
+
import type { Color } from "../model/color.js";
|
|
5
|
+
import type { AbstractFontWeight, Component, GrowthDirection } from "../model/component.js";
|
|
4
6
|
import type { Point } from "../model/point.js";
|
|
5
7
|
import { createPoint } from "../model/point.js";
|
|
6
|
-
import type { AbstractFontWeight, Component, GrowthDirection } from "../model/component.js";
|
|
7
|
-
import type { Color } from "../model/color.js";
|
|
8
8
|
import type { Optional } from "../model/shared.js";
|
|
9
9
|
|
|
10
10
|
export interface ReactSvgCallbacks {
|
|
@@ -32,7 +32,7 @@ export function ReactSvg({
|
|
|
32
32
|
const opts: ReactSvgOptions = {
|
|
33
33
|
imageDataByUrl: options?.imageDataByUrl ?? {},
|
|
34
34
|
};
|
|
35
|
-
const cb = callbacks
|
|
35
|
+
const cb = callbacks ?? {};
|
|
36
36
|
const id = "ai_root";
|
|
37
37
|
return (
|
|
38
38
|
<svg
|
|
@@ -85,13 +85,7 @@ function getIdAttr(target: Element | undefined, rootId: string): string | undefi
|
|
|
85
85
|
return parts[1];
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
function JsxComponent({
|
|
89
|
-
component,
|
|
90
|
-
options,
|
|
91
|
-
}: {
|
|
92
|
-
readonly component: Component;
|
|
93
|
-
readonly options: ReactSvgOptions;
|
|
94
|
-
}): React.JSX.Element {
|
|
88
|
+
function JsxComponent({ component, options }: { readonly component: Component; readonly options: ReactSvgOptions }): React.JSX.Element {
|
|
95
89
|
switch (component.type) {
|
|
96
90
|
case "group":
|
|
97
91
|
return (
|
|
@@ -109,8 +103,8 @@ function JsxComponent({
|
|
|
109
103
|
const id = makeIdAttr(component.id);
|
|
110
104
|
if (component.data.type === "url") {
|
|
111
105
|
const data = options.imageDataByUrl[component.data.url];
|
|
112
|
-
if (typeof data === "string"
|
|
113
|
-
return <image x={x} y={y} width={width} height={height} id={id} href={data
|
|
106
|
+
if (typeof data === "string") {
|
|
107
|
+
return <image x={x} y={y} width={width} height={height} id={id} href={data} />;
|
|
114
108
|
}
|
|
115
109
|
const scale = Math.min(width / (data.size.width || 1), height / (data.size.height || 1));
|
|
116
110
|
return (
|
|
@@ -145,10 +139,8 @@ function JsxComponent({
|
|
|
145
139
|
);
|
|
146
140
|
}
|
|
147
141
|
case "line": {
|
|
148
|
-
const strokeDasharray =
|
|
149
|
-
|
|
150
|
-
const strokeDashoffset =
|
|
151
|
-
component.strokeDashStyle.dashes.length > 0 ? component.strokeDashStyle.offset : undefined;
|
|
142
|
+
const strokeDasharray = component.strokeDashStyle.dashes.length > 0 ? component.strokeDashStyle.dashes.join(" ") : undefined;
|
|
143
|
+
const strokeDashoffset = component.strokeDashStyle.dashes.length > 0 ? component.strokeDashStyle.offset : undefined;
|
|
152
144
|
return (
|
|
153
145
|
<line
|
|
154
146
|
id={makeIdAttr(component.id)}
|
|
@@ -171,7 +163,7 @@ function JsxComponent({
|
|
|
171
163
|
}
|
|
172
164
|
const alignmentBaseline = getBaselineAdjustment(component.verticalGrowthDirection);
|
|
173
165
|
const transform = `rotate(${component.clockwiseRotationDegrees} ${component.position.x} ${component.position.y})`;
|
|
174
|
-
const lines
|
|
166
|
+
const lines = component.text.split("\n");
|
|
175
167
|
const tSpans = lines.map((t, i) => (
|
|
176
168
|
<TSpan
|
|
177
169
|
key={t}
|
|
@@ -192,7 +184,7 @@ function JsxComponent({
|
|
|
192
184
|
};
|
|
193
185
|
return (
|
|
194
186
|
<>
|
|
195
|
-
{component.strokeThickness > 0 &&
|
|
187
|
+
{component.strokeThickness > 0 && (
|
|
196
188
|
<text
|
|
197
189
|
style={{
|
|
198
190
|
...baseStyle,
|
|
@@ -205,11 +197,7 @@ function JsxComponent({
|
|
|
205
197
|
{tSpans}
|
|
206
198
|
</text>
|
|
207
199
|
)}
|
|
208
|
-
<text
|
|
209
|
-
style={{ ...baseStyle, fill: colorToRgb(component.textColor) }}
|
|
210
|
-
transform={transform}
|
|
211
|
-
id={makeIdAttr(component.id)}
|
|
212
|
-
>
|
|
200
|
+
<text style={{ ...baseStyle, fill: colorToRgb(component.textColor) }} transform={transform} id={makeIdAttr(component.id)}>
|
|
213
201
|
{tSpans}
|
|
214
202
|
</text>
|
|
215
203
|
</>
|
|
@@ -220,10 +208,8 @@ function JsxComponent({
|
|
|
220
208
|
const ry = Math.abs(component.bottomRight.y - component.topLeft.y) * 0.5;
|
|
221
209
|
const cx = (component.bottomRight.x + component.topLeft.x) * 0.5;
|
|
222
210
|
const cy = (component.bottomRight.y + component.topLeft.y) * 0.5;
|
|
223
|
-
const strokeDasharray =
|
|
224
|
-
|
|
225
|
-
const strokeDashoffset =
|
|
226
|
-
component.strokeDashStyle.dashes.length > 0 ? component.strokeDashStyle.offset : undefined;
|
|
211
|
+
const strokeDasharray = component.strokeDashStyle.dashes.length > 0 ? component.strokeDashStyle.dashes.join(" ") : undefined;
|
|
212
|
+
const strokeDashoffset = component.strokeDashStyle.dashes.length > 0 ? component.strokeDashStyle.offset : undefined;
|
|
227
213
|
return (
|
|
228
214
|
<ellipse
|
|
229
215
|
id={makeIdAttr(component.id)}
|
|
@@ -242,11 +228,9 @@ function JsxComponent({
|
|
|
242
228
|
);
|
|
243
229
|
}
|
|
244
230
|
case "polyline": {
|
|
245
|
-
|
|
246
|
-
const strokeDasharray =
|
|
247
|
-
|
|
248
|
-
const strokeDashoffset =
|
|
249
|
-
component.strokeDashStyle.dashes.length > 0 ? component.strokeDashStyle.offset : undefined;
|
|
231
|
+
const linePoints = component.points.map((p) => p.x.toString() + "," + p.y.toString()).join(" ");
|
|
232
|
+
const strokeDasharray = component.strokeDashStyle.dashes.length > 0 ? component.strokeDashStyle.dashes.join(" ") : undefined;
|
|
233
|
+
const strokeDashoffset = component.strokeDashStyle.dashes.length > 0 ? component.strokeDashStyle.offset : undefined;
|
|
250
234
|
return (
|
|
251
235
|
<polyline
|
|
252
236
|
id={makeIdAttr(component.id)}
|
|
@@ -263,11 +247,9 @@ function JsxComponent({
|
|
|
263
247
|
);
|
|
264
248
|
}
|
|
265
249
|
case "polygon": {
|
|
266
|
-
|
|
267
|
-
const strokeDasharray =
|
|
268
|
-
|
|
269
|
-
const strokeDashoffset =
|
|
270
|
-
component.strokeDashStyle.dashes.length > 0 ? component.strokeDashStyle.offset : undefined;
|
|
250
|
+
const points = component.points.map((p) => p.x.toString() + "," + p.y.toString()).join(" ");
|
|
251
|
+
const strokeDasharray = component.strokeDashStyle.dashes.length > 0 ? component.strokeDashStyle.dashes.join(" ") : undefined;
|
|
252
|
+
const strokeDashoffset = component.strokeDashStyle.dashes.length > 0 ? component.strokeDashStyle.offset : undefined;
|
|
271
253
|
return (
|
|
272
254
|
<polygon
|
|
273
255
|
id={makeIdAttr(component.id)}
|
|
@@ -284,10 +266,8 @@ function JsxComponent({
|
|
|
284
266
|
);
|
|
285
267
|
}
|
|
286
268
|
case "rectangle": {
|
|
287
|
-
const strokeDasharray =
|
|
288
|
-
|
|
289
|
-
const strokeDashoffset =
|
|
290
|
-
component.strokeDashStyle.dashes.length > 0 ? component.strokeDashStyle.offset : undefined;
|
|
269
|
+
const strokeDasharray = component.strokeDashStyle.dashes.length > 0 ? component.strokeDashStyle.dashes.join(" ") : undefined;
|
|
270
|
+
const strokeDashoffset = component.strokeDashStyle.dashes.length > 0 ? component.strokeDashStyle.offset : undefined;
|
|
291
271
|
return (
|
|
292
272
|
<rect
|
|
293
273
|
id={makeIdAttr(component.id)}
|
|
@@ -343,12 +323,7 @@ function TSpan({
|
|
|
343
323
|
const splitText = split[i];
|
|
344
324
|
if (inside) {
|
|
345
325
|
tags.push(
|
|
346
|
-
<tspan
|
|
347
|
-
key={i}
|
|
348
|
-
baselineShift="sub"
|
|
349
|
-
alignmentBaseline={alignmentBaseline}
|
|
350
|
-
style={{ fontSize: (fontSize * 0.8).toString() + "px" }}
|
|
351
|
-
>
|
|
326
|
+
<tspan key={i} baselineShift="sub" alignmentBaseline={alignmentBaseline} style={{ fontSize: (fontSize * 0.8).toString() + "px" }}>
|
|
352
327
|
{splitText}
|
|
353
328
|
</tspan>
|
|
354
329
|
);
|
|
@@ -378,7 +353,7 @@ function getBaselineAdjustment(d: GrowthDirection): "baseline" | "central" | "ha
|
|
|
378
353
|
if (d === "down") {
|
|
379
354
|
return "hanging";
|
|
380
355
|
}
|
|
381
|
-
throw "Unknown text alignment " + d;
|
|
356
|
+
throw new Error("Unknown text alignment " + d);
|
|
382
357
|
}
|
|
383
358
|
|
|
384
359
|
function getTextAnchor(d: GrowthDirection): "end" | "middle" | "start" {
|
|
@@ -391,7 +366,7 @@ function getTextAnchor(d: GrowthDirection): "end" | "middle" | "start" {
|
|
|
391
366
|
if (d === "right") {
|
|
392
367
|
return "start";
|
|
393
368
|
}
|
|
394
|
-
throw "Unknown text anchor " + d;
|
|
369
|
+
throw new Error("Unknown text anchor " + d);
|
|
395
370
|
}
|
|
396
371
|
|
|
397
372
|
function colorToRgb(color: Color): string {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fromByteArray } from "base64-js";
|
|
2
|
-
import type { Component, GrowthDirection } from "../model/component.js";
|
|
3
2
|
import type { AbstractImage } from "../model/abstract-image.js";
|
|
4
3
|
import type { Color } from "../model/color.js";
|
|
4
|
+
import type { Component, GrowthDirection } from "../model/component.js";
|
|
5
5
|
import type { Optional } from "../model/shared.js";
|
|
6
6
|
|
|
7
7
|
export const SVG_DATA_URL = "data:image/svg+xml,";
|
|
@@ -15,8 +15,8 @@ export type SvgOptions = {
|
|
|
15
15
|
export function createSVG(image: AbstractImage, options?: Optional<SvgOptions>): string {
|
|
16
16
|
const opts: SvgOptions = {
|
|
17
17
|
imageDataByUrl: options?.imageDataByUrl ?? {},
|
|
18
|
-
pixelWidth: options?.pixelWidth
|
|
19
|
-
pixelHeight: options?.pixelHeight
|
|
18
|
+
pixelWidth: options?.pixelWidth ?? image.size.width,
|
|
19
|
+
pixelHeight: options?.pixelHeight ?? image.size.height,
|
|
20
20
|
};
|
|
21
21
|
const subOptions: SvgOptions = { ...opts, pixelWidth: 0, pixelHeight: 0 };
|
|
22
22
|
const imageElements = image.components.map((c: Component) => abstractComponentToSVG(c, subOptions));
|
|
@@ -75,15 +75,10 @@ function abstractComponentToSVG(component: Component, options: SvgOptions): stri
|
|
|
75
75
|
return "";
|
|
76
76
|
}
|
|
77
77
|
case "subimage": {
|
|
78
|
-
const scale = Math.min(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
);
|
|
82
|
-
return createElement(
|
|
83
|
-
"g",
|
|
84
|
-
{ transform: `translate(${component.topLeft.x}, ${component.topLeft.y}) scale(${scale})` },
|
|
85
|
-
[createSVG(component.image, { ...options, pixelWidth: undefined, pixelHeight: undefined })]
|
|
86
|
-
);
|
|
78
|
+
const scale = Math.min(component.size.width / (component.image.size.width || 1), component.size.height / (component.image.size.height || 1));
|
|
79
|
+
return createElement("g", { transform: `translate(${component.topLeft.x}, ${component.topLeft.y}) scale(${scale})` }, [
|
|
80
|
+
createSVG(component.image, { ...options, pixelWidth: undefined, pixelHeight: undefined }),
|
|
81
|
+
]);
|
|
87
82
|
}
|
|
88
83
|
case "line": {
|
|
89
84
|
const dashStyle: Attributes =
|
|
@@ -297,7 +292,7 @@ interface Attributes {
|
|
|
297
292
|
readonly [key: string]: string;
|
|
298
293
|
}
|
|
299
294
|
|
|
300
|
-
function createElement(elementName: string, attributes: Attributes, innerElements: string
|
|
295
|
+
function createElement(elementName: string, attributes: Attributes, innerElements: Array<string>): string {
|
|
301
296
|
const formattedName = convertUpperToHyphenLower(elementName);
|
|
302
297
|
let element = `<${formattedName}`;
|
|
303
298
|
|
|
@@ -360,7 +355,7 @@ function getBaselineAdjustment(d: GrowthDirection): "baseline" | "central" | "ha
|
|
|
360
355
|
if (d === "down") {
|
|
361
356
|
return "hanging";
|
|
362
357
|
}
|
|
363
|
-
throw "Unknown text alignment " + d;
|
|
358
|
+
throw new Error("Unknown text alignment " + d);
|
|
364
359
|
}
|
|
365
360
|
|
|
366
361
|
function getTextAnchor(d: GrowthDirection): string {
|
|
@@ -373,7 +368,7 @@ function getTextAnchor(d: GrowthDirection): string {
|
|
|
373
368
|
if (d === "right") {
|
|
374
369
|
return "start";
|
|
375
370
|
}
|
|
376
|
-
throw "Unknown text anchor " + d;
|
|
371
|
+
throw new Error("Unknown text anchor " + d);
|
|
377
372
|
}
|
|
378
373
|
|
|
379
374
|
function colorToRgb(color: Color): string {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { Size } from "./size.js";
|
|
2
1
|
import type { Color } from "./color.js";
|
|
3
2
|
import type { Component } from "./component.js";
|
|
4
3
|
import type { Point } from "./point.js";
|
|
4
|
+
import type { Size } from "./size.js";
|
|
5
5
|
|
|
6
6
|
export interface AbstractImage {
|
|
7
7
|
readonly topLeft: Point;
|
|
@@ -10,12 +10,7 @@ export interface AbstractImage {
|
|
|
10
10
|
readonly components: Array<Component>;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export function createAbstractImage(
|
|
14
|
-
topLeft: Point,
|
|
15
|
-
size: Size,
|
|
16
|
-
backgroundColor: Color,
|
|
17
|
-
components: Array<Component>
|
|
18
|
-
): AbstractImage {
|
|
13
|
+
export function createAbstractImage(topLeft: Point, size: Size, backgroundColor: Color, components: Array<Component>): AbstractImage {
|
|
19
14
|
return {
|
|
20
15
|
topLeft: topLeft,
|
|
21
16
|
size: size,
|
package/src/model/color.ts
CHANGED
|
@@ -10,15 +10,11 @@ export function fromArgb(a: number, r: number, g: number, b: number): Color {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export function toString6Hex(color: Color): string {
|
|
13
|
-
return (
|
|
14
|
-
("00" + color.r.toString(16)).substr(-2) +
|
|
15
|
-
("00" + color.g.toString(16)).substr(-2) +
|
|
16
|
-
("00" + color.b.toString(16)).substr(-2)
|
|
17
|
-
);
|
|
13
|
+
return ("00" + color.r.toString(16)).substr(-2) + ("00" + color.g.toString(16)).substr(-2) + ("00" + color.b.toString(16)).substr(-2);
|
|
18
14
|
}
|
|
19
15
|
|
|
20
16
|
export function fromString(s: string): Color | undefined {
|
|
21
|
-
if (s
|
|
17
|
+
if (s?.length !== 9 || !s.startsWith("#")) {
|
|
22
18
|
return undefined;
|
|
23
19
|
}
|
|
24
20
|
|
|
@@ -27,7 +23,7 @@ export function fromString(s: string): Color | undefined {
|
|
|
27
23
|
const g: number = parseInt(s.substring(5, 5 + 2), 16);
|
|
28
24
|
const b: number = parseInt(s.substring(7, 7 + 2), 16);
|
|
29
25
|
|
|
30
|
-
if (isNaN(a) || isNaN(r) || isNaN(g) || isNaN(b)) {
|
|
26
|
+
if (Number.isNaN(a) || Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) {
|
|
31
27
|
return undefined;
|
|
32
28
|
}
|
|
33
29
|
|
|
@@ -37,12 +33,7 @@ export function fromString(s: string): Color | undefined {
|
|
|
37
33
|
export function fromString2(s: string, def?: Color): Color {
|
|
38
34
|
if (s.startsWith("#")) {
|
|
39
35
|
if (s.length === 9) {
|
|
40
|
-
return fromArgb(
|
|
41
|
-
parseInt(s.slice(1, 3), 16),
|
|
42
|
-
parseInt(s.slice(3, 5), 16),
|
|
43
|
-
parseInt(s.slice(5, 7), 16),
|
|
44
|
-
parseInt(s.slice(7, 9), 16)
|
|
45
|
-
);
|
|
36
|
+
return fromArgb(parseInt(s.slice(1, 3), 16), parseInt(s.slice(3, 5), 16), parseInt(s.slice(5, 7), 16), parseInt(s.slice(7, 9), 16));
|
|
46
37
|
}
|
|
47
38
|
return fromArgb(255, parseInt(s.slice(1, 3), 16), parseInt(s.slice(3, 5), 16), parseInt(s.slice(5, 7), 16));
|
|
48
39
|
}
|
package/src/model/component.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { createPoint } from "./point.js";
|
|
1
|
+
import type { AbstractImage } from "./abstract-image.js";
|
|
3
2
|
import type { Color } from "./color.js";
|
|
4
3
|
import type { DashStyle } from "./dash-style.js";
|
|
5
4
|
import { solidLine } from "./dash-style.js";
|
|
6
|
-
import type {
|
|
5
|
+
import type { Point } from "./point.js";
|
|
6
|
+
import { createPoint } from "./point.js";
|
|
7
7
|
import type { Size } from "./size.js";
|
|
8
8
|
|
|
9
9
|
export type Component = BinaryImage | Ellipse | Line | PolyLine | Polygon | Rectangle | Text | SubImage | Group;
|
|
@@ -22,9 +22,7 @@ export function createGroup(name: string, children: Array<Component>): Group {
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
/**
|
|
26
|
-
* Embed a foreign binary image in any suported format.
|
|
27
|
-
*/
|
|
25
|
+
/** Embed a foreign binary image in any suported format. */
|
|
28
26
|
|
|
29
27
|
export type BinaryFormat = "svg" | "png" | "dxf";
|
|
30
28
|
|
|
@@ -49,13 +47,7 @@ export interface ImageUrl {
|
|
|
49
47
|
readonly url: string;
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
export function createBinaryImage(
|
|
53
|
-
topLeft: Point,
|
|
54
|
-
bottomRight: Point,
|
|
55
|
-
format: BinaryFormat,
|
|
56
|
-
data: ImageData,
|
|
57
|
-
id?: string
|
|
58
|
-
): BinaryImage {
|
|
50
|
+
export function createBinaryImage(topLeft: Point, bottomRight: Point, format: BinaryFormat, data: ImageData, id?: string): BinaryImage {
|
|
59
51
|
return {
|
|
60
52
|
type: "binaryimage",
|
|
61
53
|
topLeft: topLeft,
|