abstract-image 3.3.2 → 3.3.3

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.
Files changed (106) hide show
  1. package/CHANGELOG.md +44 -38
  2. package/LICENSE +21 -21
  3. package/README.md +73 -73
  4. package/lib/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-ellipse.js +379 -379
  5. package/lib/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-group.js +123 -123
  6. package/lib/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-line.js +55 -55
  7. package/lib/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-polygon.js +89 -89
  8. package/lib/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-polyline.js +79 -79
  9. package/lib/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-rectangle.js +99 -99
  10. package/lib/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-text-growth-directions.js +135 -135
  11. package/lib/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-text.js +63 -63
  12. package/lib/exporters/__tests__/eps-export-image/test-defs/eps-ellipse.js +24 -24
  13. package/lib/exporters/__tests__/eps-export-image/test-defs/eps-empty-text.js +26 -26
  14. package/lib/exporters/__tests__/eps-export-image/test-defs/eps-group.js +31 -31
  15. package/lib/exporters/__tests__/eps-export-image/test-defs/eps-line.js +20 -20
  16. package/lib/exporters/__tests__/eps-export-image/test-defs/eps-polygon.js +34 -34
  17. package/lib/exporters/__tests__/eps-export-image/test-defs/eps-polyline.js +26 -26
  18. package/lib/exporters/__tests__/eps-export-image/test-defs/eps-rectangle.js +20 -20
  19. package/lib/exporters/__tests__/eps-export-image/test-defs/eps-text-growth-directions.js +59 -59
  20. package/lib/exporters/__tests__/eps-export-image/test-defs/eps-text.js +26 -26
  21. package/package.json +4 -2
  22. package/src/__stories__/react-svg-export/example-1.stories.tsx +54 -54
  23. package/src/__stories__/svg-export/example-1.stories.tsx +42 -42
  24. package/src/exporters/__tests__/dxf2d-export-image/export-test-def.ts +11 -11
  25. package/src/exporters/__tests__/dxf2d-export-image/export.test.tsx +13 -13
  26. package/src/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-ellipse.ts +405 -405
  27. package/src/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-group.ts +166 -166
  28. package/src/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-line.ts +80 -80
  29. package/src/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-polygon.ts +114 -114
  30. package/src/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-polyline.ts +103 -103
  31. package/src/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-rectangle.ts +125 -125
  32. package/src/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-text-growth-directions.ts +214 -214
  33. package/src/exporters/__tests__/dxf2d-export-image/test-defs/dxf2d-text.ts +97 -97
  34. package/src/exporters/__tests__/eps-export-image/export-test-def.ts +11 -11
  35. package/src/exporters/__tests__/eps-export-image/export.test.tsx +13 -13
  36. package/src/exporters/__tests__/eps-export-image/test-defs/eps-ellipse.ts +50 -50
  37. package/src/exporters/__tests__/eps-export-image/test-defs/eps-empty-text.ts +60 -60
  38. package/src/exporters/__tests__/eps-export-image/test-defs/eps-group.ts +74 -74
  39. package/src/exporters/__tests__/eps-export-image/test-defs/eps-line.ts +45 -45
  40. package/src/exporters/__tests__/eps-export-image/test-defs/eps-polygon.ts +65 -65
  41. package/src/exporters/__tests__/eps-export-image/test-defs/eps-polyline.ts +58 -58
  42. package/src/exporters/__tests__/eps-export-image/test-defs/eps-rectangle.ts +46 -46
  43. package/src/exporters/__tests__/eps-export-image/test-defs/eps-text-growth-directions.ts +138 -138
  44. package/src/exporters/__tests__/eps-export-image/test-defs/eps-text.ts +60 -60
  45. package/src/exporters/__tests__/exception/png-unsupported.test.tsx +25 -25
  46. package/src/exporters/__tests__/exception/react-svg-direction-exception.test.tsx +65 -65
  47. package/src/exporters/__tests__/exception/svg-direction-exception.test.tsx +65 -65
  48. package/src/exporters/__tests__/png-export-image/export-test-def.ts +11 -11
  49. package/src/exporters/__tests__/png-export-image/export.test.tsx +13 -13
  50. package/src/exporters/__tests__/png-export-image/test-defs/png-createPNG.tsx +26 -26
  51. package/src/exporters/__tests__/react-svg-export-image/export-test-def.tsx +13 -13
  52. package/src/exporters/__tests__/react-svg-export-image/export.test.tsx +13 -13
  53. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-binary-png.tsx +26 -26
  54. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-binary-url.tsx +26 -26
  55. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-binary.tsx +25 -25
  56. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-callback.tsx +60 -60
  57. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-ellipse.tsx +28 -28
  58. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-empty-text.tsx +35 -35
  59. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-group.tsx +44 -44
  60. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-line.tsx +26 -26
  61. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-polygon.tsx +32 -32
  62. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-polyline.tsx +33 -33
  63. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-rectangle.tsx +27 -27
  64. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-subimage.tsx +36 -36
  65. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-text-bold.tsx +50 -50
  66. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-text-growth-directions.tsx +80 -80
  67. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-text-italic.tsx +65 -65
  68. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-text-sub.tsx +35 -35
  69. package/src/exporters/__tests__/react-svg-export-image/test-defs/react-svg-text.tsx +35 -35
  70. package/src/exporters/__tests__/svg-export-image/export-test-def.ts +11 -11
  71. package/src/exporters/__tests__/svg-export-image/export.test.tsx +13 -13
  72. package/src/exporters/__tests__/svg-export-image/test-defs/svg-binary.tsx +25 -25
  73. package/src/exporters/__tests__/svg-export-image/test-defs/svg-ellipse.ts +27 -27
  74. package/src/exporters/__tests__/svg-export-image/test-defs/svg-empty-text.ts +34 -34
  75. package/src/exporters/__tests__/svg-export-image/test-defs/svg-group.ts +44 -44
  76. package/src/exporters/__tests__/svg-export-image/test-defs/svg-line.ts +26 -26
  77. package/src/exporters/__tests__/svg-export-image/test-defs/svg-polygon.ts +32 -32
  78. package/src/exporters/__tests__/svg-export-image/test-defs/svg-polyline.ts +33 -33
  79. package/src/exporters/__tests__/svg-export-image/test-defs/svg-rectangle.ts +27 -27
  80. package/src/exporters/__tests__/svg-export-image/test-defs/svg-text-bold.ts +50 -50
  81. package/src/exporters/__tests__/svg-export-image/test-defs/svg-text-growth-directions.ts +80 -80
  82. package/src/exporters/__tests__/svg-export-image/test-defs/svg-text-italic.ts +65 -65
  83. package/src/exporters/__tests__/svg-export-image/test-defs/svg-text.ts +35 -35
  84. package/src/exporters/dxf2d-export-image.ts +218 -218
  85. package/src/exporters/eps-export-image.ts +154 -154
  86. package/src/exporters/index.ts +3 -3
  87. package/src/exporters/png-export-image.ts +12 -12
  88. package/src/exporters/react-svg-export-image.tsx +315 -315
  89. package/src/exporters/svg-export-image.ts +309 -309
  90. package/src/index.ts +11 -11
  91. package/src/model/__tests__/color/export-test-def.ts +13 -13
  92. package/src/model/__tests__/color/export.test.tsx +14 -14
  93. package/src/model/__tests__/color/test-defs/color-from-string.ts +46 -46
  94. package/src/model/__tests__/color/test-defs/color-to-string.ts +35 -35
  95. package/src/model/__tests__/color/test-defs/color-undefined-2.ts +8 -8
  96. package/src/model/__tests__/color/test-defs/color-undefined.ts +8 -8
  97. package/src/model/abstract-image.ts +25 -25
  98. package/src/model/color.ts +52 -52
  99. package/src/model/component.ts +279 -279
  100. package/src/model/index.ts +5 -5
  101. package/src/model/point.ts +11 -11
  102. package/src/model/size.ts +11 -11
  103. package/lib/exporters/__tests__/svg-export-image.test.d.ts +0 -2
  104. package/lib/exporters/__tests__/svg-export-image.test.d.ts.map +0 -1
  105. package/lib/exporters/__tests__/svg-export-image.test.js +0 -35
  106. package/lib/exporters/__tests__/svg-export-image.test.js.map +0 -1
@@ -1,309 +1,309 @@
1
- import * as B64 from "base64-js";
2
- import * as AbstractImage from "../model/index";
3
-
4
- export function createSVG(image: AbstractImage.AbstractImage, pixelWidth?: number, pixelHeight?: number): string {
5
- const imageElements = image.components.map((c: AbstractImage.Component) => abstractComponentToSVG(c));
6
-
7
- return createElement(
8
- "svg",
9
- {
10
- xmlns: "http://www.w3.org/2000/svg",
11
- width: `${pixelWidth || image.size.width}px`,
12
- height: `${pixelHeight || image.size.height}px`,
13
- viewBox: [0, 0, image.size.width, image.size.height].join(" "),
14
- },
15
- imageElements
16
- );
17
- }
18
-
19
- function abstractComponentToSVG(component: AbstractImage.Component): string {
20
- switch (component.type) {
21
- case "group":
22
- return createElement(
23
- "g",
24
- {
25
- name: component.name,
26
- },
27
- component.children.map((c) => abstractComponentToSVG(c))
28
- );
29
- case "binaryimage":
30
- const url = getImageUrl(component.format, component.data);
31
- return createElement(
32
- "image",
33
- {
34
- x: component.topLeft.x.toString(),
35
- y: component.topLeft.y.toString(),
36
- width: (component.bottomRight.x - component.topLeft.x).toString(),
37
- height: (component.bottomRight.y - component.topLeft.y).toString(),
38
- href: url,
39
- },
40
- []
41
- );
42
- case "subimage":
43
- return "";
44
- case "line":
45
- return createElement(
46
- "line",
47
- {
48
- x1: component.start.x.toString(),
49
- y1: component.start.y.toString(),
50
- x2: component.end.x.toString(),
51
- y2: component.end.y.toString(),
52
- stroke: colorToRgb(component.strokeColor),
53
- strokeOpacity: colorToOpacity(component.strokeColor),
54
- strokeWidth: component.strokeThickness.toString(),
55
- },
56
- []
57
- );
58
- case "polyline":
59
- return createElement(
60
- "polyline",
61
- {
62
- fill: "none",
63
- points: component.points.map((p) => p.x.toString() + "," + p.y.toString()).join(" "),
64
- stroke: colorToRgb(component.strokeColor),
65
- strokeOpacity: colorToOpacity(component.strokeColor),
66
- strokeWidth: component.strokeThickness.toString(),
67
- },
68
- []
69
- );
70
- case "text":
71
- if (!component.text) {
72
- return "";
73
- }
74
- const lineHeight = component.fontSize;
75
-
76
- const shadowStyle = {
77
- textAnchor: getTextAnchor(component.horizontalGrowthDirection),
78
- fontSize: component.fontSize.toString() + "px",
79
- fontWeight: component.fontWeight,
80
- fontFamily: component.fontFamily,
81
- stroke: colorToRgb(component.strokeColor),
82
- strokeOpacity: colorToOpacity(component.strokeColor),
83
- strokeWidth: component.strokeThickness.toString() + "px",
84
- };
85
-
86
- const style = {
87
- textAnchor: getTextAnchor(component.horizontalGrowthDirection),
88
- fontSize: component.fontSize.toString() + "px",
89
- fontWeight: component.fontWeight,
90
- fontFamily: component.fontFamily,
91
- fill: colorToRgb(component.textColor),
92
- fillOpacity: colorToOpacity(component.textColor),
93
- };
94
-
95
- const dy = getBaselineAdjustment(component.verticalGrowthDirection);
96
-
97
- const transform =
98
- "rotate(" +
99
- component.clockwiseRotationDegrees.toString() +
100
- " " +
101
- component.position.x.toString() +
102
- " " +
103
- component.position.y.toString() +
104
- ")";
105
-
106
- const lines: Array<string> = component.text !== null ? component.text.split("\n") : [];
107
-
108
- const tSpans = lines.map((t) =>
109
- createElement(
110
- "tspan",
111
- {
112
- x: component.position.x.toString(),
113
- y: (component.position.y + (lines.indexOf(t) + dy) * lineHeight).toString(),
114
- height: lineHeight.toString() + "px",
115
- },
116
- [
117
- t
118
- .replace("<sub>", `<tspan style="font-size: ${component.fontSize * 0.8}px" baseline-shift="sub">`)
119
- .replace("</sub>", "</tspan>"),
120
- ]
121
- )
122
- );
123
-
124
- const cs: Array<string> = [];
125
-
126
- if (component.strokeThickness > 0 && component.strokeColor !== null) {
127
- cs.push(
128
- createElement(
129
- "text",
130
- {
131
- style: objectToAttributeValue(shadowStyle),
132
- transform: transform,
133
- },
134
- tSpans
135
- )
136
- );
137
- }
138
- cs.push(
139
- createElement(
140
- "text",
141
- {
142
- style: objectToAttributeValue(style),
143
- transform: transform,
144
- },
145
- tSpans
146
- )
147
- );
148
- return cs.join();
149
- case "ellipse":
150
- const rx = Math.abs(component.bottomRight.x - component.topLeft.x) * 0.5;
151
- const ry = Math.abs(component.bottomRight.y - component.topLeft.y) * 0.5;
152
- const cx = (component.bottomRight.x + component.topLeft.x) * 0.5;
153
- const cy = (component.bottomRight.y + component.topLeft.y) * 0.5;
154
- return createElement(
155
- "ellipse",
156
- {
157
- cx: cx.toString(),
158
- cy: cy.toString(),
159
- rx: rx.toString(),
160
- ry: ry.toString(),
161
- stroke: colorToRgb(component.strokeColor),
162
- strokeOpacity: colorToOpacity(component.strokeColor),
163
- strokeWidth: component.strokeThickness.toString(),
164
- fill: colorToRgb(component.fillColor),
165
- fillOpacity: colorToOpacity(component.fillColor),
166
- },
167
- []
168
- );
169
- case "polygon":
170
- return createElement(
171
- "polygon",
172
- {
173
- points: component.points.map((p) => p.x.toString() + "," + p.y.toString()).join(" "),
174
- stroke: colorToRgb(component.strokeColor),
175
- strokeOpacity: colorToOpacity(component.strokeColor),
176
- strokeWidth: component.strokeThickness.toString(),
177
- fill: colorToRgb(component.fillColor),
178
- fillOpacity: colorToOpacity(component.fillColor),
179
- },
180
- []
181
- );
182
- case "rectangle":
183
- return createElement(
184
- "rect",
185
- {
186
- x: component.topLeft.x.toString(),
187
- y: component.topLeft.y.toString(),
188
- width: Math.abs(component.bottomRight.x - component.topLeft.x).toString(),
189
- height: Math.abs(component.bottomRight.y - component.topLeft.y).toString(),
190
- stroke: colorToRgb(component.strokeColor),
191
- strokeOpacity: colorToOpacity(component.strokeColor),
192
- strokeWidth: component.strokeThickness.toString(),
193
- fill: colorToRgb(component.fillColor),
194
- fillOpacity: colorToOpacity(component.fillColor),
195
- },
196
- []
197
- );
198
- default:
199
- return "";
200
- }
201
- }
202
-
203
- interface Attributes {
204
- readonly [key: string]: string;
205
- }
206
-
207
- function createElement(elementName: string, attributes: Attributes, innerElements: string[]): string {
208
- const formattedName = convertUpperToHyphenLower(elementName);
209
- let element = `<${formattedName}`;
210
-
211
- if (Object.keys(attributes).length > 0) {
212
- element = Object.keys(attributes).reduce((previousValue: string, currentValue: string) => {
213
- if (attributes[currentValue]) {
214
- return previousValue + ` ${convertUpperToHyphenLower(currentValue)}="${attributes[currentValue]}"`;
215
- } else {
216
- return previousValue;
217
- }
218
- }, element);
219
- }
220
-
221
- element += ">";
222
-
223
- if (innerElements.length > 0) {
224
- element = innerElements.reduce((previousValue: string, currentValue: string) => {
225
- if (!currentValue || currentValue.length < 1) {
226
- return previousValue;
227
- } else {
228
- return previousValue + `${currentValue}`;
229
- }
230
- }, element);
231
- }
232
-
233
- element += `</${formattedName}>`;
234
-
235
- return element;
236
- }
237
-
238
- function objectToAttributeValue(attributes: Attributes): string {
239
- if (attributes && Object.keys(attributes).length > 0) {
240
- return Object.keys(attributes).reduce((previousValue: string, currentValue: string) => {
241
- if (attributes[currentValue]) {
242
- return previousValue + `${convertUpperToHyphenLower(currentValue)}:${attributes[currentValue]};`;
243
- } else {
244
- return previousValue;
245
- }
246
- }, "");
247
- }
248
-
249
- return "";
250
- }
251
-
252
- function convertUpperToHyphenLower(elementName: string): string {
253
- function upperToHyphenLower(match: string): string {
254
- return "-" + match.toLowerCase();
255
- }
256
-
257
- return elementName !== "viewBox" ? elementName.replace(/[A-Z]/g, upperToHyphenLower) : elementName;
258
- }
259
-
260
- function getBaselineAdjustment(d: AbstractImage.GrowthDirection): number {
261
- if (d === "up") {
262
- return 0.0;
263
- }
264
- if (d === "uniform") {
265
- return 0.5;
266
- }
267
- if (d === "down") {
268
- return 1.0;
269
- }
270
- throw "Unknown text alignment " + d;
271
- }
272
-
273
- function getTextAnchor(d: AbstractImage.GrowthDirection): string {
274
- if (d === "left") {
275
- return "end";
276
- }
277
- if (d === "uniform") {
278
- return "middle";
279
- }
280
- if (d === "right") {
281
- return "start";
282
- }
283
- throw "Unknown text alignment " + d;
284
- }
285
-
286
- function colorToRgb(color: AbstractImage.Color): string {
287
- return `rgb(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()})`;
288
- }
289
-
290
- function colorToOpacity(color: AbstractImage.Color): string {
291
- return (color.a / 255).toString();
292
- }
293
-
294
- function getImageUrl(format: AbstractImage.BinaryFormat, data: AbstractImage.ImageData): string {
295
- if (data.type === "url") {
296
- return data.url;
297
- } else if (format === "png") {
298
- const base64 = B64.fromByteArray(data.bytes);
299
- return `data:image/png;base64,${base64}`;
300
- } else {
301
- const svg = String.fromCharCode(...data.bytes).replace('<?xml version="1.0" encoding="utf-8"?>', "");
302
- const bytes = [];
303
- for (let i = 0; i < svg.length; ++i) {
304
- bytes.push(svg.charCodeAt(i));
305
- }
306
- const base64 = B64.fromByteArray(new Uint8Array(bytes));
307
- return `data:image/svg+xml;base64,${base64}`;
308
- }
309
- }
1
+ import * as B64 from "base64-js";
2
+ import * as AbstractImage from "../model/index";
3
+
4
+ export function createSVG(image: AbstractImage.AbstractImage, pixelWidth?: number, pixelHeight?: number): string {
5
+ const imageElements = image.components.map((c: AbstractImage.Component) => abstractComponentToSVG(c));
6
+
7
+ return createElement(
8
+ "svg",
9
+ {
10
+ xmlns: "http://www.w3.org/2000/svg",
11
+ width: `${pixelWidth || image.size.width}px`,
12
+ height: `${pixelHeight || image.size.height}px`,
13
+ viewBox: [0, 0, image.size.width, image.size.height].join(" "),
14
+ },
15
+ imageElements
16
+ );
17
+ }
18
+
19
+ function abstractComponentToSVG(component: AbstractImage.Component): string {
20
+ switch (component.type) {
21
+ case "group":
22
+ return createElement(
23
+ "g",
24
+ {
25
+ name: component.name,
26
+ },
27
+ component.children.map((c) => abstractComponentToSVG(c))
28
+ );
29
+ case "binaryimage":
30
+ const url = getImageUrl(component.format, component.data);
31
+ return createElement(
32
+ "image",
33
+ {
34
+ x: component.topLeft.x.toString(),
35
+ y: component.topLeft.y.toString(),
36
+ width: (component.bottomRight.x - component.topLeft.x).toString(),
37
+ height: (component.bottomRight.y - component.topLeft.y).toString(),
38
+ href: url,
39
+ },
40
+ []
41
+ );
42
+ case "subimage":
43
+ return "";
44
+ case "line":
45
+ return createElement(
46
+ "line",
47
+ {
48
+ x1: component.start.x.toString(),
49
+ y1: component.start.y.toString(),
50
+ x2: component.end.x.toString(),
51
+ y2: component.end.y.toString(),
52
+ stroke: colorToRgb(component.strokeColor),
53
+ strokeOpacity: colorToOpacity(component.strokeColor),
54
+ strokeWidth: component.strokeThickness.toString(),
55
+ },
56
+ []
57
+ );
58
+ case "polyline":
59
+ return createElement(
60
+ "polyline",
61
+ {
62
+ fill: "none",
63
+ points: component.points.map((p) => p.x.toString() + "," + p.y.toString()).join(" "),
64
+ stroke: colorToRgb(component.strokeColor),
65
+ strokeOpacity: colorToOpacity(component.strokeColor),
66
+ strokeWidth: component.strokeThickness.toString(),
67
+ },
68
+ []
69
+ );
70
+ case "text":
71
+ if (!component.text) {
72
+ return "";
73
+ }
74
+ const lineHeight = component.fontSize;
75
+
76
+ const shadowStyle = {
77
+ textAnchor: getTextAnchor(component.horizontalGrowthDirection),
78
+ fontSize: component.fontSize.toString() + "px",
79
+ fontWeight: component.fontWeight,
80
+ fontFamily: component.fontFamily,
81
+ stroke: colorToRgb(component.strokeColor),
82
+ strokeOpacity: colorToOpacity(component.strokeColor),
83
+ strokeWidth: component.strokeThickness.toString() + "px",
84
+ };
85
+
86
+ const style = {
87
+ textAnchor: getTextAnchor(component.horizontalGrowthDirection),
88
+ fontSize: component.fontSize.toString() + "px",
89
+ fontWeight: component.fontWeight,
90
+ fontFamily: component.fontFamily,
91
+ fill: colorToRgb(component.textColor),
92
+ fillOpacity: colorToOpacity(component.textColor),
93
+ };
94
+
95
+ const dy = getBaselineAdjustment(component.verticalGrowthDirection);
96
+
97
+ const transform =
98
+ "rotate(" +
99
+ component.clockwiseRotationDegrees.toString() +
100
+ " " +
101
+ component.position.x.toString() +
102
+ " " +
103
+ component.position.y.toString() +
104
+ ")";
105
+
106
+ const lines: Array<string> = component.text !== null ? component.text.split("\n") : [];
107
+
108
+ const tSpans = lines.map((t) =>
109
+ createElement(
110
+ "tspan",
111
+ {
112
+ x: component.position.x.toString(),
113
+ y: (component.position.y + (lines.indexOf(t) + dy) * lineHeight).toString(),
114
+ height: lineHeight.toString() + "px",
115
+ },
116
+ [
117
+ t
118
+ .replace("<sub>", `<tspan style="font-size: ${component.fontSize * 0.8}px" baseline-shift="sub">`)
119
+ .replace("</sub>", "</tspan>"),
120
+ ]
121
+ )
122
+ );
123
+
124
+ const cs: Array<string> = [];
125
+
126
+ if (component.strokeThickness > 0 && component.strokeColor !== null) {
127
+ cs.push(
128
+ createElement(
129
+ "text",
130
+ {
131
+ style: objectToAttributeValue(shadowStyle),
132
+ transform: transform,
133
+ },
134
+ tSpans
135
+ )
136
+ );
137
+ }
138
+ cs.push(
139
+ createElement(
140
+ "text",
141
+ {
142
+ style: objectToAttributeValue(style),
143
+ transform: transform,
144
+ },
145
+ tSpans
146
+ )
147
+ );
148
+ return cs.join();
149
+ case "ellipse":
150
+ const rx = Math.abs(component.bottomRight.x - component.topLeft.x) * 0.5;
151
+ const ry = Math.abs(component.bottomRight.y - component.topLeft.y) * 0.5;
152
+ const cx = (component.bottomRight.x + component.topLeft.x) * 0.5;
153
+ const cy = (component.bottomRight.y + component.topLeft.y) * 0.5;
154
+ return createElement(
155
+ "ellipse",
156
+ {
157
+ cx: cx.toString(),
158
+ cy: cy.toString(),
159
+ rx: rx.toString(),
160
+ ry: ry.toString(),
161
+ stroke: colorToRgb(component.strokeColor),
162
+ strokeOpacity: colorToOpacity(component.strokeColor),
163
+ strokeWidth: component.strokeThickness.toString(),
164
+ fill: colorToRgb(component.fillColor),
165
+ fillOpacity: colorToOpacity(component.fillColor),
166
+ },
167
+ []
168
+ );
169
+ case "polygon":
170
+ return createElement(
171
+ "polygon",
172
+ {
173
+ points: component.points.map((p) => p.x.toString() + "," + p.y.toString()).join(" "),
174
+ stroke: colorToRgb(component.strokeColor),
175
+ strokeOpacity: colorToOpacity(component.strokeColor),
176
+ strokeWidth: component.strokeThickness.toString(),
177
+ fill: colorToRgb(component.fillColor),
178
+ fillOpacity: colorToOpacity(component.fillColor),
179
+ },
180
+ []
181
+ );
182
+ case "rectangle":
183
+ return createElement(
184
+ "rect",
185
+ {
186
+ x: component.topLeft.x.toString(),
187
+ y: component.topLeft.y.toString(),
188
+ width: Math.abs(component.bottomRight.x - component.topLeft.x).toString(),
189
+ height: Math.abs(component.bottomRight.y - component.topLeft.y).toString(),
190
+ stroke: colorToRgb(component.strokeColor),
191
+ strokeOpacity: colorToOpacity(component.strokeColor),
192
+ strokeWidth: component.strokeThickness.toString(),
193
+ fill: colorToRgb(component.fillColor),
194
+ fillOpacity: colorToOpacity(component.fillColor),
195
+ },
196
+ []
197
+ );
198
+ default:
199
+ return "";
200
+ }
201
+ }
202
+
203
+ interface Attributes {
204
+ readonly [key: string]: string;
205
+ }
206
+
207
+ function createElement(elementName: string, attributes: Attributes, innerElements: string[]): string {
208
+ const formattedName = convertUpperToHyphenLower(elementName);
209
+ let element = `<${formattedName}`;
210
+
211
+ if (Object.keys(attributes).length > 0) {
212
+ element = Object.keys(attributes).reduce((previousValue: string, currentValue: string) => {
213
+ if (attributes[currentValue]) {
214
+ return previousValue + ` ${convertUpperToHyphenLower(currentValue)}="${attributes[currentValue]}"`;
215
+ } else {
216
+ return previousValue;
217
+ }
218
+ }, element);
219
+ }
220
+
221
+ element += ">";
222
+
223
+ if (innerElements.length > 0) {
224
+ element = innerElements.reduce((previousValue: string, currentValue: string) => {
225
+ if (!currentValue || currentValue.length < 1) {
226
+ return previousValue;
227
+ } else {
228
+ return previousValue + `${currentValue}`;
229
+ }
230
+ }, element);
231
+ }
232
+
233
+ element += `</${formattedName}>`;
234
+
235
+ return element;
236
+ }
237
+
238
+ function objectToAttributeValue(attributes: Attributes): string {
239
+ if (attributes && Object.keys(attributes).length > 0) {
240
+ return Object.keys(attributes).reduce((previousValue: string, currentValue: string) => {
241
+ if (attributes[currentValue]) {
242
+ return previousValue + `${convertUpperToHyphenLower(currentValue)}:${attributes[currentValue]};`;
243
+ } else {
244
+ return previousValue;
245
+ }
246
+ }, "");
247
+ }
248
+
249
+ return "";
250
+ }
251
+
252
+ function convertUpperToHyphenLower(elementName: string): string {
253
+ function upperToHyphenLower(match: string): string {
254
+ return "-" + match.toLowerCase();
255
+ }
256
+
257
+ return elementName !== "viewBox" ? elementName.replace(/[A-Z]/g, upperToHyphenLower) : elementName;
258
+ }
259
+
260
+ function getBaselineAdjustment(d: AbstractImage.GrowthDirection): number {
261
+ if (d === "up") {
262
+ return 0.0;
263
+ }
264
+ if (d === "uniform") {
265
+ return 0.5;
266
+ }
267
+ if (d === "down") {
268
+ return 1.0;
269
+ }
270
+ throw "Unknown text alignment " + d;
271
+ }
272
+
273
+ function getTextAnchor(d: AbstractImage.GrowthDirection): string {
274
+ if (d === "left") {
275
+ return "end";
276
+ }
277
+ if (d === "uniform") {
278
+ return "middle";
279
+ }
280
+ if (d === "right") {
281
+ return "start";
282
+ }
283
+ throw "Unknown text alignment " + d;
284
+ }
285
+
286
+ function colorToRgb(color: AbstractImage.Color): string {
287
+ return `rgb(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()})`;
288
+ }
289
+
290
+ function colorToOpacity(color: AbstractImage.Color): string {
291
+ return (color.a / 255).toString();
292
+ }
293
+
294
+ function getImageUrl(format: AbstractImage.BinaryFormat, data: AbstractImage.ImageData): string {
295
+ if (data.type === "url") {
296
+ return data.url;
297
+ } else if (format === "png") {
298
+ const base64 = B64.fromByteArray(data.bytes);
299
+ return `data:image/png;base64,${base64}`;
300
+ } else {
301
+ const svg = String.fromCharCode(...data.bytes).replace('<?xml version="1.0" encoding="utf-8"?>', "");
302
+ const bytes = [];
303
+ for (let i = 0; i < svg.length; ++i) {
304
+ bytes.push(svg.charCodeAt(i));
305
+ }
306
+ const base64 = B64.fromByteArray(new Uint8Array(bytes));
307
+ return `data:image/svg+xml;base64,${base64}`;
308
+ }
309
+ }
package/src/index.ts CHANGED
@@ -1,11 +1,11 @@
1
- export * from "./model/abstract-image";
2
- export * from "./model/color";
3
- export * from "./model/component";
4
- export * from "./model/point";
5
- export * from "./model/size";
6
-
7
- export * from "./exporters/svg-export-image";
8
- export * from "./exporters/png-export-image";
9
- export * from "./exporters/dxf2d-export-image";
10
- export * from "./exporters/react-svg-export-image";
11
- export * from "./exporters/eps-export-image";
1
+ export * from "./model/abstract-image";
2
+ export * from "./model/color";
3
+ export * from "./model/component";
4
+ export * from "./model/point";
5
+ export * from "./model/size";
6
+
7
+ export * from "./exporters/svg-export-image";
8
+ export * from "./exporters/png-export-image";
9
+ export * from "./exporters/dxf2d-export-image";
10
+ export * from "./exporters/react-svg-export-image";
11
+ export * from "./exporters/eps-export-image";
@@ -1,13 +1,13 @@
1
- /**
2
- * Defines a data-type that represents a single test for the Docx render function
3
- */
4
-
5
- import * as AbstractImage from "../../../../src/index";
6
-
7
- export type ExportTestDef = {
8
- readonly name: string;
9
- readonly only?: boolean;
10
- readonly skip?: boolean;
11
- readonly abstractColor: {} | AbstractImage.Color | undefined;
12
- readonly expectedColor: {} | undefined;
13
- };
1
+ /**
2
+ * Defines a data-type that represents a single test for the Docx render function
3
+ */
4
+
5
+ import * as AbstractImage from "../../../../src/index";
6
+
7
+ export type ExportTestDef = {
8
+ readonly name: string;
9
+ readonly only?: boolean;
10
+ readonly skip?: boolean;
11
+ readonly abstractColor: {} | AbstractImage.Color | undefined;
12
+ readonly expectedColor: {} | undefined;
13
+ };