diff --git a/demo/demo1.js b/demo/demo1.js index 1a550b5977..dbada3a890 100644 --- a/demo/demo1.js +++ b/demo/demo1.js @@ -10,13 +10,7 @@ paragraph.addRun(dateText); doc.addParagraph(paragraph); -// Feature coming soon -// var media = new docx.Media(); -// media.addMedia("happy-penguins", "./demo/penguins.jpg"); -// var pictureRun = new docx.PictureRun(media.getMedia("happy-penguins")); - -// var exporter = new docx.LocalPacker(doc); var exporter = new docx.LocalPacker(doc); exporter.pack('My Document'); -console.log('Document created succesfully at project root!'); \ No newline at end of file +console.log('Document created succesfully at project root!'); diff --git a/demo/demo5.js b/demo/demo5.js new file mode 100644 index 0000000000..1d6a9b3ac4 --- /dev/null +++ b/demo/demo5.js @@ -0,0 +1,17 @@ +const docx = require('../build'); + +var doc = new docx.File(); + +var paragraph = new docx.Paragraph("Hello World"); +doc.addParagraph(paragraph); + +const image = doc.createImage("./demo/images/image1.jpeg"); +const image2 = doc.createImage("./demo/images/dog.png"); +const image3 = doc.createImage("./demo/images/cat.jpg"); +const image4 = doc.createImage("./demo/images/parrots.bmp"); +const image5 = doc.createImage("./demo/images/pizza.gif"); + +var exporter = new docx.LocalPacker(doc); +exporter.pack('My Document'); + +console.log('Document created successfully at project root!'); diff --git a/demo/images/cat.jpg b/demo/images/cat.jpg new file mode 100644 index 0000000000..9b8def5f30 Binary files /dev/null and b/demo/images/cat.jpg differ diff --git a/demo/images/dog.png b/demo/images/dog.png new file mode 100644 index 0000000000..2791b64087 Binary files /dev/null and b/demo/images/dog.png differ diff --git a/demo/penguins.jpg b/demo/images/image1.jpeg similarity index 100% rename from demo/penguins.jpg rename to demo/images/image1.jpeg diff --git a/demo/images/parrots.bmp b/demo/images/parrots.bmp new file mode 100644 index 0000000000..9e088598eb Binary files /dev/null and b/demo/images/parrots.bmp differ diff --git a/demo/images/pizza.gif b/demo/images/pizza.gif new file mode 100644 index 0000000000..8ea63e5ef4 Binary files /dev/null and b/demo/images/pizza.gif differ diff --git a/package.json b/package.json index f08aeec4fe..0b960e86a6 100644 --- a/package.json +++ b/package.json @@ -39,9 +39,11 @@ "dependencies": { "@types/archiver": "^1.3.4", "@types/express": "^4.0.35", + "@types/image-size": "0.0.29", "@types/request": "^2.0.3", "@types/request-promise": "^4.1.39", "archiver": "^1.3.0", + "image-size": "^0.6.2", "request": "^2.83.0", "request-promise": "^4.2.2", "xml": "^1.0.1" diff --git a/src/export/packer/compiler.ts b/src/export/packer/compiler.ts index 45be0d7a15..afce89f525 100644 --- a/src/export/packer/compiler.ts +++ b/src/export/packer/compiler.ts @@ -32,7 +32,7 @@ export class Compiler { cwd: TEMPLATE_PATH, }); - const xmlDocument = xml(this.formatter.format(this.file.Document)); + const xmlDocument = xml(this.formatter.format(this.file.Document), true); const xmlStyles = xml(this.formatter.format(this.file.Styles)); const xmlProperties = xml(this.formatter.format(this.file.Properties), { declaration: { @@ -41,6 +41,7 @@ export class Compiler { }, }); const xmlNumbering = xml(this.formatter.format(this.file.Numbering)); + const xmlRelationships = xml(this.formatter.format(this.file.Relationships)); this.archive.append(xmlDocument, { name: "word/document.xml", @@ -58,9 +59,13 @@ export class Compiler { name: "word/numbering.xml", }); + this.archive.append(xmlRelationships, { + name: "word/_rels/document.xml.rels", + }); + for (const data of this.file.Media.array) { this.archive.append(data.stream, { - name: `media/${data.fileName}`, + name: `word/media/${data.fileName}`, }); } diff --git a/src/file/document/document.ts b/src/file/document/document.ts index 23b73a97fd..5e16212f86 100644 --- a/src/file/document/document.ts +++ b/src/file/document/document.ts @@ -1,6 +1,7 @@ // http://officeopenxml.com/WPdocument.php +import { IMediaData } from "file/media"; import { XmlComponent } from "file/xml-components"; -import { Paragraph } from "../paragraph"; +import { Paragraph, PictureRun } from "../paragraph"; import { Table } from "../table"; import { Body } from "./body"; import { DocumentAttributes } from "./document-attributes"; @@ -52,4 +53,18 @@ export class Document extends XmlComponent { this.addTable(table); return table; } + + public addDrawing(imageData: IMediaData): void { + const paragraph = new Paragraph(); + const run = new PictureRun(imageData); + paragraph.addRun(run); + + this.body.push(paragraph); + } + + public createDrawing(imageData: IMediaData): void { + this.addDrawing(imageData); + + return; + } } diff --git a/src/file/drawing/drawing.spec.ts b/src/file/drawing/drawing.spec.ts index 8bda6243e7..9b113da0bf 100644 --- a/src/file/drawing/drawing.spec.ts +++ b/src/file/drawing/drawing.spec.ts @@ -8,12 +8,22 @@ describe("Drawing", () => { let currentBreak: Drawing; beforeEach(() => { - const path = "./demo/penguins.jpg"; + const path = "./demo/images/image1.jpeg"; currentBreak = new Drawing({ fileName: "test.jpg", referenceId: 1, stream: fs.createReadStream(path), path: path, + dimensions: { + pixels: { + x: 100, + y: 100, + }, + emus: { + x: 100 * 9525, + y: 100 * 9525, + }, + }, }); }); diff --git a/src/file/drawing/drawing.ts b/src/file/drawing/drawing.ts new file mode 100644 index 0000000000..fcaaa960c0 --- /dev/null +++ b/src/file/drawing/drawing.ts @@ -0,0 +1,16 @@ +import { IMediaData } from "file/media"; +import { XmlComponent } from "file/xml-components"; +import { Inline } from "./inline"; + +export class Drawing extends XmlComponent { + + constructor(imageData: IMediaData) { + super("w:drawing"); + + if (imageData === undefined) { + throw new Error("imageData cannot be undefined"); + } + + this.root.push(new Inline(imageData.referenceId, imageData.dimensions)); + } +} diff --git a/src/file/drawing/index.ts b/src/file/drawing/index.ts index fe79f86673..ba96e11de9 100644 --- a/src/file/drawing/index.ts +++ b/src/file/drawing/index.ts @@ -1,16 +1 @@ -import { IData } from "file/media"; -import { XmlComponent } from "file/xml-components"; -import { Inline } from "./inline"; - -export class Drawing extends XmlComponent { - - constructor(imageData: IData) { - super("w:drawing"); - - if (imageData === undefined) { - throw new Error("imageData cannot be undefined"); - } - - this.root.push(new Inline(imageData.referenceId)); - } -} +export { Drawing } from "./drawing"; diff --git a/src/file/drawing/inline/doc-properties/doc-properties-attributes.ts b/src/file/drawing/inline/doc-properties/doc-properties-attributes.ts new file mode 100644 index 0000000000..ae75d35096 --- /dev/null +++ b/src/file/drawing/inline/doc-properties/doc-properties-attributes.ts @@ -0,0 +1,15 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IDocPropertiesAttributes { + id?: number; + name?: string; + descr?: string; +} + +export class DocPropertiesAttributes extends XmlAttributeComponent { + protected xmlKeys = { + id: "id", + name: "name", + descr: "descr", + }; +} diff --git a/src/file/drawing/inline/doc-properties/doc-properties.ts b/src/file/drawing/inline/doc-properties/doc-properties.ts new file mode 100644 index 0000000000..b6e03d6953 --- /dev/null +++ b/src/file/drawing/inline/doc-properties/doc-properties.ts @@ -0,0 +1,15 @@ +import { XmlComponent } from "file/xml-components"; +import { DocPropertiesAttributes } from "./doc-properties-attributes"; + +export class DocProperties extends XmlComponent { + + constructor() { + super("wp:docPr"); + + this.root.push(new DocPropertiesAttributes({ + id: 0, + name: "", + descr: "", + })); + } +} diff --git a/src/file/drawing/inline/effect-extent/effect-extent-attributes.ts b/src/file/drawing/inline/effect-extent/effect-extent-attributes.ts new file mode 100644 index 0000000000..c97f4b123d --- /dev/null +++ b/src/file/drawing/inline/effect-extent/effect-extent-attributes.ts @@ -0,0 +1,17 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IEffectExtentAttributes { + b?: number; + l?: number; + r?: number; + t?: number; +} + +export class EffectExtentAttributes extends XmlAttributeComponent { + protected xmlKeys = { + b: "b", + l: "l", + r: "r", + t: "t", + }; +} diff --git a/src/file/drawing/inline/effect-extent/effect-extent.ts b/src/file/drawing/inline/effect-extent/effect-extent.ts new file mode 100644 index 0000000000..97c6caa098 --- /dev/null +++ b/src/file/drawing/inline/effect-extent/effect-extent.ts @@ -0,0 +1,16 @@ +import { XmlComponent } from "file/xml-components"; +import { EffectExtentAttributes } from "./effect-extent-attributes"; + +export class EffectExtent extends XmlComponent { + + constructor() { + super("wp:effectExtent"); + + this.root.push(new EffectExtentAttributes({ + b: 0, + l: 0, + r: 0, + t: 0, + })); + } +} diff --git a/src/file/drawing/inline/extent/extent-attributes.ts b/src/file/drawing/inline/extent/extent-attributes.ts new file mode 100644 index 0000000000..89a02167f6 --- /dev/null +++ b/src/file/drawing/inline/extent/extent-attributes.ts @@ -0,0 +1,13 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IExtentAttributes { + cx?: number; + cy?: number; +} + +export class ExtentAttributes extends XmlAttributeComponent { + protected xmlKeys = { + cx: "cx", + cy: "cy", + }; +} diff --git a/src/file/drawing/inline/extent/extent.ts b/src/file/drawing/inline/extent/extent.ts new file mode 100644 index 0000000000..3b787e0e66 --- /dev/null +++ b/src/file/drawing/inline/extent/extent.ts @@ -0,0 +1,14 @@ +import { XmlComponent } from "file/xml-components"; +import { ExtentAttributes } from "./extent-attributes"; + +export class Extent extends XmlComponent { + + constructor(x: number, y: number) { + super("wp:extent"); + + this.root.push(new ExtentAttributes({ + cx: x, + cy: y, + })); + } +} diff --git a/src/file/drawing/inline/graphic-frame/graphic-frame-locks/graphic-frame-lock-attributes.ts b/src/file/drawing/inline/graphic-frame/graphic-frame-locks/graphic-frame-lock-attributes.ts new file mode 100644 index 0000000000..dad7841ed1 --- /dev/null +++ b/src/file/drawing/inline/graphic-frame/graphic-frame-locks/graphic-frame-lock-attributes.ts @@ -0,0 +1,13 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IGraphicFrameLockAttributes { + xmlns?: string; + noChangeAspect?: number; +} + +export class GraphicFrameLockAttributes extends XmlAttributeComponent { + protected xmlKeys = { + xmlns: "xmlns:a", + noChangeAspect: "noChangeAspect", + }; +} diff --git a/src/file/drawing/inline/graphic-frame/graphic-frame-locks/graphic-frame-locks.ts b/src/file/drawing/inline/graphic-frame/graphic-frame-locks/graphic-frame-locks.ts new file mode 100644 index 0000000000..c6e70d02ce --- /dev/null +++ b/src/file/drawing/inline/graphic-frame/graphic-frame-locks/graphic-frame-locks.ts @@ -0,0 +1,14 @@ +import { XmlComponent } from "file/xml-components"; +import { GraphicFrameLockAttributes } from "./graphic-frame-lock-attributes"; + +export class GraphicFrameLocks extends XmlComponent { + + constructor() { + super("a:graphicFrameLocks"); + + this.root.push(new GraphicFrameLockAttributes({ + xmlns: "http://schemas.openxmlformats.org/drawingml/2006/main", + noChangeAspect: 1, + })); + } +} diff --git a/src/file/drawing/inline/graphic-frame/graphic-frame-properties.ts b/src/file/drawing/inline/graphic-frame/graphic-frame-properties.ts new file mode 100644 index 0000000000..764fb05b19 --- /dev/null +++ b/src/file/drawing/inline/graphic-frame/graphic-frame-properties.ts @@ -0,0 +1,11 @@ +import { XmlComponent } from "file/xml-components"; +import { GraphicFrameLocks } from "./graphic-frame-locks/graphic-frame-locks"; + +export class GraphicFrameProperties extends XmlComponent { + + constructor() { + super("wp:cNvGraphicFramePr"); + + this.root.push(new GraphicFrameLocks()); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/graphic-data-attribute.ts b/src/file/drawing/inline/graphic/graphic-data/graphic-data-attribute.ts new file mode 100644 index 0000000000..a248ecabf0 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/graphic-data-attribute.ts @@ -0,0 +1,11 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IGraphicDataAttributes { + uri?: string; +} + +export class GraphicDataAttributes extends XmlAttributeComponent { + protected xmlKeys = { + uri: "uri", + }; +} diff --git a/src/file/drawing/inline/graphic/graphic-data/graphic-data.ts b/src/file/drawing/inline/graphic/graphic-data/graphic-data.ts new file mode 100644 index 0000000000..4b32b25cc4 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/graphic-data.ts @@ -0,0 +1,16 @@ +import { XmlComponent } from "file/xml-components"; +import { GraphicDataAttributes } from "./graphic-data-attribute"; +import { Pic } from "./pic"; + +export class GraphicData extends XmlComponent { + + constructor(referenceId: number, x: number, y: number) { + super("a:graphicData"); + + this.root.push(new GraphicDataAttributes({ + uri: "http://schemas.openxmlformats.org/drawingml/2006/picture", + })); + + this.root.push(new Pic(referenceId, x, y)); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/index.ts b/src/file/drawing/inline/graphic/graphic-data/index.ts index 0f462b62ae..1196483b8a 100644 --- a/src/file/drawing/inline/graphic/graphic-data/index.ts +++ b/src/file/drawing/inline/graphic/graphic-data/index.ts @@ -1,10 +1 @@ -import { XmlComponent } from "file/xml-components"; -import { Pic } from "./pic"; - -export class GraphicData extends XmlComponent { - - constructor(referenceId: number) { - super("a:graphicData"); - this.root.push(new Pic(referenceId)); - } -} +export * from "./graphic-data"; diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/blip/blip.ts b/src/file/drawing/inline/graphic/graphic-data/pic/blip/blip.ts index c4aca1f156..095bae8696 100644 --- a/src/file/drawing/inline/graphic/graphic-data/pic/blip/blip.ts +++ b/src/file/drawing/inline/graphic/graphic-data/pic/blip/blip.ts @@ -2,11 +2,13 @@ import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; interface IBlipProperties { embed: string; + cstate: string; } class BlipAttributes extends XmlAttributeComponent { protected xmlKeys = { embed: "r:embed", + cstate: "cstate", }; } @@ -16,6 +18,7 @@ export class Blip extends XmlComponent { super("a:blip"); this.root.push(new BlipAttributes({ embed: `rId${referenceId}`, + cstate: "none", })); } } diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/index.ts b/src/file/drawing/inline/graphic/graphic-data/pic/index.ts index b7907e20dc..84e1d96f7b 100644 --- a/src/file/drawing/inline/graphic/graphic-data/pic/index.ts +++ b/src/file/drawing/inline/graphic/graphic-data/pic/index.ts @@ -1,10 +1 @@ -import { XmlComponent } from "file/xml-components"; -import { BlipFill } from "./blip/blip-fill"; - -export class Pic extends XmlComponent { - - constructor(referenceId: number) { - super("pic:pic"); - this.root.push(new BlipFill(referenceId)); - } -} +export * from "./pic"; diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/child-non-visual-pic-properties/child-non-visual-pic-properties.ts b/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/child-non-visual-pic-properties/child-non-visual-pic-properties.ts new file mode 100644 index 0000000000..f1e56fe332 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/child-non-visual-pic-properties/child-non-visual-pic-properties.ts @@ -0,0 +1,11 @@ +import { XmlComponent } from "file/xml-components"; +import { PicLocks } from "./pic-locks/pic-locks"; + +export class ChildNonVisualProperties extends XmlComponent { + + constructor() { + super("pic:cNvPicPr"); + + this.root.push(new PicLocks()); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/child-non-visual-pic-properties/pic-locks/pic-locks-attributes.ts b/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/child-non-visual-pic-properties/pic-locks/pic-locks-attributes.ts new file mode 100644 index 0000000000..b5fe12fc48 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/child-non-visual-pic-properties/pic-locks/pic-locks-attributes.ts @@ -0,0 +1,13 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IPicLocksAttributes { + noChangeAspect?: number; + noChangeArrowheads?: number; +} + +export class PicLocksAttributes extends XmlAttributeComponent { + protected xmlKeys = { + noChangeAspect: "noChangeAspect", + noChangeArrowheads: "noChangeArrowheads", + }; +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/child-non-visual-pic-properties/pic-locks/pic-locks.ts b/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/child-non-visual-pic-properties/pic-locks/pic-locks.ts new file mode 100644 index 0000000000..6a6027b89d --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/child-non-visual-pic-properties/pic-locks/pic-locks.ts @@ -0,0 +1,13 @@ +import { XmlComponent } from "file/xml-components"; +import { PicLocksAttributes } from "./pic-locks-attributes"; + +export class PicLocks extends XmlComponent { + + constructor() { + super("a:picLocks"); + this.root.push(new PicLocksAttributes({ + noChangeAspect: 1, + noChangeArrowheads: 1, + })); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/non-visual-pic-properties.ts b/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/non-visual-pic-properties.ts new file mode 100644 index 0000000000..50551a9c58 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/non-visual-pic-properties.ts @@ -0,0 +1,14 @@ +import { XmlComponent } from "file/xml-components"; +import { ChildNonVisualProperties } from "./child-non-visual-pic-properties/child-non-visual-pic-properties"; +import { NonVisualProperties } from "./non-visual-properties/non-visual-properties"; + +export class NonVisualPicProperties extends XmlComponent { + + constructor() { + super("pic:nvPicPr"); + + this.root.push(new NonVisualProperties()); + this.root.push(new ChildNonVisualProperties()); + + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/non-visual-properties/non-visual-properties-attributes.ts b/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/non-visual-properties/non-visual-properties-attributes.ts new file mode 100644 index 0000000000..1f4abe7204 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/non-visual-properties/non-visual-properties-attributes.ts @@ -0,0 +1,15 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface INonVisualPropertiesAttributes { + id?: number; + name?: string; + descr?: string; +} + +export class NonVisualPropertiesAttributes extends XmlAttributeComponent { + protected xmlKeys = { + id: "id", + name: "name", + descr: "desc", + }; +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/non-visual-properties/non-visual-properties.ts b/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/non-visual-properties/non-visual-properties.ts new file mode 100644 index 0000000000..b37e3f77ba --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/non-visual-properties/non-visual-properties.ts @@ -0,0 +1,15 @@ +import { XmlComponent } from "file/xml-components"; +import { NonVisualPropertiesAttributes } from "./non-visual-properties-attributes"; + +export class NonVisualProperties extends XmlComponent { + + constructor() { + super("pic:cNvPr"); + + this.root.push(new NonVisualPropertiesAttributes({ + id: 0, + name: "", + descr: "", + })); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/pic-attributes.ts b/src/file/drawing/inline/graphic/graphic-data/pic/pic-attributes.ts new file mode 100644 index 0000000000..b73c6c8cd0 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/pic-attributes.ts @@ -0,0 +1,11 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IPicAttributes { + xmlns?: string; +} + +export class PicAttributes extends XmlAttributeComponent { + protected xmlKeys = { + xmlns: "xmlns:pic", + }; +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/pic.ts b/src/file/drawing/inline/graphic/graphic-data/pic/pic.ts new file mode 100644 index 0000000000..31bee69136 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/pic.ts @@ -0,0 +1,19 @@ +// http://officeopenxml.com/drwPic.php +import { XmlComponent } from "file/xml-components"; +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"; + +export class Pic extends XmlComponent { + constructor(referenceId: number, x: number, y: number) { + super("pic:pic"); + + this.root.push(new PicAttributes({ + xmlns: "http://schemas.openxmlformats.org/drawingml/2006/picture", + })); + this.root.push(new NonVisualPicProperties()); + this.root.push(new BlipFill(referenceId)); + this.root.push(new ShapeProperties(x, y)); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/extents/extents-attributes.ts b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/extents/extents-attributes.ts new file mode 100644 index 0000000000..c502231dc7 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/extents/extents-attributes.ts @@ -0,0 +1,13 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IExtentsAttributes { + cx?: number; + cy?: number; +} + +export class ExtentsAttributes extends XmlAttributeComponent { + protected xmlKeys = { + cx: "cx", + cy: "cy", + }; +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/extents/extents.ts b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/extents/extents.ts new file mode 100644 index 0000000000..de38caab18 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/extents/extents.ts @@ -0,0 +1,15 @@ +// http://officeopenxml.com/drwSp-size.php +import { XmlComponent } from "file/xml-components"; +import { ExtentsAttributes } from "./extents-attributes"; + +export class Extents extends XmlComponent { + + constructor(x: number, y: number) { + super("a:ext"); + + this.root.push(new ExtentsAttributes({ + cx: x, + cy: y, + })); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/form.ts b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/form.ts new file mode 100644 index 0000000000..94ed24e1eb --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/form.ts @@ -0,0 +1,14 @@ +// http://officeopenxml.com/drwSp-size.php +import { XmlComponent } from "file/xml-components"; +import { Extents } from "./extents/extents"; +import { Offset } from "./offset/off"; + +export class Form extends XmlComponent { + + constructor(x: number, y: number) { + super("a:xfrm"); + + this.root.push(new Extents(x, y)); + this.root.push(new Offset()); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/index.ts b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/index.ts new file mode 100644 index 0000000000..c4a75a7a69 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/index.ts @@ -0,0 +1 @@ +export * from "./form"; diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/offset/off-attributes.ts b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/offset/off-attributes.ts new file mode 100644 index 0000000000..9f72211ff9 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/offset/off-attributes.ts @@ -0,0 +1,13 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IOffsetAttributes { + x?: number; + y?: number; +} + +export class OffsetAttributes extends XmlAttributeComponent { + protected xmlKeys = { + x: "x", + y: "y", + }; +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/offset/off.ts b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/offset/off.ts new file mode 100644 index 0000000000..32c2fcca76 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/offset/off.ts @@ -0,0 +1,15 @@ +// http://officeopenxml.com/drwSp-size.php +import { XmlComponent } from "file/xml-components"; +import { OffsetAttributes } from "./off-attributes"; + +export class Offset extends XmlComponent { + + constructor() { + super("a:off"); + + this.root.push(new OffsetAttributes({ + x: 0, + y: 0, + })); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/no-fill.ts b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/no-fill.ts new file mode 100644 index 0000000000..bbccc05664 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/no-fill.ts @@ -0,0 +1,8 @@ +import { XmlComponent } from "file/xml-components"; + +export class NoFill extends XmlComponent { + + constructor() { + super("a:noFill"); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/outline/no-fill.ts b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/outline/no-fill.ts new file mode 100644 index 0000000000..bbccc05664 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/outline/no-fill.ts @@ -0,0 +1,8 @@ +import { XmlComponent } from "file/xml-components"; + +export class NoFill extends XmlComponent { + + constructor() { + super("a:noFill"); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/outline/outline.ts b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/outline/outline.ts new file mode 100644 index 0000000000..5735deb3e5 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/outline/outline.ts @@ -0,0 +1,12 @@ +// http://officeopenxml.com/drwSp-outline.php +import { XmlComponent } from "file/xml-components"; +import { NoFill } from "./no-fill"; + +export class Outline extends XmlComponent { + + constructor() { + super("a:ln"); + + this.root.push(new NoFill()); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/preset-geometry/adjustment-values/adjustment-values.ts b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/preset-geometry/adjustment-values/adjustment-values.ts new file mode 100644 index 0000000000..395f61f866 --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/preset-geometry/adjustment-values/adjustment-values.ts @@ -0,0 +1,9 @@ +// http://officeopenxml.com/drwSp-prstGeom.php +import { XmlComponent } from "file/xml-components"; + +export class AdjustmentValues extends XmlComponent { + + constructor() { + super("a:avLst"); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/preset-geometry/preset-geometry-attributes.ts b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/preset-geometry/preset-geometry-attributes.ts new file mode 100644 index 0000000000..bd1c70feaa --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/preset-geometry/preset-geometry-attributes.ts @@ -0,0 +1,11 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IPresetGeometryAttributes { + prst?: string; +} + +export class PresetGeometryAttributes extends XmlAttributeComponent { + protected xmlKeys = { + prst: "prst", + }; +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/preset-geometry/preset-geometry.ts b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/preset-geometry/preset-geometry.ts new file mode 100644 index 0000000000..67668bc36a --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/preset-geometry/preset-geometry.ts @@ -0,0 +1,17 @@ +// http://officeopenxml.com/drwSp-prstGeom.php +import { XmlComponent } from "file/xml-components"; +import { AdjustmentValues } from "./adjustment-values/adjustment-values"; +import { PresetGeometryAttributes } from "./preset-geometry-attributes"; + +export class PresetGeometry extends XmlComponent { + + constructor() { + super("a:prstGeom"); + + this.root.push(new PresetGeometryAttributes({ + prst: "rect", + })); + + this.root.push(new AdjustmentValues()); + } +} diff --git a/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/shape-properties-attributes.ts b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/shape-properties-attributes.ts new file mode 100644 index 0000000000..4e4761bcde --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/shape-properties-attributes.ts @@ -0,0 +1,11 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IShapePropertiesAttributes { + bwMode?: string; +} + +export class ShapePropertiesAttributes extends XmlAttributeComponent { + protected xmlKeys = { + bwMode: "bwMode", + }; +} 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 new file mode 100644 index 0000000000..41b914a0fd --- /dev/null +++ b/src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/shape-properties.ts @@ -0,0 +1,23 @@ +// http://officeopenxml.com/drwSp-SpPr.php +import { XmlComponent } from "file/xml-components"; +import { Form } from "./form"; +// import { NoFill } from "./no-fill"; +// import { Outline } from "./outline/outline"; +import { PresetGeometry } from "./preset-geometry/preset-geometry"; +import { ShapePropertiesAttributes } from "./shape-properties-attributes"; + +export class ShapeProperties extends XmlComponent { + + constructor(x: number, y: number) { + super("pic:spPr"); + + this.root.push(new ShapePropertiesAttributes({ + bwMode: "auto", + })); + + this.root.push(new Form(x, y)); + this.root.push(new PresetGeometry()); + // this.root.push(new NoFill()); + // this.root.push(new Outline()); + } +} diff --git a/src/file/drawing/inline/graphic/index.ts b/src/file/drawing/inline/graphic/index.ts index 81251fd41c..60b336f6ba 100644 --- a/src/file/drawing/inline/graphic/index.ts +++ b/src/file/drawing/inline/graphic/index.ts @@ -13,11 +13,11 @@ class GraphicAttributes extends XmlAttributeComponent { export class Graphic extends XmlComponent { - constructor(referenceId: number) { + constructor(referenceId: number, x: number, y: number) { super("a:graphic"); this.root.push(new GraphicAttributes({ a: "http://schemas.openxmlformats.org/drawingml/2006/main", })); - this.root.push(new GraphicData(referenceId)); + this.root.push(new GraphicData(referenceId, x, y)); } } diff --git a/src/file/drawing/inline/index.ts b/src/file/drawing/inline/index.ts index 3e7ab22831..2fdaa4a91f 100644 --- a/src/file/drawing/inline/index.ts +++ b/src/file/drawing/inline/index.ts @@ -1,10 +1 @@ -import { XmlComponent } from "file/xml-components"; -import { Graphic } from "./graphic"; - -export class Inline extends XmlComponent { - - constructor(referenceId: number) { - super("wp:inline"); - this.root.push(new Graphic(referenceId)); - } -} +export * from "./inline"; diff --git a/src/file/drawing/inline/inline-attributes.ts b/src/file/drawing/inline/inline-attributes.ts new file mode 100644 index 0000000000..1a4ef74e3c --- /dev/null +++ b/src/file/drawing/inline/inline-attributes.ts @@ -0,0 +1,17 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IInlineAttributes { + distT?: number; + distB?: number; + distL?: number; + distR?: number; +} + +export class InlineAttributes extends XmlAttributeComponent { + protected xmlKeys = { + distT: "distT", + distB: "distB", + distL: "distL", + distR: "distR", + }; +} diff --git a/src/file/drawing/inline/inline.ts b/src/file/drawing/inline/inline.ts new file mode 100644 index 0000000000..15facb5681 --- /dev/null +++ b/src/file/drawing/inline/inline.ts @@ -0,0 +1,29 @@ +// http://officeopenxml.com/drwPicInline.php +import { IMediaDataDimensions } from "file/media"; +import { XmlComponent } from "file/xml-components"; +import { DocProperties } from "./doc-properties/doc-properties"; +import { EffectExtent } from "./effect-extent/effect-extent"; +import { Extent } from "./extent/extent"; +import { Graphic } from "./graphic"; +import { GraphicFrameProperties } from "./graphic-frame/graphic-frame-properties"; +import { InlineAttributes } from "./inline-attributes"; + +export class Inline extends XmlComponent { + + constructor(referenceId: number, dimensions: IMediaDataDimensions) { + super("wp:inline"); + + this.root.push(new InlineAttributes({ + distT: 0, + distB: 0, + distL: 0, + distR: 0, + })); + + this.root.push(new Extent(dimensions.emus.x, dimensions.emus.y)); + this.root.push(new EffectExtent()); + this.root.push(new DocProperties()); + this.root.push(new GraphicFrameProperties()); + this.root.push(new Graphic(referenceId, dimensions.emus.x, dimensions.emus.y)); + } +} diff --git a/src/file/file.ts b/src/file/file.ts index 59e913743f..a2af594339 100644 --- a/src/file/file.ts +++ b/src/file/file.ts @@ -1,3 +1,4 @@ +import { Relationships } from "file/relationships"; import { Document } from "./document"; import { Media } from "./media"; import { Numbering } from "./numbering"; @@ -14,6 +15,7 @@ export class File { private properties: Properties; private numbering: Numbering; private media: Media; + private relationships: Relationships; constructor(options?: IPropertiesOptions) { this.document = new Document(); @@ -31,6 +33,7 @@ export class File { this.properties = new Properties(options); this.numbering = new Numbering(); this.media = new Media(); + this.relationships = new Relationships(); } public addParagraph(paragraph: Paragraph): void { @@ -49,6 +52,12 @@ export class File { return this.document.createTable(rows, cols); } + public createImage(image: string): void { + const mediaData = this.media.addMedia(image); + this.relationships.createRelationship(mediaData.referenceId, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", `media/${mediaData.fileName}`); + this.document.createDrawing(mediaData); + } + public get Document(): Document { return this.document; } @@ -68,4 +77,8 @@ export class File { public get Media(): Media { return this.media; } + + public get Relationships(): Relationships { + return this.relationships; + } } diff --git a/src/file/media/data.ts b/src/file/media/data.ts index ada1231659..ea75493f79 100644 --- a/src/file/media/data.ts +++ b/src/file/media/data.ts @@ -1,8 +1,20 @@ import * as fs from "fs"; -export interface IData { +export interface IMediaDataDimensions { + pixels: { + x: number; + y: number; + }; + emus: { + x: number; + y: number; + }; +} + +export interface IMediaData { referenceId: number; stream: fs.ReadStream; path: string; fileName: string; + dimensions: IMediaDataDimensions; } diff --git a/src/file/media/media.ts b/src/file/media/media.ts index 66cddca4ad..b683e5a3d8 100644 --- a/src/file/media/media.ts +++ b/src/file/media/media.ts @@ -1,15 +1,17 @@ import * as fs from "fs"; +import * as sizeOf from "image-size"; import * as path from "path"; -import { IData } from "./data"; + +import {IMediaData} from "./data"; export class Media { - private map: Map; + private map: Map; constructor() { - this.map = new Map(); + this.map = new Map(); } - public getMedia(key: string): IData { + public getMedia(key: string): IMediaData { const data = this.map.get(key); if (data === undefined) { @@ -19,17 +21,33 @@ export class Media { return data; } - public addMedia(key: string, filePath: string): void { - this.map.set(key, { - referenceId: this.map.values.length, + public addMedia(filePath: string): IMediaData { + const key = path.basename(filePath); + const dimensions = sizeOf(filePath); + + const imageData = { + referenceId: this.map.size + 3, stream: fs.createReadStream(filePath), path: filePath, - fileName: path.basename(filePath), - }); + fileName: key, + dimensions: { + pixels: { + x: dimensions.width, + y: dimensions.height, + }, + emus: { + x: dimensions.width * 9525, + y: dimensions.height * 9525, + }, + }, + }; + this.map.set(key, imageData); + + return imageData; } - public get array(): IData[] { - const array = new Array(); + public get array(): IMediaData[] { + const array = new Array(); this.map.forEach((data) => { array.push(data); diff --git a/src/file/paragraph/paragraph.ts b/src/file/paragraph/paragraph.ts index 766b7d7d14..0bf128acd3 100644 --- a/src/file/paragraph/paragraph.ts +++ b/src/file/paragraph/paragraph.ts @@ -1,5 +1,5 @@ // http://officeopenxml.com/WPparagraph.php -import { IData } from "file/media"; +import { IMediaData } from "file/media"; import { Num } from "file/numbering/num"; import { XmlComponent } from "file/xml-components"; import { PictureRun, Run, TextRun } from "./run"; @@ -38,7 +38,7 @@ export class Paragraph extends XmlComponent { return run; } - public createPictureRun(imageData: IData): PictureRun { + public createPictureRun(imageData: IMediaData): PictureRun { const run = new PictureRun(imageData); this.addRun(run); return run; diff --git a/src/file/paragraph/run/picture-run.ts b/src/file/paragraph/run/picture-run.ts index f5d7f4e763..c211adcaeb 100644 --- a/src/file/paragraph/run/picture-run.ts +++ b/src/file/paragraph/run/picture-run.ts @@ -1,10 +1,10 @@ import { Drawing } from "../../drawing"; -import { IData } from "../../media/data"; +import { IMediaData } from "../../media/data"; import { Run } from "../run"; export class PictureRun extends Run { - constructor(imageData: IData) { + constructor(imageData: IMediaData) { super(); if (imageData === undefined) { diff --git a/src/file/relationships/relationship/relationship-attributes.ts b/src/file/relationships/relationship/relationship-attributes.ts new file mode 100644 index 0000000000..1b23e26977 --- /dev/null +++ b/src/file/relationships/relationship/relationship-attributes.ts @@ -0,0 +1,15 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IRelationshipAttributesProperties { + id: string; + type: string; + target: string; +} + +export class RelationshipAttributes extends XmlAttributeComponent { + protected xmlKeys = { + id: "Id", + type: "Type", + target: "Target", + }; +} diff --git a/src/file/relationships/relationship/relationship.ts b/src/file/relationships/relationship/relationship.ts new file mode 100644 index 0000000000..a19536b09c --- /dev/null +++ b/src/file/relationships/relationship/relationship.ts @@ -0,0 +1,23 @@ +import { XmlComponent } from "file/xml-components"; +import { RelationshipAttributes } from "./relationship-attributes"; + +export type RelationshipType = + | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" + | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" + | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" + | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" + | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" + | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings" + | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering"; + +export class Relationship extends XmlComponent { + constructor(id: string, type: RelationshipType, target: string) { + super("Relationship"); + + this.root.push(new RelationshipAttributes({ + id, + type, + target, + })); + } +} diff --git a/src/file/relationships/relationships.ts b/src/file/relationships/relationships.ts index d9c0562a74..a38d85f828 100644 --- a/src/file/relationships/relationships.ts +++ b/src/file/relationships/relationships.ts @@ -1,5 +1,6 @@ import { XmlComponent } from "file/xml-components"; import { RelationshipsAttributes } from "./attributes"; +import { Relationship, RelationshipType } from "./relationship/relationship"; export class Relationships extends XmlComponent { @@ -9,6 +10,18 @@ export class Relationships extends XmlComponent { xmlns: "http://schemas.openxmlformats.org/package/2006/relationships", })); - // this.root.push(new Created()); + this.createRelationship(1, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", "styles.xml"); + this.createRelationship(2, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering", "numbering.xml"); + } + + public addRelationship(relationship: Relationship): void { + this.root.push(relationship); + } + + public createRelationship(id: number, type: RelationshipType, target: string): Relationship { + const relationship = new Relationship(`rId${id}`, type, target); + this.addRelationship(relationship); + + return relationship; } } diff --git a/template/[Content_Types].xml b/template/[Content_Types].xml index 419d57897f..996f6a2bea 100644 --- a/template/[Content_Types].xml +++ b/template/[Content_Types].xml @@ -1,5 +1,10 @@ + + + + + diff --git a/template/word/_rels/document.xml.rels b/template/word/_rels/document.xml.rels deleted file mode 100644 index 50d83cc54c..0000000000 --- a/template/word/_rels/document.xml.rels +++ /dev/null @@ -1,5 +0,0 @@ - - - - -