Compare commits
56 Commits
Author | SHA1 | Date | |
---|---|---|---|
444e7771b4 | |||
962795743c | |||
f98f852a55 | |||
e379a7fe04 | |||
022b25cfcd | |||
e20bd66663 | |||
6b8e22368b | |||
4304e82751 | |||
75715fde37 | |||
e779f6ea62 | |||
9280cdba50 | |||
8410d0c06d | |||
d47d85bdcf | |||
6ae45327fe | |||
464cd946dc | |||
cbff540b6e | |||
a8e6ba4c49 | |||
efc1ceaf1a | |||
c4ed19e589 | |||
13cf3eee5a | |||
24c159de37 | |||
7570fc2bf5 | |||
6929dee846 | |||
d4ac2a08ee | |||
010ef05ce3 | |||
fa401297da | |||
ce0e9936c3 | |||
c13e9938cf | |||
b8f97553b3 | |||
2550da199d | |||
682b679bdb | |||
e0fd7e751c | |||
9b57db4716 | |||
d23f453d28 | |||
6c28f8bab0 | |||
10b87b5a70 | |||
6b6f9d7ed4 | |||
0434d00ff7 | |||
7e3acc25b9 | |||
62ad8f12b7 | |||
a6a656f1a0 | |||
1bf36009e8 | |||
86bdf3e199 | |||
a3c796aae3 | |||
dbe0586f70 | |||
7e2538dffc | |||
c3080ff9d9 | |||
772fc8462a | |||
e194780cd1 | |||
5b80ea32d7 | |||
31b7e07ab3 | |||
939d418af1 | |||
4258dd2a2e | |||
b7334a1ab5 | |||
9229f45d59 | |||
2bd4aacdd5 |
@ -21,6 +21,7 @@
|
||||
"iife",
|
||||
"Initializable",
|
||||
"iroha",
|
||||
"JOHAB",
|
||||
"jsonify",
|
||||
"jszip",
|
||||
"NUMPAGES",
|
||||
@ -54,7 +55,8 @@
|
||||
"\\.to\\.include\\.members\\(\\[[^\\]]+]\\)",
|
||||
"/new [a-zA-Z]+\\({[^£]+}\\)/g",
|
||||
"/<element name=\"[a-z]+\"/gi",
|
||||
"/<attribute name=\"[a-z]+\"/gi"
|
||||
"/<attribute name=\"[a-z]+\"/gi",
|
||||
"/key: \".+\"/"
|
||||
],
|
||||
"ignorePaths": ["package.json", "docs/api", "*.docx", "build"],
|
||||
"allowCompoundWords": true,
|
||||
|
@ -92,6 +92,7 @@ rules:
|
||||
format:
|
||||
- camelCase
|
||||
- PascalCase
|
||||
- UPPER_CASE # for constants
|
||||
filter:
|
||||
regex: (^[a-z]+:.+)|_attr|[0-9]
|
||||
match: false
|
||||
|
12
.github/actions/install-and-build/action.yml
vendored
Normal file
12
.github/actions/install-and-build/action.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
name: Install dependencies and build ⚙️
|
||||
description: Install dependencies and build
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
run: npm ci --force
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: npm run build
|
14
.github/actions/validate-docx/action.yml
vendored
Normal file
14
.github/actions/validate-docx/action.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
name: Extract and Validate Document ⚙️
|
||||
description: Extract the document and validate the XML against the schema.
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Extract Word Document
|
||||
shell: bash
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
9
.github/workflows/default.yml
vendored
9
.github/workflows/default.yml
vendored
@ -14,10 +14,7 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@master
|
||||
- name: Install Dependencies
|
||||
run: npm ci --force
|
||||
- name: Build
|
||||
run: npm run build
|
||||
- uses: "./.github/actions/install-and-build"
|
||||
- name: Archive Production Artifact
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
@ -32,7 +29,7 @@ jobs:
|
||||
- name: Install Dependencies
|
||||
run: npm ci --force
|
||||
- name: Test
|
||||
run: npm run test.ci
|
||||
run: npm run test:ci
|
||||
- name: Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
@ -57,7 +54,7 @@ jobs:
|
||||
- name: Install Dependencies
|
||||
run: npm ci --force
|
||||
- name: Prettier
|
||||
run: npm run style
|
||||
run: npm run prettier
|
||||
cspell:
|
||||
name: CSpell
|
||||
runs-on: ubuntu-latest
|
||||
|
939
.github/workflows/demos.yml
vendored
939
.github/workflows/demos.yml
vendored
@ -8,792 +8,189 @@ on:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@master
|
||||
- name: Install Dependencies
|
||||
run: npm ci --force
|
||||
- name: Build
|
||||
run: npm run build
|
||||
- name: Archive Production Artifact
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: build
|
||||
path: build
|
||||
demos:
|
||||
name: Run Demos and Validate
|
||||
needs: [build]
|
||||
name: Demos
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@master
|
||||
- name: Install Dependencies
|
||||
run: npm ci --force
|
||||
- name: Download Artifact
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: build
|
||||
path: build
|
||||
- name: Run Demo
|
||||
- uses: actions/checkout@master
|
||||
- uses: "./.github/actions/install-and-build"
|
||||
- name: Run Demos
|
||||
run: npm run run-ts -- ./demo/1-basic.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/2-declaritive-styles.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/3-numbering-and-bullet-points.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/4-basic-table.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/5-images.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/6-page-borders.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/7-landscape.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/8-header-footer.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/9-images-in-header-and-footer.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/10-my-cv.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/11-declaritive-styles-2.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/12-scaling-images.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/13-xml-styles.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/14-page-numbers.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/15-page-break-before.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/16-multiple-sections.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/17-footnotes.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/2-declaritive-styles.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/3-numbering-and-bullet-points.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/4-basic-table.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/5-images.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/6-page-borders.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/7-landscape.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/8-header-footer.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/9-images-in-header-and-footer.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/10-my-cv.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/11-declaritive-styles-2.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/12-scaling-images.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/13-xml-styles.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/14-page-numbers.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/15-page-break-before.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/16-multiple-sections.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/17-footnotes.ts
|
||||
# element r: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}r': This element is not expected.
|
||||
# - name: Validate XML
|
||||
# uses: ChristophWurst/xmllint-action@v1
|
||||
# with:
|
||||
# xml-file: build/extracted-doc/word/document.xml
|
||||
# xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/18-image-from-buffer.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/19-export-to-base64.ts
|
||||
# - uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/18-image-from-buffer.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/19-export-to-base64.ts
|
||||
# Base 64 No longer works, abruptly. Node issue?
|
||||
# - name: Extract Word Document
|
||||
# run: npm run extract
|
||||
# - name: Validate XML
|
||||
# uses: ChristophWurst/xmllint-action@v1
|
||||
# with:
|
||||
# xml-file: build/extracted-doc/word/document.xml
|
||||
# xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/20-table-cell-borders.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/21-bookmarks.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
# - uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/20-table-cell-borders.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/21-bookmarks.ts
|
||||
# Bad ID - need numeric ID
|
||||
# - name: Validate XML
|
||||
# uses: ChristophWurst/xmllint-action@v1
|
||||
# with:
|
||||
# xml-file: build/extracted-doc/word/document.xml
|
||||
# xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/22-right-to-left-text.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/23-base64-images.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/24-images-to-table-cell.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/25-table-xml-styles.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/26-paragraph-borders.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/27-declaritive-styles-3.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/28-table-of-contents.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/29-numbered-lists.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/31-tables.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/32-merge-and-shade-table-cells.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/33-sequential-captions.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/34-floating-tables.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
# - uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/22-right-to-left-text.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/23-base64-images.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/24-images-to-table-cell.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/25-table-xml-styles.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/26-paragraph-borders.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/27-declaritive-styles-3.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/28-table-of-contents.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/29-numbered-lists.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/31-tables.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/32-merge-and-shade-table-cells.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/33-sequential-captions.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/34-floating-tables.ts
|
||||
# element tblpPr: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}tblpPr', attribute 'overlap': The attribute 'overlap' is not allowed.
|
||||
# element tblpPr: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}tblpPr': Element content is not allowed, because the content type is empty.
|
||||
# - name: Validate XML
|
||||
# uses: ChristophWurst/xmllint-action@v1
|
||||
# with:
|
||||
# xml-file: build/extracted-doc/word/document.xml
|
||||
# xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/35-hyperlinks.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/36-image-to-table-cell.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/37-images-to-header-and-footer.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/38-text-wrapping.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/39-page-numbers.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/40-line-numbers.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/41-merge-table-cells-2.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/42-restart-page-numbers.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/43-images-to-table-cell-2.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/44-multiple-columns.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/45-highlighting-text.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/46-shading-text.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/47-number-of-total-pages-section.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/48-vertical-align.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/49-table-borders.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/50-readme-demo.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/51-character-styles.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/52-japanese.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/53-chinese.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/54-custom-properties.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/55-math.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
# - uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/35-hyperlinks.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/36-image-to-table-cell.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/37-images-to-header-and-footer.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/38-text-wrapping.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/39-page-numbers.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/40-line-numbers.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/41-merge-table-cells-2.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/42-restart-page-numbers.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/43-images-to-table-cell-2.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/44-multiple-columns.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/45-highlighting-text.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/46-shading-text.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/47-number-of-total-pages-section.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/48-vertical-align.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/49-table-borders.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/50-readme-demo.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/51-character-styles.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/52-japanese.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/53-chinese.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/54-custom-properties.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/55-math.ts
|
||||
#: element subHide: Schemas validity error : Element '{http://schemas.openxmlformats.org/officeDocument/2006/math}subHide': This element is not expected. Expected is ( {http://schemas.openxmlformats.org/officeDocument/2006/math}ctrlPr ).
|
||||
#: element e: Schemas validity error : Element '{http://schemas.openxmlformats.org/officeDocument/2006/math}e': This element is not expected. Expected is ( {http://schemas.openxmlformats.org/officeDocument/2006/math}sub ).
|
||||
#: element e: Schemas validity error : Element '{http://schemas.openxmlformats.org/officeDocument/2006/math}e': This element is not expected. Expected is ( {http://schemas.openxmlformats.org/officeDocument/2006/math}sup ).
|
||||
#: element e: Schemas validity error : Element '{http://schemas.openxmlformats.org/officeDocument/2006/math}e': This element is not expected. Expected is ( {http://schemas.openxmlformats.org/officeDocument/2006/math}sub ).
|
||||
# - name: Validate XML
|
||||
# uses: ChristophWurst/xmllint-action@v1
|
||||
# with:
|
||||
# xml-file: build/extracted-doc/word/document.xml
|
||||
# xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/56-background-color.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/57-add-parent-numbered-lists.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/58-section-types.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/59-header-footer-margins.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/60-track-revisions.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
# - uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/56-background-color.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/57-add-parent-numbered-lists.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/58-section-types.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/59-header-footer-margins.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/60-track-revisions.ts
|
||||
# element r: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}r': This element is not expected.
|
||||
# - name: Validate XML
|
||||
# uses: ChristophWurst/xmllint-action@v1
|
||||
# with:
|
||||
# xml-file: build/extracted-doc/word/document.xml
|
||||
# xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/61-text-frame.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
# - uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/61-text-frame.ts
|
||||
# element left: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}left': This element is not expected. Expected is one of ( {http://schemas.openxmlformats.org/wordprocessingml/2006/main}right, {http://schemas.openxmlformats.org/wordprocessingml/2006/main}between, {http://schemas.openxmlformats.org/wordprocessingml/2006/main}bar ).
|
||||
# - name: Validate XML
|
||||
# uses: ChristophWurst/xmllint-action@v1
|
||||
# with:
|
||||
# xml-file: build/extracted-doc/word/document.xml
|
||||
# xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/62-paragraph-spacing.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/63-odd-even-header-footer.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/64-complex-numbering-text.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/65-page-sizes.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/66-fields.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
# - uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/62-paragraph-spacing.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/63-odd-even-header-footer.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/64-complex-numbering-text.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/65-page-sizes.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/66-fields.ts
|
||||
# element bookmarkStart: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}bookmarkStart', attribute '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}id': '-irrswq-ln94j4fdgdjxs' is not a valid value of the atomic type '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}ST_DecimalNumber'.
|
||||
# element bookmarkEnd: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}bookmarkEnd', attribute '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}id': '-irrswq-ln94j4fdgdjxs' is not a valid value of the atomic type '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}ST_DecimalNumber'.
|
||||
# - name: Validate XML
|
||||
# uses: ChristophWurst/xmllint-action@v1
|
||||
# with:
|
||||
# xml-file: build/extracted-doc/word/document.xml
|
||||
# xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/67-column-break.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/68-numbering-instances-and-starting-number.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/69-different-width-columns.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/70-line-numbers-suppression.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/71-page-borders-2.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/72-word-wrap.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/73-comments.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/73-comments.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
# - name: Run Demo
|
||||
# - uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/67-column-break.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/68-numbering-instances-and-starting-number.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/69-different-width-columns.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/70-line-numbers-suppression.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/71-page-borders-2.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/72-word-wrap.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/73-comments.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/74-nodejs-stream.ts
|
||||
# - uses: "./.github/actions/validate-docx"
|
||||
# run: npm run run-ts -- ./demo/75-tab-stops.ts
|
||||
# - name: Extract Word Document
|
||||
# run: npm run extract
|
||||
# - name: Validate XML
|
||||
# uses: ChristophWurst/xmllint-action@v1
|
||||
# with:
|
||||
# xml-file: build/extracted-doc/word/document.xml
|
||||
# xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/76-compatibility.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/77-side-by-side-tables.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/78-thai-distributed.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/79-table-from-data-source.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/80-thai-distributed.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/81-continuous-header.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/82-new-headers-new-section.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/83-setting-languages.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
- name: Run Demo
|
||||
run: npm run run-ts -- ./demo/84-positional-tabs.ts
|
||||
- name: Extract Word Document
|
||||
run: npm run extract
|
||||
- name: Validate XML
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: build/extracted-doc/word/document.xml
|
||||
xml-schema-file: ooxml-schemas/microsoft/wml-2010.xsd
|
||||
# - uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/76-compatibility.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/77-side-by-side-tables.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/78-thai-distributed.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/79-table-from-data-source.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/80-thai-distributed.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/81-continuous-header.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/82-new-headers-new-section.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/83-setting-languages.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
- run: npm run run-ts -- ./demo/84-positional-tabs.ts
|
||||
- uses: "./.github/actions/validate-docx"
|
||||
|
@ -45,7 +45,7 @@ const doc = new Document({
|
||||
children: [
|
||||
new TextRun("My Title "),
|
||||
new TextRun({
|
||||
children: ["Footer - Page ", PageNumber.CURRENT],
|
||||
children: ["Footer - Page ", PageNumber.CURRENT, " of ", PageNumber.TOTAL_PAGES],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
import * as fs from "fs";
|
||||
import {
|
||||
convertMillimetersToTwip,
|
||||
Document,
|
||||
HorizontalPositionAlign,
|
||||
HorizontalPositionRelativeFrom,
|
||||
@ -20,6 +21,7 @@ const doc = new Document({
|
||||
new Paragraph({
|
||||
children: [
|
||||
new ImageRun({
|
||||
type: "jpg",
|
||||
data: fs.readFileSync("./demo/images/image1.jpeg"),
|
||||
transformation: {
|
||||
width: 100,
|
||||
@ -36,17 +38,24 @@ const doc = new Document({
|
||||
new Paragraph({
|
||||
children: [
|
||||
new ImageRun({
|
||||
type: "png",
|
||||
data: fs.readFileSync("./demo/images/dog.png").toString("base64"),
|
||||
transformation: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
},
|
||||
outline: {
|
||||
type: "solidFill",
|
||||
solidFillType: "rgb",
|
||||
value: "FF0000",
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new ImageRun({
|
||||
type: "jpg",
|
||||
data: fs.readFileSync("./demo/images/cat.jpg"),
|
||||
transformation: {
|
||||
width: 100,
|
||||
@ -55,12 +64,19 @@ const doc = new Document({
|
||||
vertical: true,
|
||||
},
|
||||
},
|
||||
outline: {
|
||||
type: "solidFill",
|
||||
solidFillType: "rgb",
|
||||
value: "0000FF",
|
||||
width: convertMillimetersToTwip(600),
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new ImageRun({
|
||||
type: "bmp",
|
||||
data: fs.readFileSync("./demo/images/parrots.bmp"),
|
||||
transformation: {
|
||||
width: 150,
|
||||
@ -76,6 +92,7 @@ const doc = new Document({
|
||||
new Paragraph({
|
||||
children: [
|
||||
new ImageRun({
|
||||
type: "gif",
|
||||
data: fs.readFileSync("./demo/images/pizza.gif"),
|
||||
transformation: {
|
||||
width: 200,
|
||||
@ -91,6 +108,7 @@ const doc = new Document({
|
||||
new Paragraph({
|
||||
children: [
|
||||
new ImageRun({
|
||||
type: "gif",
|
||||
data: fs.readFileSync("./demo/images/pizza.gif"),
|
||||
transformation: {
|
||||
width: 200,
|
||||
@ -112,6 +130,7 @@ const doc = new Document({
|
||||
new Paragraph({
|
||||
children: [
|
||||
new ImageRun({
|
||||
type: "jpg",
|
||||
data: fs.readFileSync("./demo/images/cat.jpg"),
|
||||
transformation: {
|
||||
width: 200,
|
||||
@ -131,6 +150,22 @@ const doc = new Document({
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new ImageRun({
|
||||
type: "svg",
|
||||
data: fs.readFileSync("./demo/images/linux-svg.svg"),
|
||||
transformation: {
|
||||
width: 200,
|
||||
height: 200,
|
||||
},
|
||||
fallback: {
|
||||
type: "png",
|
||||
data: fs.readFileSync("./demo/images/linux-png.png"),
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -21,6 +21,8 @@ import {
|
||||
Packer,
|
||||
Paragraph,
|
||||
TextRun,
|
||||
MathLimitLower,
|
||||
MathLimitUpper,
|
||||
} from "docx";
|
||||
|
||||
const doc = new Document({
|
||||
@ -316,6 +318,23 @@ const doc = new Document({
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new Math({
|
||||
children: [
|
||||
new MathLimitUpper({
|
||||
children: [new MathRun("x")],
|
||||
limit: [new MathRun("-")],
|
||||
}),
|
||||
new MathRun("="),
|
||||
new MathLimitLower({
|
||||
children: [new MathRun("lim")],
|
||||
limit: [new MathRun("x→0")],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
import * as fs from "fs";
|
||||
import {
|
||||
AlignmentType,
|
||||
BorderStyle,
|
||||
Document,
|
||||
FrameAnchorType,
|
||||
@ -20,6 +21,7 @@ const doc = new Document({
|
||||
children: [
|
||||
new Paragraph({
|
||||
frame: {
|
||||
type: "absolute",
|
||||
position: {
|
||||
x: 1000,
|
||||
y: 3000,
|
||||
@ -30,6 +32,54 @@ const doc = new Document({
|
||||
horizontal: FrameAnchorType.MARGIN,
|
||||
vertical: FrameAnchorType.MARGIN,
|
||||
},
|
||||
},
|
||||
border: {
|
||||
top: {
|
||||
color: "auto",
|
||||
space: 1,
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 6,
|
||||
},
|
||||
bottom: {
|
||||
color: "auto",
|
||||
space: 1,
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 6,
|
||||
},
|
||||
left: {
|
||||
color: "auto",
|
||||
space: 1,
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 6,
|
||||
},
|
||||
right: {
|
||||
color: "auto",
|
||||
space: 1,
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 6,
|
||||
},
|
||||
},
|
||||
children: [
|
||||
new TextRun("Hello World"),
|
||||
new TextRun({
|
||||
text: "Foo Bar",
|
||||
bold: true,
|
||||
}),
|
||||
new TextRun({
|
||||
children: [new Tab(), "Github is the best"],
|
||||
bold: true,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
frame: {
|
||||
type: "alignment",
|
||||
width: 4000,
|
||||
height: 1000,
|
||||
anchor: {
|
||||
horizontal: FrameAnchorType.MARGIN,
|
||||
vertical: FrameAnchorType.MARGIN,
|
||||
},
|
||||
alignment: {
|
||||
x: HorizontalPositionAlign.CENTER,
|
||||
y: VerticalPositionAlign.TOP,
|
||||
@ -73,6 +123,59 @@ const doc = new Document({
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
frame: {
|
||||
type: "alignment",
|
||||
width: 4000,
|
||||
height: 1000,
|
||||
anchor: {
|
||||
horizontal: FrameAnchorType.MARGIN,
|
||||
vertical: FrameAnchorType.MARGIN,
|
||||
},
|
||||
alignment: {
|
||||
x: HorizontalPositionAlign.CENTER,
|
||||
y: VerticalPositionAlign.BOTTOM,
|
||||
},
|
||||
},
|
||||
border: {
|
||||
top: {
|
||||
color: "auto",
|
||||
space: 1,
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 6,
|
||||
},
|
||||
bottom: {
|
||||
color: "auto",
|
||||
space: 1,
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 6,
|
||||
},
|
||||
left: {
|
||||
color: "auto",
|
||||
space: 1,
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 6,
|
||||
},
|
||||
right: {
|
||||
color: "auto",
|
||||
space: 1,
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 6,
|
||||
},
|
||||
},
|
||||
alignment: AlignmentType.RIGHT,
|
||||
children: [
|
||||
new TextRun("Hello World"),
|
||||
new TextRun({
|
||||
text: "Foo Bar",
|
||||
bold: true,
|
||||
}),
|
||||
new TextRun({
|
||||
children: [new Tab(), "Github is the best"],
|
||||
bold: true,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -107,5 +107,5 @@ const doc = new Document({
|
||||
|
||||
// Used to export the file into a .docx file
|
||||
Packer.toBuffer(doc).then((buffer) => {
|
||||
fs.writeFileSync("6-numbering.docx", buffer);
|
||||
fs.writeFileSync("My Document.docx", buffer);
|
||||
});
|
||||
|
@ -18,6 +18,7 @@ const receiptTabStops = [
|
||||
const twoTabStops = [{ type: TabStopType.RIGHT, position: TabStopPosition.MAX }];
|
||||
|
||||
const doc = new Document({
|
||||
defaultTabStop: 0,
|
||||
sections: [
|
||||
{
|
||||
properties: {},
|
||||
|
@ -16,7 +16,9 @@ import {
|
||||
VerticalAlign,
|
||||
} from "docx";
|
||||
|
||||
patchDocument(fs.readFileSync("demo/assets/simple-template.docx"), {
|
||||
patchDocument({
|
||||
outputType: "nodebuffer",
|
||||
data: fs.readFileSync("demo/assets/simple-template.docx"),
|
||||
patches: {
|
||||
name: {
|
||||
type: PatchType.PARAGRAPH,
|
||||
@ -56,7 +58,11 @@ patchDocument(fs.readFileSync("demo/assets/simple-template.docx"), {
|
||||
],
|
||||
link: "https://www.google.co.uk",
|
||||
}),
|
||||
new ImageRun({ data: fs.readFileSync("./demo/images/dog.png"), transformation: { width: 100, height: 100 } }),
|
||||
new ImageRun({
|
||||
type: "png",
|
||||
data: fs.readFileSync("./demo/images/dog.png"),
|
||||
transformation: { width: 100, height: 100 },
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
@ -82,7 +88,13 @@ patchDocument(fs.readFileSync("demo/assets/simple-template.docx"), {
|
||||
},
|
||||
image_test: {
|
||||
type: PatchType.PARAGRAPH,
|
||||
children: [new ImageRun({ data: fs.readFileSync("./demo/images/image1.jpeg"), transformation: { width: 100, height: 100 } })],
|
||||
children: [
|
||||
new ImageRun({
|
||||
type: "jpg",
|
||||
data: fs.readFileSync("./demo/images/image1.jpeg"),
|
||||
transformation: { width: 100, height: 100 },
|
||||
}),
|
||||
],
|
||||
},
|
||||
table: {
|
||||
type: PatchType.DOCUMENT,
|
||||
|
@ -3,7 +3,9 @@
|
||||
import * as fs from "fs";
|
||||
import { patchDocument, PatchType, TextRun } from "docx";
|
||||
|
||||
patchDocument(fs.readFileSync("demo/assets/simple-template-2.docx"), {
|
||||
patchDocument({
|
||||
outputType: "nodebuffer",
|
||||
data: fs.readFileSync("demo/assets/simple-template-2.docx"),
|
||||
patches: {
|
||||
name: {
|
||||
type: PatchType.PARAGRAPH,
|
||||
|
@ -24,7 +24,9 @@ const patches = getPatches({
|
||||
paragraph_replace: "Lorem ipsum paragraph",
|
||||
});
|
||||
|
||||
patchDocument(fs.readFileSync("demo/assets/simple-template.docx"), {
|
||||
patchDocument({
|
||||
outputType: "nodebuffer",
|
||||
data: fs.readFileSync("demo/assets/simple-template.docx"),
|
||||
patches,
|
||||
}).then((doc) => {
|
||||
fs.writeFileSync("My Document.docx", doc);
|
||||
|
@ -22,8 +22,11 @@ const patches = getPatches({
|
||||
"first-name": "John",
|
||||
});
|
||||
|
||||
patchDocument(fs.readFileSync("demo/assets/simple-template-3.docx"), {
|
||||
patchDocument({
|
||||
outputType: "nodebuffer",
|
||||
data: fs.readFileSync("demo/assets/simple-template-3.docx"),
|
||||
patches,
|
||||
keepOriginalStyles: true,
|
||||
}).then((doc) => {
|
||||
fs.writeFileSync("My Document.docx", doc);
|
||||
});
|
||||
|
40
demo/91-custom-fonts.ts
Normal file
40
demo/91-custom-fonts.ts
Normal file
@ -0,0 +1,40 @@
|
||||
// Simple example to add text to a document
|
||||
|
||||
import * as fs from "fs";
|
||||
import { CharacterSet, Document, Packer, Paragraph, Tab, TextRun } from "docx";
|
||||
|
||||
const font = fs.readFileSync("./demo/assets/Pacifico.ttf");
|
||||
|
||||
const doc = new Document({
|
||||
sections: [
|
||||
{
|
||||
properties: {},
|
||||
children: [
|
||||
new Paragraph({
|
||||
run: {
|
||||
font: "Pacifico",
|
||||
},
|
||||
children: [
|
||||
new TextRun("Hello World"),
|
||||
new TextRun({
|
||||
text: "Foo Bar",
|
||||
bold: true,
|
||||
size: 40,
|
||||
font: "Pacifico",
|
||||
}),
|
||||
new TextRun({
|
||||
children: [new Tab(), "Github is the best"],
|
||||
bold: true,
|
||||
font: "Pacifico",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
fonts: [{ name: "Pacifico", data: font, characterSet: CharacterSet.ANSI }],
|
||||
});
|
||||
|
||||
Packer.toBuffer(doc).then((buffer) => {
|
||||
fs.writeFileSync("My Document.docx", buffer);
|
||||
});
|
44
demo/92-declarative-custom-fonts.ts
Normal file
44
demo/92-declarative-custom-fonts.ts
Normal file
@ -0,0 +1,44 @@
|
||||
// Simple example to add text to a document
|
||||
|
||||
import * as fs from "fs";
|
||||
import { Document, Packer, Paragraph, Tab, TextRun } from "docx";
|
||||
|
||||
const font = fs.readFileSync("./demo/assets/Pacifico.ttf");
|
||||
|
||||
const doc = new Document({
|
||||
styles: {
|
||||
default: {
|
||||
document: {
|
||||
run: {
|
||||
font: "Pacifico",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
sections: [
|
||||
{
|
||||
properties: {},
|
||||
children: [
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun("Hello World"),
|
||||
new TextRun({
|
||||
text: "Foo Bar",
|
||||
bold: true,
|
||||
size: 40,
|
||||
}),
|
||||
new TextRun({
|
||||
children: [new Tab(), "Github is the best"],
|
||||
bold: true,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
fonts: [{ name: "Pacifico", data: font, characterSet: "00" }],
|
||||
});
|
||||
|
||||
Packer.toBuffer(doc).then((buffer) => {
|
||||
fs.writeFileSync("My Document.docx", buffer);
|
||||
});
|
BIN
demo/assets/Pacifico.ttf
Normal file
BIN
demo/assets/Pacifico.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
demo/images/linux-png.png
Normal file
BIN
demo/images/linux-png.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
183
demo/images/linux-svg.svg
Normal file
183
demo/images/linux-svg.svg
Normal file
@ -0,0 +1,183 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="500pt" height="600pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/">
|
||||
|
||||
<defs>
|
||||
|
||||
<linearGradient id="linearGradient172">
|
||||
|
||||
<stop style="stop-color:#3f2600;stop-opacity:0.6;" offset="0" id="stop173" />
|
||||
|
||||
<stop style="stop-color:#3f2600;stop-opacity:0;" offset="1" id="stop174" />
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient167">
|
||||
|
||||
<stop style="stop-color:#ffffff;stop-opacity:0.65;" offset="0" id="stop168" />
|
||||
|
||||
<stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop169" />
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient162">
|
||||
|
||||
<stop style="stop-color:#ffa63f;stop-opacity:1;" offset="0" id="stop163" />
|
||||
|
||||
<stop style="stop-color:#ffff00;stop-opacity:1;" offset="1" id="stop164" />
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient153">
|
||||
|
||||
<stop style="stop-color:#ffeed7;stop-opacity:1;" offset="0" id="stop154" />
|
||||
|
||||
<stop style="stop-color:#bdbfc2;stop-opacity:1;" offset="1" id="stop155" /></linearGradient>
|
||||
|
||||
<linearGradient id="linearGradient138">
|
||||
|
||||
<stop style="stop-color:#ffffff;stop-opacity:0.8;" offset="0" id="stop139" />
|
||||
|
||||
<stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop140" />
|
||||
</linearGradient>
|
||||
<linearGradient xlink:href="#linearGradient138" id="linearGradient141" x1="0.47424799" y1="0.020191999" x2="0.417539" y2="0.90125799" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient142" x1="0.55880702" y1="0.031192999" x2="0.553922" y2="0.94531101" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient143" x1="0.46557701" y1="0.028819799" x2="0.41365999" y2="0.93366498" gradientUnits="objectBoundingBox"/>
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient144" x1="0.70346397" y1="0.059404202" x2="0.64553201" y2="0.94063401" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient145" x1="0.46741399" y1="-0.036155298" x2="0.86741799" y2="0.75857902" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient146" x1="0.57152498" y1="0.023441499" x2="0.57143003" y2="0.71875" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient147" x1="0.5" y1="0.0234362" x2="0.5" y2="0.8125" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient148" x1="0.50799799" y1="0.37435901" x2="0.51599997" y2="0.92820501" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient138" id="linearGradient149" x1="0.5" y1="0.131707" x2="0.50400001" y2="0.94634098" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient150" x1="-0.30509499" y1="0.099496603" x2="0.156323" y2="0.94191301" gradientUnits="objectBoundingBox" gradientTransform="matrix(-0.928523,0.283938,0.435332,0.943857,-1.91327e-7,5.49908e-8)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient151" x1="0.433979" y1="0.022184599" x2="0.487055" y2="1.02569" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient153" id="linearGradient152" x1="0.5" y1="0.89842999" x2="0.5" y2="0.40625" gradientUnits="objectBoundingBox" spreadMethod="reflect" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient153" id="linearGradient156" x1="0.43568701" y1="0.98882002" x2="0.453989" y2="0.23093501" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient153" id="linearGradient157" x1="0.49180499" y1="1.15284" x2="0.49482101" y2="0.41252401" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient153" id="linearGradient158" x1="0.51730198" y1="0.85418499" x2="0.49843901" y2="0.136172" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient153" id="linearGradient159" x1="0.46201" y1="0.87917101" x2="0.49215299" y2="0.096282303" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient162" id="linearGradient161" x1="0.50086302" y1="0.34872901" x2="0.41209599" y2="0.98558098" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient162" id="linearGradient165" x1="0.60399801" y1="0.51020199" x2="0.46399999" y2="0.98367399" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient162" id="linearGradient166" x1="0.50000501" y1="0.191616" x2="0.50800002" y2="0.97005898" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<radialGradient xlink:href="#linearGradient172" id="radialGradient171" cx="0.5" cy="0.5" fx="0.5" fy="0.5" r="0.5" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<radialGradient xlink:href="#linearGradient172" id="radialGradient176" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient153" id="linearGradient178" x1="0.94027299" y1="1.2934099" x2="0.19452" y2="-0.675295" gradientUnits="objectBoundingBox" />
|
||||
|
||||
<radialGradient xlink:href="#linearGradient172" id="radialGradient1399" gradientTransform="scale(1.045233,0.956725)" cx="446.77762" cy="1219.4125" fx="446.77762" fy="1219.4125" r="195.07191" gradientUnits="userSpaceOnUse" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient153" id="linearGradient1401" gradientUnits="userSpaceOnUse" x1="400.57785" y1="369.53015" x2="400.84448" y2="304.07886" gradientTransform="scale(0.575262,1.738339)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient138" id="linearGradient1403" gradientUnits="userSpaceOnUse" x1="303.01761" y1="237.93179" x2="297.0856" y2="330.09561" gradientTransform="scale(1.116071,0.896001)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient153" id="linearGradient1405" gradientUnits="userSpaceOnUse" gradientTransform="scale(0.816497,1.224744)" x1="378.93771" y1="278.60202" x2="380.27319" y2="243.91606" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient153" id="linearGradient1407" gradientUnits="userSpaceOnUse" x1="381.38742" y1="277.495" x2="380.5517" y2="245.68338" gradientTransform="scale(0.816497,1.224744)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient1409" gradientUnits="userSpaceOnUse" gradientTransform="scale(0.816497,1.224744)" x1="379.09573" y1="240.92712" x2="376.79556" y2="281.01636" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient1411" gradientUnits="userSpaceOnUse" x1="389.63535" y1="242.28218" x2="387.06866" y2="281.32513" gradientTransform="scale(0.816497,1.224744)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient153" id="linearGradient1413" gradientUnits="userSpaceOnUse" spreadMethod="reflect" x1="437.57941" y1="528.87177" x2="437.57941" y2="394.10361" gradientTransform="scale(0.812855,1.230232)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient153" id="linearGradient1415" gradientUnits="userSpaceOnUse" x1="375.17325" y1="419.78485" x2="377.48541" y2="324.03815" gradientTransform="scale(0.649784,1.538974)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient138" id="linearGradient1417" gradientUnits="userSpaceOnUse" x1="320.75104" y1="498.17776" x2="321.32224" y2="614.50439" gradientTransform="scale(1.074798,0.930408)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient1419" gradientUnits="userSpaceOnUse" x1="322.48257" y1="435.26761" x2="323.2514" y2="488.48251" gradientTransform="scale(1.077001,0.928504)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient1421" gradientUnits="userSpaceOnUse" x1="411.2215" y1="242.94365" x2="411.2215" y2="331.44858" gradientTransform="scale(0.571707,1.749147)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient1423" gradientUnits="userSpaceOnUse" x1="867.34546" y1="234.73897" x2="867.33453" y2="314.83911" gradientTransform="scale(0.572667,1.746214)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient162" id="linearGradient1425" gradientUnits="userSpaceOnUse" x1="236.25362" y1="657.11133" x2="212.5099" y2="737.41229" gradientTransform="scale(1.011514,0.988617)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient153" id="linearGradient1427" gradientUnits="userSpaceOnUse" x1="381.56607" y1="655.73102" x2="279.64313" y2="386.66583" gradientTransform="scale(1.065499,0.938527)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient162" id="linearGradient1429" gradientUnits="userSpaceOnUse" x1="218.11714" y1="630.30475" x2="203.12654" y2="737.8537" gradientTransform="scale(1.009851,0.990245)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient1431" gradientUnits="userSpaceOnUse" gradientTransform="scale(1.007724,0.992335)" x1="117.88966" y1="587.23602" x2="182.24524" y2="704.73077" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient1433" gradientUnits="userSpaceOnUse" x1="223.10072" y1="570.41809" x2="230.53499" y2="710.97723" gradientTransform="scale(0.999504,1.000496)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient1435" gradientUnits="userSpaceOnUse" x1="316.93988" y1="474.01779" x2="371.60889" y2="582.63507" gradientTransform="scale(1.065499,0.938527)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient162" id="linearGradient1437" gradientUnits="userSpaceOnUse" x1="284.68652" y1="410.46326" x2="285.45923" y2="485.69934" gradientTransform="scale(1.218684,0.820557)" />
|
||||
|
||||
<linearGradient xlink:href="#linearGradient167" id="linearGradient1439" gradientUnits="userSpaceOnUse" x1="288.82358" y1="398.85422" x2="288.37628" y2="482.55939" gradientTransform="scale(1.221941,0.81837)" />
|
||||
</defs>
|
||||
|
||||
<g id="g1369" transform="translate(-310.7524,-64.25268)">
|
||||
|
||||
<path transform="matrix(1.4177,0,0,0.414745,-38.7944,222.194)" d="M 670.88202 1166.6423 A 203.89551 186.63016 0 1 1 263.091,1166.6423 A 203.89551 186.63016 0 1 1 670.88202 1166.6423 z" id="path175" style="fill:url(#radialGradient1399);stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter" />
|
||||
|
||||
<path transform="matrix(1.25,0,0,1.25,185.454,-167.505)" id="path106" d="M 223.627,632.24 C 201.239,600.017 196.873,495.256 249.114,430.81 C 275,399.892 281.604,378.345 283.645,349.417 C 285.034,316.438 260.32,217.975 353.528,210.473 C 447.934,202.941 442.864,296.133 442.321,345.448 C 441.87,387.088 472.895,410.689 494.117,443.143 C 533.396,502.773 530.074,605.443 486.718,661.015 C 431.801,730.583 384.765,700.413 353.528,702.945 C 295.035,706.147 293.101,737.336 223.627,632.24 z " style="fill:#000000;stroke:none;stroke-width:1.25;" />
|
||||
|
||||
<path transform="matrix(-1.67739,-2.24516e-2,-2.11236e-2,1.4709,1173.58,-293.017)" id="path113" d="M 246.571,470.864 C 234.332,483.36 202.175,539.956 251.44,576.224 C 268.809,588.857 235.063,635.719 219.435,612.532 C 191.865,570.914 210.604,505.591 227.75,482.344 C 239.402,465.857 256.98,459.668 246.571,470.864 z " style="fill:url(#linearGradient1401);stroke:none;stroke-width:0.99464899;" />
|
||||
|
||||
<path transform="matrix(-1.67755,0,0,1.52374,1174.62,-318.082)" id="path111" d="M 256.513,459.837 C 236.598,477.554 200.337,539.928 253.225,580.443 C 270.595,593.075 237.832,632.906 219.435,612.532 C 155.472,541.712 221.104,460.278 243.697,432.282 C 263.889,407.935 281.775,438.034 256.513,459.837 z " style="fill:#000000;stroke:#000000;stroke-width:0.97729802;" />
|
||||
|
||||
<path transform="matrix(1.26626,-7.13667e-2,-4.59795e-2,1.19574,202.143,-125.761)" d="M 399.56879 258.15753 A 58.37323 46.863022 0 1 1 282.82233,258.15753 A 58.37323 46.863022 0 1 1 399.56879 258.15753 z" id="path114" style="fill:url(#linearGradient1403);stroke:none;stroke-width:1.26498997;" />
|
||||
|
||||
<path transform="matrix(1.30445,-7.55326e-2,7.71251e-2,1.34257,144.757,-177.617)" d="M 328.86324 320.64151 A 18.087479 27.131195 0 1 1 292.68828,320.64151 A 18.087479 27.131195 0 1 1 328.86324 320.64151 z" id="path115" style="fill:url(#linearGradient1405);stroke:none;stroke-width:1.17873001;" />
|
||||
|
||||
<path transform="matrix(-1.81082,4.95107e-2,3.17324e-2,1.55333,1207.46,-284.777)" d="M 328.86324 320.64151 A 18.087479 27.131195 0 1 1 292.68828,320.64151 A 18.087479 27.131195 0 1 1 328.86324 320.64151 z" id="path116" style="fill:url(#linearGradient1407);stroke:none;stroke-width:0.93138498;" />
|
||||
|
||||
<path transform="matrix(-0.823196,-1.76123e-3,-1.82321e-2,0.852662,913.674,-37.9902)" d="M 328.86324 320.64151 A 18.087479 27.131195 0 1 1 292.68828,320.64151 A 18.087479 27.131195 0 1 1 328.86324 320.64151 z" id="path117" style="fill:#000000;stroke:none;stroke-width:1.86495996;" />
|
||||
|
||||
<path transform="matrix(0.59438,-7.22959e-2,6.88176e-2,0.705838,367.448,32.4186)" d="M 328.86324 320.64151 A 18.087479 27.131195 0 1 1 292.68828,320.64151 A 18.087479 27.131195 0 1 1 328.86324 320.64151 z" id="path118" style="fill:#000000;stroke:none;stroke-width:2.39814997;" />
|
||||
|
||||
<path transform="matrix(-0.480323,-3.6454e-2,-4.67935e-2,0.475606,813.496,87.0124)" d="M 328.86324 320.64151 A 18.087479 27.131195 0 1 1 292.68828,320.64151 A 18.087479 27.131195 0 1 1 328.86324 320.64151 z" id="path121" style="fill:url(#linearGradient1409);stroke:none;stroke-width:3.1916101;" />
|
||||
|
||||
<path transform="matrix(0.35691,-4.08211e-2,4.13232e-2,0.398544,449.334,114.991)" d="M 328.86324 320.64151 A 18.087479 27.131195 0 1 1 292.68828,320.64151 A 18.087479 27.131195 0 1 1 328.86324 320.64151 z" id="path122" style="fill:url(#linearGradient1411);stroke:none;stroke-width:4.12025976;" />
|
||||
|
||||
<path transform="matrix(1.25,0,0,1.25,185.454,-168.23)" id="path128" d="M 258.702,495.425 C 271.538,466.322 298.816,415.199 299.397,375.667 C 299.397,344.225 393.576,336.716 401.134,368.109 C 408.692,399.502 427.875,446.592 440.084,469.265 C 452.292,491.937 487.893,563.96 449.968,626.811 C 415.811,682.455 312.243,726.477 256.958,619.254 C 238.355,582.047 241.673,535.939 258.702,495.425 z " style="fill:url(#linearGradient1413);stroke:none;stroke-width:1.25;" />
|
||||
|
||||
<path transform="matrix(1.38936,-0.111074,0.102211,1.30214,108.413,-165.938)" id="path112" d="M 242.905,473.815 C 231.642,492.782 207.405,543.124 255.042,575.862 C 306.353,610.682 301.515,672.924 239.435,637.817 C 182.658,606.028 216.59,500.039 234.925,475.551 C 247.032,458.337 264.822,437.52 242.905,473.815 z " style="fill:url(#linearGradient1415);stroke:none;stroke-width:1.15804005;" />
|
||||
|
||||
<path transform="matrix(1.25,0,0,1.25,185.454,-167.505)" id="path109" d="M 256.513,449.72 C 239.048,478.228 197.136,545.533 253.225,580.443 C 328.794,626.798 307.398,673.154 238.426,631.417 C 141.317,573.153 226.601,455.801 265.557,411.079 C 310.001,360.879 274.111,420.166 256.513,449.72 z " style="fill:#000000;stroke:#000000;stroke-width:1.25;" />
|
||||
|
||||
<path id="path125" d="M 421.481,504.727 C 421.481,537.139 392.209,579.243 341.953,578.865 C 290.125,579.32 268.004,537.139 268.004,504.727 C 268.004,472.315 302.383,446.01 344.743,446.01 C 387.102,446.01 421.481,472.315 421.481,504.727 z " style="font-size:12px;fill:url(#linearGradient1417);stroke:none;stroke-width:1.23705006;stroke-dasharray:none" transform="matrix(1.30209,0,0,1.22525,170.042,-153.557)" />
|
||||
|
||||
<path id="path127" d="M 398.227,412.292 C 397.615,450.864 375.047,459.963 346.487,459.963 C 317.926,459.963 297.195,454.269 294.746,412.292 C 294.746,385.978 317.926,370.75 346.487,370.75 C 375.047,370.75 398.227,385.978 398.227,412.292 z " style="font-size:12px;fill:url(#linearGradient1419);stroke:none;stroke-width:1.38846004;stroke-dasharray:none" transform="matrix(1.1868,0,0,1.06708,210.623,-100.078)" />
|
||||
|
||||
<path transform="matrix(1.25,0,0,1.25,185.454,-167.505)" id="path129" d="M 234.285,456.475 C 252.001,429.479 289.3,388.111 241.262,462.288 C 202.311,523.331 226.859,562.561 239.518,573.327 C 276.045,605.889 274.484,627.676 245.913,610.533 C 184.288,573.907 197.078,512.285 234.285,456.475 z " style="fill:url(#linearGradient1421);stroke:none;stroke-width:1.25;" />
|
||||
|
||||
<path transform="matrix(1.25,0,0,1.25,185.454,-167.505)" id="path131" d="M 490.662,467.52 C 475.343,435.819 426.528,355.618 492.988,448.917 C 553.449,533.214 511.01,591.93 503.452,597.744 C 495.895,603.557 470.315,615.184 477.873,594.837 C 485.43,574.49 523.107,535.864 490.662,467.52 z " style="fill:url(#linearGradient1423);stroke:none;stroke-width:1.25;" />
|
||||
|
||||
<path transform="matrix(1.25,0,0,1.25,185.454,-167.505)" id="path132" d="M 220.915,716.921 C 180.473,695.505 121.663,721.045 143.013,662.855 C 147.289,649.617 136.638,629.847 143.594,616.929 C 151.733,601.231 169.174,604.72 179.639,594.255 C 189.957,583.364 196.498,564.606 215.683,567.513 C 234.867,570.42 247.628,593.974 261.027,622.742 C 270.91,643.38 305.968,672.406 303.677,695.5 C 300.981,731 260.65,737.69 220.915,716.921 z " style="fill:url(#linearGradient1425);stroke:#e68c3f;stroke-width:6.25;" />
|
||||
|
||||
<path id="path177" d="M 415.072,495.764 C 412.065,520.67 379.259,572.391 345.554,577.298 C 311.294,582.634 279.122,543.238 271.407,506.184 C 261.518,464.978 293.994,448.584 343.345,449.557 C 396.646,451.211 417.466,463.448 415.072,495.764 z " style="font-size:12px;fill:url(#linearGradient1427);stroke:none;stroke-width:2.85509992;stroke-dasharray:none" transform="matrix(0.598206,0.268584,-0.239623,0.617213,700.568,140.464)" />
|
||||
|
||||
<path transform="matrix(-1.1685,0.423145,0.475283,1.16478,728.343,-213.821)" id="path133" d="M 220.274,718.402 C 178.947,694.812 120.38,724.007 143.013,662.855 C 147.749,649.787 136.417,629.303 143.373,616.385 C 151.512,600.687 169.174,604.72 179.639,594.255 C 189.957,583.364 198.466,566.387 217.651,569.294 C 236.835,572.201 247.628,593.974 261.027,622.742 C 270.91,643.38 304.442,671.713 302.151,694.807 C 299.455,730.307 259.427,740.278 220.274,718.402 z " style="fill:url(#linearGradient1429);stroke:#e68c3f;stroke-width:6.25067997;" />
|
||||
|
||||
<path transform="matrix(-0.945096,0.343745,0.424076,0.956058,714.328,-64.342)" id="path134" d="M 216.482,675.68 C 129.951,618.177 169.174,604.72 179.639,594.255 C 189.957,583.364 198.466,566.387 217.651,569.294 C 236.835,572.201 247.628,593.974 261.027,622.742 C 270.91,643.38 304.087,671.66 302.151,694.807 C 299.535,721.917 253.961,700.294 216.482,675.68 z " style="fill:url(#linearGradient1431);stroke:none;stroke-width:1.52532005;" />
|
||||
|
||||
<path transform="matrix(1.00431,-5.2286e-2,-1.74e-2,1.04575,244.191,-28.4653)" id="path135" d="M 216.506,677.071 C 129.975,619.568 169.709,603.501 182.56,595.791 C 197.959,585.849 197.718,564.96 216.903,567.867 C 236.087,570.774 247.628,593.974 261.027,622.742 C 270.91,643.38 304.087,671.66 302.151,694.807 C 299.535,721.917 253.985,701.685 216.506,677.071 z " style="fill:url(#linearGradient1433);stroke:none;stroke-width:1.52532005;" />
|
||||
|
||||
<path id="path136" d="M 415.072,495.764 C 412.065,520.67 379.259,572.391 345.554,577.298 C 311.294,582.634 279.122,543.238 271.407,506.184 C 261.518,464.978 293.994,448.584 343.345,449.557 C 396.646,451.211 417.466,463.448 415.072,495.764 z " style="font-size:12px;fill:#000000;stroke:none;stroke-width:2.85509992;" transform="matrix(0.515584,0.215259,-0.206526,0.49467,713.3,222.559)" />
|
||||
|
||||
<path id="path137" d="M 415.072,495.764 C 412.065,520.67 379.259,572.391 345.554,577.298 C 311.294,582.634 279.122,543.238 271.407,506.184 C 261.518,464.978 293.994,448.584 343.345,449.557 C 396.646,451.211 417.466,463.448 415.072,495.764 z " style="font-size:12px;fill:url(#linearGradient1435);stroke:none;stroke-width:2.85509992;" transform="matrix(0.351231,0.149463,-0.128856,0.343469,724.522,318.291)" />
|
||||
|
||||
<path transform="matrix(1.25,0,0,1.25,185.454,-167.505)" id="path119" d="M 309.954,338.729 C 317.101,331.959 334.765,311.663 367.915,332.974 C 374.077,336.984 379.077,337.351 390.936,342.429 C 414.662,352.178 403.318,375.688 378.192,383.537 C 367.434,387.026 357.656,400.093 338.063,398.976 C 321.329,397.999 316.944,387.102 306.665,381.07 C 288.396,370.759 285.7,356.816 295.565,349.417 C 305.431,342.018 309.29,339.358 309.954,338.729 z " style="fill:url(#linearGradient1437);stroke:#e68c3f;stroke-width:3.75;" />
|
||||
|
||||
<path transform="matrix(1.25,0,0,1.25,185.454,-167.505)" id="path120" d="M 391.251,357.645 C 381.368,358.226 359.858,379.736 337.185,379.736 C 314.512,379.736 301.141,358.807 297.653,358.807" style="fill:none;stroke:#e68c3f;stroke-width:2.5;" />
|
||||
|
||||
<path transform="matrix(0.627885,0,0,0.595666,392.366,51.8173)" id="path123" d="M 309.954,338.729 C 317.101,331.959 339.645,313.381 369.542,332.401 C 375.841,336.167 382.346,340.266 392.02,345.865 C 411.182,357.613 401.691,374.543 378.734,385.255 C 368.316,389.75 351.141,399.67 338.063,398.976 C 323.53,397.568 314.128,387.577 304.496,381.07 C 286.826,368.767 287.899,358.833 296.107,350.562 C 302.312,344.883 309.29,339.358 309.954,338.729 z " style="fill:url(#linearGradient1439);stroke:none;" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 21 KiB |
10
demo/tsconfig.json
Normal file
10
demo/tsconfig.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./",
|
||||
"paths": {
|
||||
"docx": ["../build"]
|
||||
}
|
||||
},
|
||||
"include": ["../demo"]
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
|
||||
- Simple, declarative API
|
||||
- 80+ usage examples
|
||||
- Battle tested, mature, 99.9%+ coverage
|
||||
- Battle tested, mature, 100% coverage (yes, every line is tested)
|
||||
|
||||
[GitHub](https://github.com/dolanmiu/docx)
|
||||
[Get Started](#Welcome)
|
||||
|
@ -6,6 +6,7 @@ To create a `floating` image on top of text:
|
||||
|
||||
```ts
|
||||
const image = new ImageRun({
|
||||
type: 'gif',
|
||||
data: fs.readFileSync("./demo/images/pizza.gif"),
|
||||
transformation: {
|
||||
width: 200,
|
||||
@ -26,6 +27,7 @@ By default with no arguments, its an `inline` image:
|
||||
|
||||
```ts
|
||||
const image = new ImageRun({
|
||||
type: 'gif',
|
||||
data: fs.readFileSync("./demo/images/pizza.gif"),
|
||||
transformation: {
|
||||
width: 100,
|
||||
@ -59,6 +61,7 @@ const doc = new Document({
|
||||
new Paragraph({
|
||||
children: [
|
||||
new ImageRun({
|
||||
type: [IMAGE_TYPE],
|
||||
data: [IMAGE_BUFFER],
|
||||
transformation: {
|
||||
width: [IMAGE_SIZE],
|
||||
@ -97,6 +100,7 @@ To change the position the image to be on top of the text, simply add the `float
|
||||
|
||||
```ts
|
||||
const image = new ImageRun({
|
||||
type: 'png',
|
||||
data: buffer,
|
||||
transformation: {
|
||||
width: 903,
|
||||
@ -115,6 +119,7 @@ const image = new ImageRun({
|
||||
|
||||
```ts
|
||||
const image = new ImageRun({
|
||||
type: 'png',
|
||||
data: buffer,
|
||||
transformation: {
|
||||
width: 903,
|
||||
@ -180,6 +185,7 @@ For example:
|
||||
|
||||
```ts
|
||||
const image = new ImageRun({
|
||||
type: 'gif',
|
||||
data: fs.readFileSync("./demo/images/pizza.gif"),
|
||||
transformation: {
|
||||
width: 200,
|
||||
@ -228,6 +234,7 @@ For example:
|
||||
|
||||
```ts
|
||||
const image = new ImageRun({
|
||||
type: 'gif',
|
||||
data: fs.readFileSync("./demo/images/pizza.gif"),
|
||||
transformation: {
|
||||
width: 200,
|
||||
@ -258,6 +265,7 @@ Specifies common non-visual DrawingML properties. A name, title and description
|
||||
|
||||
```ts
|
||||
const image = new ImageRun({
|
||||
type: 'gif',
|
||||
data: fs.readFileSync("./demo/images/pizza.gif"),
|
||||
altText: {
|
||||
title: "This is an ultimate title",
|
||||
|
@ -263,3 +263,23 @@ new MathAngledBrackets({
|
||||
],
|
||||
}),
|
||||
```
|
||||
|
||||
### Limit
|
||||
|
||||
#### Limit Upper
|
||||
|
||||
```ts
|
||||
new MathLimitUpper({
|
||||
children: [new MathRun("x")],
|
||||
limit: [new MathRun("-")],
|
||||
}),
|
||||
```
|
||||
|
||||
#### Limit Lower
|
||||
|
||||
```ts
|
||||
new MathLimitLower({
|
||||
children: [new MathRun("lim")],
|
||||
limit: [new MathRun("x→0")],
|
||||
}),
|
||||
```
|
||||
|
@ -130,6 +130,62 @@ new Paragraph({
|
||||
}),
|
||||
```
|
||||
|
||||
## Disabling numbering inherited from paragraph style
|
||||
|
||||
If the numbering is set on a paragraph style, you may wish to disable it for a specific paragraph:
|
||||
|
||||
```ts
|
||||
const doc = new Document({
|
||||
...
|
||||
numbering: {
|
||||
config: [
|
||||
{
|
||||
reference: "my-bullet-points",
|
||||
levels: [
|
||||
{
|
||||
level: 0,
|
||||
format: LevelFormat.BULLET,
|
||||
text: "\u1F60",
|
||||
alignment: AlignmentType.LEFT,
|
||||
style: {
|
||||
paragraph: {
|
||||
indent: { left: convertInchesToTwip(0.5), hanging: convertInchesToTwip(0.25) },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
styles: {
|
||||
paragraphStyles: [
|
||||
{
|
||||
id: 'bullet',
|
||||
name: 'Bullet',
|
||||
basedOn: 'Normal',
|
||||
next: 'Normal',
|
||||
run: {},
|
||||
paragraph: {
|
||||
numbering: {
|
||||
reference: 'my-bullet-points',
|
||||
level: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
...
|
||||
});
|
||||
```
|
||||
|
||||
```ts
|
||||
new Paragraph({
|
||||
text: "No bullet points!",
|
||||
style: "Bullet",
|
||||
numbering: false,
|
||||
}),
|
||||
```
|
||||
|
||||
## Full Example
|
||||
|
||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/3-numbering-and-bullet-points.ts ":include")
|
||||
|
@ -35,6 +35,9 @@ interface Patch {
|
||||
| type | `PatchType` | Required | `DOCUMENT`, `PARAGRAPH` |
|
||||
| children | `FileChild[] or ParagraphChild[]` | Required | The contents to replace with. A `FileChild` is a `Paragraph` or `Table`, whereas a `ParagraphChild` is typical `Paragraph` children. |
|
||||
|
||||
|
||||
The patcher also takes in a `keepOriginalStyles` boolean, which will preserve the styles of the patched text when set to true.
|
||||
|
||||
### How to patch existing document
|
||||
|
||||
1. Open your existing word document in your favorite Word Processor
|
||||
@ -76,7 +79,7 @@ patchDocument(fs.readFileSync("My Document.docx"), {
|
||||
],
|
||||
link: "https://www.google.co.uk",
|
||||
}),
|
||||
new ImageRun({ data: fs.readFileSync("./demo/images/dog.png"), transformation: { width: 100, height: 100 } }),
|
||||
new ImageRun({ type: 'png', data: fs.readFileSync("./demo/images/dog.png"), transformation: { width: 100, height: 100 } }),
|
||||
],
|
||||
}),
|
||||
],
|
||||
|
5290
package-lock.json
generated
5290
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
30
package.json
30
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docx",
|
||||
"version": "8.3.0",
|
||||
"version": "8.6.0",
|
||||
"description": "Easily generate .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.",
|
||||
"type": "module",
|
||||
"main": "build/index.umd.js",
|
||||
@ -20,21 +20,21 @@
|
||||
"scripts": {
|
||||
"build": "tsc && vite build",
|
||||
"test": "vitest --ui --coverage",
|
||||
"test.ci": "vitest run --coverage",
|
||||
"test:ci": "vitest run --coverage",
|
||||
"prepublishOnly": "npm run build --omit=dev",
|
||||
"lint": "eslint --ext .ts src",
|
||||
"predemo": "npm run build",
|
||||
"demo": "tsx ./demo/index.ts",
|
||||
"typedoc": "typedoc src/index.ts --tsconfig tsconfig.typedoc.json",
|
||||
"style": "prettier -l \"{src,scripts,demo}/**/*.{ts,html}\"",
|
||||
"style.fix": "npm run style -- --write",
|
||||
"prettier": "prettier -l \"{src,scripts,demo}/**/*.{ts,html}\"",
|
||||
"prettier:fix": "npm run prettier -- --write",
|
||||
"cspell": "cspell \"{src,demo,docs,scripts}/**/*.{ts,scss,html,md}\" && cspell \"./*.*\"",
|
||||
"serve.docs": "cd docs && docsify serve",
|
||||
"extract": "tsx scripts/extract-document.ts",
|
||||
"run-ts": "tsx"
|
||||
},
|
||||
"pre-commit": [
|
||||
"style",
|
||||
"prettier",
|
||||
"lint"
|
||||
],
|
||||
"repository": {
|
||||
@ -73,33 +73,33 @@
|
||||
"@types/xml": "^1.0.8",
|
||||
"@typescript-eslint/eslint-plugin": "^6.9.1",
|
||||
"@typescript-eslint/parser": "^6.9.1",
|
||||
"@vitest/coverage-v8": "^0.34.6",
|
||||
"@vitest/ui": "^0.33.0",
|
||||
"cspell": "^7.3.8",
|
||||
"@vitest/coverage-v8": "^1.1.0",
|
||||
"@vitest/ui": "^1.1.0",
|
||||
"cspell": "^8.2.3",
|
||||
"docsify-cli": "^4.3.0",
|
||||
"eslint": "^8.23.0",
|
||||
"eslint-plugin-functional": "^6.0.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-jsdoc": "^46.2.6",
|
||||
"eslint-plugin-jsdoc": "^48.0.2",
|
||||
"eslint-plugin-no-null": "^1.0.2",
|
||||
"eslint-plugin-prefer-arrow": "^1.2.3",
|
||||
"eslint-plugin-unicorn": "^50.0.1",
|
||||
"execa": "^8.0.1",
|
||||
"glob": "^10.2.7",
|
||||
"inquirer": "^9.2.7",
|
||||
"jsdom": "^22.1.0",
|
||||
"jsdom": "^23.0.1",
|
||||
"pre-commit": "^1.2.2",
|
||||
"prettier": "^3.0.0",
|
||||
"prettier": "^3.1.1",
|
||||
"tsconfig-paths": "^4.0.0",
|
||||
"tsx": "^4.7.0",
|
||||
"typedoc": "^0.24.8",
|
||||
"typescript": "5.1.6",
|
||||
"typedoc": "^0.25.4",
|
||||
"typescript": "5.3.3",
|
||||
"unzipper": "^0.10.11",
|
||||
"vite": "^5.0.10",
|
||||
"vite-plugin-dts": "^3.3.1",
|
||||
"vite-plugin-node-polyfills": "^0.9.0",
|
||||
"vite-plugin-node-polyfills": "^0.19.0",
|
||||
"vite-tsconfig-paths": "^4.2.0",
|
||||
"vitest": "^0.33.0"
|
||||
"vitest": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
|
@ -12,7 +12,8 @@ describe("ImageReplacer", () => {
|
||||
"test {test-image.png} test",
|
||||
[
|
||||
{
|
||||
stream: Buffer.from(""),
|
||||
type: "png",
|
||||
data: Buffer.from(""),
|
||||
fileName: "test-image.png",
|
||||
transformation: {
|
||||
pixels: {
|
||||
|
@ -36,7 +36,7 @@ describe("Compiler", () => {
|
||||
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
|
||||
|
||||
expect(fileNames).is.an.instanceof(Array);
|
||||
expect(fileNames).has.length(17);
|
||||
expect(fileNames).has.length(19);
|
||||
expect(fileNames).to.include("word/document.xml");
|
||||
expect(fileNames).to.include("word/styles.xml");
|
||||
expect(fileNames).to.include("docProps/core.xml");
|
||||
@ -47,7 +47,9 @@ describe("Compiler", () => {
|
||||
expect(fileNames).to.include("word/_rels/footnotes.xml.rels");
|
||||
expect(fileNames).to.include("word/settings.xml");
|
||||
expect(fileNames).to.include("word/comments.xml");
|
||||
expect(fileNames).to.include("word/fontTable.xml");
|
||||
expect(fileNames).to.include("word/_rels/document.xml.rels");
|
||||
expect(fileNames).to.include("word/_rels/fontTable.xml.rels");
|
||||
expect(fileNames).to.include("[Content_Types].xml");
|
||||
expect(fileNames).to.include("_rels/.rels");
|
||||
},
|
||||
@ -94,7 +96,7 @@ describe("Compiler", () => {
|
||||
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
|
||||
|
||||
expect(fileNames).is.an.instanceof(Array);
|
||||
expect(fileNames).has.length(25);
|
||||
expect(fileNames).has.length(27);
|
||||
|
||||
expect(fileNames).to.include("word/header1.xml");
|
||||
expect(fileNames).to.include("word/_rels/header1.xml.rels");
|
||||
@ -127,12 +129,10 @@ describe("Compiler", () => {
|
||||
const spy = vi.spyOn(compiler["formatter"], "format");
|
||||
|
||||
compiler.compile(file);
|
||||
expect(spy).toBeCalledTimes(13);
|
||||
expect(spy).toBeCalledTimes(15);
|
||||
});
|
||||
|
||||
it("should work with media datas", () => {
|
||||
// This test is required because before, there was a case where Document was formatted twice, which was inefficient
|
||||
// This also caused issues such as running prepForXml multiple times as format() was ran multiple times.
|
||||
const file = new File({
|
||||
sections: [
|
||||
{
|
||||
@ -150,12 +150,25 @@ describe("Compiler", () => {
|
||||
new Paragraph({
|
||||
children: [
|
||||
new ImageRun({
|
||||
type: "png",
|
||||
data: Buffer.from("", "base64"),
|
||||
transformation: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
},
|
||||
}),
|
||||
new ImageRun({
|
||||
type: "svg",
|
||||
data: Buffer.from("", "base64"),
|
||||
transformation: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
},
|
||||
fallback: {
|
||||
type: "png",
|
||||
data: Buffer.from("", "base64"),
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
@ -165,7 +178,8 @@ describe("Compiler", () => {
|
||||
|
||||
vi.spyOn(compiler["imageReplacer"], "getMediaData").mockReturnValue([
|
||||
{
|
||||
stream: Buffer.from(""),
|
||||
type: "png",
|
||||
data: Buffer.from(""),
|
||||
fileName: "test",
|
||||
transformation: {
|
||||
pixels: {
|
||||
@ -178,9 +192,48 @@ describe("Compiler", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "svg",
|
||||
data: Buffer.from(""),
|
||||
fileName: "test",
|
||||
transformation: {
|
||||
pixels: {
|
||||
x: 100,
|
||||
y: 100,
|
||||
},
|
||||
emus: {
|
||||
x: 100,
|
||||
y: 100,
|
||||
},
|
||||
},
|
||||
fallback: {
|
||||
type: "png",
|
||||
data: Buffer.from(""),
|
||||
fileName: "test",
|
||||
transformation: {
|
||||
pixels: {
|
||||
x: 100,
|
||||
y: 100,
|
||||
},
|
||||
emus: {
|
||||
x: 100,
|
||||
y: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
compiler.compile(file);
|
||||
});
|
||||
|
||||
it("should work with fonts", () => {
|
||||
const file = new File({
|
||||
sections: [],
|
||||
fonts: [{ name: "Pacifico", data: Buffer.from("") }],
|
||||
});
|
||||
|
||||
compiler.compile(file);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -2,6 +2,7 @@ import JSZip from "jszip";
|
||||
import xml from "xml";
|
||||
|
||||
import { File } from "@file/file";
|
||||
import { obfuscate } from "@file/fonts/obfuscate-ttf-to-odttf";
|
||||
|
||||
import { Formatter } from "../formatter";
|
||||
import { ImageReplacer } from "./image-replacer";
|
||||
@ -31,6 +32,8 @@ interface IXmlifyedFileMapping {
|
||||
readonly FootNotesRelationships: IXmlifyedFile;
|
||||
readonly Settings: IXmlifyedFile;
|
||||
readonly Comments?: IXmlifyedFile;
|
||||
readonly FontTable?: IXmlifyedFile;
|
||||
readonly FontTableRelationships?: IXmlifyedFile;
|
||||
}
|
||||
|
||||
export class Compiler {
|
||||
@ -59,8 +62,18 @@ export class Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
for (const { stream, fileName } of file.Media.Array) {
|
||||
zip.file(`word/media/${fileName}`, stream);
|
||||
for (const data of file.Media.Array) {
|
||||
if (data.type !== "svg") {
|
||||
zip.file(`word/media/${data.fileName}`, data.data);
|
||||
} else {
|
||||
zip.file(`word/media/${data.fileName}`, data.data);
|
||||
zip.file(`word/media/${data.fallback.fileName}`, data.fallback.data);
|
||||
}
|
||||
}
|
||||
|
||||
for (const { data: buffer, name, fontKey } of file.FontTable.fontOptionsWithKey) {
|
||||
const [nameWithoutExtension] = name.split(".");
|
||||
zip.file(`word/fonts/${nameWithoutExtension}.odttf`, obfuscate(buffer, fontKey));
|
||||
}
|
||||
|
||||
return zip;
|
||||
@ -439,6 +452,40 @@ export class Compiler {
|
||||
),
|
||||
path: "word/comments.xml",
|
||||
},
|
||||
FontTable: {
|
||||
data: xml(
|
||||
this.formatter.format(file.FontTable.View, {
|
||||
viewWrapper: file.Document,
|
||||
file,
|
||||
stack: [],
|
||||
}),
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
standalone: "yes",
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
),
|
||||
path: "word/fontTable.xml",
|
||||
},
|
||||
FontTableRelationships: {
|
||||
data: (() =>
|
||||
xml(
|
||||
this.formatter.format(file.FontTable.Relationships, {
|
||||
viewWrapper: file.Document,
|
||||
file,
|
||||
stack: [],
|
||||
}),
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
))(),
|
||||
path: "word/_rels/fontTable.xml.rels",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -25,11 +25,21 @@ describe("ContentTypes", () => {
|
||||
expect(tree["Types"][3]).to.deep.equal({ Default: { _attr: { ContentType: "image/jpeg", Extension: "jpg" } } });
|
||||
expect(tree["Types"][4]).to.deep.equal({ Default: { _attr: { ContentType: "image/bmp", Extension: "bmp" } } });
|
||||
expect(tree["Types"][5]).to.deep.equal({ Default: { _attr: { ContentType: "image/gif", Extension: "gif" } } });
|
||||
expect(tree["Types"][6]).to.deep.equal({
|
||||
expect(tree["Types"][6]).to.deep.equal({ Default: { _attr: { ContentType: "image/svg+xml", Extension: "svg" } } });
|
||||
expect(tree["Types"][7]).to.deep.equal({
|
||||
Default: { _attr: { ContentType: "application/vnd.openxmlformats-package.relationships+xml", Extension: "rels" } },
|
||||
});
|
||||
expect(tree["Types"][7]).to.deep.equal({ Default: { _attr: { ContentType: "application/xml", Extension: "xml" } } });
|
||||
expect(tree["Types"][8]).to.deep.equal({
|
||||
expect(tree["Types"][8]).to.deep.equal({ Default: { _attr: { ContentType: "application/xml", Extension: "xml" } } });
|
||||
|
||||
expect(tree["Types"][9]).to.deep.equal({
|
||||
Default: {
|
||||
_attr: {
|
||||
ContentType: "application/vnd.openxmlformats-officedocument.obfuscatedFont",
|
||||
Extension: "odttf",
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(tree["Types"][10]).to.deep.equal({
|
||||
Override: {
|
||||
_attr: {
|
||||
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml",
|
||||
@ -37,7 +47,7 @@ describe("ContentTypes", () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(tree["Types"][9]).to.deep.equal({
|
||||
expect(tree["Types"][11]).to.deep.equal({
|
||||
Override: {
|
||||
_attr: {
|
||||
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml",
|
||||
@ -45,7 +55,7 @@ describe("ContentTypes", () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(tree["Types"][10]).to.deep.equal({
|
||||
expect(tree["Types"][12]).to.deep.equal({
|
||||
Override: {
|
||||
_attr: {
|
||||
ContentType: "application/vnd.openxmlformats-package.core-properties+xml",
|
||||
@ -53,7 +63,7 @@ describe("ContentTypes", () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(tree["Types"][11]).to.deep.equal({
|
||||
expect(tree["Types"][13]).to.deep.equal({
|
||||
Override: {
|
||||
_attr: {
|
||||
ContentType: "application/vnd.openxmlformats-officedocument.custom-properties+xml",
|
||||
@ -61,7 +71,7 @@ describe("ContentTypes", () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(tree["Types"][12]).to.deep.equal({
|
||||
expect(tree["Types"][14]).to.deep.equal({
|
||||
Override: {
|
||||
_attr: {
|
||||
ContentType: "application/vnd.openxmlformats-officedocument.extended-properties+xml",
|
||||
@ -69,7 +79,7 @@ describe("ContentTypes", () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(tree["Types"][13]).to.deep.equal({
|
||||
expect(tree["Types"][15]).to.deep.equal({
|
||||
Override: {
|
||||
_attr: {
|
||||
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml",
|
||||
@ -77,7 +87,7 @@ describe("ContentTypes", () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(tree["Types"][14]).to.deep.equal({
|
||||
expect(tree["Types"][16]).to.deep.equal({
|
||||
Override: {
|
||||
_attr: {
|
||||
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml",
|
||||
@ -85,7 +95,7 @@ describe("ContentTypes", () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(tree["Types"][15]).to.deep.equal({
|
||||
expect(tree["Types"][17]).to.deep.equal({
|
||||
Override: {
|
||||
_attr: {
|
||||
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml",
|
||||
@ -102,7 +112,7 @@ describe("ContentTypes", () => {
|
||||
contentTypes.addFooter(102);
|
||||
const tree = new Formatter().format(contentTypes);
|
||||
|
||||
expect(tree["Types"][17]).to.deep.equal({
|
||||
expect(tree["Types"][20]).to.deep.equal({
|
||||
Override: {
|
||||
_attr: {
|
||||
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml",
|
||||
@ -111,7 +121,7 @@ describe("ContentTypes", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(tree["Types"][18]).to.deep.equal({
|
||||
expect(tree["Types"][21]).to.deep.equal({
|
||||
Override: {
|
||||
_attr: {
|
||||
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml",
|
||||
@ -128,7 +138,7 @@ describe("ContentTypes", () => {
|
||||
contentTypes.addHeader(202);
|
||||
const tree = new Formatter().format(contentTypes);
|
||||
|
||||
expect(tree["Types"][17]).to.deep.equal({
|
||||
expect(tree["Types"][20]).to.deep.equal({
|
||||
Override: {
|
||||
_attr: {
|
||||
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml",
|
||||
@ -137,7 +147,7 @@ describe("ContentTypes", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(tree["Types"][18]).to.deep.equal({
|
||||
expect(tree["Types"][21]).to.deep.equal({
|
||||
Override: {
|
||||
_attr: {
|
||||
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml",
|
||||
|
@ -18,8 +18,10 @@ export class ContentTypes extends XmlComponent {
|
||||
this.root.push(new Default("image/jpeg", "jpg"));
|
||||
this.root.push(new Default("image/bmp", "bmp"));
|
||||
this.root.push(new Default("image/gif", "gif"));
|
||||
this.root.push(new Default("image/svg+xml", "svg"));
|
||||
this.root.push(new Default("application/vnd.openxmlformats-package.relationships+xml", "rels"));
|
||||
this.root.push(new Default("application/xml", "xml"));
|
||||
this.root.push(new Default("application/vnd.openxmlformats-officedocument.obfuscatedFont", "odttf"));
|
||||
|
||||
this.root.push(
|
||||
new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", "/word/document.xml"),
|
||||
@ -33,6 +35,7 @@ export class ContentTypes extends XmlComponent {
|
||||
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml", "/word/footnotes.xml"));
|
||||
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml", "/word/settings.xml"));
|
||||
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml", "/word/comments.xml"));
|
||||
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml", "/word/fontTable.xml"));
|
||||
}
|
||||
|
||||
public addFooter(index: number): void {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { ICommentsOptions } from "@file/paragraph/run/comment-run";
|
||||
import { ICompatibilityOptions } from "@file/settings/compatibility";
|
||||
import { FontOptions } from "@file/fonts/font-table";
|
||||
import { StringContainer, XmlComponent } from "@file/xml-components";
|
||||
import { dateTimeValue } from "@util/values";
|
||||
|
||||
@ -39,6 +40,8 @@ export interface IPropertiesOptions {
|
||||
readonly compatibility?: ICompatibilityOptions;
|
||||
readonly customProperties?: readonly ICustomPropertyOptions[];
|
||||
readonly evenAndOddHeaderAndFooters?: boolean;
|
||||
readonly defaultTabStop?: number;
|
||||
readonly fonts?: readonly FontOptions[];
|
||||
}
|
||||
|
||||
// <xs:element name="coreProperties" type="CT_CoreProperties"/>
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { XmlComponent } from "./xml-components";
|
||||
import { Document, IDocumentOptions } from "./document";
|
||||
import { Footer } from "./footer/footer";
|
||||
import { FootNotes } from "./footnotes";
|
||||
@ -5,7 +6,7 @@ import { Header } from "./header/header";
|
||||
import { Relationships } from "./relationships";
|
||||
|
||||
export interface IViewWrapper {
|
||||
readonly View: Document | Footer | Header | FootNotes;
|
||||
readonly View: Document | Footer | Header | FootNotes | XmlComponent;
|
||||
readonly Relationships: Relationships;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// http://officeopenxml.com/WPsectionLineNumbering.php
|
||||
import { NextAttributeComponent, XmlComponent } from "@file/xml-components";
|
||||
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||
import { decimalNumber, PositiveUniversalMeasure, twipsMeasureValue } from "@util/values";
|
||||
|
||||
// <xsd:simpleType name="ST_LineNumberRestart">
|
||||
@ -25,23 +25,17 @@ export const LineNumberRestartFormat = {
|
||||
// <xsd:attribute name="restart" type="ST_LineNumberRestart" use="optional" default="newPage"/>
|
||||
// </xsd:complexType>
|
||||
|
||||
export interface ILineNumberAttributes {
|
||||
export type ILineNumberAttributes = {
|
||||
readonly countBy?: number;
|
||||
readonly start?: number;
|
||||
readonly restart?: (typeof LineNumberRestartFormat)[keyof typeof LineNumberRestartFormat];
|
||||
readonly distance?: number | PositiveUniversalMeasure;
|
||||
}
|
||||
};
|
||||
|
||||
export class LineNumberType extends XmlComponent {
|
||||
public constructor({ countBy, start, restart, distance }: ILineNumberAttributes) {
|
||||
super("w:lnNumType");
|
||||
this.root.push(
|
||||
new NextAttributeComponent<{
|
||||
readonly countBy?: number;
|
||||
readonly start?: number;
|
||||
readonly restart?: (typeof LineNumberRestartFormat)[keyof typeof LineNumberRestartFormat];
|
||||
readonly distance?: number | PositiveUniversalMeasure;
|
||||
}>({
|
||||
export const createLineNumberType = ({ countBy, start, restart, distance }: ILineNumberAttributes): XmlComponent =>
|
||||
new BuilderElement<ILineNumberAttributes>({
|
||||
name: "w:lnNumType",
|
||||
attributes: {
|
||||
countBy: { key: "w:countBy", value: countBy === undefined ? undefined : decimalNumber(countBy) },
|
||||
start: { key: "w:start", value: start === undefined ? undefined : decimalNumber(start) },
|
||||
restart: { key: "w:restart", value: restart },
|
||||
@ -49,7 +43,5 @@ export class LineNumberType extends XmlComponent {
|
||||
key: "w:distance",
|
||||
value: distance === undefined ? undefined : twipsMeasureValue(distance),
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@ -9,7 +9,7 @@ import { OnOffElement, XmlComponent } from "@file/xml-components";
|
||||
import { HeaderFooterReference, HeaderFooterReferenceType, HeaderFooterType } from "./properties/header-footer-reference";
|
||||
import { Columns, IColumnsAttributes } from "./properties/columns";
|
||||
import { DocumentGrid, IDocGridAttributesProperties } from "./properties/doc-grid";
|
||||
import { ILineNumberAttributes, LineNumberType } from "./properties/line-number";
|
||||
import { ILineNumberAttributes, createLineNumberType } from "./properties/line-number";
|
||||
import { IPageBordersOptions, PageBorders } from "./properties/page-borders";
|
||||
import { IPageMarginAttributes, PageMargin } from "./properties/page-margin";
|
||||
import { IPageNumberTypeAttributes, PageNumberType } from "./properties/page-number";
|
||||
@ -137,7 +137,7 @@ export class SectionProperties extends XmlComponent {
|
||||
}
|
||||
|
||||
if (lineNumbers) {
|
||||
this.root.push(new LineNumberType(lineNumbers));
|
||||
this.root.push(createLineNumberType(lineNumbers));
|
||||
}
|
||||
|
||||
this.root.push(new PageNumberType(pageNumbers));
|
||||
|
@ -9,10 +9,11 @@ import { TextWrappingType } from "../text-wrap";
|
||||
import { Anchor } from "./anchor";
|
||||
|
||||
const createAnchor = (drawingOptions: IDrawingOptions): Anchor =>
|
||||
new Anchor(
|
||||
{
|
||||
new Anchor({
|
||||
mediaData: {
|
||||
type: "png",
|
||||
fileName: "test.png",
|
||||
stream: new Buffer(""),
|
||||
data: Buffer.from(""),
|
||||
transformation: {
|
||||
pixels: {
|
||||
x: 0,
|
||||
@ -24,7 +25,7 @@ const createAnchor = (drawingOptions: IDrawingOptions): Anchor =>
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
transform: {
|
||||
pixels: {
|
||||
x: 100,
|
||||
y: 100,
|
||||
@ -35,7 +36,7 @@ const createAnchor = (drawingOptions: IDrawingOptions): Anchor =>
|
||||
},
|
||||
},
|
||||
drawingOptions,
|
||||
);
|
||||
});
|
||||
|
||||
describe("Anchor", () => {
|
||||
let anchor: Anchor;
|
||||
|
@ -6,7 +6,7 @@ import { HorizontalPosition, IFloating, SimplePos, VerticalPosition } from "../f
|
||||
import { Graphic } from "../inline/graphic";
|
||||
import { TextWrappingType, WrapNone, WrapSquare, WrapTight, WrapTopAndBottom } from "../text-wrap";
|
||||
import { DocProperties } from "./../doc-properties/doc-properties";
|
||||
import { EffectExtent } from "./../effect-extent/effect-extent";
|
||||
import { createEffectExtent } from "./../effect-extent/effect-extent";
|
||||
import { Extent } from "./../extent/extent";
|
||||
import { GraphicFrameProperties } from "./../graphic-frame/graphic-frame-properties";
|
||||
import { AnchorAttributes } from "./anchor-attributes";
|
||||
@ -37,7 +37,15 @@ import { AnchorAttributes } from "./anchor-attributes";
|
||||
// <xsd:attribute name="allowOverlap" type="xsd:boolean" use="required"/>
|
||||
// </xsd:complexType>
|
||||
export class Anchor extends XmlComponent {
|
||||
public constructor(mediaData: IMediaData, transform: IMediaDataTransformation, drawingOptions: IDrawingOptions) {
|
||||
public constructor({
|
||||
mediaData,
|
||||
transform,
|
||||
drawingOptions,
|
||||
}: {
|
||||
readonly mediaData: IMediaData;
|
||||
readonly transform: IMediaDataTransformation;
|
||||
readonly drawingOptions: IDrawingOptions;
|
||||
}) {
|
||||
super("wp:anchor");
|
||||
|
||||
const floating: IFloating = {
|
||||
@ -69,7 +77,7 @@ export class Anchor extends XmlComponent {
|
||||
this.root.push(new HorizontalPosition(floating.horizontalPosition));
|
||||
this.root.push(new VerticalPosition(floating.verticalPosition));
|
||||
this.root.push(new Extent(transform.emus.x, transform.emus.y));
|
||||
this.root.push(new EffectExtent());
|
||||
this.root.push(createEffectExtent({ top: 0, right: 0, bottom: 0, left: 0 }));
|
||||
|
||||
if (drawingOptions.floating !== undefined && drawingOptions.floating.wrap !== undefined) {
|
||||
switch (drawingOptions.floating.wrap.type) {
|
||||
@ -92,6 +100,6 @@ export class Anchor extends XmlComponent {
|
||||
|
||||
this.root.push(new DocProperties(drawingOptions.docProperties));
|
||||
this.root.push(new GraphicFrameProperties());
|
||||
this.root.push(new Graphic(mediaData, transform));
|
||||
this.root.push(new Graphic({ mediaData, transform, outline: drawingOptions.outline }));
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,9 @@ const imageBase64Data = `iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAACzVBMVEU
|
||||
const createDrawing = (drawingOptions?: IDrawingOptions): Drawing =>
|
||||
new Drawing(
|
||||
{
|
||||
type: "jpg",
|
||||
fileName: "test.jpg",
|
||||
stream: Buffer.from(imageBase64Data, "base64"),
|
||||
data: Buffer.from(imageBase64Data, "base64"),
|
||||
transformation: {
|
||||
pixels: {
|
||||
x: 100,
|
||||
|
@ -4,18 +4,20 @@ import { XmlComponent } from "@file/xml-components";
|
||||
import { Anchor } from "./anchor";
|
||||
import { DocPropertiesOptions } from "./doc-properties/doc-properties";
|
||||
import { IFloating } from "./floating";
|
||||
import { Inline } from "./inline";
|
||||
import { createInline } from "./inline";
|
||||
import { OutlineOptions } from "./inline/graphic/graphic-data/pic/shape-properties/outline/outline";
|
||||
|
||||
export interface IDistance {
|
||||
export type IDistance = {
|
||||
readonly distT?: number;
|
||||
readonly distB?: number;
|
||||
readonly distL?: number;
|
||||
readonly distR?: number;
|
||||
}
|
||||
};
|
||||
|
||||
export interface IDrawingOptions {
|
||||
readonly floating?: IFloating;
|
||||
readonly docProperties?: DocPropertiesOptions;
|
||||
readonly outline?: OutlineOptions;
|
||||
}
|
||||
|
||||
// <xsd:complexType name="CT_Drawing">
|
||||
@ -30,14 +32,16 @@ export class Drawing extends XmlComponent {
|
||||
super("w:drawing");
|
||||
|
||||
if (!drawingOptions.floating) {
|
||||
const inline = new Inline({
|
||||
this.root.push(
|
||||
createInline({
|
||||
mediaData: imageData,
|
||||
transform: imageData.transformation,
|
||||
docProperties: drawingOptions.docProperties,
|
||||
});
|
||||
this.root.push(inline);
|
||||
outline: drawingOptions.outline,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
this.root.push(new Anchor(imageData, imageData.transformation, drawingOptions));
|
||||
this.root.push(new Anchor({ mediaData: imageData, transform: imageData.transformation, drawingOptions }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
import { XmlAttributeComponent } from "@file/xml-components";
|
||||
|
||||
export class EffectExtentAttributes extends XmlAttributeComponent<{
|
||||
readonly b?: number;
|
||||
readonly l?: number;
|
||||
readonly r?: number;
|
||||
readonly t?: number;
|
||||
}> {
|
||||
protected readonly xmlKeys = {
|
||||
b: "b",
|
||||
l: "l",
|
||||
r: "r",
|
||||
t: "t",
|
||||
};
|
||||
}
|
@ -1,17 +1,31 @@
|
||||
import { XmlComponent } from "@file/xml-components";
|
||||
import { EffectExtentAttributes } from "./effect-extent-attributes";
|
||||
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||
|
||||
export class EffectExtent extends XmlComponent {
|
||||
public constructor() {
|
||||
super("wp:effectExtent");
|
||||
export type EffectExtentAttributes = {
|
||||
readonly top: number;
|
||||
readonly right: number;
|
||||
readonly bottom: number;
|
||||
readonly left: number;
|
||||
};
|
||||
|
||||
this.root.push(
|
||||
new EffectExtentAttributes({
|
||||
b: 0,
|
||||
l: 0,
|
||||
r: 0,
|
||||
t: 0,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
export const createEffectExtent = ({ top, right, bottom, left }: EffectExtentAttributes): XmlComponent =>
|
||||
new BuilderElement<EffectExtentAttributes>({
|
||||
name: "wp:effectExtent",
|
||||
attributes: {
|
||||
top: {
|
||||
key: "t",
|
||||
value: top,
|
||||
},
|
||||
right: {
|
||||
key: "r",
|
||||
value: right,
|
||||
},
|
||||
bottom: {
|
||||
key: "b",
|
||||
value: bottom,
|
||||
},
|
||||
left: {
|
||||
key: "l",
|
||||
value: left,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -3,11 +3,20 @@ import { XmlComponent } from "@file/xml-components";
|
||||
|
||||
import { GraphicDataAttributes } from "./graphic-data-attribute";
|
||||
import { Pic } from "./pic";
|
||||
import { OutlineOptions } from "./pic/shape-properties/outline/outline";
|
||||
|
||||
export class GraphicData extends XmlComponent {
|
||||
private readonly pic: Pic;
|
||||
|
||||
public constructor(mediaData: IMediaData, transform: IMediaDataTransformation) {
|
||||
public constructor({
|
||||
mediaData,
|
||||
transform,
|
||||
outline,
|
||||
}: {
|
||||
readonly mediaData: IMediaData;
|
||||
readonly transform: IMediaDataTransformation;
|
||||
readonly outline?: OutlineOptions;
|
||||
}) {
|
||||
super("a:graphicData");
|
||||
|
||||
this.root.push(
|
||||
@ -16,7 +25,7 @@ export class GraphicData extends XmlComponent {
|
||||
}),
|
||||
);
|
||||
|
||||
this.pic = new Pic(mediaData, transform);
|
||||
this.pic = new Pic({ mediaData, transform, outline });
|
||||
|
||||
this.root.push(this.pic);
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||
import { IMediaData } from "@file/media";
|
||||
|
||||
const createSvgBlip = (mediaData: IMediaData): XmlComponent =>
|
||||
new BuilderElement({
|
||||
name: "asvg:svgBlip",
|
||||
attributes: {
|
||||
asvg: {
|
||||
key: "xmlns:asvg",
|
||||
value: "http://schemas.microsoft.com/office/drawing/2016/SVG/main",
|
||||
},
|
||||
embed: {
|
||||
key: "r:embed",
|
||||
value: `rId{${mediaData.fileName}}`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const createExtention = (mediaData: IMediaData): XmlComponent =>
|
||||
new BuilderElement({
|
||||
name: "a:ext",
|
||||
attributes: {
|
||||
uri: {
|
||||
key: "uri",
|
||||
value: "{96DAC541-7B7A-43D3-8B79-37D633B846F1}",
|
||||
},
|
||||
},
|
||||
children: [createSvgBlip(mediaData)],
|
||||
});
|
||||
|
||||
export const createExtentionList = (mediaData: IMediaData): XmlComponent =>
|
||||
new BuilderElement({
|
||||
name: "a:extLst",
|
||||
children: [createExtention(mediaData)],
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
import { IMediaData } from "@file/media";
|
||||
import { XmlComponent } from "@file/xml-components";
|
||||
|
||||
import { Blip } from "./blip";
|
||||
import { createBlip } from "./blip";
|
||||
import { SourceRectangle } from "./source-rectangle";
|
||||
import { Stretch } from "./stretch";
|
||||
|
||||
@ -9,7 +9,7 @@ export class BlipFill extends XmlComponent {
|
||||
public constructor(mediaData: IMediaData) {
|
||||
super("pic:blipFill");
|
||||
|
||||
this.root.push(new Blip(mediaData));
|
||||
this.root.push(createBlip(mediaData));
|
||||
this.root.push(new SourceRectangle());
|
||||
this.root.push(new Stretch());
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
import { IMediaData } from "@file/media";
|
||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
||||
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||
import { createExtentionList } from "./blip-extentions";
|
||||
|
||||
class BlipAttributes extends XmlAttributeComponent<{
|
||||
type BlipAttributes = {
|
||||
readonly embed: string;
|
||||
readonly cstate: string;
|
||||
}> {
|
||||
protected readonly xmlKeys = {
|
||||
embed: "r:embed",
|
||||
cstate: "cstate",
|
||||
};
|
||||
}
|
||||
|
||||
export class Blip extends XmlComponent {
|
||||
public constructor(mediaData: IMediaData) {
|
||||
super("a:blip");
|
||||
this.root.push(
|
||||
new BlipAttributes({
|
||||
embed: `rId{${mediaData.fileName}}`,
|
||||
cstate: "none",
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
export const createBlip = (mediaData: IMediaData): XmlComponent =>
|
||||
new BuilderElement<BlipAttributes>({
|
||||
name: "a:blip",
|
||||
attributes: {
|
||||
embed: {
|
||||
key: "r:embed",
|
||||
value: `rId{${mediaData.type === "svg" ? mediaData.fallback.fileName : mediaData.fileName}}`,
|
||||
},
|
||||
cstate: {
|
||||
key: "cstate",
|
||||
value: "none",
|
||||
},
|
||||
},
|
||||
children: mediaData.type === "svg" ? [createExtentionList(mediaData)] : [],
|
||||
});
|
||||
|
@ -6,9 +6,18 @@ import { BlipFill } from "./blip/blip-fill";
|
||||
import { NonVisualPicProperties } from "./non-visual-pic-properties/non-visual-pic-properties";
|
||||
import { PicAttributes } from "./pic-attributes";
|
||||
import { ShapeProperties } from "./shape-properties/shape-properties";
|
||||
import { OutlineOptions } from "./shape-properties/outline/outline";
|
||||
|
||||
export class Pic extends XmlComponent {
|
||||
public constructor(mediaData: IMediaData, transform: IMediaDataTransformation) {
|
||||
public constructor({
|
||||
mediaData,
|
||||
transform,
|
||||
outline,
|
||||
}: {
|
||||
readonly mediaData: IMediaData;
|
||||
readonly transform: IMediaDataTransformation;
|
||||
readonly outline?: OutlineOptions;
|
||||
}) {
|
||||
super("pic:pic");
|
||||
|
||||
this.root.push(
|
||||
@ -19,6 +28,6 @@ export class Pic extends XmlComponent {
|
||||
|
||||
this.root.push(new NonVisualPicProperties());
|
||||
this.root.push(new BlipFill(mediaData));
|
||||
this.root.push(new ShapeProperties(transform));
|
||||
this.root.push(new ShapeProperties({ transform, outline }));
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
|
||||
|
||||
import { Formatter } from "@export/formatter";
|
||||
|
||||
import { NoFill } from "./no-fill";
|
||||
import { createNoFill } from "./no-fill";
|
||||
|
||||
describe("NoFill", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create", () => {
|
||||
const tree = new Formatter().format(new NoFill());
|
||||
const tree = new Formatter().format(createNoFill());
|
||||
expect(tree).to.deep.equal({
|
||||
"a:noFill": {},
|
||||
});
|
||||
|
@ -1,7 +1,3 @@
|
||||
import { XmlComponent } from "@file/xml-components";
|
||||
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||
|
||||
export class NoFill extends XmlComponent {
|
||||
public constructor() {
|
||||
super("a:noFill");
|
||||
}
|
||||
}
|
||||
export const createNoFill = (): XmlComponent => new BuilderElement({ name: "a:noFill" });
|
||||
|
@ -1,19 +1,66 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { Formatter } from "@export/formatter";
|
||||
import { Outline } from "./outline";
|
||||
|
||||
describe("Outline", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create", () => {
|
||||
const tree = new Formatter().format(new Outline());
|
||||
import { createOutline } from "./outline";
|
||||
import { SchemeColor } from "./scheme-color";
|
||||
|
||||
describe("createOutline", () => {
|
||||
it("should create no fill", () => {
|
||||
const tree = new Formatter().format(createOutline({ type: "noFill" }));
|
||||
expect(tree).to.deep.equal({
|
||||
"a:ln": [
|
||||
{
|
||||
_attr: {},
|
||||
},
|
||||
{
|
||||
"a:noFill": {},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should create solid rgb fill", () => {
|
||||
const tree = new Formatter().format(createOutline({ type: "solidFill", solidFillType: "rgb", value: "FFFFFF" }));
|
||||
expect(tree).to.deep.equal({
|
||||
"a:ln": [
|
||||
{
|
||||
_attr: {},
|
||||
},
|
||||
{
|
||||
"a:solidFill": [
|
||||
{
|
||||
"a:srgbClr": {
|
||||
_attr: {
|
||||
val: "FFFFFF",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should create solid scheme fill", () => {
|
||||
const tree = new Formatter().format(createOutline({ type: "solidFill", solidFillType: "scheme", value: SchemeColor.ACCENT1 }));
|
||||
expect(tree).to.deep.equal({
|
||||
"a:ln": [
|
||||
{
|
||||
_attr: {},
|
||||
},
|
||||
{
|
||||
"a:solidFill": [
|
||||
{
|
||||
"a:schemeClr": {
|
||||
_attr: {
|
||||
val: "accent1",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,11 +1,130 @@
|
||||
// http://officeopenxml.com/drwSp-outline.php
|
||||
import { XmlComponent } from "@file/xml-components";
|
||||
import { NoFill } from "./no-fill";
|
||||
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||
import { createNoFill } from "./no-fill";
|
||||
import { createSolidFill } from "./solid-fill";
|
||||
import { SchemeColor } from "./scheme-color";
|
||||
|
||||
export class Outline extends XmlComponent {
|
||||
public constructor() {
|
||||
super("a:ln");
|
||||
// <xsd:complexType name="CT_TextOutlineEffect">
|
||||
// <xsd:sequence>
|
||||
// <xsd:group ref="EG_FillProperties" minOccurs="0"/>
|
||||
// <xsd:group ref="EG_LineDashProperties" minOccurs="0"/>
|
||||
// <xsd:group ref="EG_LineJoinProperties" minOccurs="0"/>
|
||||
// </xsd:sequence>
|
||||
// <xsd:attribute name="w" use="optional" type="a:ST_LineWidth"/>
|
||||
// <xsd:attribute name="cap" use="optional" type="ST_LineCap"/>
|
||||
// <xsd:attribute name="cmpd" use="optional" type="ST_CompoundLine"/>
|
||||
// <xsd:attribute name="algn" use="optional" type="ST_PenAlignment"/>
|
||||
// </xsd:complexType>
|
||||
|
||||
this.root.push(new NoFill());
|
||||
}
|
||||
}
|
||||
// <xsd:simpleType name="ST_LineCap">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:enumeration value="rnd"/>
|
||||
// <xsd:enumeration value="sq"/>
|
||||
// <xsd:enumeration value="flat"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
export const LineCap = {
|
||||
ROUND: "rnd",
|
||||
SQUARE: "sq",
|
||||
FLAT: "flat",
|
||||
} as const;
|
||||
|
||||
// <xsd:simpleType name="ST_CompoundLine">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:enumeration value="sng"/>
|
||||
// <xsd:enumeration value="dbl"/>
|
||||
// <xsd:enumeration value="thickThin"/>
|
||||
// <xsd:enumeration value="thinThick"/>
|
||||
// <xsd:enumeration value="tri"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
export const CompoundLine = {
|
||||
SINGLE: "sng",
|
||||
DOUBLE: "dbl",
|
||||
THICK_THIN: "thickThin",
|
||||
THIN_THICK: "thinThick",
|
||||
TRI: "tri",
|
||||
} as const;
|
||||
|
||||
// <xsd:simpleType name="ST_PenAlignment">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:enumeration value="ctr"/>
|
||||
// <xsd:enumeration value="in"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
export const PenAlignment = {
|
||||
CENTER: "ctr",
|
||||
INSET: "in",
|
||||
} as const;
|
||||
|
||||
export type OutlineAttributes = {
|
||||
readonly width?: number;
|
||||
readonly cap?: keyof typeof LineCap;
|
||||
readonly compoundLine?: keyof typeof CompoundLine;
|
||||
readonly align?: keyof typeof PenAlignment;
|
||||
};
|
||||
|
||||
type OutlineNoFill = {
|
||||
readonly type: "noFill";
|
||||
};
|
||||
|
||||
type OutlineRgbSolidFill = {
|
||||
readonly type: "solidFill";
|
||||
readonly solidFillType: "rgb";
|
||||
readonly value: string;
|
||||
};
|
||||
|
||||
type OutlineSchemeSolidFill = {
|
||||
readonly type: "solidFill";
|
||||
readonly solidFillType: "scheme";
|
||||
readonly value: (typeof SchemeColor)[keyof typeof SchemeColor];
|
||||
};
|
||||
|
||||
type OutlineSolidFill = OutlineRgbSolidFill | OutlineSchemeSolidFill;
|
||||
|
||||
// <xsd:group name="EG_FillProperties">
|
||||
// <xsd:choice>
|
||||
// <xsd:element name="noFill" type="w:CT_Empty"/>
|
||||
// <xsd:element name="solidFill" type="CT_SolidColorFillProperties"/>
|
||||
// <xsd:element name="gradFill" type="CT_GradientFillProperties"/>
|
||||
// </xsd:choice>
|
||||
// </xsd:group>
|
||||
type OutlineFillProperties = OutlineNoFill | OutlineSolidFill;
|
||||
|
||||
export type OutlineOptions = OutlineAttributes & OutlineFillProperties;
|
||||
|
||||
export const createOutline = (options: OutlineOptions): XmlComponent =>
|
||||
new BuilderElement<OutlineAttributes>({
|
||||
name: "a:ln",
|
||||
attributes: {
|
||||
width: {
|
||||
key: "w",
|
||||
value: options.width,
|
||||
},
|
||||
cap: {
|
||||
key: "cap",
|
||||
value: options.cap,
|
||||
},
|
||||
compoundLine: {
|
||||
key: "cmpd",
|
||||
value: options.compoundLine,
|
||||
},
|
||||
align: {
|
||||
key: "algn",
|
||||
value: options.align,
|
||||
},
|
||||
},
|
||||
children: [
|
||||
options.type === "noFill"
|
||||
? createNoFill()
|
||||
: options.solidFillType === "rgb"
|
||||
? createSolidFill({
|
||||
type: "rgb",
|
||||
value: options.value,
|
||||
})
|
||||
: createSolidFill({
|
||||
type: "scheme",
|
||||
value: options.value,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
@ -0,0 +1,22 @@
|
||||
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||
|
||||
type SolidRgbColorOptions = {
|
||||
readonly value: string;
|
||||
};
|
||||
|
||||
// <xsd:complexType name="CT_SRgbColor">
|
||||
// <xsd:sequence>
|
||||
// <xsd:group ref="EG_ColorTransform" minOccurs="0" maxOccurs="unbounded"/>
|
||||
// </xsd:sequence>
|
||||
// <xsd:attribute name="val" type="s:ST_HexColorRGB" use="required"/>
|
||||
// </xsd:complexType>
|
||||
export const createSolidRgbColor = (options: SolidRgbColorOptions): XmlComponent =>
|
||||
new BuilderElement<SolidRgbColorOptions>({
|
||||
name: "a:srgbClr",
|
||||
attributes: {
|
||||
value: {
|
||||
key: "val",
|
||||
value: options.value,
|
||||
},
|
||||
},
|
||||
});
|
@ -0,0 +1,65 @@
|
||||
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||
|
||||
type SchemeColorOptions = {
|
||||
readonly value: (typeof SchemeColor)[keyof typeof SchemeColor];
|
||||
};
|
||||
|
||||
// <xsd:simpleType name="ST_SchemeColorVal">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:enumeration value="bg1"/>
|
||||
// <xsd:enumeration value="tx1"/>
|
||||
// <xsd:enumeration value="bg2"/>
|
||||
// <xsd:enumeration value="tx2"/>
|
||||
// <xsd:enumeration value="accent1"/>
|
||||
// <xsd:enumeration value="accent2"/>
|
||||
// <xsd:enumeration value="accent3"/>
|
||||
// <xsd:enumeration value="accent4"/>
|
||||
// <xsd:enumeration value="accent5"/>
|
||||
// <xsd:enumeration value="accent6"/>
|
||||
// <xsd:enumeration value="hlink"/>
|
||||
// <xsd:enumeration value="folHlink"/>
|
||||
// <xsd:enumeration value="dk1"/>
|
||||
// <xsd:enumeration value="lt1"/>
|
||||
// <xsd:enumeration value="dk2"/>
|
||||
// <xsd:enumeration value="lt2"/>
|
||||
// <xsd:enumeration value="phClr"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
|
||||
// cspell:ignore folHlink, phClr, hlink
|
||||
export const SchemeColor = {
|
||||
BG1: "bg1",
|
||||
TX1: "tx1",
|
||||
BG2: "bg2",
|
||||
TX2: "tx2",
|
||||
ACCENT1: "accent1",
|
||||
ACCENT2: "accent2",
|
||||
ACCENT3: "accent3",
|
||||
ACCENT4: "accent4",
|
||||
ACCENT5: "accent5",
|
||||
ACCENT6: "accent6",
|
||||
HLINK: "hlink",
|
||||
FOLHLINK: "folHlink",
|
||||
DK1: "dk1",
|
||||
LT1: "lt1",
|
||||
DK2: "dk2",
|
||||
LT2: "lt2",
|
||||
PHCLR: "phClr",
|
||||
} as const;
|
||||
|
||||
// <xsd:complexType name="CT_SchemeColor">
|
||||
// <xsd:sequence>
|
||||
// <xsd:group ref="EG_ColorTransform" minOccurs="0" maxOccurs="unbounded"/>
|
||||
// </xsd:sequence>
|
||||
// <xsd:attribute name="val" type="ST_SchemeColorVal" use="required"/>
|
||||
// </xsd:complexType>
|
||||
export const createSchemeColor = (options: SchemeColorOptions): XmlComponent =>
|
||||
new BuilderElement<SchemeColorOptions>({
|
||||
name: "a:schemeClr",
|
||||
attributes: {
|
||||
value: {
|
||||
key: "val",
|
||||
value: options.value,
|
||||
},
|
||||
},
|
||||
});
|
@ -0,0 +1,38 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { Formatter } from "@export/formatter";
|
||||
|
||||
import { createSolidFill } from "./solid-fill";
|
||||
import { SchemeColor } from "./scheme-color";
|
||||
|
||||
describe("createSolidFill", () => {
|
||||
it("should create of rgb", () => {
|
||||
const tree = new Formatter().format(createSolidFill({ type: "rgb", value: "FFFFFF" }));
|
||||
expect(tree).to.deep.equal({
|
||||
"a:solidFill": [
|
||||
{
|
||||
"a:srgbClr": {
|
||||
_attr: {
|
||||
val: "FFFFFF",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should create of scheme", () => {
|
||||
const tree = new Formatter().format(createSolidFill({ type: "scheme", value: SchemeColor.TX1 }));
|
||||
expect(tree).to.deep.equal({
|
||||
"a:solidFill": [
|
||||
{
|
||||
"a:schemeClr": {
|
||||
_attr: {
|
||||
val: "tx1",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,22 @@
|
||||
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||
|
||||
import { createSchemeColor, SchemeColor } from "./scheme-color";
|
||||
import { createSolidRgbColor } from "./rgb-color";
|
||||
|
||||
export type RgbColorOptions = {
|
||||
readonly type: "rgb";
|
||||
readonly value: string;
|
||||
};
|
||||
|
||||
export type SchemeColorOptions = {
|
||||
readonly type: "scheme";
|
||||
readonly value: (typeof SchemeColor)[keyof typeof SchemeColor];
|
||||
};
|
||||
|
||||
export type SolidFillOptions = RgbColorOptions | SchemeColorOptions;
|
||||
|
||||
export const createSolidFill = (options: SolidFillOptions): XmlComponent =>
|
||||
new BuilderElement({
|
||||
name: "a:solidFill",
|
||||
children: [options.type === "rgb" ? createSolidRgbColor(options) : createSchemeColor(options)],
|
||||
});
|
@ -2,15 +2,15 @@
|
||||
import { IMediaDataTransformation } from "@file/media";
|
||||
import { XmlComponent } from "@file/xml-components";
|
||||
import { Form } from "./form";
|
||||
// import { NoFill } from "./no-fill";
|
||||
// import { Outline } from "./outline/outline";
|
||||
import { OutlineOptions, createOutline } from "./outline/outline";
|
||||
import { PresetGeometry } from "./preset-geometry/preset-geometry";
|
||||
import { ShapePropertiesAttributes } from "./shape-properties-attributes";
|
||||
import { createNoFill } from "./outline/no-fill";
|
||||
|
||||
export class ShapeProperties extends XmlComponent {
|
||||
private readonly form: Form;
|
||||
|
||||
public constructor(transform: IMediaDataTransformation) {
|
||||
public constructor({ outline, transform }: { readonly outline?: OutlineOptions; readonly transform: IMediaDataTransformation }) {
|
||||
super("pic:spPr");
|
||||
|
||||
this.root.push(
|
||||
@ -23,7 +23,10 @@ export class ShapeProperties extends XmlComponent {
|
||||
|
||||
this.root.push(this.form);
|
||||
this.root.push(new PresetGeometry());
|
||||
// this.root.push(new NoFill());
|
||||
// this.root.push(new Outline());
|
||||
|
||||
if (outline) {
|
||||
this.root.push(createNoFill());
|
||||
this.root.push(createOutline(outline));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { IMediaData, IMediaDataTransformation } from "@file/media";
|
||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
||||
|
||||
import { GraphicData } from "./graphic-data";
|
||||
import { OutlineOptions } from "./graphic-data/pic/shape-properties/outline/outline";
|
||||
|
||||
class GraphicAttributes extends XmlAttributeComponent<{
|
||||
readonly a: string;
|
||||
@ -14,7 +15,15 @@ class GraphicAttributes extends XmlAttributeComponent<{
|
||||
export class Graphic extends XmlComponent {
|
||||
private readonly data: GraphicData;
|
||||
|
||||
public constructor(mediaData: IMediaData, transform: IMediaDataTransformation) {
|
||||
public constructor({
|
||||
mediaData,
|
||||
transform,
|
||||
outline,
|
||||
}: {
|
||||
readonly mediaData: IMediaData;
|
||||
readonly transform: IMediaDataTransformation;
|
||||
readonly outline?: OutlineOptions;
|
||||
}) {
|
||||
super("a:graphic");
|
||||
this.root.push(
|
||||
new GraphicAttributes({
|
||||
@ -22,7 +31,7 @@ export class Graphic extends XmlComponent {
|
||||
}),
|
||||
);
|
||||
|
||||
this.data = new GraphicData(mediaData, transform);
|
||||
this.data = new GraphicData({ mediaData, transform, outline });
|
||||
|
||||
this.root.push(this.data);
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
import { XmlAttributeComponent } from "@file/xml-components";
|
||||
import { IDistance } from "../drawing";
|
||||
|
||||
// distT, distB etc have no effect on inline images, only floating
|
||||
export class InlineAttributes extends XmlAttributeComponent<IDistance> {
|
||||
protected readonly xmlKeys = {
|
||||
distT: "distT",
|
||||
distB: "distB",
|
||||
distL: "distL",
|
||||
distR: "distR",
|
||||
};
|
||||
}
|
59
src/file/drawing/inline/inline.spec.ts
Normal file
59
src/file/drawing/inline/inline.spec.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { Formatter } from "@export/formatter";
|
||||
import { createInline } from "./inline";
|
||||
|
||||
describe("Inline", () => {
|
||||
it("should create with default effect extent", () => {
|
||||
const tree = new Formatter().format(
|
||||
createInline({
|
||||
mediaData: {
|
||||
type: "png",
|
||||
fileName: "test.png",
|
||||
data: Buffer.from(""),
|
||||
transformation: {
|
||||
pixels: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
emus: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
transform: {
|
||||
pixels: {
|
||||
x: 100,
|
||||
y: 100,
|
||||
},
|
||||
emus: {
|
||||
x: 100,
|
||||
y: 100,
|
||||
},
|
||||
},
|
||||
docProperties: {
|
||||
name: "test",
|
||||
description: "test",
|
||||
title: "test",
|
||||
},
|
||||
outline: { type: "solidFill", solidFillType: "rgb", value: "FFFFFF" },
|
||||
}),
|
||||
);
|
||||
|
||||
expect(tree).toStrictEqual({
|
||||
"wp:inline": expect.arrayContaining([
|
||||
{
|
||||
"wp:effectExtent": {
|
||||
_attr: {
|
||||
b: 19050,
|
||||
l: 19050,
|
||||
r: 19050,
|
||||
t: 19050,
|
||||
},
|
||||
},
|
||||
},
|
||||
]),
|
||||
});
|
||||
});
|
||||
});
|
@ -1,18 +1,19 @@
|
||||
// http://officeopenxml.com/drwPicInline.php
|
||||
import { IMediaData, IMediaDataTransformation } from "@file/media";
|
||||
import { XmlComponent } from "@file/xml-components";
|
||||
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||
import { DocProperties, DocPropertiesOptions } from "./../doc-properties/doc-properties";
|
||||
import { EffectExtent } from "./../effect-extent/effect-extent";
|
||||
import { createEffectExtent } from "./../effect-extent/effect-extent";
|
||||
import { Extent } from "./../extent/extent";
|
||||
import { GraphicFrameProperties } from "./../graphic-frame/graphic-frame-properties";
|
||||
import { Graphic } from "./../inline/graphic";
|
||||
import { InlineAttributes } from "./inline-attributes";
|
||||
import { OutlineOptions } from "./graphic/graphic-data/pic/shape-properties/outline/outline";
|
||||
|
||||
interface InlineOptions {
|
||||
type InlineOptions = {
|
||||
readonly mediaData: IMediaData;
|
||||
readonly transform: IMediaDataTransformation;
|
||||
readonly docProperties?: DocPropertiesOptions;
|
||||
}
|
||||
readonly outline?: OutlineOptions;
|
||||
};
|
||||
|
||||
// <xsd:complexType name="CT_Inline">
|
||||
// <xsd:sequence>
|
||||
@ -28,29 +29,41 @@ interface InlineOptions {
|
||||
// <xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||
// <xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||
// </xsd:complexType>
|
||||
export class Inline extends XmlComponent {
|
||||
private readonly extent: Extent;
|
||||
private readonly graphic: Graphic;
|
||||
|
||||
public constructor({ mediaData, transform, docProperties }: InlineOptions) {
|
||||
super("wp:inline");
|
||||
|
||||
this.root.push(
|
||||
new InlineAttributes({
|
||||
distT: 0,
|
||||
distB: 0,
|
||||
distL: 0,
|
||||
distR: 0,
|
||||
}),
|
||||
);
|
||||
|
||||
this.extent = new Extent(transform.emus.x, transform.emus.y);
|
||||
this.graphic = new Graphic(mediaData, transform);
|
||||
|
||||
this.root.push(this.extent);
|
||||
this.root.push(new EffectExtent());
|
||||
this.root.push(new DocProperties(docProperties));
|
||||
this.root.push(new GraphicFrameProperties());
|
||||
this.root.push(this.graphic);
|
||||
}
|
||||
export const createInline = ({ mediaData, transform, docProperties, outline }: InlineOptions): XmlComponent =>
|
||||
new BuilderElement({
|
||||
name: "wp:inline",
|
||||
attributes: {
|
||||
distanceTop: {
|
||||
key: "distT",
|
||||
value: 0,
|
||||
},
|
||||
distanceBottom: {
|
||||
key: "distB",
|
||||
value: 0,
|
||||
},
|
||||
distanceLeft: {
|
||||
key: "distL",
|
||||
value: 0,
|
||||
},
|
||||
distanceRight: {
|
||||
key: "distR",
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
children: [
|
||||
new Extent(transform.emus.x, transform.emus.y),
|
||||
createEffectExtent(
|
||||
outline
|
||||
? {
|
||||
top: (outline.width ?? 9525) * 2,
|
||||
right: (outline.width ?? 9525) * 2,
|
||||
bottom: (outline.width ?? 9525) * 2,
|
||||
left: (outline.width ?? 9525) * 2,
|
||||
}
|
||||
: { top: 0, right: 0, bottom: 0, left: 0 },
|
||||
),
|
||||
new DocProperties(docProperties),
|
||||
new GraphicFrameProperties(),
|
||||
new Graphic({ mediaData, transform, outline }),
|
||||
],
|
||||
});
|
||||
|
@ -436,7 +436,44 @@ describe("File", () => {
|
||||
it("should work with external styles", () => {
|
||||
const doc = new File({
|
||||
sections: [],
|
||||
externalStyles: "",
|
||||
externalStyles: `
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<w:styles xmlns:mc="first" xmlns:r="second">
|
||||
<w:docDefaults>
|
||||
<w:rPrDefault>
|
||||
<w:rPr>
|
||||
<w:rFonts w:ascii="Arial" w:eastAsiaTheme="minorHAnsi" w:hAnsi="Arial" w:cstheme="minorHAnsi"/>
|
||||
<w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA"/>
|
||||
</w:rPr>
|
||||
</w:rPrDefault>
|
||||
<w:pPrDefault>
|
||||
<w:pPr>
|
||||
<w:spacing w:after="160" w:line="259" w:lineRule="auto"/>
|
||||
</w:pPr>
|
||||
</w:pPrDefault>
|
||||
</w:docDefaults>
|
||||
|
||||
<w:latentStyles w:defLockedState="1" w:defUIPriority="99">
|
||||
</w:latentStyles>
|
||||
|
||||
<w:style w:type="paragraph" w:default="1" w:styleId="Normal">
|
||||
<w:name w:val="Normal"/>
|
||||
<w:qFormat/>
|
||||
</w:style>
|
||||
|
||||
<w:style w:type="paragraph" w:styleId="Heading1">
|
||||
<w:name w:val="heading 1"/>
|
||||
<w:basedOn w:val="Normal"/>
|
||||
<w:pPr>
|
||||
<w:keepNext/>
|
||||
<w:keepLines/>
|
||||
|
||||
<w:pBdr>
|
||||
<w:bottom w:val="single" w:sz="4" w:space="1" w:color="auto"/>
|
||||
</w:pBdr>
|
||||
</w:pPr>
|
||||
</w:style>
|
||||
</w:styles>`,
|
||||
});
|
||||
|
||||
expect(doc.Styles).to.not.be.undefined;
|
||||
|
@ -17,6 +17,7 @@ import { Styles } from "./styles";
|
||||
import { ExternalStylesFactory } from "./styles/external-styles-factory";
|
||||
import { DefaultStylesFactory } from "./styles/factory";
|
||||
import { FileChild } from "./file-child";
|
||||
import { FontWrapper } from "./fonts/font-wrapper";
|
||||
|
||||
export interface ISectionOptions {
|
||||
readonly headers?: {
|
||||
@ -53,6 +54,7 @@ export class File {
|
||||
private readonly appProperties: AppProperties;
|
||||
private readonly styles: Styles;
|
||||
private readonly comments: Comments;
|
||||
private readonly fontWrapper: FontWrapper;
|
||||
|
||||
public constructor(options: IPropertiesOptions) {
|
||||
this.coreProperties = new CoreProperties({
|
||||
@ -77,11 +79,12 @@ export class File {
|
||||
evenAndOddHeaders: options.evenAndOddHeaderAndFooters ? true : false,
|
||||
trackRevisions: options.features?.trackRevisions,
|
||||
updateFields: options.features?.updateFields,
|
||||
defaultTabStop: options.defaultTabStop,
|
||||
});
|
||||
|
||||
this.media = new Media();
|
||||
|
||||
if (options.externalStyles) {
|
||||
if (options.externalStyles !== undefined) {
|
||||
const stylesFactory = new ExternalStylesFactory();
|
||||
this.styles = stylesFactory.newInstance(options.externalStyles);
|
||||
} else if (options.styles) {
|
||||
@ -108,6 +111,8 @@ export class File {
|
||||
this.footnotesWrapper.View.createFootNote(parseFloat(key), options.footnotes[key].children);
|
||||
}
|
||||
}
|
||||
|
||||
this.fontWrapper = new FontWrapper(options.fonts ?? []);
|
||||
}
|
||||
|
||||
private addSection({ headers = {}, footers = {}, children, properties }: ISectionOptions): void {
|
||||
@ -291,4 +296,8 @@ export class File {
|
||||
public get Comments(): Comments {
|
||||
return this.comments;
|
||||
}
|
||||
|
||||
public get FontTable(): FontWrapper {
|
||||
return this.fontWrapper;
|
||||
}
|
||||
}
|
||||
|
33
src/file/fonts/create-regular-font.ts
Normal file
33
src/file/fonts/create-regular-font.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { XmlComponent } from "@file/xml-components";
|
||||
|
||||
import { CharacterSet, createFont } from "./font";
|
||||
|
||||
export const createRegularFont = ({
|
||||
name,
|
||||
index,
|
||||
fontKey,
|
||||
characterSet,
|
||||
}: {
|
||||
readonly name: string;
|
||||
readonly index: number;
|
||||
readonly fontKey: string;
|
||||
readonly characterSet?: (typeof CharacterSet)[keyof typeof CharacterSet];
|
||||
}): XmlComponent =>
|
||||
createFont({
|
||||
name,
|
||||
sig: {
|
||||
usb0: "E0002AFF",
|
||||
usb1: "C000247B",
|
||||
usb2: "00000009",
|
||||
usb3: "00000000",
|
||||
csb0: "000001FF",
|
||||
csb1: "00000000",
|
||||
},
|
||||
charset: characterSet,
|
||||
family: "auto",
|
||||
pitch: "variable",
|
||||
embedRegular: {
|
||||
fontKey,
|
||||
id: `rId${index}`,
|
||||
},
|
||||
});
|
44
src/file/fonts/font-table.ts
Normal file
44
src/file/fonts/font-table.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||
|
||||
import { createRegularFont } from "./create-regular-font";
|
||||
import { FontOptionsWithKey } from "./font-wrapper";
|
||||
import { CharacterSet } from "./font";
|
||||
|
||||
// <xsd:complexType name="CT_FontsList">
|
||||
// <xsd:sequence>
|
||||
// <xsd:element name="font" type="CT_Font" minOccurs="0" maxOccurs="unbounded"/>
|
||||
// </xsd:sequence>
|
||||
// </xsd:complexType>
|
||||
|
||||
export type FontOptions = {
|
||||
readonly name: string;
|
||||
readonly data: Buffer;
|
||||
readonly characterSet?: (typeof CharacterSet)[keyof typeof CharacterSet];
|
||||
};
|
||||
|
||||
export const createFontTable = (fonts: readonly FontOptionsWithKey[]): XmlComponent =>
|
||||
// https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_Font_topic_ID0ERNCU.html
|
||||
// http://www.datypic.com/sc/ooxml/e-w_fonts.html
|
||||
new BuilderElement({
|
||||
name: "w:fonts",
|
||||
attributes: {
|
||||
mc: { key: "xmlns:mc", value: "http://schemas.openxmlformats.org/markup-compatibility/2006" },
|
||||
r: { key: "xmlns:r", value: "http://schemas.openxmlformats.org/officeDocument/2006/relationships" },
|
||||
w: { key: "xmlns:w", value: "http://schemas.openxmlformats.org/wordprocessingml/2006/main" },
|
||||
w14: { key: "xmlns:w14", value: "http://schemas.microsoft.com/office/word/2010/wordml" },
|
||||
w15: { key: "xmlns:w15", value: "http://schemas.microsoft.com/office/word/2012/wordml" },
|
||||
w16cex: { key: "xmlns:w16cex", value: "http://schemas.microsoft.com/office/word/2018/wordml/cex" },
|
||||
w16cid: { key: "xmlns:w16cid", value: "http://schemas.microsoft.com/office/word/2016/wordml/cid" },
|
||||
w16: { key: "xmlns:w16", value: "http://schemas.microsoft.com/office/word/2018/wordml" },
|
||||
w16sdtdh: { key: "xmlns:w16sdtdh", value: "http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" },
|
||||
w16se: { key: "xmlns:w16se", value: "http://schemas.microsoft.com/office/word/2015/wordml/symex" },
|
||||
Ignorable: { key: "mc:Ignorable", value: "w14 w15 w16se w16cid w16 w16cex w16sdtdh" },
|
||||
},
|
||||
children: fonts.map((font, i) =>
|
||||
createRegularFont({
|
||||
name: font.name,
|
||||
index: i + 1,
|
||||
fontKey: font.fontKey,
|
||||
}),
|
||||
),
|
||||
});
|
36
src/file/fonts/font-wrapper.ts
Normal file
36
src/file/fonts/font-wrapper.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { IViewWrapper } from "@file/document-wrapper";
|
||||
import { Relationships } from "@file/relationships";
|
||||
import { XmlComponent } from "@file/xml-components";
|
||||
import { uniqueUuid } from "@util/convenience-functions";
|
||||
|
||||
import { FontOptions, createFontTable } from "./font-table";
|
||||
|
||||
export type FontOptionsWithKey = FontOptions & { readonly fontKey: string };
|
||||
|
||||
export class FontWrapper implements IViewWrapper {
|
||||
private readonly fontTable: XmlComponent;
|
||||
private readonly relationships: Relationships;
|
||||
public readonly fontOptionsWithKey: readonly FontOptionsWithKey[] = [];
|
||||
|
||||
public constructor(public readonly options: readonly FontOptions[]) {
|
||||
this.fontOptionsWithKey = options.map((o) => ({ ...o, fontKey: uniqueUuid() }));
|
||||
this.fontTable = createFontTable(this.fontOptionsWithKey);
|
||||
this.relationships = new Relationships();
|
||||
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
this.relationships.createRelationship(
|
||||
i + 1,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/font",
|
||||
`fonts/${options[i].name}.odttf`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public get View(): XmlComponent {
|
||||
return this.fontTable;
|
||||
}
|
||||
|
||||
public get Relationships(): Relationships {
|
||||
return this.relationships;
|
||||
}
|
||||
}
|
223
src/file/fonts/font.spec.ts
Normal file
223
src/file/fonts/font.spec.ts
Normal file
@ -0,0 +1,223 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { Formatter } from "@export/formatter";
|
||||
|
||||
import { createFont } from "./font";
|
||||
|
||||
describe("font", () => {
|
||||
it("should work", () => {
|
||||
const tree = new Formatter().format(
|
||||
createFont({
|
||||
name: "Times New Roman",
|
||||
altName: "Times New Roman",
|
||||
family: "roman",
|
||||
charset: "00",
|
||||
panose1: "02020603050405020304",
|
||||
pitch: "variable",
|
||||
embedRegular: {
|
||||
id: "rId0",
|
||||
fontKey: "00000000-0000-0000-0000-000000000000",
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(tree).to.deep.equal({
|
||||
"w:font": [
|
||||
{
|
||||
_attr: {
|
||||
"w:name": "Times New Roman",
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:altName": {
|
||||
_attr: {
|
||||
"w:val": "Times New Roman",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:panose1": {
|
||||
_attr: {
|
||||
"w:val": "02020603050405020304",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:charset": {
|
||||
_attr: {
|
||||
"w:val": "00",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:family": {
|
||||
_attr: {
|
||||
"w:val": "roman",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:pitch": {
|
||||
_attr: {
|
||||
"w:val": "variable",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:embedRegular": {
|
||||
_attr: {
|
||||
"r:id": "rId0",
|
||||
"w:fontKey": "{00000000-0000-0000-0000-000000000000}",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should work for embedBold", () => {
|
||||
const tree = new Formatter().format(
|
||||
createFont({
|
||||
name: "Times New Roman",
|
||||
embedBold: {
|
||||
id: "rId0",
|
||||
fontKey: "00000000-0000-0000-0000-000000000000",
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(tree).toStrictEqual({
|
||||
"w:font": expect.arrayContaining([
|
||||
{
|
||||
"w:embedBold": {
|
||||
_attr: {
|
||||
"r:id": "rId0",
|
||||
"w:fontKey": "{00000000-0000-0000-0000-000000000000}",
|
||||
},
|
||||
},
|
||||
},
|
||||
]),
|
||||
});
|
||||
});
|
||||
|
||||
it("should work for embedBoldItalic", () => {
|
||||
const tree = new Formatter().format(
|
||||
createFont({
|
||||
name: "Times New Roman",
|
||||
embedBoldItalic: {
|
||||
id: "rId0",
|
||||
fontKey: "00000000-0000-0000-0000-000000000000",
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(tree).toStrictEqual({
|
||||
"w:font": expect.arrayContaining([
|
||||
{
|
||||
"w:embedBoldItalic": {
|
||||
_attr: {
|
||||
"r:id": "rId0",
|
||||
"w:fontKey": "{00000000-0000-0000-0000-000000000000}",
|
||||
},
|
||||
},
|
||||
},
|
||||
]),
|
||||
});
|
||||
});
|
||||
|
||||
it("should work for embedItalic", () => {
|
||||
const tree = new Formatter().format(
|
||||
createFont({
|
||||
name: "Times New Roman",
|
||||
embedItalic: {
|
||||
id: "rId0",
|
||||
fontKey: "00000000-0000-0000-0000-000000000000",
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(tree).toStrictEqual({
|
||||
"w:font": expect.arrayContaining([
|
||||
{
|
||||
"w:embedItalic": {
|
||||
_attr: {
|
||||
"r:id": "rId0",
|
||||
"w:fontKey": "{00000000-0000-0000-0000-000000000000}",
|
||||
},
|
||||
},
|
||||
},
|
||||
]),
|
||||
});
|
||||
});
|
||||
|
||||
it("should work for notTrueType", () => {
|
||||
const tree = new Formatter().format(
|
||||
createFont({
|
||||
name: "Times New Roman",
|
||||
embedRegular: {
|
||||
id: "rId0",
|
||||
fontKey: "00000000-0000-0000-0000-000000000000",
|
||||
subsetted: true,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(tree).toStrictEqual({
|
||||
"w:font": expect.arrayContaining([
|
||||
{
|
||||
"w:embedRegular": [
|
||||
{
|
||||
_attr: {
|
||||
"r:id": "rId0",
|
||||
"w:fontKey": "{00000000-0000-0000-0000-000000000000}",
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:subsetted": {},
|
||||
},
|
||||
],
|
||||
},
|
||||
]),
|
||||
});
|
||||
});
|
||||
|
||||
it("should work for subsetted", () => {
|
||||
const tree = new Formatter().format(
|
||||
createFont({
|
||||
name: "Times New Roman",
|
||||
notTrueType: true,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(tree).toStrictEqual({
|
||||
"w:font": expect.arrayContaining([
|
||||
{
|
||||
"w:notTrueType": {},
|
||||
},
|
||||
]),
|
||||
});
|
||||
});
|
||||
|
||||
it("should work without fontKey", () => {
|
||||
const tree = new Formatter().format(
|
||||
createFont({
|
||||
name: "Times New Roman",
|
||||
embedItalic: {
|
||||
id: "rId0",
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(tree).toStrictEqual({
|
||||
"w:font": expect.arrayContaining([
|
||||
{
|
||||
"w:embedItalic": {
|
||||
_attr: {
|
||||
"r:id": "rId0",
|
||||
},
|
||||
},
|
||||
},
|
||||
]),
|
||||
});
|
||||
});
|
||||
});
|
156
src/file/fonts/font.ts
Normal file
156
src/file/fonts/font.ts
Normal file
@ -0,0 +1,156 @@
|
||||
import { BuilderElement, createStringElement, OnOffElement, XmlComponent } from "@file/xml-components";
|
||||
|
||||
// <xsd:complexType name="CT_Font">
|
||||
// <xsd:sequence>
|
||||
// <xsd:element name="altName" type="CT_String" minOccurs="0" maxOccurs="1"/>
|
||||
// <xsd:element name="panose1" type="CT_Panose" minOccurs="0" maxOccurs="1"/>
|
||||
// <xsd:element name="charset" type="CT_Charset" minOccurs="0" maxOccurs="1"/>
|
||||
// <xsd:element name="family" type="CT_FontFamily" minOccurs="0" maxOccurs="1"/>
|
||||
// <xsd:element name="notTrueType" type="CT_OnOff" minOccurs="0" maxOccurs="1"/>
|
||||
// <xsd:element name="pitch" type="CT_Pitch" minOccurs="0" maxOccurs="1"/>
|
||||
// <xsd:element name="sig" type="CT_FontSig" minOccurs="0" maxOccurs="1"/>
|
||||
// <xsd:element name="embedRegular" type="CT_FontRel" minOccurs="0" maxOccurs="1"/>
|
||||
// <xsd:element name="embedBold" type="CT_FontRel" minOccurs="0" maxOccurs="1"/>
|
||||
// <xsd:element name="embedItalic" type="CT_FontRel" minOccurs="0" maxOccurs="1"/>
|
||||
// <xsd:element name="embedBoldItalic" type="CT_FontRel" minOccurs="0" maxOccurs="1"/>
|
||||
// </xsd:sequence>
|
||||
// <xsd:attribute name="name" type="s:ST_String" use="required"/>
|
||||
// </xsd:complexType>
|
||||
|
||||
// <xsd:complexType name="CT_FontRel">
|
||||
// <xsd:complexContent>
|
||||
// <xsd:extension base="CT_Rel">
|
||||
// <xsd:attribute name="fontKey" type="s:ST_Guid" />
|
||||
// <xsd:attribute name="subsetted" type="s:ST_OnOff" />
|
||||
// </xsd:extension>
|
||||
// </xsd:complexContent>
|
||||
// </xsd:complexType>
|
||||
|
||||
// http://www.datypic.com/sc/ooxml/e-w_embedRegular-1.html
|
||||
export interface IFontRelationshipOptions {
|
||||
/**
|
||||
* Relationship to Part
|
||||
*/
|
||||
readonly id: string;
|
||||
/**
|
||||
* Embedded Font Obfuscation Key
|
||||
*/
|
||||
readonly fontKey?: string;
|
||||
/**
|
||||
* Embedded Font Is Subsetted
|
||||
*/
|
||||
readonly subsetted?: boolean;
|
||||
}
|
||||
|
||||
export const CharacterSet = {
|
||||
ANSI: "00",
|
||||
DEFAULT: "01",
|
||||
SYMBOL: "02",
|
||||
MAC: "4D",
|
||||
JIS: "80",
|
||||
HANGUL: "81",
|
||||
JOHAB: "82",
|
||||
GB_2312: "86",
|
||||
CHINESEBIG5: "88",
|
||||
GREEK: "A1",
|
||||
TURKISH: "A2",
|
||||
VIETNAMESE: "A3",
|
||||
HEBREW: "B1",
|
||||
ARABIC: "B2",
|
||||
BALTIC: "BA",
|
||||
RUSSIAN: "CC",
|
||||
THAI: "DE",
|
||||
EASTEUROPE: "EE",
|
||||
OEM: "FF",
|
||||
} as const;
|
||||
|
||||
export type FontOptions = {
|
||||
readonly name: string;
|
||||
readonly altName?: string;
|
||||
readonly panose1?: string;
|
||||
readonly charset?: (typeof CharacterSet)[keyof typeof CharacterSet];
|
||||
readonly family?: string;
|
||||
readonly notTrueType?: boolean;
|
||||
readonly pitch?: string;
|
||||
readonly sig?: {
|
||||
readonly usb0: string;
|
||||
readonly usb1: string;
|
||||
readonly usb2: string;
|
||||
readonly usb3: string;
|
||||
readonly csb0: string;
|
||||
readonly csb1: string;
|
||||
};
|
||||
readonly embedRegular?: IFontRelationshipOptions;
|
||||
readonly embedBold?: IFontRelationshipOptions;
|
||||
readonly embedItalic?: IFontRelationshipOptions;
|
||||
readonly embedBoldItalic?: IFontRelationshipOptions;
|
||||
};
|
||||
|
||||
const createFontRelationship = ({ id, fontKey, subsetted }: IFontRelationshipOptions, name: string): XmlComponent =>
|
||||
new BuilderElement({
|
||||
name,
|
||||
attributes: {
|
||||
id: { key: "r:id", value: id },
|
||||
...(fontKey ? { fontKey: { key: "w:fontKey", value: `{${fontKey}}` } } : {}),
|
||||
},
|
||||
children: [...(subsetted ? [new OnOffElement("w:subsetted", subsetted)] : [])],
|
||||
});
|
||||
|
||||
export const createFont = ({
|
||||
name,
|
||||
altName,
|
||||
panose1,
|
||||
charset,
|
||||
family,
|
||||
notTrueType,
|
||||
pitch,
|
||||
sig,
|
||||
embedRegular,
|
||||
embedBold,
|
||||
embedItalic,
|
||||
embedBoldItalic,
|
||||
}: FontOptions): XmlComponent =>
|
||||
// http://www.datypic.com/sc/ooxml/e-w_font-1.html
|
||||
new BuilderElement({
|
||||
name: "w:font",
|
||||
attributes: {
|
||||
name: { key: "w:name", value: name },
|
||||
},
|
||||
children: [
|
||||
// http://www.datypic.com/sc/ooxml/e-w_altName-1.html
|
||||
...(altName ? [createStringElement("w:altName", altName)] : []),
|
||||
// http://www.datypic.com/sc/ooxml/e-w_panose1-1.html
|
||||
...(panose1 ? [createStringElement("w:panose1", panose1)] : []),
|
||||
// http://www.datypic.com/sc/ooxml/e-w_charset-1.html
|
||||
...(charset ? [createStringElement("w:charset", charset)] : []),
|
||||
// http://www.datypic.com/sc/ooxml/e-w_family-1.html
|
||||
...(family ? [createStringElement("w:family", family)] : []),
|
||||
// http://www.datypic.com/sc/ooxml/e-w_notTrueType-1.html
|
||||
...(notTrueType ? [new OnOffElement("w:notTrueType", notTrueType)] : []),
|
||||
...(pitch ? [createStringElement("w:pitch", pitch)] : []),
|
||||
// http://www.datypic.com/sc/ooxml/e-w_sig-1.html
|
||||
...(sig
|
||||
? [
|
||||
new BuilderElement({
|
||||
name: "w:sig",
|
||||
attributes: {
|
||||
usb0: { key: "w:usb0", value: sig.usb0 },
|
||||
usb1: { key: "w:usb1", value: sig.usb1 },
|
||||
usb2: { key: "w:usb2", value: sig.usb2 },
|
||||
usb3: { key: "w:usb3", value: sig.usb3 },
|
||||
csb0: { key: "w:csb0", value: sig.csb0 },
|
||||
csb1: { key: "w:csb1", value: sig.csb1 },
|
||||
},
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
// http://www.datypic.com/sc/ooxml/e-w_embedRegular-1.html
|
||||
...(embedRegular ? [createFontRelationship(embedRegular, "w:embedRegular")] : []),
|
||||
// http://www.datypic.com/sc/ooxml/e-w_embedBold-1.html
|
||||
...(embedBold ? [createFontRelationship(embedBold, "w:embedBold")] : []),
|
||||
// http://www.datypic.com/sc/ooxml/e-w_embedItalic-1.html
|
||||
...(embedItalic ? [createFontRelationship(embedItalic, "w:embedItalic")] : []),
|
||||
// http://www.datypic.com/sc/ooxml/e-w_embedBoldItalic-1.html
|
||||
...(embedBoldItalic ? [createFontRelationship(embedBoldItalic, "w:embedBoldItalic")] : []),
|
||||
],
|
||||
});
|
1
src/file/fonts/index.ts
Normal file
1
src/file/fonts/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { CharacterSet } from "./font";
|
22
src/file/fonts/obfuscate-ttf-to-odttf.ts
Normal file
22
src/file/fonts/obfuscate-ttf-to-odttf.ts
Normal file
@ -0,0 +1,22 @@
|
||||
const obfuscatedStartOffset = 0;
|
||||
const obfuscatedEndOffset = 32;
|
||||
const guidSize = 32;
|
||||
|
||||
export const obfuscate = (buf: Buffer, fontKey: string): Buffer => {
|
||||
const guid = fontKey.replace(/-/g, "");
|
||||
if (guid.length !== guidSize) {
|
||||
throw new Error(`Error: Cannot extract GUID from font filename: ${fontKey}`);
|
||||
}
|
||||
|
||||
const hexStrings = guid.replace(/(..)/g, "$1 ").trim().split(" ");
|
||||
const hexNumbers = hexStrings.map((hexString) => parseInt(hexString, 16));
|
||||
// eslint-disable-next-line functional/immutable-data
|
||||
hexNumbers.reverse();
|
||||
|
||||
const bytesToObfuscate = buf.slice(obfuscatedStartOffset, obfuscatedEndOffset);
|
||||
// eslint-disable-next-line no-bitwise
|
||||
const obfuscatedBytes = bytesToObfuscate.map((byte, i) => byte ^ hexNumbers[i % hexNumbers.length]);
|
||||
|
||||
const out = Buffer.concat([buf.slice(0, obfuscatedStartOffset), obfuscatedBytes, buf.slice(obfuscatedEndOffset)]);
|
||||
return out;
|
||||
};
|
14
src/file/fonts/obsfuscate-ttf-to-odtts.spec.ts
Normal file
14
src/file/fonts/obsfuscate-ttf-to-odtts.spec.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { obfuscate } from "./obfuscate-ttf-to-odttf";
|
||||
|
||||
describe("obfuscate", () => {
|
||||
it("should work", () => {
|
||||
const buffer = obfuscate(Buffer.from(""), "00000000-0000-0000-0000-000000000000");
|
||||
expect(buffer).toBeDefined();
|
||||
});
|
||||
|
||||
it("should throw error if uuid is not correct", () => {
|
||||
expect(() => obfuscate(Buffer.from(""), "bad-uuid")).toThrowError();
|
||||
});
|
||||
});
|
@ -1,6 +1,7 @@
|
||||
export * from "./paragraph";
|
||||
export * from "./table";
|
||||
export * from "./file";
|
||||
export * from "./file-child";
|
||||
export * from "./numbering";
|
||||
export * from "./media";
|
||||
export * from "./drawing";
|
||||
@ -18,3 +19,4 @@ export * from "./shared";
|
||||
export * from "./border";
|
||||
export * from "./vertical-align";
|
||||
export * from "./checkbox";
|
||||
export * from "./fonts";
|
||||
|
@ -14,11 +14,25 @@ export interface IMediaDataTransformation {
|
||||
readonly rotation?: number;
|
||||
}
|
||||
|
||||
export interface IMediaData {
|
||||
readonly stream: Buffer | Uint8Array | ArrayBuffer;
|
||||
type CoreMediaData = {
|
||||
readonly fileName: string;
|
||||
readonly transformation: IMediaDataTransformation;
|
||||
}
|
||||
readonly data: Buffer | Uint8Array | ArrayBuffer;
|
||||
};
|
||||
|
||||
type RegularMediaData = {
|
||||
readonly type: "jpg" | "png" | "gif" | "bmp";
|
||||
};
|
||||
|
||||
type SvgMediaData = {
|
||||
readonly type: "svg";
|
||||
/**
|
||||
* Required in case the Word processor does not support SVG.
|
||||
*/
|
||||
readonly fallback: RegularMediaData & CoreMediaData;
|
||||
};
|
||||
|
||||
export type IMediaData = (RegularMediaData | SvgMediaData) & CoreMediaData;
|
||||
|
||||
// Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432
|
||||
/**
|
||||
|
@ -19,7 +19,8 @@ describe("Media", () => {
|
||||
const media = new Media();
|
||||
|
||||
media.addImage("test2.png", {
|
||||
stream: Buffer.from(""),
|
||||
type: "png",
|
||||
data: Buffer.from(""),
|
||||
fileName: "test.png",
|
||||
transformation: {
|
||||
pixels: {
|
||||
|
@ -4,6 +4,7 @@ import { Formatter } from "@export/formatter";
|
||||
|
||||
import { AlignmentType, EmphasisMarkType, TabStopPosition } from "../paragraph";
|
||||
import { UnderlineType } from "../paragraph/run/underline";
|
||||
import { HighlightColor } from "../paragraph/run/properties";
|
||||
import { ShadingType } from "../shading";
|
||||
import { AbstractNumbering } from "./abstract-numbering";
|
||||
import { LevelFormat, LevelSuffix } from "./level";
|
||||
@ -2048,23 +2049,23 @@ describe("AbstractNumbering", () => {
|
||||
|
||||
const highlightTests = [
|
||||
{
|
||||
highlight: "005599",
|
||||
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "005599" } } }],
|
||||
highlight: HighlightColor.YELLOW,
|
||||
expected: [{ "w:highlight": { _attr: { "w:val": "yellow" } } }, { "w:highlightCs": { _attr: { "w:val": "yellow" } } }],
|
||||
},
|
||||
{
|
||||
highlight: "005599",
|
||||
highlight: HighlightColor.YELLOW,
|
||||
highlightComplexScript: true,
|
||||
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "005599" } } }],
|
||||
expected: [{ "w:highlight": { _attr: { "w:val": "yellow" } } }, { "w:highlightCs": { _attr: { "w:val": "yellow" } } }],
|
||||
},
|
||||
{
|
||||
highlight: "005599",
|
||||
highlight: HighlightColor.YELLOW,
|
||||
highlightComplexScript: false,
|
||||
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }],
|
||||
expected: [{ "w:highlight": { _attr: { "w:val": "yellow" } } }],
|
||||
},
|
||||
{
|
||||
highlight: "005599",
|
||||
highlight: HighlightColor.YELLOW,
|
||||
highlightComplexScript: "550099",
|
||||
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "550099" } } }],
|
||||
expected: [{ "w:highlight": { _attr: { "w:val": "yellow" } } }, { "w:highlightCs": { _attr: { "w:val": "550099" } } }],
|
||||
},
|
||||
];
|
||||
highlightTests.forEach(({ highlight, highlightComplexScript, expected }) => {
|
||||
|
@ -3,12 +3,12 @@ import { describe, expect, it } from "vitest";
|
||||
import { Formatter } from "@export/formatter";
|
||||
import { HorizontalPositionAlign, VerticalPositionAlign } from "@file/shared";
|
||||
|
||||
import { FrameAnchorType, FrameProperties } from "./frame-properties";
|
||||
import { FrameAnchorType, createFrameProperties } from "./frame-properties";
|
||||
|
||||
describe("FrameProperties", () => {
|
||||
describe("#constructor()", () => {
|
||||
describe("createFrameProperties", () => {
|
||||
it("should create", () => {
|
||||
const currentFrameProperties = new FrameProperties({
|
||||
const currentFrameProperties = createFrameProperties({
|
||||
type: "absolute",
|
||||
position: {
|
||||
x: 1000,
|
||||
y: 3000,
|
||||
@ -19,10 +19,6 @@ describe("FrameProperties", () => {
|
||||
horizontal: FrameAnchorType.MARGIN,
|
||||
vertical: FrameAnchorType.MARGIN,
|
||||
},
|
||||
alignment: {
|
||||
x: HorizontalPositionAlign.CENTER,
|
||||
y: VerticalPositionAlign.TOP,
|
||||
},
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(currentFrameProperties);
|
||||
@ -34,16 +30,15 @@ describe("FrameProperties", () => {
|
||||
"w:vAnchor": "margin",
|
||||
"w:w": 4000,
|
||||
"w:x": 1000,
|
||||
"w:xAlign": "center",
|
||||
"w:y": 3000,
|
||||
"w:yAlign": "top",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("should create with the space attribute", () => {
|
||||
const currentFrameProperties = new FrameProperties({
|
||||
const currentFrameProperties = createFrameProperties({
|
||||
type: "absolute",
|
||||
position: {
|
||||
x: 1000,
|
||||
y: 3000,
|
||||
@ -54,10 +49,6 @@ describe("FrameProperties", () => {
|
||||
horizontal: FrameAnchorType.MARGIN,
|
||||
vertical: FrameAnchorType.MARGIN,
|
||||
},
|
||||
alignment: {
|
||||
x: HorizontalPositionAlign.CENTER,
|
||||
y: VerticalPositionAlign.TOP,
|
||||
},
|
||||
space: {
|
||||
horizontal: 100,
|
||||
vertical: 200,
|
||||
@ -73,9 +64,7 @@ describe("FrameProperties", () => {
|
||||
"w:vAnchor": "margin",
|
||||
"w:w": 4000,
|
||||
"w:x": 1000,
|
||||
"w:xAlign": "center",
|
||||
"w:y": 3000,
|
||||
"w:yAlign": "top",
|
||||
"w:hSpace": 100,
|
||||
"w:vSpace": 200,
|
||||
},
|
||||
@ -84,7 +73,8 @@ describe("FrameProperties", () => {
|
||||
});
|
||||
|
||||
it("should create without x and y", () => {
|
||||
const currentFrameProperties = new FrameProperties({
|
||||
const currentFrameProperties = createFrameProperties({
|
||||
type: "alignment",
|
||||
width: 4000,
|
||||
height: 1000,
|
||||
anchor: {
|
||||
@ -119,7 +109,8 @@ describe("FrameProperties", () => {
|
||||
});
|
||||
|
||||
it("should create without alignments", () => {
|
||||
const currentFrameProperties = new FrameProperties({
|
||||
const currentFrameProperties = createFrameProperties({
|
||||
type: "absolute",
|
||||
position: {
|
||||
x: 1000,
|
||||
y: 3000,
|
||||
@ -153,4 +144,3 @@ describe("FrameProperties", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
// http://officeopenxml.com/WPparagraph-textFrames.php
|
||||
import { HorizontalPositionAlign, VerticalPositionAlign } from "@file/shared/alignment";
|
||||
import { HeightRule } from "@file/table";
|
||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
||||
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||
|
||||
export const DropCapType = {
|
||||
NONE: "none",
|
||||
@ -44,6 +44,7 @@ interface IBaseFrameOptions {
|
||||
}
|
||||
|
||||
export interface IXYFrameOptions extends IBaseFrameOptions {
|
||||
readonly type: "absolute";
|
||||
readonly position: {
|
||||
readonly x: number;
|
||||
readonly y: number;
|
||||
@ -51,6 +52,7 @@ export interface IXYFrameOptions extends IBaseFrameOptions {
|
||||
}
|
||||
|
||||
export interface IAlignmentFrameOptions extends IBaseFrameOptions {
|
||||
readonly type: "alignment";
|
||||
readonly alignment: {
|
||||
readonly x: (typeof HorizontalPositionAlign)[keyof typeof HorizontalPositionAlign];
|
||||
readonly y: (typeof VerticalPositionAlign)[keyof typeof VerticalPositionAlign];
|
||||
@ -61,7 +63,24 @@ export interface IAlignmentFrameOptions extends IBaseFrameOptions {
|
||||
// https://stackoverflow.com/q/46370222/3481582
|
||||
export type IFrameOptions = IXYFrameOptions | IAlignmentFrameOptions;
|
||||
|
||||
export class FramePropertiesAttributes extends XmlAttributeComponent<{
|
||||
// <xsd:complexType name="CT_FramePr">
|
||||
// <xsd:attribute name="dropCap" type="ST_DropCap" use="optional"/>
|
||||
// <xsd:attribute name="lines" type="ST_DecimalNumber" use="optional"/>
|
||||
// <xsd:attribute name="w" type="s:ST_TwipsMeasure" use="optional"/>
|
||||
// <xsd:attribute name="h" type="s:ST_TwipsMeasure" use="optional"/>
|
||||
// <xsd:attribute name="vSpace" type="s:ST_TwipsMeasure" use="optional"/>
|
||||
// <xsd:attribute name="hSpace" type="s:ST_TwipsMeasure" use="optional"/>
|
||||
// <xsd:attribute name="wrap" type="ST_Wrap" use="optional"/>
|
||||
// <xsd:attribute name="hAnchor" type="ST_HAnchor" use="optional"/>
|
||||
// <xsd:attribute name="vAnchor" type="ST_VAnchor" use="optional"/>
|
||||
// <xsd:attribute name="x" type="ST_SignedTwipsMeasure" use="optional"/>
|
||||
// <xsd:attribute name="xAlign" type="s:ST_XAlign" use="optional"/>
|
||||
// <xsd:attribute name="y" type="ST_SignedTwipsMeasure" use="optional"/>
|
||||
// <xsd:attribute name="yAlign" type="s:ST_YAlign" use="optional"/>
|
||||
// <xsd:attribute name="hRule" type="ST_HeightRule" use="optional"/>
|
||||
// <xsd:attribute name="anchorLock" type="s:ST_OnOff" use="optional"/>
|
||||
// </xsd:complexType>
|
||||
type FramePropertiesAttributes = {
|
||||
readonly anchorLock?: boolean;
|
||||
readonly dropCap?: (typeof DropCapType)[keyof typeof DropCapType];
|
||||
readonly width: number;
|
||||
@ -77,47 +96,71 @@ export class FramePropertiesAttributes extends XmlAttributeComponent<{
|
||||
readonly rule?: (typeof HeightRule)[keyof typeof HeightRule];
|
||||
readonly alignmentX?: (typeof HorizontalPositionAlign)[keyof typeof HorizontalPositionAlign];
|
||||
readonly alignmentY?: (typeof VerticalPositionAlign)[keyof typeof VerticalPositionAlign];
|
||||
}> {
|
||||
protected readonly xmlKeys = {
|
||||
anchorLock: "w:anchorLock",
|
||||
dropCap: "w:dropCap",
|
||||
width: "w:w",
|
||||
height: "w:h",
|
||||
x: "w:x",
|
||||
y: "w:y",
|
||||
anchorHorizontal: "w:hAnchor",
|
||||
anchorVertical: "w:vAnchor",
|
||||
spaceHorizontal: "w:hSpace",
|
||||
spaceVertical: "w:vSpace",
|
||||
rule: "w:hRule",
|
||||
alignmentX: "w:xAlign",
|
||||
alignmentY: "w:yAlign",
|
||||
lines: "w:lines",
|
||||
wrap: "w:wrap",
|
||||
};
|
||||
}
|
||||
|
||||
export class FrameProperties extends XmlComponent {
|
||||
public constructor(options: IFrameOptions) {
|
||||
super("w:framePr");
|
||||
this.root.push(
|
||||
new FramePropertiesAttributes({
|
||||
anchorLock: options.anchorLock,
|
||||
dropCap: options.dropCap,
|
||||
width: options.width,
|
||||
height: options.height,
|
||||
x: (options as IXYFrameOptions).position ? (options as IXYFrameOptions).position.x : undefined,
|
||||
y: (options as IXYFrameOptions).position ? (options as IXYFrameOptions).position.y : undefined,
|
||||
anchorHorizontal: options.anchor.horizontal,
|
||||
anchorVertical: options.anchor.vertical,
|
||||
spaceHorizontal: options.space?.horizontal,
|
||||
spaceVertical: options.space?.vertical,
|
||||
rule: options.rule,
|
||||
alignmentX: (options as IAlignmentFrameOptions).alignment ? (options as IAlignmentFrameOptions).alignment.x : undefined,
|
||||
alignmentY: (options as IAlignmentFrameOptions).alignment ? (options as IAlignmentFrameOptions).alignment.y : undefined,
|
||||
lines: options.lines,
|
||||
wrap: options.wrap,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
export const createFrameProperties = (options: IFrameOptions): XmlComponent =>
|
||||
new BuilderElement<FramePropertiesAttributes>({
|
||||
name: "w:framePr",
|
||||
attributes: {
|
||||
anchorLock: {
|
||||
key: "w:anchorLock",
|
||||
value: options.anchorLock,
|
||||
},
|
||||
dropCap: {
|
||||
key: "w:dropCap",
|
||||
value: options.dropCap,
|
||||
},
|
||||
width: {
|
||||
key: "w:w",
|
||||
value: options.width,
|
||||
},
|
||||
height: {
|
||||
key: "w:h",
|
||||
value: options.height,
|
||||
},
|
||||
x: {
|
||||
key: "w:x",
|
||||
value: (options as IXYFrameOptions).position ? (options as IXYFrameOptions).position.x : undefined,
|
||||
},
|
||||
y: {
|
||||
key: "w:y",
|
||||
value: (options as IXYFrameOptions).position ? (options as IXYFrameOptions).position.y : undefined,
|
||||
},
|
||||
anchorHorizontal: {
|
||||
key: "w:hAnchor",
|
||||
value: options.anchor.horizontal,
|
||||
},
|
||||
anchorVertical: {
|
||||
key: "w:vAnchor",
|
||||
value: options.anchor.vertical,
|
||||
},
|
||||
spaceHorizontal: {
|
||||
key: "w:hSpace",
|
||||
value: options.space?.horizontal,
|
||||
},
|
||||
spaceVertical: {
|
||||
key: "w:vSpace",
|
||||
value: options.space?.vertical,
|
||||
},
|
||||
rule: {
|
||||
key: "w:hRule",
|
||||
value: options.rule,
|
||||
},
|
||||
alignmentX: {
|
||||
key: "w:xAlign",
|
||||
value: (options as IAlignmentFrameOptions).alignment ? (options as IAlignmentFrameOptions).alignment.x : undefined,
|
||||
},
|
||||
alignmentY: {
|
||||
key: "w:yAlign",
|
||||
value: (options as IAlignmentFrameOptions).alignment ? (options as IAlignmentFrameOptions).alignment.y : undefined,
|
||||
},
|
||||
lines: {
|
||||
key: "w:lines",
|
||||
value: options.lines,
|
||||
},
|
||||
wrap: {
|
||||
key: "w:wrap",
|
||||
value: options.wrap,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -2,7 +2,7 @@ import { SpaceType } from "@file/shared";
|
||||
import { XmlComponent } from "@file/xml-components";
|
||||
|
||||
import { TextAttributes } from "../run/text-attributes";
|
||||
import { IPageReferenceOptions } from "./pageref-properties";
|
||||
import { IPageReferenceOptions } from "./pageref";
|
||||
|
||||
export class PageReferenceFieldInstruction extends XmlComponent {
|
||||
public constructor(bookmarkId: string, options: IPageReferenceOptions = {}) {
|
||||
|
@ -1,16 +0,0 @@
|
||||
// Options according to https://www.ecma-international.org/publications/standards/Ecma-376.htm (at Part 1, Page 1234)
|
||||
|
||||
export interface IPageReferenceOptions {
|
||||
/**
|
||||
* \h option - Creates a hyperlink to the bookmarked paragraph.
|
||||
*/
|
||||
readonly hyperlink?: boolean;
|
||||
/**
|
||||
* \p option - Causes the field to display its position relative to the source
|
||||
* bookmark. If the PAGEREF field is on the same page as the
|
||||
* bookmark, it omits "on page #" and returns "above" or "below"
|
||||
* only. If the PAGEREF field is not on the same page as the
|
||||
* bookmark, the string "on page #" is used.
|
||||
*/
|
||||
readonly useRelativePosition?: boolean;
|
||||
}
|
@ -2,7 +2,22 @@
|
||||
import { Begin, End } from "@file/paragraph/run/field";
|
||||
import { Run } from "../run";
|
||||
import { PageReferenceFieldInstruction } from "./pageref-field-instruction";
|
||||
import type { IPageReferenceOptions } from "./pageref-properties";
|
||||
|
||||
// Options according to https://www.ecma-international.org/publications/standards/Ecma-376.htm (at Part 1, Page 1234)
|
||||
export type IPageReferenceOptions = {
|
||||
/**
|
||||
* \h option - Creates a hyperlink to the bookmarked paragraph.
|
||||
*/
|
||||
readonly hyperlink?: boolean;
|
||||
/**
|
||||
* \p option - Causes the field to display its position relative to the source
|
||||
* bookmark. If the PAGEREF field is on the same page as the
|
||||
* bookmark, it omits "on page #" and returns "above" or "below"
|
||||
* only. If the PAGEREF field is not on the same page as the
|
||||
* bookmark, the string "on page #" is used.
|
||||
*/
|
||||
readonly useRelativePosition?: boolean;
|
||||
};
|
||||
|
||||
export class PageReference extends Run {
|
||||
public constructor(bookmarkId: string, options: IPageReferenceOptions = {}) {
|
||||
|
@ -6,3 +6,6 @@ export * from "./math-sub-script";
|
||||
export * from "./math-sum";
|
||||
export * from "./math-integral";
|
||||
export * from "./math-super-script";
|
||||
export * from "./math-limit";
|
||||
export * from "./math-limit-upper";
|
||||
export * from "./math-limit-lower";
|
||||
|
@ -22,7 +22,7 @@ describe("MathIntegral", () => {
|
||||
{
|
||||
"m:limLoc": {
|
||||
_attr: {
|
||||
"m:val": "undOvr",
|
||||
"m:val": "subSup",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -78,7 +78,7 @@ describe("MathIntegral", () => {
|
||||
{
|
||||
"m:limLoc": {
|
||||
_attr: {
|
||||
"m:val": "undOvr",
|
||||
"m:val": "subSup",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -16,7 +16,7 @@ export class MathIntegral extends XmlComponent {
|
||||
public constructor(options: IMathIntegralOptions) {
|
||||
super("m:nary");
|
||||
|
||||
this.root.push(new MathNAryProperties("", !!options.superScript, !!options.subScript));
|
||||
this.root.push(new MathNAryProperties("", !!options.superScript, !!options.subScript, "subSup"));
|
||||
|
||||
if (!!options.subScript) {
|
||||
this.root.push(new MathSubScriptElement(options.subScript));
|
||||
|
@ -6,9 +6,9 @@ class MathLimitLocationAttributes extends XmlAttributeComponent<{ readonly value
|
||||
}
|
||||
|
||||
export class MathLimitLocation extends XmlComponent {
|
||||
public constructor() {
|
||||
public constructor(value?: string) {
|
||||
super("m:limLoc");
|
||||
|
||||
this.root.push(new MathLimitLocationAttributes({ value: "undOvr" }));
|
||||
this.root.push(new MathLimitLocationAttributes({ value: value || "undOvr" }));
|
||||
}
|
||||
}
|
||||
|
45
src/file/paragraph/math/n-ary/math-limit-lower.spec.ts
Normal file
45
src/file/paragraph/math/n-ary/math-limit-lower.spec.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { Formatter } from "@export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathLimitLower } from "./math-limit-lower";
|
||||
|
||||
describe("MathLimitLower", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathLimitLower with correct root key", () => {
|
||||
const mathLimitLower = new MathLimitLower({
|
||||
children: [new MathRun("lim")],
|
||||
limit: [new MathRun("x→0")],
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(mathLimitLower);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:limLow": [
|
||||
{
|
||||
"m:e": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["lim"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"m:lim": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["x→0"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
19
src/file/paragraph/math/n-ary/math-limit-lower.ts
Normal file
19
src/file/paragraph/math/n-ary/math-limit-lower.ts
Normal file
@ -0,0 +1,19 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_limLow-1.html
|
||||
import { XmlComponent } from "@file/xml-components";
|
||||
import { MathComponent } from "../math-component";
|
||||
import { MathBase } from "./math-base";
|
||||
import { MathLimit } from "./math-limit";
|
||||
|
||||
export interface IMathLimitLowerOptions {
|
||||
readonly children: readonly MathComponent[];
|
||||
readonly limit: readonly MathComponent[];
|
||||
}
|
||||
|
||||
export class MathLimitLower extends XmlComponent {
|
||||
public constructor(options: IMathLimitLowerOptions) {
|
||||
super("m:limLow");
|
||||
|
||||
this.root.push(new MathBase(options.children));
|
||||
this.root.push(new MathLimit(options.limit));
|
||||
}
|
||||
}
|
45
src/file/paragraph/math/n-ary/math-limit-upper.spec.ts
Normal file
45
src/file/paragraph/math/n-ary/math-limit-upper.spec.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { Formatter } from "@export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathLimitUpper } from "./math-limit-upper";
|
||||
|
||||
describe("MathLimitUpper", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathLimitUpper with correct root key", () => {
|
||||
const mathLimitUpper = new MathLimitUpper({
|
||||
children: [new MathRun("x")],
|
||||
limit: [new MathRun("-")],
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(mathLimitUpper);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:limUpp": [
|
||||
{
|
||||
"m:e": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["x"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"m:lim": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["-"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
19
src/file/paragraph/math/n-ary/math-limit-upper.ts
Normal file
19
src/file/paragraph/math/n-ary/math-limit-upper.ts
Normal file
@ -0,0 +1,19 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_limUpp-1.html
|
||||
import { XmlComponent } from "@file/xml-components";
|
||||
import { MathComponent } from "../math-component";
|
||||
import { MathBase } from "./math-base";
|
||||
import { MathLimit } from "./math-limit";
|
||||
|
||||
export interface IMathLimitUpperOptions {
|
||||
readonly children: readonly MathComponent[];
|
||||
readonly limit: readonly MathComponent[];
|
||||
}
|
||||
|
||||
export class MathLimitUpper extends XmlComponent {
|
||||
public constructor(options: IMathLimitUpperOptions) {
|
||||
super("m:limUpp");
|
||||
|
||||
this.root.push(new MathBase(options.children));
|
||||
this.root.push(new MathLimit(options.limit));
|
||||
}
|
||||
}
|
27
src/file/paragraph/math/n-ary/math-limit.spec.ts
Normal file
27
src/file/paragraph/math/n-ary/math-limit.spec.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { Formatter } from "@export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathLimit } from "./math-limit";
|
||||
|
||||
describe("MathLimit", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathLimit with correct root key", () => {
|
||||
const mathLimit = new MathLimit([new MathRun("x→0")]);
|
||||
|
||||
const tree = new Formatter().format(mathLimit);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:lim": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["x→0"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
13
src/file/paragraph/math/n-ary/math-limit.ts
Normal file
13
src/file/paragraph/math/n-ary/math-limit.ts
Normal file
@ -0,0 +1,13 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_lim-1.html
|
||||
import { XmlComponent } from "@file/xml-components";
|
||||
import { MathComponent } from "../math-component";
|
||||
|
||||
export class MathLimit extends XmlComponent {
|
||||
public constructor(children: readonly MathComponent[]) {
|
||||
super("m:lim");
|
||||
|
||||
for (const child of children) {
|
||||
this.root.push(child);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,13 +7,13 @@ import { MathSubScriptHide } from "./math-sub-script-hide";
|
||||
import { MathSuperScriptHide } from "./math-super-script-hide";
|
||||
|
||||
export class MathNAryProperties extends XmlComponent {
|
||||
public constructor(accent: string, hasSuperScript: boolean, hasSubScript: boolean) {
|
||||
public constructor(accent: string, hasSuperScript: boolean, hasSubScript: boolean, limitLocationVal?: string) {
|
||||
super("m:naryPr");
|
||||
|
||||
if (!!accent) {
|
||||
this.root.push(new MathAccentCharacter(accent));
|
||||
}
|
||||
this.root.push(new MathLimitLocation());
|
||||
this.root.push(new MathLimitLocation(limitLocationVal));
|
||||
|
||||
if (!hasSuperScript) {
|
||||
this.root.push(new MathSuperScriptHide());
|
||||
|
@ -890,10 +890,7 @@ describe("Paragraph", () => {
|
||||
it("should set frame attribute", () => {
|
||||
const paragraph = new Paragraph({
|
||||
frame: {
|
||||
position: {
|
||||
x: 1000,
|
||||
y: 3000,
|
||||
},
|
||||
type: "alignment",
|
||||
width: 4000,
|
||||
height: 1000,
|
||||
anchor: {
|
||||
@ -918,9 +915,7 @@ describe("Paragraph", () => {
|
||||
"w:hAnchor": "margin",
|
||||
"w:vAnchor": "margin",
|
||||
"w:w": 4000,
|
||||
"w:x": 1000,
|
||||
"w:xAlign": "center",
|
||||
"w:y": 3000,
|
||||
"w:yAlign": "top",
|
||||
},
|
||||
},
|
||||
|
@ -65,6 +65,36 @@ describe("ParagraphProperties", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should create with numbering disabled", () => {
|
||||
const properties = new ParagraphProperties({
|
||||
numbering: false,
|
||||
});
|
||||
const tree = new Formatter().format(properties);
|
||||
|
||||
expect(tree).to.deep.equal({
|
||||
"w:pPr": [
|
||||
{
|
||||
"w:numPr": [
|
||||
{
|
||||
"w:ilvl": {
|
||||
_attr: {
|
||||
"w:val": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:numId": {
|
||||
_attr: {
|
||||
"w:val": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should create with widowControl", () => {
|
||||
const properties = new ParagraphProperties({
|
||||
widowControl: true,
|
||||
@ -159,6 +189,21 @@ describe("ParagraphProperties", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should create with the overflowPunct property", () => {
|
||||
const properties = new ParagraphProperties({
|
||||
overflowPunctuation: true,
|
||||
});
|
||||
const tree = new Formatter().format(properties);
|
||||
|
||||
expect(tree).to.deep.equal({
|
||||
"w:pPr": [
|
||||
{
|
||||
"w:overflowPunct": {},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should create with the run property", () => {
|
||||
const properties = new ParagraphProperties({
|
||||
run: {
|
||||
|
@ -13,7 +13,7 @@ import { HeadingLevel, Style } from "./formatting/style";
|
||||
import { TabStop, TabStopDefinition, TabStopType } from "./formatting/tab-stop";
|
||||
import { NumberProperties } from "./formatting/unordered-list";
|
||||
import { WordWrap } from "./formatting/word-wrap";
|
||||
import { FrameProperties, IFrameOptions } from "./frame/frame-properties";
|
||||
import { createFrameProperties, IFrameOptions } from "./frame/frame-properties";
|
||||
import { OutlineLevel } from "./links";
|
||||
import { IRunOptions, RunProperties } from ".";
|
||||
|
||||
@ -37,12 +37,14 @@ export interface ILevelParagraphStylePropertiesOptions {
|
||||
}
|
||||
|
||||
export interface IParagraphStylePropertiesOptions extends ILevelParagraphStylePropertiesOptions {
|
||||
readonly numbering?: {
|
||||
readonly numbering?:
|
||||
| {
|
||||
readonly reference: string;
|
||||
readonly level: number;
|
||||
readonly instance?: number;
|
||||
readonly custom?: boolean;
|
||||
};
|
||||
}
|
||||
| false;
|
||||
}
|
||||
|
||||
export interface IParagraphPropertiesOptions extends IParagraphStylePropertiesOptions {
|
||||
@ -60,6 +62,7 @@ export interface IParagraphPropertiesOptions extends IParagraphStylePropertiesOp
|
||||
readonly frame?: IFrameOptions;
|
||||
readonly suppressLineNumbers?: boolean;
|
||||
readonly wordWrap?: boolean;
|
||||
readonly overflowPunctuation?: boolean;
|
||||
readonly scale?: number;
|
||||
/**
|
||||
* This element specifies whether inter-character spacing shall automatically be adjusted between regions of numbers and regions of East Asian text in the current paragraph. These regions shall be determined by the Unicode character values of the text content within the paragraph.
|
||||
@ -116,7 +119,7 @@ export class ParagraphProperties extends IgnoreIfEmptyXmlComponent {
|
||||
}
|
||||
|
||||
if (options.frame) {
|
||||
this.push(new FrameProperties(options.frame));
|
||||
this.push(createFrameProperties(options.frame));
|
||||
}
|
||||
|
||||
if (options.widowControl !== undefined) {
|
||||
@ -134,6 +137,8 @@ export class ParagraphProperties extends IgnoreIfEmptyXmlComponent {
|
||||
});
|
||||
|
||||
this.push(new NumberProperties(`${options.numbering.reference}-${options.numbering.instance ?? 0}`, options.numbering.level));
|
||||
} else if (options.numbering === false) {
|
||||
this.push(new NumberProperties(0, 0));
|
||||
}
|
||||
|
||||
if (options.border) {
|
||||
@ -152,14 +157,18 @@ export class ParagraphProperties extends IgnoreIfEmptyXmlComponent {
|
||||
this.push(new WordWrap());
|
||||
}
|
||||
|
||||
if (options.overflowPunctuation) {
|
||||
this.push(new OnOffElement("w:overflowPunct", options.overflowPunctuation));
|
||||
}
|
||||
|
||||
/**
|
||||
* FIX: Multitab support for Libre Writer
|
||||
* Ensure there is only one w:tabs tag with multiple w:tab
|
||||
*/
|
||||
const tabDefinitions: readonly TabStopDefinition[] = [
|
||||
...(options.rightTabStop ? [{ type: TabStopType.RIGHT, position: options.rightTabStop }] : []),
|
||||
...(options.rightTabStop !== undefined ? [{ type: TabStopType.RIGHT, position: options.rightTabStop }] : []),
|
||||
...(options.tabStops ? options.tabStops : []),
|
||||
...(options.leftTabStop ? [{ type: TabStopType.LEFT, position: options.leftTabStop }] : []),
|
||||
...(options.leftTabStop !== undefined ? [{ type: TabStopType.LEFT, position: options.leftTabStop }] : []),
|
||||
];
|
||||
|
||||
if (tabDefinitions.length > 0) {
|
||||
|
@ -19,6 +19,7 @@ describe("ImageRun", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create with Buffer", () => {
|
||||
const currentImageRun = new ImageRun({
|
||||
type: "png",
|
||||
data: Buffer.from(""),
|
||||
transformation: {
|
||||
width: 200,
|
||||
@ -39,8 +40,7 @@ describe("ImageRun", () => {
|
||||
const tree = new Formatter().format(currentImageRun, {
|
||||
file: {
|
||||
Media: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
addImage: () => {},
|
||||
addImage: vi.fn(),
|
||||
},
|
||||
} as unknown as File,
|
||||
viewWrapper: {} as unknown as IViewWrapper,
|
||||
@ -271,6 +271,7 @@ describe("ImageRun", () => {
|
||||
|
||||
it("should create with string", () => {
|
||||
const currentImageRun = new ImageRun({
|
||||
type: "png",
|
||||
data: "",
|
||||
transformation: {
|
||||
width: 200,
|
||||
@ -291,8 +292,7 @@ describe("ImageRun", () => {
|
||||
const tree = new Formatter().format(currentImageRun, {
|
||||
file: {
|
||||
Media: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
addImage: () => {},
|
||||
addImage: vi.fn(),
|
||||
},
|
||||
} as unknown as File,
|
||||
viewWrapper: {} as unknown as IViewWrapper,
|
||||
@ -522,10 +522,10 @@ describe("ImageRun", () => {
|
||||
});
|
||||
|
||||
it("should return UInt8Array if atob is present", () => {
|
||||
// eslint-disable-next-line functional/immutable-data
|
||||
global.atob = () => "atob result";
|
||||
vi.spyOn(global, "atob").mockReturnValue("atob result");
|
||||
|
||||
const currentImageRun = new ImageRun({
|
||||
type: "png",
|
||||
data: "",
|
||||
transformation: {
|
||||
width: 200,
|
||||
@ -546,8 +546,7 @@ describe("ImageRun", () => {
|
||||
const tree = new Formatter().format(currentImageRun, {
|
||||
file: {
|
||||
Media: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
addImage: () => {},
|
||||
addImage: vi.fn(),
|
||||
},
|
||||
} as unknown as File,
|
||||
viewWrapper: {} as unknown as IViewWrapper,
|
||||
@ -775,16 +774,13 @@ describe("ImageRun", () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, functional/immutable-data
|
||||
(global as any).atob = undefined;
|
||||
});
|
||||
|
||||
it("should use data as is if its not a string", () => {
|
||||
// eslint-disable-next-line functional/immutable-data
|
||||
global.atob = () => "atob result";
|
||||
vi.spyOn(global, "atob").mockReturnValue("atob result");
|
||||
|
||||
const currentImageRun = new ImageRun({
|
||||
type: "png",
|
||||
data: "",
|
||||
transformation: {
|
||||
width: 200,
|
||||
@ -805,8 +801,7 @@ describe("ImageRun", () => {
|
||||
const tree = new Formatter().format(currentImageRun, {
|
||||
file: {
|
||||
Media: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
addImage: () => {},
|
||||
addImage: vi.fn(),
|
||||
},
|
||||
} as unknown as File,
|
||||
viewWrapper: {} as unknown as IViewWrapper,
|
||||
@ -1034,9 +1029,107 @@ describe("ImageRun", () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, functional/immutable-data
|
||||
(global as any).atob = undefined;
|
||||
it("should strip base64 marker", () => {
|
||||
const spy = vi.spyOn(global, "atob").mockReturnValue("atob result");
|
||||
|
||||
new ImageRun({
|
||||
type: "png",
|
||||
data: ";base64,",
|
||||
transformation: {
|
||||
width: 200,
|
||||
height: 200,
|
||||
rotation: 45,
|
||||
},
|
||||
});
|
||||
|
||||
expect(spy).toBeCalledWith("");
|
||||
});
|
||||
|
||||
it("should work with svgs", () => {
|
||||
const currentImageRun = new ImageRun({
|
||||
type: "svg",
|
||||
data: Buffer.from(""),
|
||||
transformation: {
|
||||
width: 200,
|
||||
height: 200,
|
||||
},
|
||||
fallback: {
|
||||
type: "png",
|
||||
data: Buffer.from(""),
|
||||
},
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(currentImageRun, {
|
||||
file: {
|
||||
Media: {
|
||||
addImage: vi.fn(),
|
||||
},
|
||||
} as unknown as File,
|
||||
viewWrapper: {} as unknown as IViewWrapper,
|
||||
stack: [],
|
||||
});
|
||||
|
||||
expect(tree).toStrictEqual({
|
||||
"w:r": [
|
||||
{
|
||||
"w:drawing": [
|
||||
{
|
||||
"wp:inline": expect.arrayContaining([
|
||||
{
|
||||
"a:graphic": expect.arrayContaining([
|
||||
{
|
||||
"a:graphicData": expect.arrayContaining([
|
||||
{
|
||||
"pic:pic": expect.arrayContaining([
|
||||
{
|
||||
"pic:blipFill": expect.arrayContaining([
|
||||
{
|
||||
"a:blip": [
|
||||
{
|
||||
_attr: {
|
||||
cstate: "none",
|
||||
"r:embed": "rId{test-unique-id.png}",
|
||||
},
|
||||
},
|
||||
{
|
||||
"a:extLst": [
|
||||
{
|
||||
"a:ext": [
|
||||
{
|
||||
_attr: {
|
||||
uri: "{96DAC541-7B7A-43D3-8B79-37D633B846F1}",
|
||||
},
|
||||
},
|
||||
{
|
||||
"asvg:svgBlip": {
|
||||
_attr: expect.objectContaining({
|
||||
"r:embed":
|
||||
"rId{test-unique-id.svg}",
|
||||
}),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]),
|
||||
},
|
||||
]),
|
||||
},
|
||||
]),
|
||||
},
|
||||
]),
|
||||
},
|
||||
]),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -3,54 +3,36 @@ import { uniqueId } from "@util/convenience-functions";
|
||||
import { IContext, IXmlableObject } from "@file/xml-components";
|
||||
import { DocPropertiesOptions } from "@file/drawing/doc-properties/doc-properties";
|
||||
|
||||
import { OutlineOptions } from "../../drawing/inline/graphic/graphic-data/pic/shape-properties/outline/outline";
|
||||
import { Drawing, IFloating } from "../../drawing";
|
||||
import { IMediaTransformation } from "../../media";
|
||||
import { IMediaData } from "../../media/data";
|
||||
import { Run } from "../run";
|
||||
|
||||
export interface IImageOptions {
|
||||
readonly data: Buffer | string | Uint8Array | ArrayBuffer;
|
||||
type CoreImageOptions = {
|
||||
readonly transformation: IMediaTransformation;
|
||||
readonly floating?: IFloating;
|
||||
readonly altText?: DocPropertiesOptions;
|
||||
}
|
||||
|
||||
export class ImageRun extends Run {
|
||||
private readonly key = `${uniqueId()}.png`;
|
||||
private readonly imageData: IMediaData;
|
||||
|
||||
public constructor(options: IImageOptions) {
|
||||
super({});
|
||||
const newData = typeof options.data === "string" ? this.convertDataURIToBinary(options.data) : options.data;
|
||||
|
||||
this.imageData = {
|
||||
stream: newData,
|
||||
fileName: this.key,
|
||||
transformation: {
|
||||
pixels: {
|
||||
x: Math.round(options.transformation.width),
|
||||
y: Math.round(options.transformation.height),
|
||||
},
|
||||
emus: {
|
||||
x: Math.round(options.transformation.width * 9525),
|
||||
y: Math.round(options.transformation.height * 9525),
|
||||
},
|
||||
flip: options.transformation.flip,
|
||||
rotation: options.transformation.rotation ? options.transformation.rotation * 60000 : undefined,
|
||||
},
|
||||
readonly outline?: OutlineOptions;
|
||||
};
|
||||
const drawing = new Drawing(this.imageData, { floating: options.floating, docProperties: options.altText });
|
||||
|
||||
this.root.push(drawing);
|
||||
}
|
||||
type RegularImageOptions = {
|
||||
readonly type: "jpg" | "png" | "gif" | "bmp";
|
||||
readonly data: Buffer | string | Uint8Array | ArrayBuffer;
|
||||
};
|
||||
|
||||
public prepForXml(context: IContext): IXmlableObject | undefined {
|
||||
context.file.Media.addImage(this.key, this.imageData);
|
||||
type SvgMediaOptions = {
|
||||
readonly type: "svg";
|
||||
readonly data: Buffer | string | Uint8Array | ArrayBuffer;
|
||||
/**
|
||||
* Required in case the Word processor does not support SVG.
|
||||
*/
|
||||
readonly fallback: RegularImageOptions;
|
||||
};
|
||||
|
||||
return super.prepForXml(context);
|
||||
}
|
||||
export type IImageOptions = (RegularImageOptions | SvgMediaOptions) & CoreImageOptions;
|
||||
|
||||
private convertDataURIToBinary(dataURI: string): Uint8Array {
|
||||
const convertDataURIToBinary = (dataURI: string): Uint8Array => {
|
||||
if (typeof atob === "function") {
|
||||
// https://gist.github.com/borismus/1032746
|
||||
// https://github.com/mafintosh/base64-to-uint8array
|
||||
@ -64,10 +46,81 @@ export class ImageRun extends Run {
|
||||
.split("")
|
||||
.map((c) => c.charCodeAt(0)),
|
||||
);
|
||||
/* c8 ignore next 6 */
|
||||
} else {
|
||||
// Not possible to test this branch in NodeJS
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
||||
const b = require("buf" + "fer");
|
||||
return new b.Buffer(dataURI, "base64");
|
||||
}
|
||||
};
|
||||
|
||||
const standardizeData = (data: string | Buffer | Uint8Array | ArrayBuffer): Buffer | Uint8Array | ArrayBuffer =>
|
||||
typeof data === "string" ? convertDataURIToBinary(data) : data;
|
||||
|
||||
const createImageData = (options: IImageOptions, key: string): Pick<IMediaData, "data" | "fileName" | "transformation"> => ({
|
||||
data: standardizeData(options.data),
|
||||
fileName: key,
|
||||
transformation: {
|
||||
pixels: {
|
||||
x: Math.round(options.transformation.width),
|
||||
y: Math.round(options.transformation.height),
|
||||
},
|
||||
emus: {
|
||||
x: Math.round(options.transformation.width * 9525),
|
||||
y: Math.round(options.transformation.height * 9525),
|
||||
},
|
||||
flip: options.transformation.flip,
|
||||
rotation: options.transformation.rotation ? options.transformation.rotation * 60000 : undefined,
|
||||
},
|
||||
});
|
||||
|
||||
export class ImageRun extends Run {
|
||||
private readonly key: string;
|
||||
private readonly fallbackKey = `${uniqueId()}.png`;
|
||||
private readonly imageData: IMediaData;
|
||||
|
||||
public constructor(options: IImageOptions) {
|
||||
super({});
|
||||
|
||||
this.key = `${uniqueId()}.${options.type}`;
|
||||
|
||||
this.imageData =
|
||||
options.type === "svg"
|
||||
? {
|
||||
type: options.type,
|
||||
...createImageData(options, this.key),
|
||||
fallback: {
|
||||
type: options.fallback.type,
|
||||
...createImageData(
|
||||
{
|
||||
...options.fallback,
|
||||
transformation: options.transformation,
|
||||
},
|
||||
this.fallbackKey,
|
||||
),
|
||||
},
|
||||
}
|
||||
: {
|
||||
type: options.type,
|
||||
...createImageData(options, this.key),
|
||||
};
|
||||
const drawing = new Drawing(this.imageData, {
|
||||
floating: options.floating,
|
||||
docProperties: options.altText,
|
||||
outline: options.outline,
|
||||
});
|
||||
|
||||
this.root.push(drawing);
|
||||
}
|
||||
|
||||
public prepForXml(context: IContext): IXmlableObject | undefined {
|
||||
context.file.Media.addImage(this.key, this.imageData);
|
||||
|
||||
if (this.imageData.type === "svg") {
|
||||
context.file.Media.addImage(this.fallbackKey, this.imageData.fallback);
|
||||
}
|
||||
|
||||
return super.prepForXml(context);
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,11 @@ import { describe, expect, it } from "vitest";
|
||||
|
||||
import { Formatter } from "@export/formatter";
|
||||
|
||||
import { NumberOfPages, NumberOfPagesSection, Page } from "./page-number";
|
||||
import { CurrentSection, NumberOfPages, NumberOfPagesSection, Page } from "./page-number";
|
||||
|
||||
describe("Page", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("uses the font name for both ascii and hAnsi", () => {
|
||||
it("should work", () => {
|
||||
const tree = new Formatter().format(new Page());
|
||||
expect(tree).to.deep.equal({ "w:instrText": [{ _attr: { "xml:space": "preserve" } }, "PAGE"] });
|
||||
});
|
||||
@ -15,7 +15,7 @@ describe("Page", () => {
|
||||
|
||||
describe("NumberOfPages", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("uses the font name for both ascii and hAnsi", () => {
|
||||
it("should work", () => {
|
||||
const tree = new Formatter().format(new NumberOfPages());
|
||||
expect(tree).to.deep.equal({ "w:instrText": [{ _attr: { "xml:space": "preserve" } }, "NUMPAGES"] });
|
||||
});
|
||||
@ -24,9 +24,18 @@ describe("NumberOfPages", () => {
|
||||
|
||||
describe("NumberOfPagesSection", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("uses the font name for both ascii and hAnsi", () => {
|
||||
it("should work", () => {
|
||||
const tree = new Formatter().format(new NumberOfPagesSection());
|
||||
expect(tree).to.deep.equal({ "w:instrText": [{ _attr: { "xml:space": "preserve" } }, "SECTIONPAGES"] });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("CurrentSection", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should work", () => {
|
||||
const tree = new Formatter().format(new CurrentSection());
|
||||
expect(tree).to.deep.equal({ "w:instrText": [{ _attr: { "xml:space": "preserve" } }, "SECTION"] });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user