diff --git a/src/file/drawing/anchor/anchor.ts b/src/file/drawing/anchor/anchor.ts index 9e6d445c43..50e16174b7 100644 --- a/src/file/drawing/anchor/anchor.ts +++ b/src/file/drawing/anchor/anchor.ts @@ -1,5 +1,5 @@ // http://officeopenxml.com/drwPicFloating.php -import { IMediaData, IMediaDataTransformation } from "@file/media"; +import { IExtendedMediaData, IMediaDataTransformation } from "@file/media"; import { XmlComponent } from "@file/xml-components"; import { IDrawingOptions } from "../drawing"; @@ -43,7 +43,7 @@ export class Anchor extends XmlComponent { transform, drawingOptions, }: { - readonly mediaData: IMediaData; + readonly mediaData: IExtendedMediaData; readonly transform: IMediaDataTransformation; readonly drawingOptions: IDrawingOptions; }) { @@ -101,6 +101,6 @@ export class Anchor extends XmlComponent { this.root.push(new DocProperties(drawingOptions.docProperties)); this.root.push(createGraphicFrameProperties()); - this.root.push(new Graphic({ mediaData, transform, outline: drawingOptions.outline })); + this.root.push(new Graphic({ mediaData, transform, outline: drawingOptions.outline, solidFill: drawingOptions.solidFill })); } } diff --git a/src/file/drawing/doc-properties/doc-properties.ts b/src/file/drawing/doc-properties/doc-properties.ts index ab8470e9a2..aa5f070bb3 100644 --- a/src/file/drawing/doc-properties/doc-properties.ts +++ b/src/file/drawing/doc-properties/doc-properties.ts @@ -21,18 +21,19 @@ export type DocPropertiesOptions = { readonly name: string; readonly description?: string; readonly title?: string; + readonly id?: string; }; export class DocProperties extends XmlComponent { private readonly docPropertiesUniqueNumericId = docPropertiesUniqueNumericIdGen(); - public constructor({ name, description, title }: DocPropertiesOptions = { name: "", description: "", title: "" }) { + public constructor({ name, description, title, id }: DocPropertiesOptions = { name: "", description: "", title: "" }) { super("wp:docPr"); const attributes: Record = { id: { key: "id", - value: this.docPropertiesUniqueNumericId(), + value: id ?? this.docPropertiesUniqueNumericId(), }, name: { key: "name", diff --git a/src/file/drawing/drawing.ts b/src/file/drawing/drawing.ts index 2e6cf991fa..1551efc3ef 100644 --- a/src/file/drawing/drawing.ts +++ b/src/file/drawing/drawing.ts @@ -1,4 +1,4 @@ -import { IMediaData } from "@file/media"; +import { IExtendedMediaData } from "@file/media"; import { XmlComponent } from "@file/xml-components"; import { Anchor } from "./anchor"; @@ -6,6 +6,7 @@ import { DocPropertiesOptions } from "./doc-properties/doc-properties"; import { IFloating } from "./floating"; import { createInline } from "./inline"; import { OutlineOptions } from "./inline/graphic/graphic-data/pic/shape-properties/outline/outline"; +import { SolidFillOptions } from "./inline/graphic/graphic-data/pic/shape-properties/outline/solid-fill"; export type IDistance = { readonly distT?: number; @@ -18,6 +19,7 @@ export type IDrawingOptions = { readonly floating?: IFloating; readonly docProperties?: DocPropertiesOptions; readonly outline?: OutlineOptions; + readonly solidFill?: SolidFillOptions; }; // @@ -28,7 +30,7 @@ export type IDrawingOptions = { // export class Drawing extends XmlComponent { - public constructor(imageData: IMediaData, drawingOptions: IDrawingOptions = {}) { + public constructor(imageData: IExtendedMediaData, drawingOptions: IDrawingOptions = {}) { super("w:drawing"); if (!drawingOptions.floating) { @@ -38,6 +40,7 @@ export class Drawing extends XmlComponent { transform: imageData.transformation, docProperties: drawingOptions.docProperties, outline: drawingOptions.outline, + solidFill: drawingOptions.solidFill, }), ); } else { diff --git a/src/file/drawing/inline/graphic/graphic-data/graphic-data.ts b/src/file/drawing/inline/graphic/graphic-data/graphic-data.ts index 0ca40ef9ed..9a30b8595b 100644 --- a/src/file/drawing/inline/graphic/graphic-data/graphic-data.ts +++ b/src/file/drawing/inline/graphic/graphic-data/graphic-data.ts @@ -1,32 +1,48 @@ -import { IMediaData, IMediaDataTransformation } from "@file/media"; +import { WpsShape } from "@file/drawing/inline/graphic/graphic-data/wps/wps-shape"; +import { IExtendedMediaData, IMediaDataTransformation } from "@file/media"; import { XmlComponent } from "@file/xml-components"; import { GraphicDataAttributes } from "./graphic-data-attribute"; import { Pic } from "./pic"; import { OutlineOptions } from "./pic/shape-properties/outline/outline"; +import { SolidFillOptions } from "./pic/shape-properties/outline/solid-fill"; export class GraphicData extends XmlComponent { - private readonly pic: Pic; + // private readonly pic: Pic; public constructor({ mediaData, transform, outline, + solidFill, }: { - readonly mediaData: IMediaData; + readonly mediaData: IExtendedMediaData; readonly transform: IMediaDataTransformation; readonly outline?: OutlineOptions; + readonly solidFill?: SolidFillOptions; }) { super("a:graphicData"); - this.root.push( - new GraphicDataAttributes({ - uri: "http://schemas.openxmlformats.org/drawingml/2006/picture", - }), - ); + if (mediaData.type === "wps") { + this.root.push( + new GraphicDataAttributes({ + uri: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", + }), + ); + } else { + this.root.push( + new GraphicDataAttributes({ + uri: "http://schemas.openxmlformats.org/drawingml/2006/picture", + }), + ); + } - this.pic = new Pic({ mediaData, transform, outline }); - - this.root.push(this.pic); + if (mediaData.type !== "wps") { + const pic = new Pic({ mediaData, transform, outline }); + this.root.push(pic); + } else { + const wps = new WpsShape({ ...mediaData.data, transformation: transform, outline, solidFill }); + this.root.push(wps); + } } } diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/pic.ts b/src/file/drawing/inline/graphic/graphic-data/pic/pic.ts index da43e86f0a..5842c50095 100644 --- a/src/file/drawing/inline/graphic/graphic-data/pic/pic.ts +++ b/src/file/drawing/inline/graphic/graphic-data/pic/pic.ts @@ -28,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, outline })); + this.root.push(new ShapeProperties({ element: "pic", transform, outline })); } } diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/shape-properties.ts b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/shape-properties.ts index fb00d37eaa..069d41eec9 100644 --- a/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/shape-properties.ts +++ b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/shape-properties.ts @@ -5,14 +5,25 @@ import { XmlComponent } from "@file/xml-components"; import { Form } from "./form"; import { createNoFill } from "./outline/no-fill"; import { OutlineOptions, createOutline } from "./outline/outline"; +import { SolidFillOptions, createSolidFill } from "./outline/solid-fill"; import { PresetGeometry } from "./preset-geometry/preset-geometry"; import { ShapePropertiesAttributes } from "./shape-properties-attributes"; export class ShapeProperties extends XmlComponent { private readonly form: Form; - public constructor({ outline, transform }: { readonly outline?: OutlineOptions; readonly transform: IMediaDataTransformation }) { - super("pic:spPr"); + public constructor({ + element, + outline, + solidFill, + transform, + }: { + readonly element: string; + readonly outline?: OutlineOptions; + readonly solidFill?: SolidFillOptions; + readonly transform: IMediaDataTransformation; + }) { + super(`${element}:spPr`); this.root.push( new ShapePropertiesAttributes({ @@ -29,5 +40,9 @@ export class ShapeProperties extends XmlComponent { this.root.push(createNoFill()); this.root.push(createOutline(outline)); } + + if (solidFill) { + this.root.push(createSolidFill(solidFill)); + } } } diff --git a/src/file/drawing/inline/graphic/graphic-data/wps/body-properties.ts b/src/file/drawing/inline/graphic/graphic-data/wps/body-properties.ts new file mode 100644 index 0000000000..6f48c179b2 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/wps/body-properties.ts @@ -0,0 +1,60 @@ +import { TextWrappingType } from "@file/drawing/text-wrap"; +import { XmlAttributeComponent, XmlComponent } from "@file/xml-components"; +import { OnOffElement } from "@file/xml-components/simple-elements"; + +export enum VerticalAnchor { + CENTER = "ctr", + TOP = "t", + BOTTOM = "b", +} + +export type IBodyPropertiesOptions = { + readonly wrap?: (typeof TextWrappingType)[keyof typeof TextWrappingType]; + readonly verticalAnchor?: VerticalAnchor; + readonly margins?: { + readonly top?: number; + readonly bottom?: number; + readonly left?: number; + readonly right?: number; + }; + readonly noAutoFit?: boolean; +}; + +class BodyPropertiesAttributes extends XmlAttributeComponent<{ + // readonly wrap?: (typeof TextWrappingType)[keyof typeof TextWrappingType]; + readonly lIns?: number; + readonly rIns?: number; + readonly tIns?: number; + readonly bIns?: number; + readonly anchor?: VerticalAnchor; +}> { + protected readonly xmlKeys = { + wrap: "wrap", + lIns: "lIns", + rIns: "rIns", + tIns: "tIns", + bIns: "bIns", + anchor: "anchor", + }; +} + +export class BodyProperties extends XmlComponent { + public constructor(options: IBodyPropertiesOptions = {}) { + super("wps:bodyPr"); + + this.root.push( + new BodyPropertiesAttributes({ + // wrap: options.wrap, + lIns: options.margins?.left, + rIns: options.margins?.right, + tIns: options.margins?.top, + bIns: options.margins?.bottom, + anchor: options.verticalAnchor, + }), + ); + + if (options.noAutoFit) { + this.root.push(new OnOffElement("a:noAutofit", options.noAutoFit)); + } + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/wps/index.ts b/src/file/drawing/inline/graphic/graphic-data/wps/index.ts new file mode 100644 index 0000000000..343c9c3c42 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/wps/index.ts @@ -0,0 +1,2 @@ +export * from "./wps-shape"; +export * from "./body-properties"; diff --git a/src/file/drawing/inline/graphic/graphic-data/wps/non-visual-shape-properties.ts b/src/file/drawing/inline/graphic/graphic-data/wps/non-visual-shape-properties.ts new file mode 100644 index 0000000000..82656c31b0 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/wps/non-visual-shape-properties.ts @@ -0,0 +1,25 @@ +import { XmlAttributeComponent, XmlComponent } from "@file/xml-components"; + +export type INonVisualShapePropertiesOptions = { + readonly txBox: string; +}; + +class NonVisualShapePropertiesAttributes extends XmlAttributeComponent<{ + readonly txBox: string; +}> { + protected readonly xmlKeys = { + txBox: "txBox", + }; +} + +export class NonVisualShapeProperties extends XmlComponent { + public constructor(options: INonVisualShapePropertiesOptions = { txBox: "1" }) { + super("wps:cNvSpPr"); + + this.root.push( + new NonVisualShapePropertiesAttributes({ + txBox: options.txBox, + }), + ); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/wps/text-box-content.ts b/src/file/drawing/inline/graphic/graphic-data/wps/text-box-content.ts new file mode 100644 index 0000000000..75fc52a918 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/wps/text-box-content.ts @@ -0,0 +1,12 @@ +import { Paragraph } from "@file/paragraph"; +import { XmlComponent } from "@file/xml-components"; + +export class TextBoxContent extends XmlComponent { + public constructor(children: readonly Paragraph[]) { + super("w:txbxContent"); + + for (const child of children) { + this.root.push(child); + } + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/wps/wps-shape.ts b/src/file/drawing/inline/graphic/graphic-data/wps/wps-shape.ts new file mode 100644 index 0000000000..4034bb9dea --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/wps/wps-shape.ts @@ -0,0 +1,40 @@ +import { IMediaDataTransformation } from "@file/media"; +import { Paragraph } from "@file/paragraph"; +import { XmlComponent } from "@file/xml-components"; + +import { BodyProperties, IBodyPropertiesOptions } from "./body-properties"; +import { INonVisualShapePropertiesOptions, NonVisualShapeProperties } from "./non-visual-shape-properties"; +import { WpsTextBox } from "./wps-text-box"; +import { OutlineOptions } from "../pic/shape-properties/outline/outline"; +import { SolidFillOptions } from "../pic/shape-properties/outline/solid-fill"; +import { ShapeProperties } from "../pic/shape-properties/shape-properties"; + +export type WpsShapeCoreOptions = { + readonly children: readonly Paragraph[]; + readonly nonVisualProperties?: INonVisualShapePropertiesOptions; + readonly bodyProperties?: IBodyPropertiesOptions; +}; + +export type WpsShapeOptions = WpsShapeCoreOptions & { + readonly transformation: IMediaDataTransformation; + readonly outline?: OutlineOptions; + readonly solidFill?: SolidFillOptions; +}; + +export class WpsShape extends XmlComponent { + public constructor(options: WpsShapeOptions) { + super("wps:wsp"); + + this.root.push(new NonVisualShapeProperties(options.nonVisualProperties)); + this.root.push( + new ShapeProperties({ + element: "wps", + transform: options.transformation, + outline: options.outline, + solidFill: options.solidFill, + }), + ); + this.root.push(new WpsTextBox(options.children)); + this.root.push(new BodyProperties(options.bodyProperties)); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/wps/wps-text-box.ts b/src/file/drawing/inline/graphic/graphic-data/wps/wps-text-box.ts new file mode 100644 index 0000000000..11edf24a13 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/wps/wps-text-box.ts @@ -0,0 +1,11 @@ +import { Paragraph } from "@file/paragraph"; +import { XmlComponent } from "@file/xml-components"; + +import { TextBoxContent } from "./text-box-content"; + +export class WpsTextBox extends XmlComponent { + public constructor(children: readonly Paragraph[]) { + super("wps:txbx"); + this.root.push(new TextBoxContent(children)); + } +} diff --git a/src/file/drawing/inline/graphic/graphic.ts b/src/file/drawing/inline/graphic/graphic.ts index 9289eee49c..2cd331320f 100644 --- a/src/file/drawing/inline/graphic/graphic.ts +++ b/src/file/drawing/inline/graphic/graphic.ts @@ -1,8 +1,9 @@ -import { IMediaData, IMediaDataTransformation } from "@file/media"; +import { IExtendedMediaData, 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"; +import { SolidFillOptions } from "./graphic-data/pic/shape-properties/outline/solid-fill"; class GraphicAttributes extends XmlAttributeComponent<{ readonly a: string; @@ -19,10 +20,12 @@ export class Graphic extends XmlComponent { mediaData, transform, outline, + solidFill, }: { - readonly mediaData: IMediaData; + readonly mediaData: IExtendedMediaData; readonly transform: IMediaDataTransformation; readonly outline?: OutlineOptions; + readonly solidFill?: SolidFillOptions; }) { super("a:graphic"); this.root.push( @@ -31,7 +34,7 @@ export class Graphic extends XmlComponent { }), ); - this.data = new GraphicData({ mediaData, transform, outline }); + this.data = new GraphicData({ mediaData, transform, outline, solidFill }); this.root.push(this.data); } diff --git a/src/file/drawing/inline/inline.ts b/src/file/drawing/inline/inline.ts index ac723e6fd6..734df98992 100644 --- a/src/file/drawing/inline/inline.ts +++ b/src/file/drawing/inline/inline.ts @@ -1,5 +1,5 @@ // http://officeopenxml.com/drwPicInline.php -import { IMediaData, IMediaDataTransformation } from "@file/media"; +import { IExtendedMediaData, IMediaDataTransformation } from "@file/media"; import { BuilderElement, XmlComponent } from "@file/xml-components"; import { DocProperties, DocPropertiesOptions } from "./../doc-properties/doc-properties"; @@ -8,12 +8,14 @@ import { createExtent } from "./../extent/extent"; import { createGraphicFrameProperties } from "./../graphic-frame/graphic-frame-properties"; import { Graphic } from "./../inline/graphic"; import { OutlineOptions } from "./graphic/graphic-data/pic/shape-properties/outline/outline"; +import { SolidFillOptions } from "./graphic/graphic-data/pic/shape-properties/outline/solid-fill"; type InlineOptions = { - readonly mediaData: IMediaData; + readonly mediaData: IExtendedMediaData; readonly transform: IMediaDataTransformation; readonly docProperties?: DocPropertiesOptions; readonly outline?: OutlineOptions; + readonly solidFill?: SolidFillOptions; }; // @@ -30,7 +32,7 @@ type InlineOptions = { // // // -export const createInline = ({ mediaData, transform, docProperties, outline }: InlineOptions): XmlComponent => +export const createInline = ({ mediaData, transform, docProperties, outline, solidFill }: InlineOptions): XmlComponent => new BuilderElement({ name: "wp:inline", attributes: { @@ -65,6 +67,6 @@ export const createInline = ({ mediaData, transform, docProperties, outline }: I ), new DocProperties(docProperties), createGraphicFrameProperties(), - new Graphic({ mediaData, transform, outline }), + new Graphic({ mediaData, transform, outline, solidFill }), ], }); diff --git a/src/file/media/data.ts b/src/file/media/data.ts index 7024c74e4b..bfb9d72a95 100644 --- a/src/file/media/data.ts +++ b/src/file/media/data.ts @@ -1,3 +1,5 @@ +import { WpsShapeCoreOptions } from "@file/drawing/inline/graphic/graphic-data/wps"; + export type IMediaDataTransformation = { readonly pixels: { readonly x: number; @@ -32,6 +34,14 @@ type SvgMediaData = { readonly fallback: RegularMediaData & CoreMediaData; }; +export type WpsMediaData = { + readonly type: "wps"; + readonly transformation: IMediaDataTransformation; + readonly data: WpsShapeCoreOptions; +}; + +export type IExtendedMediaData = IMediaData | WpsMediaData; + export type IMediaData = (RegularMediaData | SvgMediaData) & CoreMediaData; // Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432 diff --git a/src/file/paragraph/run/image-run.ts b/src/file/paragraph/run/image-run.ts index d909e95808..da8f06198a 100644 --- a/src/file/paragraph/run/image-run.ts +++ b/src/file/paragraph/run/image-run.ts @@ -4,6 +4,7 @@ import { hashedId } from "@util/convenience-functions"; import { Drawing, IFloating } from "../../drawing"; import { OutlineOptions } from "../../drawing/inline/graphic/graphic-data/pic/shape-properties/outline/outline"; +import { SolidFillOptions } from "../../drawing/inline/graphic/graphic-data/pic/shape-properties/outline/solid-fill"; import { IMediaTransformation } from "../../media"; import { IMediaData } from "../../media/data"; import { Run } from "../run"; @@ -13,6 +14,7 @@ type CoreImageOptions = { readonly floating?: IFloating; readonly altText?: DocPropertiesOptions; readonly outline?: OutlineOptions; + readonly solidFill?: SolidFillOptions; }; type RegularImageOptions = { diff --git a/src/file/paragraph/run/index.ts b/src/file/paragraph/run/index.ts index f459256c59..606f44d84f 100644 --- a/src/file/paragraph/run/index.ts +++ b/src/file/paragraph/run/index.ts @@ -3,6 +3,7 @@ export * from "./properties"; export * from "./text-run"; export * from "./symbol-run"; export * from "./image-run"; +export * from "./wps-shape-run"; export * from "./run-fonts"; export * from "./sequential-identifier"; export * from "./underline"; diff --git a/src/file/paragraph/run/wps-shape-run.spec.ts b/src/file/paragraph/run/wps-shape-run.spec.ts new file mode 100644 index 0000000000..2b7f0aa58f --- /dev/null +++ b/src/file/paragraph/run/wps-shape-run.spec.ts @@ -0,0 +1,271 @@ +import { describe, it } from "vitest"; + +import { Formatter } from "@export/formatter"; +import { IViewWrapper } from "@file/document-wrapper"; +import { File } from "@file/file"; +import { Paragraph } from "@file/index"; + +import { WpsShapeRun } from "./wps-shape-run"; + +describe("WpsShapeRun", () => { + describe("#constructor()", () => { + it("should create with Buffer", () => { + const currentShapeRun = new WpsShapeRun({ + type: "wps", + children: [new Paragraph("Test Paragraph")], + transformation: { + width: 200, + height: 200, + rotation: 45, + }, + solidFill: { + type: "rgb", + value: "FF0000", + }, + floating: { + zIndex: 10, + horizontalPosition: { + offset: 1014400, + }, + verticalPosition: { + offset: 1014400, + }, + }, + }); + + const tree = new Formatter().format(currentShapeRun, { + file: { + Media: {}, + } as unknown as File, + viewWrapper: {} as unknown as IViewWrapper, + stack: [], + }); + + // eslint-disable-next-line no-console + console.log(JSON.stringify(tree, null, 2)); + + // expect(tree).to.deep.equal({ + // "w:r": [ + // { + // "w:drawing": [ + // { + // "wp:anchor": [ + // { + // _attr: { + // allowOverlap: "1", + // behindDoc: "0", + // distB: 0, + // distL: 0, + // distR: 0, + // distT: 0, + // layoutInCell: "1", + // locked: "0", + // relativeHeight: 10, + // simplePos: "0", + // }, + // }, + // { + // "wp:simplePos": { + // _attr: { + // x: 0, + // y: 0, + // }, + // }, + // }, + // { + // "wp:positionH": [ + // { + // _attr: { + // relativeFrom: "page", + // }, + // }, + // { + // "wp:posOffset": ["1014400"], + // }, + // ], + // }, + // { + // "wp:positionV": [ + // { + // _attr: { + // relativeFrom: "page", + // }, + // }, + // { + // "wp:posOffset": ["1014400"], + // }, + // ], + // }, + // { + // "wp:extent": { + // _attr: { + // cx: 1905000, + // cy: 1905000, + // }, + // }, + // }, + // { + // "wp:effectExtent": { + // _attr: { + // b: 0, + // l: 0, + // r: 0, + // t: 0, + // }, + // }, + // }, + // { + // "wp:wrapNone": {}, + // }, + // { + // "wp:docPr": { + // _attr: { + // descr: "", + // id: 1, + // name: "", + // title: "", + // }, + // }, + // }, + // { + // "wp:cNvGraphicFramePr": [ + // { + // "a:graphicFrameLocks": { + // _attr: { + // noChangeAspect: 1, + // "xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main", + // }, + // }, + // }, + // ], + // }, + // { + // "a:graphic": [ + // { + // _attr: { + // "xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main", + // }, + // }, + // { + // "a:graphicData": [ + // { + // _attr: { + // uri: "http://schemas.openxmlformats.org/drawingml/2006/picture", + // }, + // }, + // { + // "pic:pic": [ + // { + // _attr: { + // "xmlns:pic": "http://schemas.openxmlformats.org/drawingml/2006/picture", + // }, + // }, + // { + // "pic:nvPicPr": [ + // { + // "pic:cNvPr": { + // _attr: { + // descr: "", + // id: 0, + // name: "", + // }, + // }, + // }, + // { + // "pic:cNvPicPr": [ + // { + // "a:picLocks": { + // _attr: { + // noChangeArrowheads: 1, + // noChangeAspect: 1, + // }, + // }, + // }, + // ], + // }, + // ], + // }, + // { + // "pic:blipFill": [ + // { + // "a:blip": { + // _attr: { + // cstate: "none", + // "r:embed": + // "rId{da39a3ee5e6b4b0d3255bfef95601890afd80709.png}", + // }, + // }, + // }, + // { + // "a:srcRect": {}, + // }, + // { + // "a:stretch": [ + // { + // "a:fillRect": {}, + // }, + // ], + // }, + // ], + // }, + // { + // "pic:spPr": [ + // { + // _attr: { + // bwMode: "auto", + // }, + // }, + // { + // "a:xfrm": [ + // { + // _attr: { + // rot: 2700000, + // }, + // }, + // { + // "a:off": { + // _attr: { + // x: 0, + // y: 0, + // }, + // }, + // }, + // { + // "a:ext": { + // _attr: { + // cx: 1905000, + // cy: 1905000, + // }, + // }, + // }, + // ], + // }, + // { + // "a:prstGeom": [ + // { + // _attr: { + // prst: "rect", + // }, + // }, + // { + // "a:avLst": {}, + // }, + // ], + // }, + // ], + // }, + // ], + // }, + // ], + // }, + // ], + // }, + // ], + // }, + // ], + // }, + // ], + // }); + }); + }); +}); diff --git a/src/file/paragraph/run/wps-shape-run.ts b/src/file/paragraph/run/wps-shape-run.ts new file mode 100644 index 0000000000..ab51152f63 --- /dev/null +++ b/src/file/paragraph/run/wps-shape-run.ts @@ -0,0 +1,53 @@ +import { DocPropertiesOptions } from "@file/drawing/doc-properties/doc-properties"; +import { WpsShapeCoreOptions } from "@file/drawing/inline/graphic/graphic-data/wps"; + +import { Drawing, IFloating } from "../../drawing"; +import { OutlineOptions } from "../../drawing/inline/graphic/graphic-data/pic/shape-properties/outline/outline"; +import { SolidFillOptions } from "../../drawing/inline/graphic/graphic-data/pic/shape-properties/outline/solid-fill"; +import { IMediaDataTransformation, IMediaTransformation, WpsMediaData } from "../../media"; +import { Run } from "../run"; + +type CoreShapeOptions = { + readonly transformation: IMediaTransformation; + readonly floating?: IFloating; + readonly altText?: DocPropertiesOptions; + readonly outline?: OutlineOptions; + readonly solidFill?: SolidFillOptions; +}; + +export type IWpsShapeOptions = WpsShapeCoreOptions & { readonly type: "wps" } & CoreShapeOptions; + +const createTransformation = (options: IMediaTransformation): IMediaDataTransformation => ({ + pixels: { + x: Math.round(options.width), + y: Math.round(options.height), + }, + emus: { + x: Math.round(options.width * 9525), + y: Math.round(options.height * 9525), + }, + flip: options.flip, + rotation: options.rotation ? options.rotation * 60000 : undefined, +}); + +export class WpsShapeRun extends Run { + private readonly wpsShapeData: WpsMediaData; + + public constructor(options: IWpsShapeOptions) { + super({}); + + this.wpsShapeData = { + type: options.type, + transformation: createTransformation(options.transformation), + data: { ...options }, + }; + const drawing = new Drawing(this.wpsShapeData, { + floating: options.floating, + docProperties: options.altText, + outline: options.outline, + solidFill: options.solidFill, + }); + + this.root.push(drawing); + } +}