@docx4j/core-ts 0.5.0 → 0.7.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/NOTICE +4 -0
- package/README.md +92 -4
- package/dist/html/convert.mjs +2 -1
- package/dist/html/elements.mjs +2 -1
- package/dist/model/color/ColorMath.d.mts +29 -0
- package/dist/model/color/ColorMath.mjs +146 -0
- package/dist/model/color/ColorTables.d.mts +6 -0
- package/dist/model/color/ColorTables.mjs +83 -0
- package/dist/model/color/DrawingMLColors.d.mts +52 -0
- package/dist/model/color/DrawingMLColors.mjs +374 -0
- package/dist/model/color/ResolvedColor.d.mts +36 -0
- package/dist/model/color/ResolvedColor.mjs +65 -0
- package/dist/model/color/SpreadsheetColors.d.mts +36 -0
- package/dist/model/color/SpreadsheetColors.mjs +84 -0
- package/dist/model/color/StyleFill.d.mts +28 -0
- package/dist/model/color/StyleFill.mjs +21 -0
- package/dist/model/color/ThemeColors.d.mts +86 -0
- package/dist/model/color/ThemeColors.mjs +304 -0
- package/dist/model/color/WordColors.d.mts +71 -0
- package/dist/model/color/WordColors.mjs +121 -0
- package/dist/model/color/index.d.mts +6 -0
- package/dist/model/color/index.mjs +30 -0
- package/dist/model/content/Body.d.mts +145 -23
- package/dist/model/content/Body.mjs +507 -150
- package/dist/model/content/Comment.d.mts +23 -5
- package/dist/model/content/Comment.mjs +207 -26
- package/dist/model/content/ContentControl.d.mts +198 -19
- package/dist/model/content/ContentControl.mjs +672 -99
- package/dist/model/content/Font.d.mts +70 -17
- package/dist/model/content/Font.mjs +119 -36
- package/dist/model/content/InlinePicture.d.mts +11 -0
- package/dist/model/content/InlinePicture.mjs +21 -1
- package/dist/model/content/List.d.mts +6 -3
- package/dist/model/content/List.mjs +18 -8
- package/dist/model/content/Paragraph.d.mts +200 -14
- package/dist/model/content/Paragraph.mjs +898 -82
- package/dist/model/content/Range.d.mts +227 -12
- package/dist/model/content/Range.mjs +785 -59
- package/dist/model/content/ResolvedView.d.mts +104 -0
- package/dist/model/content/ResolvedView.mjs +596 -0
- package/dist/model/content/Table.d.mts +29 -3
- package/dist/model/content/Table.mjs +135 -49
- package/dist/model/content/TrackedChange.d.mts +174 -15
- package/dist/model/content/TrackedChange.mjs +734 -170
- package/dist/model/content/comments.d.mts +20 -6
- package/dist/model/content/comments.mjs +67 -57
- package/dist/model/content/generalException.d.mts +18 -0
- package/dist/model/content/generalException.mjs +24 -0
- package/dist/model/content/index.d.mts +10 -3
- package/dist/model/content/index.mjs +10 -2
- package/dist/model/content/mathText.d.mts +21 -0
- package/dist/model/content/mathText.mjs +267 -0
- package/dist/model/content/officeText.d.mts +27 -0
- package/dist/model/content/officeText.mjs +74 -0
- package/dist/model/content/ooxml.mjs +12 -1
- package/dist/model/content/outline.d.mts +5 -0
- package/dist/model/content/outline.mjs +13 -0
- package/dist/model/content/paraIds.d.mts +5 -0
- package/dist/model/content/paraIds.mjs +54 -0
- package/dist/model/content/placeholders.d.mts +110 -0
- package/dist/model/content/placeholders.mjs +253 -0
- package/dist/model/content/search.d.mts +74 -0
- package/dist/model/content/search.mjs +255 -9
- package/dist/model/content/spanEdits.d.mts +159 -0
- package/dist/model/content/spanEdits.mjs +728 -0
- package/dist/model/content/story.d.mts +47 -0
- package/dist/model/content/story.mjs +95 -0
- package/dist/model/content/tableColumns.d.mts +1 -1
- package/dist/model/content/tableColumns.mjs +108 -80
- package/dist/model/content/tableRevisions.d.mts +11 -3
- package/dist/model/content/tableRevisions.mjs +72 -42
- package/dist/model/content/tableRules.d.mts +30 -0
- package/dist/model/content/tableRules.mjs +102 -0
- package/dist/model/content/textBoxes.d.mts +18 -0
- package/dist/model/content/textBoxes.mjs +105 -0
- package/dist/model/content/trackedChangeFilter.d.mts +39 -0
- package/dist/model/content/trackedChangeFilter.mjs +81 -0
- package/dist/model/content/tracking.d.mts +63 -6
- package/dist/model/content/tracking.mjs +242 -22
- package/dist/model/content/tree.d.mts +172 -24
- package/dist/model/content/tree.mjs +328 -54
- package/dist/model/content/wordRange.d.mts +48 -0
- package/dist/model/content/wordRange.mjs +97 -0
- package/dist/model/customxml/CustomXmlPartCollection.d.mts +30 -1
- package/dist/model/customxml/CustomXmlPartCollection.mjs +81 -12
- package/dist/model/customxml/XmlMapping.d.mts +32 -8
- package/dist/model/customxml/XmlMapping.mjs +64 -10
- package/dist/model/customxml/bindings.d.mts +33 -4
- package/dist/model/customxml/bindings.mjs +171 -45
- package/dist/model/customxml/index.d.mts +1 -0
- package/dist/model/customxml/index.mjs +1 -0
- package/dist/model/customxml/kinds.d.mts +8 -3
- package/dist/model/customxml/kinds.mjs +26 -5
- package/dist/model/customxml/opendope.d.mts +4 -1
- package/dist/model/customxml/opendope.mjs +9 -6
- package/dist/model/customxml/picturePlaceholder.d.mts +17 -0
- package/dist/model/customxml/picturePlaceholder.mjs +32 -0
- package/dist/model/customxml/pictures.d.mts +4 -3
- package/dist/model/customxml/pictures.mjs +22 -8
- package/dist/model/customxml/storeItems.d.mts +57 -0
- package/dist/model/customxml/storeItems.mjs +122 -0
- package/dist/model/customxml/xhtml.mjs +23 -22
- package/dist/model/dateZone.d.mts +25 -0
- package/dist/model/dateZone.mjs +57 -0
- package/dist/model/index.d.mts +3 -0
- package/dist/model/index.mjs +5 -0
- package/dist/model/listnumbering/Emulator.d.mts +37 -5
- package/dist/model/listnumbering/Emulator.mjs +63 -9
- package/dist/model/properties/PropertyResolver.d.mts +74 -2
- package/dist/model/properties/PropertyResolver.mjs +133 -5
- package/dist/model/properties/catalogue.d.mts +19 -5
- package/dist/model/properties/catalogue.mjs +41 -15
- package/dist/model/properties/index.d.mts +1 -1
- package/dist/model/properties/log.d.mts +1 -1
- package/dist/model/properties/log.mjs +5 -5
- package/dist/model/properties/styleUtil.d.mts +3 -1
- package/dist/model/properties/styleUtil.mjs +20 -24
- package/dist/model/properties/table.mjs +4 -2
- package/dist/model/text/CaseMapping.d.mts +38 -0
- package/dist/model/text/CaseMapping.mjs +86 -0
- package/dist/model/text/Extractor.d.mts +349 -0
- package/dist/model/text/Extractor.mjs +2406 -0
- package/dist/model/text/LinkTargets.d.mts +45 -0
- package/dist/model/text/LinkTargets.mjs +170 -0
- package/dist/model/text/MarkdownExporter.d.mts +140 -0
- package/dist/model/text/MarkdownExporter.mjs +255 -0
- package/dist/model/text/PlainText.d.mts +29 -0
- package/dist/model/text/PlainText.mjs +542 -0
- package/dist/model/text/TextContext.d.mts +256 -0
- package/dist/model/text/TextContext.mjs +600 -0
- package/dist/model/text/TextOptions.d.mts +233 -0
- package/dist/model/text/TextOptions.mjs +419 -0
- package/dist/model/text/TextResult.d.mts +621 -0
- package/dist/model/text/TextResult.mjs +629 -0
- package/dist/model/text/Texts.d.mts +99 -0
- package/dist/model/text/Texts.mjs +187 -0
- package/dist/model/text/WmlToMarkdown.d.mts +120 -0
- package/dist/model/text/WmlToMarkdown.mjs +936 -0
- package/dist/model/text/caseMapping.generated.d.mts +7 -0
- package/dist/model/text/caseMapping.generated.mjs +214 -0
- package/dist/model/text/commonmark.d.mts +121 -0
- package/dist/model/text/commonmark.mjs +655 -0
- package/dist/model/text/index.d.mts +8 -0
- package/dist/model/text/index.mjs +9 -0
- package/dist/model/text/normalize.d.mts +8 -0
- package/dist/model/text/normalize.mjs +13 -0
- package/dist/model/text/outline.d.mts +4 -0
- package/dist/model/text/outline.mjs +71 -0
- package/dist/model/wordIntegers.d.mts +29 -0
- package/dist/model/wordIntegers.mjs +78 -0
- package/dist/office-js/document.mjs +15 -1
- package/dist/office-js/fragment.d.mts +7 -5
- package/dist/office-js/fragment.mjs +63 -14
- package/dist/office-js/proxy.d.mts +8 -0
- package/dist/office-js/proxy.mjs +29 -0
- package/dist/office-js/run.mjs +2 -0
- package/dist/office-js/supported.generated.mjs +16 -0
- package/dist/office-js/toApiScript.mjs +29 -12
- package/dist/opc/DirectoryPartStore.d.mts +6 -2
- package/dist/opc/DirectoryPartStore.mjs +11 -4
- package/dist/opc/FlatOpcPartStore.d.mts +4 -2
- package/dist/opc/FlatOpcPartStore.mjs +11 -8
- package/dist/opc/Load.d.mts +32 -0
- package/dist/opc/Load.mjs +115 -5
- package/dist/opc/PartStore.d.mts +34 -1
- package/dist/opc/PartStore.mjs +71 -8
- package/dist/opc/Save.d.mts +32 -0
- package/dist/opc/Save.mjs +110 -4
- package/dist/opc/ZipPartStore.d.mts +4 -2
- package/dist/opc/ZipPartStore.mjs +12 -7
- package/dist/opc/exceptions.d.mts +140 -0
- package/dist/opc/exceptions.mjs +108 -0
- package/dist/opc/index.d.mts +8 -5
- package/dist/opc/index.mjs +5 -3
- package/dist/opc/mce/preprocessor.d.mts +141 -5
- package/dist/opc/mce/preprocessor.mjs +119 -18
- package/dist/opc/mce/understood.d.mts +3 -11
- package/dist/opc/mce/understood.mjs +27 -23
- package/dist/opc/repair/breaks.d.mts +23 -0
- package/dist/opc/repair/breaks.mjs +288 -0
- package/dist/opc/repair/hosts.d.mts +12 -0
- package/dist/opc/repair/hosts.mjs +33 -0
- package/dist/opc/repair/mainRoot.d.mts +19 -0
- package/dist/opc/repair/mainRoot.mjs +168 -0
- package/dist/opc/repair/unknownElements.d.mts +8 -0
- package/dist/opc/repair/unknownElements.mjs +180 -0
- package/dist/opc/repair/wmlNames.generated.d.mts +2 -0
- package/dist/opc/repair/wmlNames.generated.mjs +80 -0
- package/dist/opc/skipped.d.mts +50 -0
- package/dist/opc/skipped.mjs +140 -0
- package/dist/packages/OpcPackage.d.mts +110 -4
- package/dist/packages/OpcPackage.mjs +123 -7
- package/dist/packages/WordprocessingMLPackage.d.mts +45 -8
- package/dist/packages/WordprocessingMLPackage.mjs +158 -21
- package/dist/packages/index.d.mts +1 -1
- package/dist/parts/DefaultXmlPart.mjs +2 -2
- package/dist/parts/Part.d.mts +14 -2
- package/dist/parts/RelationshipsPart.d.mts +15 -0
- package/dist/parts/RelationshipsPart.mjs +66 -1
- package/dist/parts/XmlPart.d.mts +63 -32
- package/dist/parts/XmlPart.mjs +240 -96
- package/dist/parts/wml/comments.mjs +30 -0
- package/dist/parts/wml/index.d.mts +12 -1
- package/dist/parts/wml/index.mjs +37 -1
- package/dist/xml/dom.d.mts +7 -0
- package/dist/xml/dom.mjs +18 -0
- package/package.json +2 -2
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type * as dml from '@docx4j/generated-objects-ts/modules/org_docx4j_dml';
|
|
2
|
+
import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
|
|
3
|
+
import type * as chart from '@docx4j/generated-objects-ts/modules/org_docx4j_dml_chart';
|
|
4
|
+
import { Part } from '../../parts/Part.mjs';
|
|
5
|
+
import type { XmlPart } from '../../parts/XmlPart.mjs';
|
|
6
|
+
import type { OpcPackage } from '../../packages/OpcPackage.mjs';
|
|
7
|
+
import { type DefaultTheme } from '../fonts/defaultTheme.mjs';
|
|
8
|
+
import { ResolvedColor } from './ResolvedColor.mjs';
|
|
9
|
+
/**
|
|
10
|
+
* A theme's colour scheme and the colour map that leads to it: all a colour reference needs. Immutable; each
|
|
11
|
+
* `with...` returns a new one. Which theme and which map apply depends on the host: {@link ThemeColors.of} takes a
|
|
12
|
+
* package (docx or xlsx) or a part (a slide, layout, master or notes part; a part of a docx or xlsx), and
|
|
13
|
+
* {@link ThemeColors.forChart} a chart in any of them - drawn in its host's theme.
|
|
14
|
+
*
|
|
15
|
+
* The scheme's slots are `dk1`, `lt1`, `dk2`, `lt2`, `accent1` to `accent6`, `hlink` and `folHlink`; the map takes
|
|
16
|
+
* `bg1`, `tx1`, `bg2`, `tx2` (and, in principle, the accents and hyperlinks) to a slot. A slot holding a system
|
|
17
|
+
* colour is the machine's colour, not its `lastClr` (docx4j CR-034 section 11).
|
|
18
|
+
*
|
|
19
|
+
* docx4j's names, but: `of(Theme)` is {@link ThemeColors.ofTheme} here (synchronous), and `of(WordprocessingMLPackage)`,
|
|
20
|
+
* `of(SpreadsheetMLPackage)` and `of(Part)` are one asynchronous {@link ThemeColors.of}; `forChart(Chart)` is
|
|
21
|
+
* asynchronous; `getFormatScheme()` and `getPlaceholder()` are the properties `formatScheme` and `placeholder`.
|
|
22
|
+
*/
|
|
23
|
+
export declare class ThemeColors {
|
|
24
|
+
private readonly slots;
|
|
25
|
+
private readonly map;
|
|
26
|
+
/** The theme's format scheme, which style references index into; undefined where the theme has none. */
|
|
27
|
+
readonly formatScheme: dml.CTStyleMatrix | undefined;
|
|
28
|
+
/** `phClr`'s colour, where a style reference supplies one. */
|
|
29
|
+
readonly placeholder: ResolvedColor | undefined;
|
|
30
|
+
private constructor();
|
|
31
|
+
/**
|
|
32
|
+
* A theme with the default colour map (docx4j `of(Theme)`).
|
|
33
|
+
*
|
|
34
|
+
* @param theme undefined for the theme Office supplies where a package has none: the bundled theme `defaultTheme`
|
|
35
|
+
* names, else {@link defaultThemeSetting}'s. Parsing it needs the objects package's context, which is built once
|
|
36
|
+
* anything has been read; {@link ThemeColors.loadDefaultTheme} builds it.
|
|
37
|
+
*/
|
|
38
|
+
static ofTheme(theme: dml.Theme | undefined, defaultTheme?: DefaultTheme): ThemeColors;
|
|
39
|
+
/** Parses a bundled theme ahead of a synchronous {@link ThemeColors.ofTheme}(undefined), building the context if need be. */
|
|
40
|
+
static loadDefaultTheme(defaultTheme?: DefaultTheme): Promise<dml.Theme>;
|
|
41
|
+
/**
|
|
42
|
+
* The theme colours of a package or a part:
|
|
43
|
+
* - a docx: the main document part's theme (or the default theme) and `w:clrSchemeMapping` from the settings,
|
|
44
|
+
* which applies to WordprocessingML theme colours and DrawingML scheme colours alike (docx4j CR-034 section 11, P2);
|
|
45
|
+
* - an xlsx: the workbook's theme (or the default theme), with the default map for its drawings;
|
|
46
|
+
* - a slide: its master's theme, its master's `p:clrMap`, then its layout's `p:clrMapOvr`, then its own; a layout,
|
|
47
|
+
* a master, a notes slide, a notes or handout master likewise;
|
|
48
|
+
* - a part of a docx or xlsx: its package's.
|
|
49
|
+
* Anything else, or a part that can't be read, gets the default theme with the default map.
|
|
50
|
+
*/
|
|
51
|
+
static of(source: OpcPackage | Part): Promise<ThemeColors>;
|
|
52
|
+
private static themed;
|
|
53
|
+
private static ofPart;
|
|
54
|
+
/** This theme with a DrawingML colour map (`p:clrMap`, `c:clrMapOvr`); undefined leaves it. */
|
|
55
|
+
withMapping(m: dml.CTColorMapping | undefined | null): ThemeColors;
|
|
56
|
+
/** `a:overrideClrMapping` replaces the map; `a:masterClrMapping` (or nothing) keeps it. */
|
|
57
|
+
withOverride(o: dml.CTColorMappingOverride | undefined | null): ThemeColors;
|
|
58
|
+
/** This theme with WordprocessingML's `w:clrSchemeMapping` (whose names differ: dark1, t1, ...). */
|
|
59
|
+
withWordMapping(m: wml.CTColorSchemeMapping | undefined | null): ThemeColors;
|
|
60
|
+
/** This theme with another colour scheme and format scheme (a theme override part's). */
|
|
61
|
+
withScheme(clrScheme: dml.CTColorScheme | undefined | null, fmt?: dml.CTStyleMatrix | null): ThemeColors;
|
|
62
|
+
/**
|
|
63
|
+
* A chart's colours: this (its host's) theme, under the chart's theme override part if it has one, and the
|
|
64
|
+
* chart's `c:clrMapOvr` if it states one.
|
|
65
|
+
*/
|
|
66
|
+
forChart(chartPart: XmlPart<chart.CTChartSpace>): Promise<ThemeColors>;
|
|
67
|
+
/** This theme with `phClr` standing for the given colour (a style reference's). */
|
|
68
|
+
withPlaceholder(color: ResolvedColor | undefined): ThemeColors;
|
|
69
|
+
/** A scheme slot's colour (dk1, lt1, ..., folHlink), not through the map. */
|
|
70
|
+
slot(slot: string): ResolvedColor | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* A DrawingML `schemeClr` value's colour: bg1, tx1, bg2, tx2 (and the accents and hyperlinks) through the map,
|
|
73
|
+
* dk1 ... lt2 directly, `phClr` the placeholder.
|
|
74
|
+
*/
|
|
75
|
+
schemeColor(val: string | undefined | null): ResolvedColor | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* A WordprocessingML `w:themeColor` value's colour: text1, background1, text2, background2 through the map,
|
|
78
|
+
* dark1 ... followedHyperlink directly; undefined for "none".
|
|
79
|
+
*/
|
|
80
|
+
wordThemeColor(themeColor: string | undefined | null): ResolvedColor | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* A SpreadsheetML `theme` index's colour. Excel swaps the first two pairs: 0 is lt1, 1 dk1, 2 lt2, 3 dk2, then
|
|
83
|
+
* accent1 to accent6, hlink, folHlink (docx4j CR-034 section 11, P4).
|
|
84
|
+
*/
|
|
85
|
+
sheetThemeColor(index: number): ResolvedColor | undefined;
|
|
86
|
+
}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { getContext, getContextSync } from '@docx4j/generated-objects-ts';
|
|
2
|
+
import { Part } from '../../parts/Part.mjs';
|
|
3
|
+
import { Namespaces } from '../../parts/Namespaces.mjs';
|
|
4
|
+
import { ThemePart, ThemeOverridePart } from '../../parts/dml/index.mjs';
|
|
5
|
+
import { SlidePart, SlideLayoutPart, SlideMasterPart, NotesSlidePart, NotesMasterPart, HandoutMasterPart, } from '../../parts/pml/index.mjs';
|
|
6
|
+
import { Docx4JException } from '../../opc/exceptions.mjs';
|
|
7
|
+
import { themeOfSettings, defaultThemeSetting } from '../fonts/defaultTheme.mjs';
|
|
8
|
+
import { DrawingMLColors } from './DrawingMLColors.mjs';
|
|
9
|
+
/** The scheme's slots. */
|
|
10
|
+
const SLOTS = ['dk1', 'lt1', 'dk2', 'lt2', 'accent1', 'accent2', 'accent3', 'accent4', 'accent5', 'accent6', 'hlink', 'folHlink'];
|
|
11
|
+
/** What a colour map takes to a slot. */
|
|
12
|
+
const MAPPED = ['bg1', 'tx1', 'bg2', 'tx2', 'accent1', 'accent2', 'accent3', 'accent4', 'accent5', 'accent6', 'hlink', 'folHlink'];
|
|
13
|
+
/** WordprocessingML's names for the scheme's slots. */
|
|
14
|
+
const WORD_NAMES = new Map([
|
|
15
|
+
['dark1', 'dk1'], ['light1', 'lt1'], ['dark2', 'dk2'], ['light2', 'lt2'],
|
|
16
|
+
['accent1', 'accent1'], ['accent2', 'accent2'], ['accent3', 'accent3'], ['accent4', 'accent4'], ['accent5', 'accent5'], ['accent6', 'accent6'],
|
|
17
|
+
['hyperlink', 'hlink'], ['followedHyperlink', 'folHlink'],
|
|
18
|
+
]);
|
|
19
|
+
/** Excel's theme indexes: the first two pairs swapped (docx4j CR-034 section 11, P4). */
|
|
20
|
+
const SHEET_ORDER = ['lt1', 'dk1', 'lt2', 'dk2', 'accent1', 'accent2', 'accent3', 'accent4', 'accent5', 'accent6', 'hlink', 'folHlink'];
|
|
21
|
+
/** The default colour map: bg1 to lt1, tx1 to dk1, bg2 to lt2, tx2 to dk2, the rest to themselves. */
|
|
22
|
+
function defaultMap() {
|
|
23
|
+
const m = new Map([['bg1', 'lt1'], ['tx1', 'dk1'], ['bg2', 'lt2'], ['tx2', 'dk2']]);
|
|
24
|
+
for (let i = 4; i < MAPPED.length; i++)
|
|
25
|
+
m.set(MAPPED[i], MAPPED[i]);
|
|
26
|
+
return m;
|
|
27
|
+
}
|
|
28
|
+
function scheme(cs) {
|
|
29
|
+
const m = new Map();
|
|
30
|
+
if (cs !== undefined && cs !== null) {
|
|
31
|
+
for (const slot of SLOTS) {
|
|
32
|
+
const c = cs[slot];
|
|
33
|
+
const r = c === undefined || c === null ? undefined : DrawingMLColors.resolve(c, undefined);
|
|
34
|
+
if (r !== undefined)
|
|
35
|
+
m.set(slot, r);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return m;
|
|
39
|
+
}
|
|
40
|
+
// ------------------------------------------------------------------ the bundled themes
|
|
41
|
+
const bundled = new Map();
|
|
42
|
+
function parseTheme(context, xml) {
|
|
43
|
+
const element = context.createUnmarshaller().unmarshalString(xml);
|
|
44
|
+
return element.value;
|
|
45
|
+
}
|
|
46
|
+
/** A bundled theme, parsed; the objects package's context must be built (it is once anything has been read). */
|
|
47
|
+
function bundledThemeSync(theme) {
|
|
48
|
+
let t = bundled.get(theme.value);
|
|
49
|
+
if (t === undefined) {
|
|
50
|
+
let context;
|
|
51
|
+
try {
|
|
52
|
+
context = getContextSync();
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
throw new Docx4JException(`The default theme ${theme.value} needs the objects context: await ThemeColors.loadDefaultTheme() first`, { cause: e });
|
|
56
|
+
}
|
|
57
|
+
t = parseTheme(context, theme.xml);
|
|
58
|
+
bundled.set(theme.value, t);
|
|
59
|
+
}
|
|
60
|
+
return t;
|
|
61
|
+
}
|
|
62
|
+
async function readQuietly(part) {
|
|
63
|
+
if (part === undefined)
|
|
64
|
+
return undefined;
|
|
65
|
+
try {
|
|
66
|
+
return await part.readContents();
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** The part a relationship of this type leads to, if it is one of this class. */
|
|
73
|
+
function related(part, type, kind) {
|
|
74
|
+
const rp = part.relationshipsPart;
|
|
75
|
+
const rel = rp === null || rp === void 0 ? void 0 : rp.getRelationshipByType(type);
|
|
76
|
+
const target = rel === undefined ? undefined : rp.getPart(rel);
|
|
77
|
+
return target instanceof kind ? target : undefined;
|
|
78
|
+
}
|
|
79
|
+
const isWord = (pkg) => typeof (pkg === null || pkg === void 0 ? void 0 : pkg.getMainDocumentPart) === 'function';
|
|
80
|
+
const isSpreadsheet = (pkg) => typeof (pkg === null || pkg === void 0 ? void 0 : pkg.getWorkbookPart) === 'function';
|
|
81
|
+
/** The default theme a package names (`pkg.fonts.defaultTheme`), else the process-wide setting. */
|
|
82
|
+
function defaultThemeOfPackage(pkg) {
|
|
83
|
+
return themeOfSettings(pkg === null || pkg === void 0 ? void 0 : pkg.fonts);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A theme's colour scheme and the colour map that leads to it: all a colour reference needs. Immutable; each
|
|
87
|
+
* `with...` returns a new one. Which theme and which map apply depends on the host: {@link ThemeColors.of} takes a
|
|
88
|
+
* package (docx or xlsx) or a part (a slide, layout, master or notes part; a part of a docx or xlsx), and
|
|
89
|
+
* {@link ThemeColors.forChart} a chart in any of them - drawn in its host's theme.
|
|
90
|
+
*
|
|
91
|
+
* The scheme's slots are `dk1`, `lt1`, `dk2`, `lt2`, `accent1` to `accent6`, `hlink` and `folHlink`; the map takes
|
|
92
|
+
* `bg1`, `tx1`, `bg2`, `tx2` (and, in principle, the accents and hyperlinks) to a slot. A slot holding a system
|
|
93
|
+
* colour is the machine's colour, not its `lastClr` (docx4j CR-034 section 11).
|
|
94
|
+
*
|
|
95
|
+
* docx4j's names, but: `of(Theme)` is {@link ThemeColors.ofTheme} here (synchronous), and `of(WordprocessingMLPackage)`,
|
|
96
|
+
* `of(SpreadsheetMLPackage)` and `of(Part)` are one asynchronous {@link ThemeColors.of}; `forChart(Chart)` is
|
|
97
|
+
* asynchronous; `getFormatScheme()` and `getPlaceholder()` are the properties `formatScheme` and `placeholder`.
|
|
98
|
+
*/
|
|
99
|
+
export class ThemeColors {
|
|
100
|
+
constructor(slots, map,
|
|
101
|
+
/** The theme's format scheme, which style references index into; undefined where the theme has none. */
|
|
102
|
+
formatScheme,
|
|
103
|
+
/** `phClr`'s colour, where a style reference supplies one. */
|
|
104
|
+
placeholder) {
|
|
105
|
+
this.slots = slots;
|
|
106
|
+
this.map = map;
|
|
107
|
+
this.formatScheme = formatScheme;
|
|
108
|
+
this.placeholder = placeholder;
|
|
109
|
+
}
|
|
110
|
+
// ------------------------------------------------------------------ making one
|
|
111
|
+
/**
|
|
112
|
+
* A theme with the default colour map (docx4j `of(Theme)`).
|
|
113
|
+
*
|
|
114
|
+
* @param theme undefined for the theme Office supplies where a package has none: the bundled theme `defaultTheme`
|
|
115
|
+
* names, else {@link defaultThemeSetting}'s. Parsing it needs the objects package's context, which is built once
|
|
116
|
+
* anything has been read; {@link ThemeColors.loadDefaultTheme} builds it.
|
|
117
|
+
*/
|
|
118
|
+
static ofTheme(theme, defaultTheme) {
|
|
119
|
+
var _a;
|
|
120
|
+
theme !== null && theme !== void 0 ? theme : (theme = bundledThemeSync(defaultTheme !== null && defaultTheme !== void 0 ? defaultTheme : defaultThemeSetting()));
|
|
121
|
+
const elements = theme.themeElements;
|
|
122
|
+
return new ThemeColors(scheme(elements === null || elements === void 0 ? void 0 : elements.clrScheme), defaultMap(), (_a = elements === null || elements === void 0 ? void 0 : elements.fmtScheme) !== null && _a !== void 0 ? _a : undefined, undefined);
|
|
123
|
+
}
|
|
124
|
+
/** Parses a bundled theme ahead of a synchronous {@link ThemeColors.ofTheme}(undefined), building the context if need be. */
|
|
125
|
+
static async loadDefaultTheme(defaultTheme = defaultThemeSetting()) {
|
|
126
|
+
let t = bundled.get(defaultTheme.value);
|
|
127
|
+
if (t === undefined) {
|
|
128
|
+
t = parseTheme(await getContext(), defaultTheme.xml);
|
|
129
|
+
bundled.set(defaultTheme.value, t);
|
|
130
|
+
}
|
|
131
|
+
return t;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* The theme colours of a package or a part:
|
|
135
|
+
* - a docx: the main document part's theme (or the default theme) and `w:clrSchemeMapping` from the settings,
|
|
136
|
+
* which applies to WordprocessingML theme colours and DrawingML scheme colours alike (docx4j CR-034 section 11, P2);
|
|
137
|
+
* - an xlsx: the workbook's theme (or the default theme), with the default map for its drawings;
|
|
138
|
+
* - a slide: its master's theme, its master's `p:clrMap`, then its layout's `p:clrMapOvr`, then its own; a layout,
|
|
139
|
+
* a master, a notes slide, a notes or handout master likewise;
|
|
140
|
+
* - a part of a docx or xlsx: its package's.
|
|
141
|
+
* Anything else, or a part that can't be read, gets the default theme with the default map.
|
|
142
|
+
*/
|
|
143
|
+
static async of(source) {
|
|
144
|
+
if (source instanceof Part)
|
|
145
|
+
return ThemeColors.ofPart(source);
|
|
146
|
+
const fallback = defaultThemeOfPackage(source);
|
|
147
|
+
if (isWord(source)) {
|
|
148
|
+
const main = source.getMainDocumentPart();
|
|
149
|
+
const tc = await ThemeColors.themed(await readQuietly(main.themePart), fallback);
|
|
150
|
+
const settings = await readQuietly(main.documentSettingsPart);
|
|
151
|
+
const m = settings === null || settings === void 0 ? void 0 : settings.clrSchemeMapping;
|
|
152
|
+
return m === undefined || m === null ? tc : tc.withWordMapping(m);
|
|
153
|
+
}
|
|
154
|
+
if (isSpreadsheet(source)) {
|
|
155
|
+
return ThemeColors.themed(await readQuietly(source.getWorkbookPart().themePart), fallback);
|
|
156
|
+
}
|
|
157
|
+
return ThemeColors.themed(undefined, fallback);
|
|
158
|
+
}
|
|
159
|
+
static async themed(theme, fallback) {
|
|
160
|
+
if (theme === undefined)
|
|
161
|
+
await ThemeColors.loadDefaultTheme(fallback);
|
|
162
|
+
return ThemeColors.ofTheme(theme, fallback);
|
|
163
|
+
}
|
|
164
|
+
static async ofPart(part) {
|
|
165
|
+
const fallback = defaultThemeOfPackage(part.package);
|
|
166
|
+
try {
|
|
167
|
+
if (part instanceof SlidePart) {
|
|
168
|
+
const layout = part.slideLayoutPart;
|
|
169
|
+
const tc = layout === undefined ? await ThemeColors.themed(undefined, fallback) : await ThemeColors.ofPart(layout);
|
|
170
|
+
return tc.withOverride((await part.readContents()).clrMapOvr);
|
|
171
|
+
}
|
|
172
|
+
if (part instanceof SlideLayoutPart) {
|
|
173
|
+
const master = part.slideMasterPart;
|
|
174
|
+
const tc = master === undefined ? await ThemeColors.themed(undefined, fallback) : await ThemeColors.ofPart(master);
|
|
175
|
+
return tc.withOverride((await part.readContents()).clrMapOvr);
|
|
176
|
+
}
|
|
177
|
+
if (part instanceof SlideMasterPart || part instanceof NotesMasterPart || part instanceof HandoutMasterPart) {
|
|
178
|
+
const theme = await readQuietly(related(part, Namespaces.THEME, ThemePart));
|
|
179
|
+
return (await ThemeColors.themed(theme, fallback)).withMapping((await part.readContents()).clrMap);
|
|
180
|
+
}
|
|
181
|
+
if (part instanceof NotesSlidePart) {
|
|
182
|
+
const master = related(part, Namespaces.PRESENTATIONML_NOTES_MASTER, NotesMasterPart);
|
|
183
|
+
const tc = master === undefined ? await ThemeColors.themed(undefined, fallback) : await ThemeColors.ofPart(master);
|
|
184
|
+
return tc.withOverride((await part.readContents()).clrMapOvr);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// docx4j logs "Couldn't read the colour map of ..." and takes the default theme
|
|
189
|
+
return ThemeColors.themed(undefined, fallback);
|
|
190
|
+
}
|
|
191
|
+
const pkg = part.package;
|
|
192
|
+
if (isWord(pkg) || isSpreadsheet(pkg))
|
|
193
|
+
return ThemeColors.of(pkg);
|
|
194
|
+
return ThemeColors.themed(undefined, fallback);
|
|
195
|
+
}
|
|
196
|
+
// ------------------------------------------------------------------ deriving one
|
|
197
|
+
/** This theme with a DrawingML colour map (`p:clrMap`, `c:clrMapOvr`); undefined leaves it. */
|
|
198
|
+
withMapping(m) {
|
|
199
|
+
if (m === undefined || m === null)
|
|
200
|
+
return this;
|
|
201
|
+
const mm = new Map(this.map);
|
|
202
|
+
for (const key of MAPPED)
|
|
203
|
+
put(mm, key, m[key]);
|
|
204
|
+
return new ThemeColors(this.slots, mm, this.formatScheme, this.placeholder);
|
|
205
|
+
}
|
|
206
|
+
/** `a:overrideClrMapping` replaces the map; `a:masterClrMapping` (or nothing) keeps it. */
|
|
207
|
+
withOverride(o) {
|
|
208
|
+
return o === undefined || o === null || o.overrideClrMapping === undefined || o.overrideClrMapping === null
|
|
209
|
+
? this : this.withMapping(o.overrideClrMapping);
|
|
210
|
+
}
|
|
211
|
+
/** This theme with WordprocessingML's `w:clrSchemeMapping` (whose names differ: dark1, t1, ...). */
|
|
212
|
+
withWordMapping(m) {
|
|
213
|
+
if (m === undefined || m === null)
|
|
214
|
+
return this;
|
|
215
|
+
const mm = new Map(this.map);
|
|
216
|
+
put(mm, 'bg1', wordSlot(m.bg1));
|
|
217
|
+
put(mm, 'tx1', wordSlot(m.t1));
|
|
218
|
+
put(mm, 'bg2', wordSlot(m.bg2));
|
|
219
|
+
put(mm, 'tx2', wordSlot(m.t2));
|
|
220
|
+
put(mm, 'accent1', wordSlot(m.accent1));
|
|
221
|
+
put(mm, 'accent2', wordSlot(m.accent2));
|
|
222
|
+
put(mm, 'accent3', wordSlot(m.accent3));
|
|
223
|
+
put(mm, 'accent4', wordSlot(m.accent4));
|
|
224
|
+
put(mm, 'accent5', wordSlot(m.accent5));
|
|
225
|
+
put(mm, 'accent6', wordSlot(m.accent6));
|
|
226
|
+
put(mm, 'hlink', wordSlot(m.hyperlink));
|
|
227
|
+
put(mm, 'folHlink', wordSlot(m.followedHyperlink));
|
|
228
|
+
return new ThemeColors(this.slots, mm, this.formatScheme, this.placeholder);
|
|
229
|
+
}
|
|
230
|
+
/** This theme with another colour scheme and format scheme (a theme override part's). */
|
|
231
|
+
withScheme(clrScheme, fmt) {
|
|
232
|
+
return new ThemeColors(clrScheme === undefined || clrScheme === null ? this.slots : scheme(clrScheme), this.map, fmt === undefined || fmt === null ? this.formatScheme : fmt, this.placeholder);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* A chart's colours: this (its host's) theme, under the chart's theme override part if it has one, and the
|
|
236
|
+
* chart's `c:clrMapOvr` if it states one.
|
|
237
|
+
*/
|
|
238
|
+
async forChart(chartPart) {
|
|
239
|
+
let tc = this;
|
|
240
|
+
try {
|
|
241
|
+
const override = await readQuietly(related(chartPart, Namespaces.THEME_OVERRIDE, ThemeOverridePart));
|
|
242
|
+
if (override !== undefined)
|
|
243
|
+
tc = tc.withScheme(override.clrScheme, override.fmtScheme);
|
|
244
|
+
tc = tc.withMapping((await chartPart.readContents()).clrMapOvr);
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
// docx4j logs "Couldn't read ...'s theme override or colour map" and keeps what it has
|
|
248
|
+
}
|
|
249
|
+
return tc;
|
|
250
|
+
}
|
|
251
|
+
/** This theme with `phClr` standing for the given colour (a style reference's). */
|
|
252
|
+
withPlaceholder(color) {
|
|
253
|
+
return new ThemeColors(this.slots, this.map, this.formatScheme, color);
|
|
254
|
+
}
|
|
255
|
+
// ------------------------------------------------------------------ reading it
|
|
256
|
+
/** A scheme slot's colour (dk1, lt1, ..., folHlink), not through the map. */
|
|
257
|
+
slot(slot) {
|
|
258
|
+
return this.slots.get(slot);
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* A DrawingML `schemeClr` value's colour: bg1, tx1, bg2, tx2 (and the accents and hyperlinks) through the map,
|
|
262
|
+
* dk1 ... lt2 directly, `phClr` the placeholder.
|
|
263
|
+
*/
|
|
264
|
+
schemeColor(val) {
|
|
265
|
+
if (val === undefined || val === null)
|
|
266
|
+
return undefined;
|
|
267
|
+
if (val === 'phClr')
|
|
268
|
+
return this.placeholder;
|
|
269
|
+
const slot = this.map.get(val);
|
|
270
|
+
return this.slots.get(slot !== null && slot !== void 0 ? slot : val);
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* A WordprocessingML `w:themeColor` value's colour: text1, background1, text2, background2 through the map,
|
|
274
|
+
* dark1 ... followedHyperlink directly; undefined for "none".
|
|
275
|
+
*/
|
|
276
|
+
wordThemeColor(themeColor) {
|
|
277
|
+
if (themeColor === undefined || themeColor === null)
|
|
278
|
+
return undefined;
|
|
279
|
+
switch (themeColor) {
|
|
280
|
+
case 'text1': return this.schemeColor('tx1');
|
|
281
|
+
case 'background1': return this.schemeColor('bg1');
|
|
282
|
+
case 'text2': return this.schemeColor('tx2');
|
|
283
|
+
case 'background2': return this.schemeColor('bg2');
|
|
284
|
+
default: {
|
|
285
|
+
const slot = WORD_NAMES.get(themeColor);
|
|
286
|
+
return slot === undefined ? undefined : this.slots.get(slot);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* A SpreadsheetML `theme` index's colour. Excel swaps the first two pairs: 0 is lt1, 1 dk1, 2 lt2, 3 dk2, then
|
|
292
|
+
* accent1 to accent6, hlink, folHlink (docx4j CR-034 section 11, P4).
|
|
293
|
+
*/
|
|
294
|
+
sheetThemeColor(index) {
|
|
295
|
+
return index < 0 || index >= SHEET_ORDER.length ? undefined : this.slots.get(SHEET_ORDER[Math.trunc(index)]);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function wordSlot(i) {
|
|
299
|
+
return i === undefined || i === null ? undefined : WORD_NAMES.get(i);
|
|
300
|
+
}
|
|
301
|
+
function put(m, key, slot) {
|
|
302
|
+
if (slot !== undefined && slot !== null)
|
|
303
|
+
m.set(key, slot);
|
|
304
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
|
|
2
|
+
import { ResolvedColor } from './ResolvedColor.mjs';
|
|
3
|
+
import type { ThemeColors } from './ThemeColors.mjs';
|
|
4
|
+
/**
|
|
5
|
+
* WordprocessingML colours (`w:color`, `w:shd`, the borders, `w:u`) resolved as Word draws them (docx4j CR-034
|
|
6
|
+
* section 11, P1).
|
|
7
|
+
*
|
|
8
|
+
* - A theme reference (`w:themeColor`, `w:themeFill`) wins over the value written beside it (`w:val`, `w:color`,
|
|
9
|
+
* `w:fill`), which is a cache Word keeps: Word draws the theme colour even where the value disagrees (an older
|
|
10
|
+
* theme's, or anything else).
|
|
11
|
+
* - `w:themeTint` and `w:themeShade` change the HSL luminance: tint t, L' = L·t + (1 − t); shade t, L' = L·t, t
|
|
12
|
+
* being the byte over 255 (MS-OI29500 2.1.72). Where both are present Word applies the tint (the same note).
|
|
13
|
+
* - Word's own rounding of that arithmetic is not reproduced exactly (within one unit per channel in all 7,700 tints
|
|
14
|
+
* and shades of four corpora), so where the written value is within one unit of the computed one - a current
|
|
15
|
+
* cache - Word's value is returned: exact for every attribute Word itself wrote against the document's theme.
|
|
16
|
+
* - A value is read as Word 365 reads it ({@link WordColors.normalise}, docx4j CR-060 and core-ts CR-015): trimmed,
|
|
17
|
+
* hex in either case with an optional `#`, or one of the 140 classic HTML colour names. One Word rejects is
|
|
18
|
+
* automatic. A fill, a pattern colour and a border's colour are read the same way, as Word reads them (round 5: a
|
|
19
|
+
* name there is drawn): docx4j's `WordColors` since `a9e0303ff` (until then it normalised in `of(Color)` and `of(U)`
|
|
20
|
+
* only; CR-015 section 11.4).
|
|
21
|
+
*
|
|
22
|
+
* docx4j's overloads `of(Color)`, `of(CTBorder)` and `of(U)` are {@link WordColors.of}, {@link WordColors.ofBorder}
|
|
23
|
+
* and {@link WordColors.ofUnderline} here, since the three objects can't be told apart by shape; its `null` (for
|
|
24
|
+
* automatic) is `undefined`.
|
|
25
|
+
*/
|
|
26
|
+
export declare const WordColors: {
|
|
27
|
+
/**
|
|
28
|
+
* The colour Word draws for a WordprocessingML colour's attributes.
|
|
29
|
+
*
|
|
30
|
+
* @param val the written value: RRGGBB, "auto", or undefined
|
|
31
|
+
* @param themeColor the theme reference, or undefined (or "none")
|
|
32
|
+
* @param themeTint a byte in hex ("99"), or undefined
|
|
33
|
+
* @param themeShade a byte in hex ("BF"), or undefined
|
|
34
|
+
* @returns undefined for automatic (no theme reference and val "auto" or absent): the caller's default
|
|
35
|
+
*/
|
|
36
|
+
resolve(val: string | undefined | null, themeColor: string | undefined | null, themeTint: string | undefined | null, themeShade: string | undefined | null, theme: ThemeColors | undefined): ResolvedColor | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* A colour value (`w:color/@w:val`, `w:u/@w:color`, `w:shd/@w:fill`, a border's `w:color`) as Word 365 reads it
|
|
39
|
+
* (docx4j CR-060 section 1, rule 3, and sections 12 and 13): surrounding whitespace trimmed, six hex digits in
|
|
40
|
+
* either case with an optional leading `#`; else a classic HTML colour name, in any case. The rule is the objects
|
|
41
|
+
* package's `wordColor` (its CR-013, held to docx4j's `WordColorValues`).
|
|
42
|
+
*
|
|
43
|
+
* @returns six upper-case hex digits; undefined for `auto` and for a value Word rejects, which Word reads as
|
|
44
|
+
* automatic in a fill or a border colour, and as absent in a text or underline colour ({@link WordColors.stated})
|
|
45
|
+
*/
|
|
46
|
+
normalise(val: string | undefined | null): string | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Whether a `w:color/@w:val` or `w:u/@w:color` value states a colour, as Word reads it (docx4j CR-060 sections 12
|
|
49
|
+
* and 13): one {@link WordColors.normalise} accepts, or exactly `auto` (automatic, which overrides a style's
|
|
50
|
+
* colour). Word reads any other value (`F00`, `bogus`, `""`, `Auto`, `" auto"`) as absent: a style's colour beneath
|
|
51
|
+
* still shows. (In a fill or a border colour it reads such a value as automatic instead.)
|
|
52
|
+
*/
|
|
53
|
+
stated(val: string | undefined | null): boolean;
|
|
54
|
+
/** A run's colour (`w:color`); undefined for automatic. */
|
|
55
|
+
of(c: wml.Color | undefined | null, theme: ThemeColors | undefined): ResolvedColor | undefined;
|
|
56
|
+
/** A shading's fill (`w:fill`, `w:themeFill`); undefined for automatic. */
|
|
57
|
+
fill(shd: wml.CTShd | undefined | null, theme: ThemeColors | undefined): ResolvedColor | undefined;
|
|
58
|
+
/** A shading's pattern colour (`w:color`, `w:themeColor`); undefined for automatic. */
|
|
59
|
+
pattern(shd: wml.CTShd | undefined | null, theme: ThemeColors | undefined): ResolvedColor | undefined;
|
|
60
|
+
/** A border's colour; undefined for automatic. docx4j `of(CTBorder)`. */
|
|
61
|
+
ofBorder(border: wml.CTBorder | undefined | null, theme: ThemeColors | undefined): ResolvedColor | undefined;
|
|
62
|
+
/** An underline's colour; undefined for automatic (the text's colour). docx4j `of(U)`. */
|
|
63
|
+
ofUnderline(u: wml.U | undefined | null, theme: ThemeColors | undefined): ResolvedColor | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Word's themeTint (tint true) or themeShade on a colour: float HSL, the channels truncated. That is what Word 365
|
|
66
|
+
* draws (docx4j CR-034 section 11: the three P1 cases with no usable written value, all exact); the values older
|
|
67
|
+
* versions of Word wrote are within one unit of it (all 119 distinct ones in four corpora, 77 exact).
|
|
68
|
+
* Package-private in docx4j; public here for the corpus vectors' test.
|
|
69
|
+
*/
|
|
70
|
+
luminance(c: ResolvedColor, t: number, tint: boolean): ResolvedColor;
|
|
71
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { wordColor } from '@docx4j/generated-objects-ts/helpers/wml';
|
|
2
|
+
import * as ColorMath from './ColorMath.mjs';
|
|
3
|
+
import { ResolvedColor } from './ResolvedColor.mjs';
|
|
4
|
+
function hexByte(s) {
|
|
5
|
+
if (s === undefined || s === null || s.length === 0)
|
|
6
|
+
return undefined;
|
|
7
|
+
// Java's Integer.parseInt(s, 16): an optional sign, then hex digits
|
|
8
|
+
if (!/^[+-]?[0-9A-Fa-f]+$/.test(s))
|
|
9
|
+
return undefined;
|
|
10
|
+
const v = Number.parseInt(s, 16);
|
|
11
|
+
return v >= 0 && v <= 255 ? v : undefined;
|
|
12
|
+
}
|
|
13
|
+
function truncate(v) {
|
|
14
|
+
return Math.floor(ColorMath.clamp01(v) * 255 + 1e-9);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* WordprocessingML colours (`w:color`, `w:shd`, the borders, `w:u`) resolved as Word draws them (docx4j CR-034
|
|
18
|
+
* section 11, P1).
|
|
19
|
+
*
|
|
20
|
+
* - A theme reference (`w:themeColor`, `w:themeFill`) wins over the value written beside it (`w:val`, `w:color`,
|
|
21
|
+
* `w:fill`), which is a cache Word keeps: Word draws the theme colour even where the value disagrees (an older
|
|
22
|
+
* theme's, or anything else).
|
|
23
|
+
* - `w:themeTint` and `w:themeShade` change the HSL luminance: tint t, L' = L·t + (1 − t); shade t, L' = L·t, t
|
|
24
|
+
* being the byte over 255 (MS-OI29500 2.1.72). Where both are present Word applies the tint (the same note).
|
|
25
|
+
* - Word's own rounding of that arithmetic is not reproduced exactly (within one unit per channel in all 7,700 tints
|
|
26
|
+
* and shades of four corpora), so where the written value is within one unit of the computed one - a current
|
|
27
|
+
* cache - Word's value is returned: exact for every attribute Word itself wrote against the document's theme.
|
|
28
|
+
* - A value is read as Word 365 reads it ({@link WordColors.normalise}, docx4j CR-060 and core-ts CR-015): trimmed,
|
|
29
|
+
* hex in either case with an optional `#`, or one of the 140 classic HTML colour names. One Word rejects is
|
|
30
|
+
* automatic. A fill, a pattern colour and a border's colour are read the same way, as Word reads them (round 5: a
|
|
31
|
+
* name there is drawn): docx4j's `WordColors` since `a9e0303ff` (until then it normalised in `of(Color)` and `of(U)`
|
|
32
|
+
* only; CR-015 section 11.4).
|
|
33
|
+
*
|
|
34
|
+
* docx4j's overloads `of(Color)`, `of(CTBorder)` and `of(U)` are {@link WordColors.of}, {@link WordColors.ofBorder}
|
|
35
|
+
* and {@link WordColors.ofUnderline} here, since the three objects can't be told apart by shape; its `null` (for
|
|
36
|
+
* automatic) is `undefined`.
|
|
37
|
+
*/
|
|
38
|
+
export const WordColors = {
|
|
39
|
+
/**
|
|
40
|
+
* The colour Word draws for a WordprocessingML colour's attributes.
|
|
41
|
+
*
|
|
42
|
+
* @param val the written value: RRGGBB, "auto", or undefined
|
|
43
|
+
* @param themeColor the theme reference, or undefined (or "none")
|
|
44
|
+
* @param themeTint a byte in hex ("99"), or undefined
|
|
45
|
+
* @param themeShade a byte in hex ("BF"), or undefined
|
|
46
|
+
* @returns undefined for automatic (no theme reference and val "auto" or absent): the caller's default
|
|
47
|
+
*/
|
|
48
|
+
resolve(val, themeColor, themeTint, themeShade, theme) {
|
|
49
|
+
const written = ResolvedColor.ofHex(val);
|
|
50
|
+
if (themeColor === undefined || themeColor === null || themeColor === 'none' || theme === undefined)
|
|
51
|
+
return written;
|
|
52
|
+
// Word's value where it is a current cache: Word's own rounding, which the computation below matches for Word 365
|
|
53
|
+
// but not for every older version that wrote the file
|
|
54
|
+
const base = theme.wordThemeColor(themeColor);
|
|
55
|
+
if (base === undefined)
|
|
56
|
+
return written;
|
|
57
|
+
const tint = hexByte(themeTint), shade = hexByte(themeShade);
|
|
58
|
+
const computed = tint !== undefined ? WordColors.luminance(base, tint / 255.0, true)
|
|
59
|
+
: shade !== undefined ? WordColors.luminance(base, shade / 255.0, false) : base;
|
|
60
|
+
return written !== undefined && written.within(computed, 1) ? written : computed;
|
|
61
|
+
},
|
|
62
|
+
/**
|
|
63
|
+
* A colour value (`w:color/@w:val`, `w:u/@w:color`, `w:shd/@w:fill`, a border's `w:color`) as Word 365 reads it
|
|
64
|
+
* (docx4j CR-060 section 1, rule 3, and sections 12 and 13): surrounding whitespace trimmed, six hex digits in
|
|
65
|
+
* either case with an optional leading `#`; else a classic HTML colour name, in any case. The rule is the objects
|
|
66
|
+
* package's `wordColor` (its CR-013, held to docx4j's `WordColorValues`).
|
|
67
|
+
*
|
|
68
|
+
* @returns six upper-case hex digits; undefined for `auto` and for a value Word rejects, which Word reads as
|
|
69
|
+
* automatic in a fill or a border colour, and as absent in a text or underline colour ({@link WordColors.stated})
|
|
70
|
+
*/
|
|
71
|
+
normalise(val) {
|
|
72
|
+
const w = typeof val === 'string' ? wordColor(val) : undefined;
|
|
73
|
+
return w === undefined || w === 'auto' ? undefined : w.substring(1);
|
|
74
|
+
},
|
|
75
|
+
/**
|
|
76
|
+
* Whether a `w:color/@w:val` or `w:u/@w:color` value states a colour, as Word reads it (docx4j CR-060 sections 12
|
|
77
|
+
* and 13): one {@link WordColors.normalise} accepts, or exactly `auto` (automatic, which overrides a style's
|
|
78
|
+
* colour). Word reads any other value (`F00`, `bogus`, `""`, `Auto`, `" auto"`) as absent: a style's colour beneath
|
|
79
|
+
* still shows. (In a fill or a border colour it reads such a value as automatic instead.)
|
|
80
|
+
*/
|
|
81
|
+
stated(val) {
|
|
82
|
+
return typeof val === 'string' && wordColor(val) !== undefined;
|
|
83
|
+
},
|
|
84
|
+
/** A run's colour (`w:color`); undefined for automatic. */
|
|
85
|
+
of(c, theme) {
|
|
86
|
+
return c === undefined || c === null ? undefined
|
|
87
|
+
: WordColors.resolve(WordColors.normalise(c.val), c.themeColor, c.themeTint, c.themeShade, theme);
|
|
88
|
+
},
|
|
89
|
+
/** A shading's fill (`w:fill`, `w:themeFill`); undefined for automatic. */
|
|
90
|
+
fill(shd, theme) {
|
|
91
|
+
return shd === undefined || shd === null ? undefined
|
|
92
|
+
: WordColors.resolve(WordColors.normalise(shd.fill), shd.themeFill, shd.themeFillTint, shd.themeFillShade, theme);
|
|
93
|
+
},
|
|
94
|
+
/** A shading's pattern colour (`w:color`, `w:themeColor`); undefined for automatic. */
|
|
95
|
+
pattern(shd, theme) {
|
|
96
|
+
return shd === undefined || shd === null ? undefined
|
|
97
|
+
: WordColors.resolve(WordColors.normalise(shd.color), shd.themeColor, shd.themeTint, shd.themeShade, theme);
|
|
98
|
+
},
|
|
99
|
+
/** A border's colour; undefined for automatic. docx4j `of(CTBorder)`. */
|
|
100
|
+
ofBorder(border, theme) {
|
|
101
|
+
return border === undefined || border === null ? undefined
|
|
102
|
+
: WordColors.resolve(WordColors.normalise(border.color), border.themeColor, border.themeTint, border.themeShade, theme);
|
|
103
|
+
},
|
|
104
|
+
/** An underline's colour; undefined for automatic (the text's colour). docx4j `of(U)`. */
|
|
105
|
+
ofUnderline(u, theme) {
|
|
106
|
+
return u === undefined || u === null ? undefined
|
|
107
|
+
: WordColors.resolve(WordColors.normalise(u.color), u.themeColor, u.themeTint, u.themeShade, theme);
|
|
108
|
+
},
|
|
109
|
+
/**
|
|
110
|
+
* Word's themeTint (tint true) or themeShade on a colour: float HSL, the channels truncated. That is what Word 365
|
|
111
|
+
* draws (docx4j CR-034 section 11: the three P1 cases with no usable written value, all exact); the values older
|
|
112
|
+
* versions of Word wrote are within one unit of it (all 119 distinct ones in four corpora, 77 exact).
|
|
113
|
+
* Package-private in docx4j; public here for the corpus vectors' test.
|
|
114
|
+
*/
|
|
115
|
+
luminance(c, t, tint) {
|
|
116
|
+
const hsl = ColorMath.rgbToHsl(c.red / 255.0, c.green / 255.0, c.blue / 255.0);
|
|
117
|
+
const l = tint ? hsl[2] * t + (1 - t) : hsl[2] * t;
|
|
118
|
+
const rgb = ColorMath.hslToRgb(hsl[0], hsl[1], ColorMath.clamp01(l));
|
|
119
|
+
return ResolvedColor.rgb(truncate(rgb[0]), truncate(rgb[1]), truncate(rgb[2]));
|
|
120
|
+
},
|
|
121
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { ResolvedColor } from './ResolvedColor.mjs';
|
|
2
|
+
export { ThemeColors } from './ThemeColors.mjs';
|
|
3
|
+
export { WordColors } from './WordColors.mjs';
|
|
4
|
+
export { DrawingMLColors } from './DrawingMLColors.mjs';
|
|
5
|
+
export { SpreadsheetColors } from './SpreadsheetColors.mjs';
|
|
6
|
+
export { StyleFill, type StyleFillKind } from './StyleFill.mjs';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// CR-008 phase 2: colours as Office draws them (docx4j `org.docx4j.model.color`, its CR-034): any colour reference in
|
|
2
|
+
// a docx, pptx or xlsx resolved to the RGB value (and alpha) Word, PowerPoint or Excel draws for it.
|
|
3
|
+
//
|
|
4
|
+
// A reference resolves against a {@link ThemeColors}: a theme's colour scheme and the colour map that leads to it,
|
|
5
|
+
// made for the reference's host by `await ThemeColors.of(pkg or part)` (a docx: the main document part's theme and
|
|
6
|
+
// the settings' `w:clrSchemeMapping`, which applies to WordprocessingML theme colours and DrawingML scheme colours
|
|
7
|
+
// alike, and is `PropertyResolver.getThemeColors()`; a slide, layout, master, notes slide, notes or handout master:
|
|
8
|
+
// its master's theme with the master's `p:clrMap`, then the layout's and the slide's `p:clrMapOvr`; an xlsx: the
|
|
9
|
+
// workbook's theme; a chart, `forChart` on its host's). A package with no theme part gets the theme Office supplies,
|
|
10
|
+
// the bundled one `pkg.fonts.defaultTheme` names (Office 2023's by default).
|
|
11
|
+
//
|
|
12
|
+
// - {@link WordColors}: `w:color`, `w:shd`, the borders and `w:u`. Word draws the theme reference and keeps the
|
|
13
|
+
// value beside it as a cache, which can be stale; `w:themeTint` and `w:themeShade` change the HSL luminance, the
|
|
14
|
+
// tint winning where both are given.
|
|
15
|
+
// - {@link DrawingMLColors}: the six DrawingML colour kinds and their transforms, applied in document order; a system
|
|
16
|
+
// colour is the machine's, not its `lastClr`. A shape's style references (`a:fillRef`, `a:lnRef`, `a:fontRef`)
|
|
17
|
+
// resolve through the theme's format scheme; an entry that is not a solid fill comes back as a {@link StyleFill} of
|
|
18
|
+
// its kind, not guessed at.
|
|
19
|
+
// - {@link SpreadsheetColors}: `rgb`, `theme` (whose first four indexes Excel reads as lt1, dk1, lt2, dk2),
|
|
20
|
+
// `indexed` (the legacy palette or the workbook's `x:indexedColors`) and `tint`, in Windows' integer HLS.
|
|
21
|
+
//
|
|
22
|
+
// Each returns a {@link ResolvedColor}, or undefined for "automatic", which is the caller's default. Every rule was
|
|
23
|
+
// read from Office's own renderings (docx4j CR-034 section 11); the probes, Office's readings and the corpus tint and
|
|
24
|
+
// shade triples are this package's vectors too (`test/theme-colors/`, CR-008 section 7).
|
|
25
|
+
export { ResolvedColor } from './ResolvedColor.mjs';
|
|
26
|
+
export { ThemeColors } from './ThemeColors.mjs';
|
|
27
|
+
export { WordColors } from './WordColors.mjs';
|
|
28
|
+
export { DrawingMLColors } from './DrawingMLColors.mjs';
|
|
29
|
+
export { SpreadsheetColors } from './SpreadsheetColors.mjs';
|
|
30
|
+
export { StyleFill } from './StyleFill.mjs';
|