Merge pull request #550 from wangfengming/feature/enhance-font
Feature/enhance font
This commit is contained in:
55
demo/53-chinese.ts
Normal file
55
demo/53-chinese.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// Chinese text - Chinese text need to use a Chinese font. And ascii text need to use a ascii font.
|
||||||
|
// Different from the `52-japanese.ts`.
|
||||||
|
// `52-japanese.ts` will set all characters to use Japanese font.
|
||||||
|
// `53-chinese.ts` will set Chinese characters to use Chinese font, and set ascii characters to use ascii font.
|
||||||
|
|
||||||
|
// Note that if the OS have not install `KaiTi` font, this demo doesn't work.
|
||||||
|
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { Document, HeadingLevel, Packer, Paragraph, TextRun } from "../build";
|
||||||
|
|
||||||
|
const doc = new Document({
|
||||||
|
styles: {
|
||||||
|
paragraphStyles: [
|
||||||
|
{
|
||||||
|
id: "Normal",
|
||||||
|
name: "Normal",
|
||||||
|
basedOn: "Normal",
|
||||||
|
next: "Normal",
|
||||||
|
quickFormat: true,
|
||||||
|
run: {
|
||||||
|
font: {
|
||||||
|
ascii: "Times",
|
||||||
|
eastAsia: "KaiTi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.addSection({
|
||||||
|
children: [
|
||||||
|
new Paragraph({
|
||||||
|
text: "中文和英文 Chinese and English",
|
||||||
|
heading: HeadingLevel.HEADING_1,
|
||||||
|
}),
|
||||||
|
new Paragraph({
|
||||||
|
text: "中文和英文 Chinese and English",
|
||||||
|
}),
|
||||||
|
new Paragraph({
|
||||||
|
children: [
|
||||||
|
new TextRun({
|
||||||
|
text: "中文和英文 Chinese and English",
|
||||||
|
font: { eastAsia: "SimSun" }, // set eastAsia to "SimSun".
|
||||||
|
// The ascii characters will use the default font ("Times") specified in paragraphStyles
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
Packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
@ -26,7 +26,7 @@ const name = new TextRun({
|
|||||||
- `emphasisMark({type="dot"})`: Set the emphasis mark style
|
- `emphasisMark({type="dot"})`: Set the emphasis mark style
|
||||||
- `color(color)`: Set the text color, using 6 hex characters for RRGGBB (no leading `#`)
|
- `color(color)`: Set the text color, using 6 hex characters for RRGGBB (no leading `#`)
|
||||||
- `size(halfPts)`: Set the font size, measured in half-points
|
- `size(halfPts)`: Set the font size, measured in half-points
|
||||||
- `font(name)`: Set the run's font
|
- `font(name)` or `font({ascii, cs, eastAsia, hAnsi, hint})`: Set the run's font
|
||||||
- `style(name)`: Apply a named run style
|
- `style(name)`: Apply a named run style
|
||||||
- `characterSpacing(value)`: Set the character spacing adjustment (in TWIPs)
|
- `characterSpacing(value)`: Set the character spacing adjustment (in TWIPs)
|
||||||
|
|
||||||
|
@ -417,7 +417,7 @@ describe("AbstractNumbering", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("#font", () => {
|
it("#font by name", () => {
|
||||||
const abstractNumbering = new AbstractNumbering(1, [
|
const abstractNumbering = new AbstractNumbering(1, [
|
||||||
{
|
{
|
||||||
level: 0,
|
level: 0,
|
||||||
@ -447,6 +447,37 @@ describe("AbstractNumbering", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("#font for ascii and eastAsia", () => {
|
||||||
|
const abstractNumbering = new AbstractNumbering(1, [
|
||||||
|
{
|
||||||
|
level: 0,
|
||||||
|
format: "lowerRoman",
|
||||||
|
text: "%0.",
|
||||||
|
style: {
|
||||||
|
run: {
|
||||||
|
font: {
|
||||||
|
ascii: "Times",
|
||||||
|
eastAsia: "KaiTi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const tree = new Formatter().format(abstractNumbering);
|
||||||
|
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({
|
||||||
|
"w:rPr": [
|
||||||
|
{
|
||||||
|
"w:rFonts": {
|
||||||
|
_attr: {
|
||||||
|
"w:ascii": "Times",
|
||||||
|
"w:eastAsia": "KaiTi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("#bold", () => {
|
it("#bold", () => {
|
||||||
const abstractNumbering = new AbstractNumbering(1, [
|
const abstractNumbering = new AbstractNumbering(1, [
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@ import { Attributes, XmlComponent } from "file/xml-components";
|
|||||||
export { Underline } from "./underline";
|
export { Underline } from "./underline";
|
||||||
export { EmphasisMark } from "./emphasis-mark";
|
export { EmphasisMark } from "./emphasis-mark";
|
||||||
export { SubScript, SuperScript } from "./script";
|
export { SubScript, SuperScript } from "./script";
|
||||||
export { RunFonts } from "./run-fonts";
|
export { RunFonts, IFontAttributesProperties } from "./run-fonts";
|
||||||
|
|
||||||
export class Bold extends XmlComponent {
|
export class Bold extends XmlComponent {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -21,5 +21,12 @@ describe("RunFonts", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses the font attrs for ascii and eastAsia", () => {
|
||||||
|
const tree = new Formatter().format(new RunFonts({ ascii: "Times", eastAsia: "KaiTi" }));
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:rFonts": { _attr: { "w:ascii": "Times", "w:eastAsia": "KaiTi" } },
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
interface IRunFontAttributesProperties {
|
export interface IFontAttributesProperties {
|
||||||
readonly ascii: string;
|
readonly ascii?: string;
|
||||||
readonly cs: string;
|
readonly cs?: string;
|
||||||
readonly eastAsia: string;
|
readonly eastAsia?: string;
|
||||||
readonly hAnsi: string;
|
readonly hAnsi?: string;
|
||||||
readonly hint?: string;
|
readonly hint?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class RunFontAttributes extends XmlAttributeComponent<IRunFontAttributesProperties> {
|
class RunFontAttributes extends XmlAttributeComponent<IFontAttributesProperties> {
|
||||||
protected readonly xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
ascii: "w:ascii",
|
ascii: "w:ascii",
|
||||||
cs: "w:cs",
|
cs: "w:cs",
|
||||||
@ -19,16 +19,26 @@ class RunFontAttributes extends XmlAttributeComponent<IRunFontAttributesProperti
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class RunFonts extends XmlComponent {
|
export class RunFonts extends XmlComponent {
|
||||||
constructor(ascii: string, hint?: string) {
|
constructor(name: string, hint?: string);
|
||||||
|
constructor(attrs: string | IFontAttributesProperties);
|
||||||
|
constructor(nameOrAttrs: string | IFontAttributesProperties, hint?: string) {
|
||||||
super("w:rFonts");
|
super("w:rFonts");
|
||||||
this.root.push(
|
if (typeof nameOrAttrs === "string") {
|
||||||
new RunFontAttributes({
|
// use constructor(name: string, hint?: string);
|
||||||
ascii: ascii,
|
const name = nameOrAttrs;
|
||||||
cs: ascii,
|
this.root.push(
|
||||||
eastAsia: ascii,
|
new RunFontAttributes({
|
||||||
hAnsi: ascii,
|
ascii: name,
|
||||||
hint: hint,
|
cs: name,
|
||||||
}),
|
eastAsia: name,
|
||||||
);
|
hAnsi: name,
|
||||||
|
hint: hint,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// use constructor(attrs: IRunFontAttributesProperties);
|
||||||
|
const attrs = nameOrAttrs;
|
||||||
|
this.root.push(new RunFontAttributes(attrs));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -275,6 +275,32 @@ describe("Run", () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should set the font for ascii and eastAsia", () => {
|
||||||
|
const run = new Run({
|
||||||
|
font: {
|
||||||
|
ascii: "Times",
|
||||||
|
eastAsia: "KaiTi",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(run);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:rPr": [
|
||||||
|
{
|
||||||
|
"w:rFonts": {
|
||||||
|
_attr: {
|
||||||
|
"w:ascii": "Times",
|
||||||
|
"w:eastAsia": "KaiTi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#color", () => {
|
describe("#color", () => {
|
||||||
|
@ -27,11 +27,16 @@ import {
|
|||||||
import { NumberOfPages, NumberOfPagesSection, Page } from "./page-number";
|
import { NumberOfPages, NumberOfPagesSection, Page } from "./page-number";
|
||||||
import { RunProperties } from "./properties";
|
import { RunProperties } from "./properties";
|
||||||
import { Text } from "./run-components/text";
|
import { Text } from "./run-components/text";
|
||||||
import { RunFonts } from "./run-fonts";
|
import { IFontAttributesProperties, RunFonts } from "./run-fonts";
|
||||||
import { SubScript, SuperScript } from "./script";
|
import { SubScript, SuperScript } from "./script";
|
||||||
import { Style } from "./style";
|
import { Style } from "./style";
|
||||||
import { Underline, UnderlineType } from "./underline";
|
import { Underline, UnderlineType } from "./underline";
|
||||||
|
|
||||||
|
interface IFontOptions {
|
||||||
|
readonly name: string;
|
||||||
|
readonly hint?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IRunOptions {
|
export interface IRunOptions {
|
||||||
readonly bold?: true;
|
readonly bold?: true;
|
||||||
readonly italics?: true;
|
readonly italics?: true;
|
||||||
@ -52,10 +57,7 @@ export interface IRunOptions {
|
|||||||
readonly subScript?: boolean;
|
readonly subScript?: boolean;
|
||||||
readonly superScript?: boolean;
|
readonly superScript?: boolean;
|
||||||
readonly style?: string;
|
readonly style?: string;
|
||||||
readonly font?: {
|
readonly font?: IFontOptions | IFontAttributesProperties;
|
||||||
readonly name: string;
|
|
||||||
readonly hint?: string;
|
|
||||||
};
|
|
||||||
readonly highlight?: string;
|
readonly highlight?: string;
|
||||||
readonly shading?: {
|
readonly shading?: {
|
||||||
readonly type: ShadingType;
|
readonly type: ShadingType;
|
||||||
@ -140,7 +142,11 @@ export class Run extends XmlComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.font) {
|
if (options.font) {
|
||||||
this.properties.push(new RunFonts(options.font.name, options.font.hint));
|
if ("name" in options.font) {
|
||||||
|
this.properties.push(new RunFonts(options.font.name, options.font.hint));
|
||||||
|
} else {
|
||||||
|
this.properties.push(new RunFonts(options.font));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.highlight) {
|
if (options.highlight) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Size, SizeComplexScript } from "file/paragraph/run/formatting";
|
import { Size, SizeComplexScript } from "file/paragraph/run/formatting";
|
||||||
import { RunProperties } from "file/paragraph/run/properties";
|
import { RunProperties } from "file/paragraph/run/properties";
|
||||||
import { RunFonts } from "file/paragraph/run/run-fonts";
|
import { IFontAttributesProperties, RunFonts } from "file/paragraph/run/run-fonts";
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
export class RunPropertiesDefaults extends XmlComponent {
|
export class RunPropertiesDefaults extends XmlComponent {
|
||||||
@ -18,8 +18,8 @@ export class RunPropertiesDefaults extends XmlComponent {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public font(fontName: string): RunPropertiesDefaults {
|
public font(font: string | IFontAttributesProperties): RunPropertiesDefaults {
|
||||||
this.properties.push(new RunFonts(fontName));
|
this.properties.push(new RunFonts(font));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
import { AlignmentType, EmphasisMarkType, IIndentAttributesProperties, ISpacingProperties, UnderlineType } from "../paragraph";
|
import {
|
||||||
|
AlignmentType,
|
||||||
|
EmphasisMarkType,
|
||||||
|
IFontAttributesProperties,
|
||||||
|
IIndentAttributesProperties,
|
||||||
|
ISpacingProperties,
|
||||||
|
UnderlineType,
|
||||||
|
} from "../paragraph";
|
||||||
import { ShadingType } from "../table";
|
import { ShadingType } from "../table";
|
||||||
|
|
||||||
export interface IRunStyleOptions {
|
export interface IRunStyleOptions {
|
||||||
@ -19,7 +26,7 @@ export interface IRunStyleOptions {
|
|||||||
readonly type?: EmphasisMarkType;
|
readonly type?: EmphasisMarkType;
|
||||||
};
|
};
|
||||||
readonly color?: string;
|
readonly color?: string;
|
||||||
readonly font?: string;
|
readonly font?: string | IFontAttributesProperties;
|
||||||
readonly characterSpacing?: number;
|
readonly characterSpacing?: number;
|
||||||
readonly highlight?: string;
|
readonly highlight?: string;
|
||||||
readonly shadow?: {
|
readonly shadow?: {
|
||||||
|
@ -202,7 +202,7 @@ describe("CharacterStyle", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should add font", () => {
|
it("should add font by name", () => {
|
||||||
const style = new CharacterStyle({
|
const style = new CharacterStyle({
|
||||||
id: "myStyleId",
|
id: "myStyleId",
|
||||||
run: {
|
run: {
|
||||||
@ -241,6 +241,46 @@ describe("CharacterStyle", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should add font for ascii and eastAsia", () => {
|
||||||
|
const style = new CharacterStyle({
|
||||||
|
id: "myStyleId",
|
||||||
|
run: {
|
||||||
|
font: {
|
||||||
|
ascii: "test font ascii",
|
||||||
|
eastAsia: "test font eastAsia",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [
|
||||||
|
{
|
||||||
|
"w:rFonts": {
|
||||||
|
_attr: {
|
||||||
|
"w:ascii": "test font ascii",
|
||||||
|
"w:eastAsia": "test font eastAsia",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": 99,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": EMPTY_OBJECT,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("should add character spacing", () => {
|
it("should add character spacing", () => {
|
||||||
const style = new CharacterStyle({
|
const style = new CharacterStyle({
|
||||||
id: "myStyleId",
|
id: "myStyleId",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { EmphasisMarkType } from "file/paragraph/run/emphasis-mark";
|
import { EmphasisMarkType } from "file/paragraph/run/emphasis-mark";
|
||||||
import * as formatting from "file/paragraph/run/formatting";
|
import * as formatting from "file/paragraph/run/formatting";
|
||||||
import { RunProperties } from "file/paragraph/run/properties";
|
import { RunProperties } from "file/paragraph/run/properties";
|
||||||
|
import { IFontAttributesProperties } from "file/paragraph/run/run-fonts";
|
||||||
import { UnderlineType } from "file/paragraph/run/underline";
|
import { UnderlineType } from "file/paragraph/run/underline";
|
||||||
|
|
||||||
import { BasedOn, Link, SemiHidden, UiPriority, UnhideWhenUsed } from "./components";
|
import { BasedOn, Link, SemiHidden, UiPriority, UnhideWhenUsed } from "./components";
|
||||||
@ -28,7 +29,7 @@ export interface IBaseCharacterStyleOptions {
|
|||||||
readonly type?: EmphasisMarkType;
|
readonly type?: EmphasisMarkType;
|
||||||
};
|
};
|
||||||
readonly color?: string;
|
readonly color?: string;
|
||||||
readonly font?: string;
|
readonly font?: string | IFontAttributesProperties;
|
||||||
readonly characterSpacing?: number;
|
readonly characterSpacing?: number;
|
||||||
readonly highlight?: string;
|
readonly highlight?: string;
|
||||||
readonly shadow?: {
|
readonly shadow?: {
|
||||||
|
@ -484,7 +484,7 @@ describe("ParagraphStyle", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("#font", () => {
|
it("#font by name", () => {
|
||||||
const style = new ParagraphStyle({
|
const style = new ParagraphStyle({
|
||||||
id: "myStyleId",
|
id: "myStyleId",
|
||||||
run: {
|
run: {
|
||||||
@ -513,6 +513,36 @@ describe("ParagraphStyle", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("#font for ascii and eastAsia", () => {
|
||||||
|
const style = new ParagraphStyle({
|
||||||
|
id: "myStyleId",
|
||||||
|
run: {
|
||||||
|
font: {
|
||||||
|
ascii: "Times",
|
||||||
|
eastAsia: "KaiTi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [
|
||||||
|
{
|
||||||
|
"w:rFonts": {
|
||||||
|
_attr: {
|
||||||
|
"w:ascii": "Times",
|
||||||
|
"w:eastAsia": "KaiTi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("#bold", () => {
|
it("#bold", () => {
|
||||||
const style = new ParagraphStyle({
|
const style = new ParagraphStyle({
|
||||||
id: "myStyleId",
|
id: "myStyleId",
|
||||||
|
Reference in New Issue
Block a user