js.documents 2.0.0 → 2.2.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/README.md +49 -29
- package/dist/codecs/registry.cjs +14 -0
- package/dist/codecs/registry.js +14 -0
- package/dist/convert/capability.cjs +10 -0
- package/dist/convert/capability.js +10 -0
- package/dist/convert/codec.cjs +30 -0
- package/dist/convert/codec.d.cts +7 -1
- package/dist/convert/codec.d.ts +7 -1
- package/dist/convert/codec.js +27 -3
- package/dist/convert/composition.cjs +49 -7
- package/dist/convert/composition.d.cts +12 -5
- package/dist/convert/composition.d.ts +12 -5
- package/dist/convert/composition.js +49 -7
- package/dist/convert/convert.cjs +48 -0
- package/dist/convert/convert.d.cts +30 -1
- package/dist/convert/convert.d.ts +30 -1
- package/dist/convert/convert.js +37 -1
- package/dist/convert/local.cjs +4 -1
- package/dist/convert/local.js +4 -1
- package/dist/convert/port.cjs +2 -0
- package/dist/convert/port.d.cts +5 -0
- package/dist/convert/port.d.ts +5 -0
- package/dist/convert/port.js +2 -0
- package/dist/csv/read.cjs +85 -0
- package/dist/csv/read.d.cts +10 -0
- package/dist/csv/read.d.ts +10 -0
- package/dist/csv/read.js +84 -0
- package/dist/csv/records.cjs +85 -0
- package/dist/csv/records.d.cts +10 -0
- package/dist/csv/records.d.ts +10 -0
- package/dist/csv/records.js +80 -0
- package/dist/csv/text.cjs +22 -0
- package/dist/csv/text.d.cts +8 -0
- package/dist/csv/text.d.ts +8 -0
- package/dist/csv/text.js +19 -0
- package/dist/csv/write.cjs +75 -0
- package/dist/csv/write.d.cts +22 -0
- package/dist/csv/write.d.ts +22 -0
- package/dist/csv/write.js +71 -0
- package/dist/edit/odg/scaffold.js +8 -8
- package/dist/edit/odp/scaffold.js +8 -8
- package/dist/edit/ods/scaffold.js +8 -8
- package/dist/edit/odt/scaffold.js +8 -8
- package/dist/index.cjs +48 -1
- package/dist/index.d.cts +13 -5
- package/dist/index.d.ts +13 -5
- package/dist/index.js +13 -5
- package/dist/layout/reconstruct.cjs +1 -1
- package/dist/layout/reconstruct.js +1 -1
- package/dist/metadata/write.cjs +2 -0
- package/dist/metadata/write.js +2 -0
- package/dist/model/bytes.cjs +7 -0
- package/dist/model/bytes.d.cts +3 -1
- package/dist/model/bytes.d.ts +3 -1
- package/dist/model/bytes.js +6 -1
- package/dist/odb/csv.cjs +3 -6
- package/dist/odb/csv.js +3 -6
- package/dist/svg/diagnostics.cjs +19 -0
- package/dist/svg/diagnostics.d.cts +10 -0
- package/dist/svg/diagnostics.d.ts +10 -0
- package/dist/svg/diagnostics.js +18 -0
- package/dist/svg/paint.cjs +817 -0
- package/dist/svg/paint.d.cts +19 -0
- package/dist/svg/paint.d.ts +19 -0
- package/dist/svg/paint.js +814 -0
- package/dist/svg/path.cjs +337 -0
- package/dist/svg/path.d.cts +22 -0
- package/dist/svg/path.d.ts +22 -0
- package/dist/svg/path.js +336 -0
- package/dist/svg/read.cjs +677 -0
- package/dist/svg/read.d.cts +12 -0
- package/dist/svg/read.d.ts +12 -0
- package/dist/svg/read.js +675 -0
- package/dist/svg/text.cjs +22 -0
- package/dist/svg/text.d.cts +8 -0
- package/dist/svg/text.d.ts +8 -0
- package/dist/svg/text.js +19 -0
- package/dist/svg/transform.cjs +206 -0
- package/dist/svg/transform.d.cts +23 -0
- package/dist/svg/transform.d.ts +23 -0
- package/dist/svg/transform.js +197 -0
- package/dist/svg/units.cjs +47 -0
- package/dist/svg/units.d.cts +12 -0
- package/dist/svg/units.d.ts +12 -0
- package/dist/svg/units.js +44 -0
- package/dist/svg/write.cjs +127 -0
- package/dist/svg/write.d.cts +23 -0
- package/dist/svg/write.d.ts +23 -0
- package/dist/svg/write.js +123 -0
- package/dist/xml/odf-text.js +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_edit_odg_svg_path = require("../edit/odg/svg-path.cjs");
|
|
3
|
+
const require_model_paint_order = require("../model/paint-order.cjs");
|
|
4
|
+
let document_schema_js = require("document-schema.js");
|
|
5
|
+
let odf_js = require("odf.js");
|
|
6
|
+
//#region src/svg/write.ts
|
|
7
|
+
var SvgUnsupportedDocumentKindError = class extends Error {
|
|
8
|
+
kind;
|
|
9
|
+
constructor(kind) {
|
|
10
|
+
super(`buildSvgText: expected a drawing ContentDocument, got kind '${kind}'`);
|
|
11
|
+
this.name = "SvgUnsupportedDocumentKindError";
|
|
12
|
+
this.kind = kind;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var SvgMultiPageNotSpecifiedError = class extends Error {
|
|
16
|
+
pageCount;
|
|
17
|
+
constructor(pageCount) {
|
|
18
|
+
super(`buildSvgText: this document has more than one page (${pageCount}) -- pass { page: <index> } to select one`);
|
|
19
|
+
this.name = "SvgMultiPageNotSpecifiedError";
|
|
20
|
+
this.pageCount = pageCount;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
var SvgPageNotFoundError = class extends Error {
|
|
24
|
+
page;
|
|
25
|
+
pageCount;
|
|
26
|
+
constructor(page, pageCount) {
|
|
27
|
+
super(`buildSvgText: page index ${page} not found -- the document has ${pageCount} page(s)`);
|
|
28
|
+
this.name = "SvgPageNotFoundError";
|
|
29
|
+
this.page = page;
|
|
30
|
+
this.pageCount = pageCount;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
function selectPage(pages, page) {
|
|
34
|
+
if (page !== void 0) {
|
|
35
|
+
const found = pages[page];
|
|
36
|
+
if (found === void 0) throw new SvgPageNotFoundError(page, pages.length);
|
|
37
|
+
return found;
|
|
38
|
+
}
|
|
39
|
+
if (pages.length === 0) throw new SvgPageNotFoundError(0, 0);
|
|
40
|
+
if (pages.length > 1) throw new SvgMultiPageNotSpecifiedError(pages.length);
|
|
41
|
+
return pages[0];
|
|
42
|
+
}
|
|
43
|
+
const DASHED_PATTERN = "6 4";
|
|
44
|
+
const DOTTED_PATTERN = "1 3";
|
|
45
|
+
function svgColor(fill) {
|
|
46
|
+
return `#${(0, document_schema_js.colorToRgbHex)(fill)}`;
|
|
47
|
+
}
|
|
48
|
+
function fillAttr(fill) {
|
|
49
|
+
return fill === void 0 ? " fill=\"none\"" : ` fill="${svgColor(fill)}"`;
|
|
50
|
+
}
|
|
51
|
+
function strokeAttr(vector, stroke, sink) {
|
|
52
|
+
let attrs = ` stroke="${svgColor(stroke.color)}" stroke-width="${require_edit_odg_svg_path.formatPathNumber(stroke.widthPt)}"`;
|
|
53
|
+
if (stroke.style === "dashed") attrs += ` stroke-dasharray="${DASHED_PATTERN}"`;
|
|
54
|
+
else if (stroke.style === "dotted") attrs += ` stroke-dasharray="${DOTTED_PATTERN}" stroke-linecap="round"`;
|
|
55
|
+
else if (stroke.style === "double") sink?.({
|
|
56
|
+
code: "svg/stroke-style-unsupported",
|
|
57
|
+
detail: `${vector.sourcePath ?? vector.kind}: stroke style 'double' written as solid`
|
|
58
|
+
});
|
|
59
|
+
return attrs;
|
|
60
|
+
}
|
|
61
|
+
function rotationAttr(rotationDeg, frame) {
|
|
62
|
+
if (rotationDeg === void 0 || rotationDeg === 0) return "";
|
|
63
|
+
const cx = frame.xPt + frame.widthPt / 2;
|
|
64
|
+
const cy = frame.yPt + frame.heightPt / 2;
|
|
65
|
+
return ` transform="rotate(${require_edit_odg_svg_path.formatPathNumber(rotationDeg)} ${require_edit_odg_svg_path.formatPathNumber(cx)} ${require_edit_odg_svg_path.formatPathNumber(cy)})"`;
|
|
66
|
+
}
|
|
67
|
+
function offsetSubpaths(subpaths, offsetX, offsetY) {
|
|
68
|
+
const offsetPoint = (point) => ({
|
|
69
|
+
xPt: point.xPt + offsetX,
|
|
70
|
+
yPt: point.yPt + offsetY
|
|
71
|
+
});
|
|
72
|
+
return subpaths.map((subpath) => ({
|
|
73
|
+
start: offsetPoint(subpath.start),
|
|
74
|
+
closed: subpath.closed,
|
|
75
|
+
segments: subpath.segments.map((segment) => segment.kind === "line" ? {
|
|
76
|
+
kind: "line",
|
|
77
|
+
to: offsetPoint(segment.to)
|
|
78
|
+
} : {
|
|
79
|
+
kind: "cubic",
|
|
80
|
+
control1: offsetPoint(segment.control1),
|
|
81
|
+
control2: offsetPoint(segment.control2),
|
|
82
|
+
to: offsetPoint(segment.to)
|
|
83
|
+
})
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
function vectorElement(vector, sink) {
|
|
87
|
+
switch (vector.kind) {
|
|
88
|
+
case "rect": return `<rect x="${require_edit_odg_svg_path.formatPathNumber(vector.frame.xPt)}" y="${require_edit_odg_svg_path.formatPathNumber(vector.frame.yPt)}" width="${require_edit_odg_svg_path.formatPathNumber(vector.frame.widthPt)}" height="${require_edit_odg_svg_path.formatPathNumber(vector.frame.heightPt)}"${fillAttr(vector.fill)}${vector.stroke === void 0 ? "" : strokeAttr(vector, vector.stroke, sink)}${rotationAttr(vector.rotationDeg, vector.frame)}/>`;
|
|
89
|
+
case "ellipse": {
|
|
90
|
+
const cx = vector.frame.xPt + vector.frame.widthPt / 2;
|
|
91
|
+
const cy = vector.frame.yPt + vector.frame.heightPt / 2;
|
|
92
|
+
const rx = vector.frame.widthPt / 2;
|
|
93
|
+
const ry = vector.frame.heightPt / 2;
|
|
94
|
+
return `<ellipse cx="${require_edit_odg_svg_path.formatPathNumber(cx)}" cy="${require_edit_odg_svg_path.formatPathNumber(cy)}" rx="${require_edit_odg_svg_path.formatPathNumber(rx)}" ry="${require_edit_odg_svg_path.formatPathNumber(ry)}"${fillAttr(vector.fill)}${vector.stroke === void 0 ? "" : strokeAttr(vector, vector.stroke, sink)}${rotationAttr(vector.rotationDeg, vector.frame)}/>`;
|
|
95
|
+
}
|
|
96
|
+
case "line": return `<line x1="${require_edit_odg_svg_path.formatPathNumber(vector.from.xPt)}" y1="${require_edit_odg_svg_path.formatPathNumber(vector.from.yPt)}" x2="${require_edit_odg_svg_path.formatPathNumber(vector.to.xPt)}" y2="${require_edit_odg_svg_path.formatPathNumber(vector.to.yPt)}"${strokeAttr(vector, vector.stroke, sink)}/>`;
|
|
97
|
+
case "path": {
|
|
98
|
+
const d = require_edit_odg_svg_path.buildSvgPathData(offsetSubpaths(vector.subpaths, vector.frame.xPt, vector.frame.yPt));
|
|
99
|
+
const fillRule = vector.fillRule === "evenodd" ? " fill-rule=\"evenodd\"" : "";
|
|
100
|
+
return `<path d="${d}"${fillAttr(vector.fill)}${vector.stroke === void 0 ? "" : strokeAttr(vector, vector.stroke, sink)}${fillRule}${rotationAttr(vector.rotationDeg, vector.frame)}/>`;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function shapeDetail(shape) {
|
|
105
|
+
return shape.name ?? shape.sourcePath ?? "shape";
|
|
106
|
+
}
|
|
107
|
+
function buildSvgText(content, options) {
|
|
108
|
+
if (content.kind !== "drawing") throw new SvgUnsupportedDocumentKindError(content.kind);
|
|
109
|
+
const sink = options?.onSvgDiagnostic;
|
|
110
|
+
const page = selectPage(content.pages, options?.page);
|
|
111
|
+
const lines = [];
|
|
112
|
+
lines.push("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
|
113
|
+
lines.push(`<svg xmlns="http://www.w3.org/2000/svg" width="${require_edit_odg_svg_path.formatPathNumber(page.size.widthPt)}pt" height="${require_edit_odg_svg_path.formatPathNumber(page.size.heightPt)}pt" viewBox="${require_edit_odg_svg_path.buildSvgViewBox(page.size.widthPt, page.size.heightPt)}">`);
|
|
114
|
+
if (content.metadata.title !== void 0 && content.metadata.title !== "") lines.push(` <title>${(0, odf_js.encodeXmlText)(content.metadata.title)}</title>`);
|
|
115
|
+
for (const entry of require_model_paint_order.mergeByPaintOrder(page.vectors, page.shapes)) if (entry.kind === "vector") lines.push(` ${vectorElement(entry.value, sink)}`);
|
|
116
|
+
else sink?.({
|
|
117
|
+
code: "svg/shape-unsupported",
|
|
118
|
+
detail: `${shapeDetail(entry.value)}: draw:frame text/image/table content has no SVG vector representation`
|
|
119
|
+
});
|
|
120
|
+
lines.push("</svg>");
|
|
121
|
+
return `${lines.join("\n")}\n`;
|
|
122
|
+
}
|
|
123
|
+
//#endregion
|
|
124
|
+
exports.SvgMultiPageNotSpecifiedError = SvgMultiPageNotSpecifiedError;
|
|
125
|
+
exports.SvgPageNotFoundError = SvgPageNotFoundError;
|
|
126
|
+
exports.SvgUnsupportedDocumentKindError = SvgUnsupportedDocumentKindError;
|
|
127
|
+
exports.buildSvgText = buildSvgText;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { SvgDiagnosticSink } from "./diagnostics.cjs";
|
|
2
|
+
import { ContentDocument } from "document-schema.js";
|
|
3
|
+
//#region src/svg/write.d.ts
|
|
4
|
+
declare class SvgUnsupportedDocumentKindError extends Error {
|
|
5
|
+
readonly kind: ContentDocument['kind'];
|
|
6
|
+
constructor(kind: ContentDocument['kind']);
|
|
7
|
+
}
|
|
8
|
+
declare class SvgMultiPageNotSpecifiedError extends Error {
|
|
9
|
+
readonly pageCount: number;
|
|
10
|
+
constructor(pageCount: number);
|
|
11
|
+
}
|
|
12
|
+
declare class SvgPageNotFoundError extends Error {
|
|
13
|
+
readonly page: number;
|
|
14
|
+
readonly pageCount: number;
|
|
15
|
+
constructor(page: number, pageCount: number);
|
|
16
|
+
}
|
|
17
|
+
interface BuildSvgTextOptions {
|
|
18
|
+
readonly page?: number;
|
|
19
|
+
readonly onSvgDiagnostic?: SvgDiagnosticSink;
|
|
20
|
+
}
|
|
21
|
+
declare function buildSvgText(content: ContentDocument, options?: BuildSvgTextOptions): string;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { BuildSvgTextOptions, SvgMultiPageNotSpecifiedError, SvgPageNotFoundError, SvgUnsupportedDocumentKindError, buildSvgText };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { SvgDiagnosticSink } from "./diagnostics.js";
|
|
2
|
+
import { ContentDocument } from "document-schema.js";
|
|
3
|
+
//#region src/svg/write.d.ts
|
|
4
|
+
declare class SvgUnsupportedDocumentKindError extends Error {
|
|
5
|
+
readonly kind: ContentDocument['kind'];
|
|
6
|
+
constructor(kind: ContentDocument['kind']);
|
|
7
|
+
}
|
|
8
|
+
declare class SvgMultiPageNotSpecifiedError extends Error {
|
|
9
|
+
readonly pageCount: number;
|
|
10
|
+
constructor(pageCount: number);
|
|
11
|
+
}
|
|
12
|
+
declare class SvgPageNotFoundError extends Error {
|
|
13
|
+
readonly page: number;
|
|
14
|
+
readonly pageCount: number;
|
|
15
|
+
constructor(page: number, pageCount: number);
|
|
16
|
+
}
|
|
17
|
+
interface BuildSvgTextOptions {
|
|
18
|
+
readonly page?: number;
|
|
19
|
+
readonly onSvgDiagnostic?: SvgDiagnosticSink;
|
|
20
|
+
}
|
|
21
|
+
declare function buildSvgText(content: ContentDocument, options?: BuildSvgTextOptions): string;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { BuildSvgTextOptions, SvgMultiPageNotSpecifiedError, SvgPageNotFoundError, SvgUnsupportedDocumentKindError, buildSvgText };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { buildSvgPathData, buildSvgViewBox, formatPathNumber } from "../edit/odg/svg-path.js";
|
|
2
|
+
import { mergeByPaintOrder } from "../model/paint-order.js";
|
|
3
|
+
import { colorToRgbHex } from "document-schema.js";
|
|
4
|
+
import { encodeXmlText } from "odf.js";
|
|
5
|
+
//#region src/svg/write.ts
|
|
6
|
+
var SvgUnsupportedDocumentKindError = class extends Error {
|
|
7
|
+
kind;
|
|
8
|
+
constructor(kind) {
|
|
9
|
+
super(`buildSvgText: expected a drawing ContentDocument, got kind '${kind}'`);
|
|
10
|
+
this.name = "SvgUnsupportedDocumentKindError";
|
|
11
|
+
this.kind = kind;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var SvgMultiPageNotSpecifiedError = class extends Error {
|
|
15
|
+
pageCount;
|
|
16
|
+
constructor(pageCount) {
|
|
17
|
+
super(`buildSvgText: this document has more than one page (${pageCount}) -- pass { page: <index> } to select one`);
|
|
18
|
+
this.name = "SvgMultiPageNotSpecifiedError";
|
|
19
|
+
this.pageCount = pageCount;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var SvgPageNotFoundError = class extends Error {
|
|
23
|
+
page;
|
|
24
|
+
pageCount;
|
|
25
|
+
constructor(page, pageCount) {
|
|
26
|
+
super(`buildSvgText: page index ${page} not found -- the document has ${pageCount} page(s)`);
|
|
27
|
+
this.name = "SvgPageNotFoundError";
|
|
28
|
+
this.page = page;
|
|
29
|
+
this.pageCount = pageCount;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
function selectPage(pages, page) {
|
|
33
|
+
if (page !== void 0) {
|
|
34
|
+
const found = pages[page];
|
|
35
|
+
if (found === void 0) throw new SvgPageNotFoundError(page, pages.length);
|
|
36
|
+
return found;
|
|
37
|
+
}
|
|
38
|
+
if (pages.length === 0) throw new SvgPageNotFoundError(0, 0);
|
|
39
|
+
if (pages.length > 1) throw new SvgMultiPageNotSpecifiedError(pages.length);
|
|
40
|
+
return pages[0];
|
|
41
|
+
}
|
|
42
|
+
const DASHED_PATTERN = "6 4";
|
|
43
|
+
const DOTTED_PATTERN = "1 3";
|
|
44
|
+
function svgColor(fill) {
|
|
45
|
+
return `#${colorToRgbHex(fill)}`;
|
|
46
|
+
}
|
|
47
|
+
function fillAttr(fill) {
|
|
48
|
+
return fill === void 0 ? " fill=\"none\"" : ` fill="${svgColor(fill)}"`;
|
|
49
|
+
}
|
|
50
|
+
function strokeAttr(vector, stroke, sink) {
|
|
51
|
+
let attrs = ` stroke="${svgColor(stroke.color)}" stroke-width="${formatPathNumber(stroke.widthPt)}"`;
|
|
52
|
+
if (stroke.style === "dashed") attrs += ` stroke-dasharray="${DASHED_PATTERN}"`;
|
|
53
|
+
else if (stroke.style === "dotted") attrs += ` stroke-dasharray="${DOTTED_PATTERN}" stroke-linecap="round"`;
|
|
54
|
+
else if (stroke.style === "double") sink?.({
|
|
55
|
+
code: "svg/stroke-style-unsupported",
|
|
56
|
+
detail: `${vector.sourcePath ?? vector.kind}: stroke style 'double' written as solid`
|
|
57
|
+
});
|
|
58
|
+
return attrs;
|
|
59
|
+
}
|
|
60
|
+
function rotationAttr(rotationDeg, frame) {
|
|
61
|
+
if (rotationDeg === void 0 || rotationDeg === 0) return "";
|
|
62
|
+
const cx = frame.xPt + frame.widthPt / 2;
|
|
63
|
+
const cy = frame.yPt + frame.heightPt / 2;
|
|
64
|
+
return ` transform="rotate(${formatPathNumber(rotationDeg)} ${formatPathNumber(cx)} ${formatPathNumber(cy)})"`;
|
|
65
|
+
}
|
|
66
|
+
function offsetSubpaths(subpaths, offsetX, offsetY) {
|
|
67
|
+
const offsetPoint = (point) => ({
|
|
68
|
+
xPt: point.xPt + offsetX,
|
|
69
|
+
yPt: point.yPt + offsetY
|
|
70
|
+
});
|
|
71
|
+
return subpaths.map((subpath) => ({
|
|
72
|
+
start: offsetPoint(subpath.start),
|
|
73
|
+
closed: subpath.closed,
|
|
74
|
+
segments: subpath.segments.map((segment) => segment.kind === "line" ? {
|
|
75
|
+
kind: "line",
|
|
76
|
+
to: offsetPoint(segment.to)
|
|
77
|
+
} : {
|
|
78
|
+
kind: "cubic",
|
|
79
|
+
control1: offsetPoint(segment.control1),
|
|
80
|
+
control2: offsetPoint(segment.control2),
|
|
81
|
+
to: offsetPoint(segment.to)
|
|
82
|
+
})
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
function vectorElement(vector, sink) {
|
|
86
|
+
switch (vector.kind) {
|
|
87
|
+
case "rect": return `<rect x="${formatPathNumber(vector.frame.xPt)}" y="${formatPathNumber(vector.frame.yPt)}" width="${formatPathNumber(vector.frame.widthPt)}" height="${formatPathNumber(vector.frame.heightPt)}"${fillAttr(vector.fill)}${vector.stroke === void 0 ? "" : strokeAttr(vector, vector.stroke, sink)}${rotationAttr(vector.rotationDeg, vector.frame)}/>`;
|
|
88
|
+
case "ellipse": {
|
|
89
|
+
const cx = vector.frame.xPt + vector.frame.widthPt / 2;
|
|
90
|
+
const cy = vector.frame.yPt + vector.frame.heightPt / 2;
|
|
91
|
+
const rx = vector.frame.widthPt / 2;
|
|
92
|
+
const ry = vector.frame.heightPt / 2;
|
|
93
|
+
return `<ellipse cx="${formatPathNumber(cx)}" cy="${formatPathNumber(cy)}" rx="${formatPathNumber(rx)}" ry="${formatPathNumber(ry)}"${fillAttr(vector.fill)}${vector.stroke === void 0 ? "" : strokeAttr(vector, vector.stroke, sink)}${rotationAttr(vector.rotationDeg, vector.frame)}/>`;
|
|
94
|
+
}
|
|
95
|
+
case "line": return `<line x1="${formatPathNumber(vector.from.xPt)}" y1="${formatPathNumber(vector.from.yPt)}" x2="${formatPathNumber(vector.to.xPt)}" y2="${formatPathNumber(vector.to.yPt)}"${strokeAttr(vector, vector.stroke, sink)}/>`;
|
|
96
|
+
case "path": {
|
|
97
|
+
const d = buildSvgPathData(offsetSubpaths(vector.subpaths, vector.frame.xPt, vector.frame.yPt));
|
|
98
|
+
const fillRule = vector.fillRule === "evenodd" ? " fill-rule=\"evenodd\"" : "";
|
|
99
|
+
return `<path d="${d}"${fillAttr(vector.fill)}${vector.stroke === void 0 ? "" : strokeAttr(vector, vector.stroke, sink)}${fillRule}${rotationAttr(vector.rotationDeg, vector.frame)}/>`;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function shapeDetail(shape) {
|
|
104
|
+
return shape.name ?? shape.sourcePath ?? "shape";
|
|
105
|
+
}
|
|
106
|
+
function buildSvgText(content, options) {
|
|
107
|
+
if (content.kind !== "drawing") throw new SvgUnsupportedDocumentKindError(content.kind);
|
|
108
|
+
const sink = options?.onSvgDiagnostic;
|
|
109
|
+
const page = selectPage(content.pages, options?.page);
|
|
110
|
+
const lines = [];
|
|
111
|
+
lines.push("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
|
112
|
+
lines.push(`<svg xmlns="http://www.w3.org/2000/svg" width="${formatPathNumber(page.size.widthPt)}pt" height="${formatPathNumber(page.size.heightPt)}pt" viewBox="${buildSvgViewBox(page.size.widthPt, page.size.heightPt)}">`);
|
|
113
|
+
if (content.metadata.title !== void 0 && content.metadata.title !== "") lines.push(` <title>${encodeXmlText(content.metadata.title)}</title>`);
|
|
114
|
+
for (const entry of mergeByPaintOrder(page.vectors, page.shapes)) if (entry.kind === "vector") lines.push(` ${vectorElement(entry.value, sink)}`);
|
|
115
|
+
else sink?.({
|
|
116
|
+
code: "svg/shape-unsupported",
|
|
117
|
+
detail: `${shapeDetail(entry.value)}: draw:frame text/image/table content has no SVG vector representation`
|
|
118
|
+
});
|
|
119
|
+
lines.push("</svg>");
|
|
120
|
+
return `${lines.join("\n")}\n`;
|
|
121
|
+
}
|
|
122
|
+
//#endregion
|
|
123
|
+
export { SvgMultiPageNotSpecifiedError, SvgPageNotFoundError, SvgUnsupportedDocumentKindError, buildSvgText };
|
package/dist/xml/odf-text.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { el, txt } from "./fragment.js";
|
|
2
|
-
import { encodeXmlText } from "./entities.js";
|
|
2
|
+
import { encodeXmlText as encodeXmlText$1 } from "./entities.js";
|
|
3
3
|
import { decodeOdfText as decodeOdfText$1 } from "odf.js";
|
|
4
4
|
//#region src/xml/odf-text.ts
|
|
5
5
|
const MIN_SPACE_RUN_FOR_TEXT_S = 2;
|
|
@@ -8,7 +8,7 @@ function encodeOdfText(text) {
|
|
|
8
8
|
let literal = "";
|
|
9
9
|
const flushLiteral = () => {
|
|
10
10
|
if (literal.length > 0) {
|
|
11
|
-
nodes.push(txt(encodeXmlText(literal)));
|
|
11
|
+
nodes.push(txt(encodeXmlText$1(literal)));
|
|
12
12
|
literal = "";
|
|
13
13
|
}
|
|
14
14
|
};
|
package/package.json
CHANGED