diff --git a/demo/demo18.js b/demo/demo18.js new file mode 100644 index 0000000000..9035d19e7a --- /dev/null +++ b/demo/demo18.js @@ -0,0 +1,15 @@ +// Insert image from a buffer +const docx = require('../build'); + +var doc = new docx.Document(); + + +const imageBase64Data = `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` + +// doc.createImageFromBuffer(Buffer.from(imageBase64Data, 'base64')); +doc.createImageFromBuffer(Buffer.from(imageBase64Data, 'base64'), 100, 100); + +var exporter = new docx.LocalPacker(doc); +exporter.pack('My Document'); + +console.log('Document created successfully at project root!'); diff --git a/demo/demo23.js b/demo/demo23.js new file mode 100644 index 0000000000..906f141e90 --- /dev/null +++ b/demo/demo23.js @@ -0,0 +1,28 @@ +// This demo adds an image to the Media cache, and then insert to the document afterwards +const docx = require("../build"); + +var doc = new docx.Document(); + +var paragraph = new docx.Paragraph("Hello World"); +doc.addParagraph(paragraph); + +const image = docx.Media.addImage(doc, "./demo/images/image1.jpeg"); +const image2 = docx.Media.addImage(doc, "./demo/images/dog.png"); +const image3 = docx.Media.addImage(doc, "./demo/images/cat.jpg"); +const image4 = docx.Media.addImage(doc, "./demo/images/parrots.bmp"); +const image5 = docx.Media.addImage(doc, "./demo/images/pizza.gif"); + +const imageBase64Data = `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` +const image6 = docx.Media.addImageFromBuffer(doc, Buffer.from(imageBase64Data, 'base64'), 100, 100); + +doc.insertImage(image); +doc.insertImage(image2); +doc.insertImage(image3); +doc.insertImage(image4); +doc.insertImage(image5); +doc.insertImage(image6); + +var exporter = new docx.LocalPacker(doc); +exporter.pack("My Document"); + +console.log("Document created successfully at project root!"); diff --git a/demo/demo24.js b/demo/demo24.js new file mode 100644 index 0000000000..a95189a6ed --- /dev/null +++ b/demo/demo24.js @@ -0,0 +1,15 @@ +// Add image to table cell +const docx = require('../build'); + +var doc = new docx.Document(); + +const table = doc.createTable(4, 4); +table.getCell(2, 2).addContent(new docx.Paragraph('Hello')); + +const image = docx.Media.addImage(doc, "./demo/images/image1.jpeg"); +table.getCell(1, 1).addContent(image); + +var exporter = new docx.LocalPacker(doc); +exporter.pack('My Document'); + +console.log('Document created successfully at project root!'); diff --git a/demo/demo5.js b/demo/demo5.js index da073f6ca8..89638ad49b 100644 --- a/demo/demo5.js +++ b/demo/demo5.js @@ -1,17 +1,17 @@ -const docx = require('../build'); +const docx = require("../build"); var doc = new docx.Document(); 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"); +doc.createImage("./demo/images/image1.jpeg"); +doc.createImage("./demo/images/dog.png"); +doc.createImage("./demo/images/cat.jpg"); +doc.createImage("./demo/images/parrots.bmp"); +doc.createImage("./demo/images/pizza.gif"); var exporter = new docx.LocalPacker(doc); -exporter.pack('My Document'); +exporter.pack("My Document"); -console.log('Document created successfully at project root!'); +console.log("Document created successfully at project root!"); diff --git a/src/file/document/document.ts b/src/file/document/document.ts index d8db84adf3..69fb55a25a 100644 --- a/src/file/document/document.ts +++ b/src/file/document/document.ts @@ -1,7 +1,6 @@ // http://officeopenxml.com/WPdocument.php -import { IMediaData } from "file/media"; import { XmlComponent } from "file/xml-components"; -import { Paragraph, PictureRun } from "../paragraph"; +import { Paragraph } from "../paragraph"; import { Table } from "../table"; import { Body } from "./body"; import { SectionPropertiesOptions } from "./body/section-properties/section-properties"; @@ -37,8 +36,9 @@ export class Document extends XmlComponent { this.root.push(this.body); } - public addParagraph(paragraph: Paragraph): void { + public addParagraph(paragraph: Paragraph): Document { this.body.push(paragraph); + return this; } public createParagraph(text?: string): Paragraph { @@ -57,20 +57,6 @@ export class Document extends XmlComponent { return table; } - public addDrawing(pictureParagraph: Paragraph): void { - this.body.push(pictureParagraph); - } - - public createDrawing(imageData: IMediaData): PictureRun { - const paragraph = new Paragraph(); - const run = new PictureRun(imageData); - - paragraph.addRun(run); - this.addDrawing(paragraph); - - return run; - } - get Body(): Body { return this.body; } diff --git a/src/file/file.ts b/src/file/file.ts index 866ddd1480..f8d13ed2bf 100644 --- a/src/file/file.ts +++ b/src/file/file.ts @@ -1,4 +1,3 @@ -import { IMediaData } from "file/media"; import { AppProperties } from "./app-properties/app-properties"; import { ContentTypes } from "./content-types/content-types"; import { CoreProperties, IPropertiesOptions } from "./core-properties"; @@ -10,7 +9,7 @@ import { FootNotes } from "./footnotes"; import { HeaderWrapper } from "./header-wrapper"; import { Media } from "./media"; import { Numbering } from "./numbering"; -import { Bookmark, Hyperlink, Paragraph, PictureRun } from "./paragraph"; +import { Bookmark, Hyperlink, Image, Paragraph } from "./paragraph"; import { Relationships } from "./relationships"; import { Styles } from "./styles"; import { ExternalStylesFactory } from "./styles/external-styles-factory"; @@ -32,7 +31,7 @@ export class File { private readonly contentTypes: ContentTypes; private readonly appProperties: AppProperties; - private nextId: number = 1; + private currentRelationshipId: number = 1; constructor(options?: IPropertiesOptions, sectionPropertiesOptions?: SectionPropertiesOptions) { if (!options) { @@ -55,19 +54,19 @@ export class File { this.numbering = new Numbering(); this.docRelationships = new Relationships(); this.docRelationships.createRelationship( - this.nextId++, + this.currentRelationshipId++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", "styles.xml", ); this.docRelationships.createRelationship( - this.nextId++, + this.currentRelationshipId++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering", "numbering.xml", ); this.contentTypes = new ContentTypes(); this.docRelationships.createRelationship( - this.nextId++, + this.currentRelationshipId++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes", "footnotes.xml", ); @@ -125,24 +124,23 @@ export class File { return this.document.createTable(rows, cols); } - public createImage(image: string): PictureRun { - const mediaData = this.media.addMedia(image, this.nextId++); - this.docRelationships.createRelationship( - mediaData.referenceId, - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - `media/${mediaData.fileName}`, - ); - return this.document.createDrawing(mediaData); + public createImage(filePath: string): Image { + const image = Media.addImage(this, filePath); + this.document.addParagraph(image); + + return image; } - public createImageData(imageName: string, data: Buffer, width?: number, height?: number): IMediaData { - const mediaData = this.media.addMediaWithData(imageName, data, this.nextId++, width, height); - this.docRelationships.createRelationship( - mediaData.referenceId, - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - `media/${mediaData.fileName}`, - ); - return mediaData; + public insertImage(image: Image): File { + this.document.addParagraph(image); + return this; + } + + public createImageFromBuffer(buffer: Buffer, width?: number, height?: number): Image { + const image = Media.addImageFromBuffer(this, buffer, width, height); + this.document.addParagraph(image); + + return image; } public createHyperlink(link: string, text?: string): Hyperlink { @@ -179,11 +177,8 @@ export class File { this.footNotes.createFootNote(paragraph); } - /** - * Creates new header. - */ public createHeader(): HeaderWrapper { - const header = new HeaderWrapper(this.media, this.nextId++); + const header = new HeaderWrapper(this.media, this.currentRelationshipId++); this.headerWrapper.push(header); this.docRelationships.createRelationship( header.Header.referenceId, @@ -194,11 +189,8 @@ export class File { return header; } - /** - * Creates new footer. - */ public createFooter(): FooterWrapper { - const footer = new FooterWrapper(this.media, this.nextId++); + const footer = new FooterWrapper(this.media, this.currentRelationshipId++); this.footerWrapper.push(footer); this.docRelationships.createRelationship( footer.Footer.referenceId, diff --git a/src/file/footer-wrapper.ts b/src/file/footer-wrapper.ts index 63c8a58978..8d90a5a941 100644 --- a/src/file/footer-wrapper.ts +++ b/src/file/footer-wrapper.ts @@ -1,7 +1,7 @@ import { XmlComponent } from "file/xml-components"; import { Footer } from "./footer/footer"; -import { IMediaData, Media } from "./media"; -import { Paragraph } from "./paragraph"; +import { Media } from "./media"; +import { Image, Paragraph } from "./paragraph"; import { Relationships } from "./relationships"; import { Table } from "./table"; @@ -32,10 +32,6 @@ export class FooterWrapper { return this.footer.createTable(rows, cols); } - public addDrawing(imageData: IMediaData): void { - this.footer.addDrawing(imageData); - } - public addChildElement(childElement: XmlComponent | string): void { this.footer.addChildElement(childElement); } @@ -47,7 +43,12 @@ export class FooterWrapper { "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", `media/${mediaData.fileName}`, ); - this.addDrawing(mediaData); + this.insertImage(new Image(mediaData)); + } + + public insertImage(image: Image): FooterWrapper { + this.footer.addParagraph(image); + return this; } public get Footer(): Footer { diff --git a/src/file/footer/footer.ts b/src/file/footer/footer.ts index cbdd4a544d..4237e350a4 100644 --- a/src/file/footer/footer.ts +++ b/src/file/footer/footer.ts @@ -1,7 +1,6 @@ // http://officeopenxml.com/WPfooters.php -import { IMediaData } from "file/media"; import { XmlComponent } from "file/xml-components"; -import { Paragraph, PictureRun } from "../paragraph"; +import { Paragraph } from "../paragraph"; import { Table } from "../table"; import { FooterAttributes } from "./footer-attributes"; @@ -36,8 +35,10 @@ export class Footer extends XmlComponent { return this.refId; } - public addParagraph(paragraph: Paragraph): void { + public addParagraph(paragraph: Paragraph): Footer { this.root.push(paragraph); + + return this; } public createParagraph(text?: string): Paragraph { @@ -55,12 +56,4 @@ export class Footer 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.root.push(paragraph); - } } diff --git a/src/file/header-wrapper.ts b/src/file/header-wrapper.ts index c23f4db448..b8183b92ba 100644 --- a/src/file/header-wrapper.ts +++ b/src/file/header-wrapper.ts @@ -1,7 +1,7 @@ import { XmlComponent } from "file/xml-components"; import { Header } from "./header/header"; -import { IMediaData, Media } from "./media"; -import { Paragraph } from "./paragraph"; +import { Media } from "./media"; +import { Image, Paragraph } from "./paragraph"; import { Relationships } from "./relationships"; import { Table } from "./table"; @@ -32,10 +32,6 @@ export class HeaderWrapper { return this.header.createTable(rows, cols); } - public addDrawing(imageData: IMediaData): void { - this.header.addDrawing(imageData); - } - public addChildElement(childElement: XmlComponent | string): void { this.header.addChildElement(childElement); } @@ -47,7 +43,12 @@ export class HeaderWrapper { "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", `media/${mediaData.fileName}`, ); - this.addDrawing(mediaData); + this.insertImage(new Image(mediaData)); + } + + public insertImage(image: Image): HeaderWrapper { + this.header.addParagraph(image); + return this; } public get Header(): Header { diff --git a/src/file/header/header.ts b/src/file/header/header.ts index b0ffaa8a63..403e922ccf 100644 --- a/src/file/header/header.ts +++ b/src/file/header/header.ts @@ -1,7 +1,6 @@ // http://officeopenxml.com/WPheaders.php -import { IMediaData } from "file/media"; import { XmlComponent } from "file/xml-components"; -import { Paragraph, PictureRun } from "../paragraph"; +import { Paragraph } from "../paragraph"; import { Table } from "../table"; import { HeaderAttributes } from "./header-attributes"; @@ -55,12 +54,4 @@ export class Header 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.root.push(paragraph); - } } diff --git a/src/file/media/media.ts b/src/file/media/media.ts index 54450fb714..ed081cc5e1 100644 --- a/src/file/media/media.ts +++ b/src/file/media/media.ts @@ -2,9 +2,58 @@ import * as fs from "fs"; import * as sizeOf from "image-size"; import * as path from "path"; +import { File } from "../file"; +import { Image } from "../paragraph"; import { IMediaData } from "./data"; +interface IHackedFile { + currentRelationshipId: number; +} + export class Media { + public static addImage(file: File, filePath: string): Image { + // Workaround to expose id without exposing to API + const exposedFile = (file as {}) as IHackedFile; + const mediaData = file.Media.addMedia(filePath, exposedFile.currentRelationshipId++); + file.DocumentRelationships.createRelationship( + mediaData.referenceId, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", + `media/${mediaData.fileName}`, + ); + return new Image(mediaData); + } + + public static addImageFromBuffer(file: File, buffer: Buffer, width?: number, height?: number): Image { + // Workaround to expose id without exposing to API + const exposedFile = (file as {}) as IHackedFile; + const mediaData = file.Media.addMediaFromBuffer( + `${Media.generateId()}.png`, + buffer, + exposedFile.currentRelationshipId++, + width, + height, + ); + file.DocumentRelationships.createRelationship( + mediaData.referenceId, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", + `media/${mediaData.fileName}`, + ); + + return new Image(mediaData); + } + + private static generateId(): string { + // https://gist.github.com/6174/6062387 + return ( + Math.random() + .toString(36) + .substring(2, 15) + + Math.random() + .toString(36) + .substring(2, 15) + ); + } + private readonly map: Map; constructor() { @@ -27,7 +76,7 @@ export class Media { return this.createMedia(key, referenceId, dimensions, fs.createReadStream(filePath), filePath); } - public addMediaWithData(fileName: string, data: Buffer, referenceId: number, width?: number, height?: number): IMediaData { + public addMediaFromBuffer(fileName: string, buffer: Buffer, referenceId: number, width?: number, height?: number): IMediaData { const key = fileName; let dimensions; if (width && height) { @@ -36,10 +85,10 @@ export class Media { height: height, }; } else { - dimensions = sizeOf(data); + dimensions = sizeOf(buffer); } - return this.createMedia(key, referenceId, dimensions, data); + return this.createMedia(key, referenceId, dimensions, buffer); } private createMedia( @@ -65,6 +114,7 @@ export class Media { }, }, }; + this.map.set(key, imageData); return imageData; diff --git a/src/file/paragraph/image.spec.ts b/src/file/paragraph/image.spec.ts new file mode 100644 index 0000000000..658a99ff81 --- /dev/null +++ b/src/file/paragraph/image.spec.ts @@ -0,0 +1,251 @@ +// tslint:disable:object-literal-key-quotes +import { assert, expect } from "chai"; + +import { Formatter } from "../../export/formatter"; +import { Image } from "./image"; + +describe("Image", () => { + let image: Image; + + beforeEach(() => { + image = new Image({ + referenceId: 0, + stream: new Buffer(""), + path: "", + fileName: "", + dimensions: { + pixels: { + x: 10, + y: 10, + }, + emus: { + x: 10, + y: 10, + }, + }, + }); + }); + + describe("#constructor()", () => { + it("should create valid JSON", () => { + const stringifiedJson = JSON.stringify(image); + + try { + JSON.parse(stringifiedJson); + } catch (e) { + assert.isTrue(false); + } + assert.isTrue(true); + }); + }); + + describe("#scale()", () => { + it("should set the scale of the object properly", () => { + image.scale(2); + const tree = new Formatter().format(image); + expect(tree).to.deep.equal({ + "w:p": [ + { + "w:pPr": [], + }, + { + "w:r": [ + { + "w:rPr": [], + }, + { + "w:drawing": [ + { + "wp:inline": [ + { + _attr: { + distB: 0, + distL: 0, + distR: 0, + distT: 0, + }, + }, + { + "wp:extent": [ + { + _attr: { + cx: 20, + cy: 20, + }, + }, + ], + }, + { + "wp:effectExtent": [ + { + _attr: { + b: 0, + l: 0, + r: 0, + t: 0, + }, + }, + ], + }, + { + "wp:docPr": [ + { + _attr: { + descr: "", + id: 0, + name: "", + }, + }, + ], + }, + { + "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: { + desc: "", + id: 0, + name: "", + }, + }, + ], + }, + { + "pic:cNvPicPr": [ + { + "a:picLocks": [ + { + _attr: { + noChangeArrowheads: 1, + noChangeAspect: 1, + }, + }, + ], + }, + ], + }, + ], + }, + { + "pic:blipFill": [ + { + "a:blip": [ + { + _attr: { + cstate: "none", + "r:embed": "rId0", + }, + }, + ], + }, + { + "a:srcRect": [], + }, + { + "a:stretch": [ + { + "a:fillRect": [], + }, + ], + }, + ], + }, + { + "pic:spPr": [ + { + _attr: { + bwMode: "auto", + }, + }, + { + "a:xfrm": [ + { + "a:ext": [ + { + _attr: { + cx: 10, + cy: 10, + }, + }, + ], + }, + { + "a:off": [ + { + _attr: { + x: 0, + y: 0, + }, + }, + ], + }, + ], + }, + { + "a:prstGeom": [ + { + _attr: { + prst: "rect", + }, + }, + { + "a:avLst": [], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }); + }); + }); +}); diff --git a/src/file/paragraph/image.ts b/src/file/paragraph/image.ts new file mode 100644 index 0000000000..214378853c --- /dev/null +++ b/src/file/paragraph/image.ts @@ -0,0 +1,18 @@ +import { IDrawingOptions } from "../drawing"; +import { IMediaData } from "../media"; +import { Paragraph } from "./paragraph"; +import { PictureRun } from "./run"; + +export class Image extends Paragraph { + private readonly pictureRun: PictureRun; + + constructor(imageData: IMediaData, drawingOptions?: IDrawingOptions) { + super(); + this.pictureRun = new PictureRun(imageData, drawingOptions); + this.root.push(this.pictureRun); + } + + public scale(factorX: number, factorY?: number): void { + this.pictureRun.scale(factorX, factorY); + } +} diff --git a/src/file/paragraph/index.ts b/src/file/paragraph/index.ts index 68a1b0b800..222cb1bf4f 100644 --- a/src/file/paragraph/index.ts +++ b/src/file/paragraph/index.ts @@ -3,3 +3,4 @@ export * from "./paragraph"; export * from "./properties"; export * from "./run"; export * from "./links"; +export * from "./image";