diff --git a/demo/11-declaritive-styles-2.ts b/demo/11-declaritive-styles-2.ts index 9c0ffa94c0..3dac550288 100644 --- a/demo/11-declaritive-styles-2.ts +++ b/demo/11-declaritive-styles-2.ts @@ -7,7 +7,7 @@ import { Document, Footer, HeadingLevel, - Media, + ImageRun, Packer, Paragraph, Table, @@ -126,15 +126,6 @@ const doc = new Document({ }, }); -const image = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/pizza.gif"), - transformation: { - width: 100, - height: 100, - }, -}); - const table = new Table({ rows: [ new TableRow({ @@ -168,23 +159,6 @@ const table = new Table({ ], }); -const image1 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/pizza.gif"), - transformation: { - width: 100, - height: 100, - }, -}); -const image2 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/pizza.gif"), - transformation: { - width: 100, - height: 100, - }, -}); - doc.addSection({ properties: { top: 700, @@ -204,7 +178,15 @@ doc.addSection({ }), }, children: [ - new Paragraph(image), + new Paragraph( + new ImageRun({ + data: fs.readFileSync("./demo/images/pizza.gif"), + transformation: { + width: 100, + height: 100, + }, + }), + ), new Paragraph({ text: "HEADING", heading: HeadingLevel.HEADING_1, @@ -243,12 +225,28 @@ doc.addSection({ style: "normalPara", }), table, - new Paragraph(image1), + new Paragraph( + new ImageRun({ + data: fs.readFileSync("./demo/images/pizza.gif"), + transformation: { + width: 100, + height: 100, + }, + }), + ), new Paragraph({ text: "Test", style: "normalPara2", }), - new Paragraph(image2), + new Paragraph( + new ImageRun({ + data: fs.readFileSync("./demo/images/pizza.gif"), + transformation: { + width: 100, + height: 100, + }, + }), + ), new Paragraph({ text: "Test 2", style: "normalPara2", diff --git a/demo/12-scaling-images.ts b/demo/12-scaling-images.ts index f6876d29b8..4d70aa2fc1 100644 --- a/demo/12-scaling-images.ts +++ b/demo/12-scaling-images.ts @@ -1,45 +1,58 @@ // Scaling images // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Media, Packer, Paragraph } from "../build"; +import { Document, ImageRun, Packer, Paragraph } from "../build"; const doc = new Document(); -const image = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/pizza.gif"), - transformation: { - width: 50, - height: 50, - }, -}); -const image2 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/pizza.gif"), - transformation: { - width: 100, - height: 100, - }, -}); -const image3 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/pizza.gif"), - transformation: { - width: 250, - height: 250, - }, -}); -const image4 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/pizza.gif"), - transformation: { - width: 400, - height: 400, - }, -}); - doc.addSection({ - children: [new Paragraph("Hello World"), new Paragraph(image), new Paragraph(image2), new Paragraph(image3), new Paragraph(image4)], + children: [ + new Paragraph("Hello World"), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/pizza.gif"), + transformation: { + width: 50, + height: 50, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/pizza.gif"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/pizza.gif"), + transformation: { + width: 250, + height: 250, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/pizza.gif"), + transformation: { + width: 400, + height: 400, + }, + }), + ], + }), + ], }); Packer.toBuffer(doc).then((buffer) => { diff --git a/demo/18-image-from-buffer.ts b/demo/18-image-from-buffer.ts index 72ba1c0257..c4a7584c5b 100644 --- a/demo/18-image-from-buffer.ts +++ b/demo/18-image-from-buffer.ts @@ -1,25 +1,24 @@ // Insert image from a buffer // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Media, Packer, Paragraph } from "../build"; +import { Document, ImageRun, Packer, Paragraph } from "../build"; const doc = new Document(); const imageBase64Data = `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`; -const image = Media.addImage({ - document: doc, - data: Buffer.from(imageBase64Data, "base64"), - transformation: { - width: 100, - height: 100, - }, -}); - doc.addSection({ children: [ new Paragraph({ - children: [image], + children: [ + new ImageRun({ + data: Buffer.from(imageBase64Data, "base64"), + transformation: { + width: 100, + height: 100, + }, + }), + ], }), ], }); diff --git a/demo/23-base64-images.ts b/demo/23-base64-images.ts index 91f48c6768..a4419bcd36 100644 --- a/demo/23-base64-images.ts +++ b/demo/23-base64-images.ts @@ -1,71 +1,81 @@ // This demo adds an image to the Media cache, and then insert to the document afterwards // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Media, Packer, Paragraph, TextRun } from "../build"; +import { Document, ImageRun, Packer, Paragraph, TextRun } from "../build"; const doc = new Document(); -const image = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/image1.jpeg"), - transformation: { - width: 100, - height: 100, - }, -}); -const image2 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/dog.png"), - transformation: { - width: 100, - height: 100, - }, -}); -const image3 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/cat.jpg"), - transformation: { - width: 100, - height: 100, - }, -}); -const image4 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/parrots.bmp"), - transformation: { - width: 100, - height: 100, - }, -}); -const image5 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/pizza.gif"), - transformation: { - width: 100, - height: 100, - }, -}); - const imageBase64Data = `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`; -const image6 = Media.addImage({ - document: doc, - data: Buffer.from(imageBase64Data, "base64"), - transformation: { - width: 100, - height: 100, - }, -}); doc.addSection({ children: [ new Paragraph({ - children: [new TextRun("Hello World"), image5], + children: [ + new TextRun("Hello World"), + new ImageRun({ + data: fs.readFileSync("./demo/images/parrots.bmp"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/image1.jpeg"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/dog.png"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/cat.jpg"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/parrots.bmp"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: Buffer.from(imageBase64Data, "base64"), + transformation: { + width: 100, + height: 100, + }, + }), + ], }), - new Paragraph(image), - new Paragraph(image2), - new Paragraph(image3), - new Paragraph(image4), - new Paragraph(image6), ], }); diff --git a/demo/24-images-to-table-cell.ts b/demo/24-images-to-table-cell.ts index 1d024a4c2d..34d70ae02e 100644 --- a/demo/24-images-to-table-cell.ts +++ b/demo/24-images-to-table-cell.ts @@ -1,19 +1,10 @@ // Add image to table cell // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Media, Packer, Paragraph, Table, TableCell, TableRow } from "../build"; +import { Document, ImageRun, Packer, Paragraph, Table, TableCell, TableRow } from "../build"; const doc = new Document(); -const image = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/image1.jpeg"), - transformation: { - width: 100, - height: 100, - }, -}); - const table = new Table({ rows: [ new TableRow({ @@ -38,7 +29,19 @@ const table = new Table({ children: [], }), new TableCell({ - children: [new Paragraph(image)], + children: [ + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/image1.jpeg"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), + ], }), new TableCell({ children: [], diff --git a/demo/35-hyperlinks.ts b/demo/35-hyperlinks.ts index 44f183d687..bb9b82a433 100644 --- a/demo/35-hyperlinks.ts +++ b/demo/35-hyperlinks.ts @@ -1,7 +1,7 @@ // Example on how to add hyperlinks to websites // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, ExternalHyperlink, Footer, FootnoteReferenceRun, Media, Packer, Paragraph, TextRun } from "../build"; +import { Document, ExternalHyperlink, Footer, FootnoteReferenceRun, ImageRun, Packer, Paragraph, TextRun } from "../build"; const doc = new Document({ footnotes: { @@ -24,15 +24,6 @@ const doc = new Document({ }, }); -const image1 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/image1.jpeg"), - transformation: { - width: 100, - height: 100, - }, -}); - doc.addSection({ footers: { default: new Footer({ @@ -86,7 +77,13 @@ doc.addSection({ new Paragraph({ children: [ new ExternalHyperlink({ - child: image1, + child: new ImageRun({ + data: fs.readFileSync("./demo/images/image1.jpeg"), + transformation: { + width: 100, + height: 100, + }, + }), link: "http://www.google.com", }), new ExternalHyperlink({ diff --git a/demo/36-image-to-table-cell.ts b/demo/36-image-to-table-cell.ts index 3a31d4d264..99ad84ddb3 100644 --- a/demo/36-image-to-table-cell.ts +++ b/demo/36-image-to-table-cell.ts @@ -1,17 +1,9 @@ // Add image to table cell in a header and body // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Header, Media, Packer, Paragraph, Table, TableCell, TableRow } from "../build"; +import { Document, Header, ImageRun, Packer, Paragraph, Table, TableCell, TableRow } from "../build"; const doc = new Document(); -const image = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/image1.jpeg"), - transformation: { - width: 100, - height: 100, - }, -}); const table = new Table({ rows: [ @@ -37,7 +29,19 @@ const table = new Table({ children: [], }), new TableCell({ - children: [new Paragraph(image)], + children: [ + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/image1.jpeg"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), + ], }), ], }), diff --git a/demo/37-images-to-header-and-footer.ts b/demo/37-images-to-header-and-footer.ts index f75385f7b5..8eaaf4db21 100644 --- a/demo/37-images-to-header-and-footer.ts +++ b/demo/37-images-to-header-and-footer.ts @@ -1,38 +1,48 @@ // Add images to header and footer // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Header, Media, Packer, Paragraph } from "../build"; +import { Document, Header, ImageRun, Packer, Paragraph } from "../build"; const doc = new Document(); -const image = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/image1.jpeg"), - transformation: { - width: 100, - height: 100, - }, -}); -const image1 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/pizza.gif"), - transformation: { - width: 100, - height: 100, - }, -}); -const image2 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/image1.jpeg"), - transformation: { - width: 100, - height: 100, - }, -}); doc.addSection({ headers: { default: new Header({ - children: [new Paragraph(image), new Paragraph(image1), new Paragraph(image2)], + children: [ + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/image1.jpeg"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/pizza.gif"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/image1.jpeg"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), + ], }), }, children: [new Paragraph("Hello World")], diff --git a/demo/38-text-wrapping.ts b/demo/38-text-wrapping.ts index 470365454e..220cf6162b 100644 --- a/demo/38-text-wrapping.ts +++ b/demo/38-text-wrapping.ts @@ -2,35 +2,10 @@ // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; // import { Document, Packer, Paragraph } from "../build"; -import { Document, Media, Packer, Paragraph, TextWrappingSide, TextWrappingType } from "../build"; +import { Document, ImageRun, Packer, Paragraph, TextWrappingSide, TextWrappingType } from "../build"; const doc = new Document(); -const image = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/pizza.gif"), - transformation: { - width: 200, - height: 200, - }, - floating: { - horizontalPosition: { - offset: 2014400, - }, - verticalPosition: { - offset: 2014400, - }, - wrap: { - type: TextWrappingType.SQUARE, - side: TextWrappingSide.BOTH_SIDES, - }, - margins: { - top: 201440, - bottom: 201440, - }, - }, -}); - doc.addSection({ children: [ new Paragraph( @@ -42,7 +17,31 @@ doc.addSection({ new Paragraph( "Ut eget diam cursus quam accumsan interdum at id ante. Ut mollis mollis arcu, eu scelerisque dui tempus in. Quisque aliquam, augue quis ornare aliquam, ex purus ultrices mauris, ut porta dolor dolor nec justo. Nunc a tempus odio, eu viverra arcu. Suspendisse vitae nibh nec mi pharetra tempus. Mauris ut ullamcorper sapien, et sagittis sapien. Vestibulum in urna metus. In scelerisque, massa id bibendum tempus, quam orci rutrum turpis, a feugiat nisi ligula id metus. Praesent id dictum purus. Proin interdum ipsum nulla.", ), - new Paragraph(image), + new Paragraph( + new ImageRun({ + data: fs.readFileSync("./demo/images/pizza.gif"), + transformation: { + width: 200, + height: 200, + }, + floating: { + horizontalPosition: { + offset: 2014400, + }, + verticalPosition: { + offset: 2014400, + }, + wrap: { + type: TextWrappingType.SQUARE, + side: TextWrappingSide.BOTH_SIDES, + }, + margins: { + top: 201440, + bottom: 201440, + }, + }, + }), + ), ], }); diff --git a/demo/5-images.ts b/demo/5-images.ts index 8509a23b80..137565d167 100644 --- a/demo/5-images.ts +++ b/demo/5-images.ts @@ -1,12 +1,11 @@ // Example of how to add images to the document - You can use Buffers, UInt8Arrays or Base64 strings // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -// import { Document, Packer, Paragraph } from "../build"; import { Document, HorizontalPositionAlign, HorizontalPositionRelativeFrom, - Media, + ImageRun, Packer, Paragraph, VerticalPositionAlign, @@ -15,106 +14,118 @@ import { const doc = new Document(); -const image1 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/image1.jpeg"), - transformation: { - width: 100, - height: 100, - }, -}); -const image2 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/dog.png").toString("base64"), - transformation: { - width: 100, - height: 100, - }, -}); -const image3 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/cat.jpg"), - transformation: { - width: 100, - height: 100, - flip: { - vertical: true, - }, - }, -}); -const image4 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/parrots.bmp"), - transformation: { - width: 150, - height: 150, - flip: { - horizontal: true, - }, - rotation: 225, - }, -}); -const image5 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/pizza.gif"), - transformation: { - width: 200, - height: 200, - flip: { - horizontal: true, - vertical: true, - }, - }, -}); -const image6 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/pizza.gif"), - transformation: { - width: 200, - height: 200, - rotation: 45, - }, - floating: { - zIndex: 10, - horizontalPosition: { - offset: 1014400, - }, - verticalPosition: { - offset: 1014400, - }, - }, -}); - -const image7 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/cat.jpg"), - transformation: { - width: 200, - height: 200, - }, - floating: { - zIndex: 5, - horizontalPosition: { - relative: HorizontalPositionRelativeFrom.PAGE, - align: HorizontalPositionAlign.RIGHT, - }, - verticalPosition: { - relative: VerticalPositionRelativeFrom.PAGE, - align: VerticalPositionAlign.BOTTOM, - }, - }, -}); - doc.addSection({ children: [ new Paragraph("Hello World"), - new Paragraph(image1), - new Paragraph(image2), - new Paragraph(image3), - new Paragraph(image4), - new Paragraph(image5), - new Paragraph(image6), - new Paragraph(image7), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/image1.jpeg"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/dog.png").toString("base64"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/cat.jpg"), + transformation: { + width: 100, + height: 100, + flip: { + vertical: true, + }, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/parrots.bmp"), + transformation: { + width: 150, + height: 150, + flip: { + horizontal: true, + }, + rotation: 225, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/pizza.gif"), + transformation: { + width: 200, + height: 200, + flip: { + horizontal: true, + vertical: true, + }, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/pizza.gif"), + transformation: { + width: 200, + height: 200, + rotation: 45, + }, + floating: { + zIndex: 10, + horizontalPosition: { + offset: 1014400, + }, + verticalPosition: { + offset: 1014400, + }, + }, + }), + ], + }), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/cat.jpg"), + transformation: { + width: 200, + height: 200, + }, + floating: { + zIndex: 5, + horizontalPosition: { + relative: HorizontalPositionRelativeFrom.PAGE, + align: HorizontalPositionAlign.RIGHT, + }, + verticalPosition: { + relative: VerticalPositionRelativeFrom.PAGE, + align: VerticalPositionAlign.BOTTOM, + }, + }, + }), + ], + }), ], }); diff --git a/demo/50-readme-demo.ts b/demo/50-readme-demo.ts index 9b69335fbe..c1bc1e3eda 100644 --- a/demo/50-readme-demo.ts +++ b/demo/50-readme-demo.ts @@ -1,33 +1,28 @@ -// Simple example to add text to a document +// The demo on the README.md // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, HeadingLevel, Media, Packer, Paragraph, Table, TableCell, TableRow, VerticalAlign } from "../build"; +import { Document, HeadingLevel, ImageRun, Packer, Paragraph, Table, TableCell, TableRow, VerticalAlign } from "../build"; const doc = new Document(); -const image1 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/image1.jpeg"), - transformation: { - width: 100, - height: 100, - }, -}); -const image2 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/pizza.gif"), - transformation: { - width: 100, - height: 100, - }, -}); - const table = new Table({ rows: [ new TableRow({ children: [ new TableCell({ - children: [new Paragraph(image1)], + children: [ + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/image1.jpeg"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), + ], verticalAlign: VerticalAlign.CENTER, }), new TableCell({ @@ -52,7 +47,19 @@ const table = new Table({ ], }), new TableCell({ - children: [new Paragraph(image1)], + children: [ + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/image1.jpeg"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), + ], }), ], }), @@ -66,7 +73,17 @@ doc.addSection({ heading: HeadingLevel.HEADING_1, }), table, - new Paragraph(image2), + new Paragraph({ + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/pizza.gif"), + transformation: { + width: 100, + height: 100, + }, + }), + ], + }), ], }); diff --git a/demo/9-images-in-header-and-footer.ts b/demo/9-images-in-header-and-footer.ts index 722d8f041d..4256956e19 100644 --- a/demo/9-images-in-header-and-footer.ts +++ b/demo/9-images-in-header-and-footer.ts @@ -1,33 +1,24 @@ // Add images to header and footer // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Footer, Header, Media, Packer, Paragraph } from "../build"; +import { Document, Footer, Header, ImageRun, Packer, Paragraph } from "../build"; const doc = new Document(); -const image1 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/pizza.gif"), - transformation: { - width: 100, - height: 100, - }, -}); -const image2 = Media.addImage({ - document: doc, - data: fs.readFileSync("./demo/images/pizza.gif"), - transformation: { - width: 100, - height: 100, - }, -}); - doc.addSection({ headers: { default: new Header({ children: [ new Paragraph({ - children: [image1], + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/pizza.gif"), + transformation: { + width: 100, + height: 100, + }, + }), + ], }), ], }), @@ -36,7 +27,15 @@ doc.addSection({ default: new Footer({ children: [ new Paragraph({ - children: [image2], + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/pizza.gif"), + transformation: { + width: 100, + height: 100, + }, + }), + ], }), ], }), diff --git a/docs/usage/images.md b/docs/usage/images.md index 19b31d49a2..2b098d073b 100644 --- a/docs/usage/images.md +++ b/docs/usage/images.md @@ -5,8 +5,7 @@ To create a `floating` image on top of text: ```ts -const image = Media.addImage({ - document: doc, +const image = new ImageRun({ data: fs.readFileSync("./demo/images/pizza.gif"), transformation: { width: 200, @@ -26,8 +25,7 @@ const image = Media.addImage({ By default with no arguments, its an `inline` image: ```ts -const image = Media.addImage({ - document: doc, +const image = new ImageRun({ data: fs.readFileSync("./demo/images/pizza.gif"), transformation: { width: 100, @@ -58,30 +56,21 @@ doc.addSection({ ## Intro -Adding images can be done in two ways: +Adding images can be easily done by creating an instance of `ImageRun`. This can be added in a `Paragraph` or `Hyperlink`: -1. Call the `createImage` method to add the image directly into the `document`: +```ts +const image = new ImageRun({ + data: [IMAGE_BUFFER], + transformation: { + width: [IMAGE_SIZE], + height: [IMAGE_SIZE], + }, +}); - ```ts - Media.addImage({}); - ``` - -2. Create an `image` first, then add it into the `document`: - - ```ts - const image = Media.addImage({ - document: doc, - data: [IMAGE_BUFFER], - transformation: { - width: [IMAGE_SIZE], - height: [IMAGE_SIZE], - }, - }); - - doc.addSection({ - children: [new Paragraph(image)], - }); - ``` +doc.addSection({ + children: [new Paragraph(image)], +}); +``` `docx` supports `jpeg`, `jpg`, `bmp`, `gif` and `png` @@ -96,7 +85,7 @@ Three types of image positioning is supported: - Floating - Inline -By default, picture are exported as `Inline` elements. +By default, images are exported as `Inline` elements. ### Usage @@ -107,8 +96,7 @@ Pass `options` into the `[POSITION_OPTIONS]` metioned in the [Intro above](#Intr To change the position the image to be on top of the text, simply add the `floating` property to the last argument. By default, the offsets are relative to the top left corner of the `page`. Offset units are in [emus](https://startbigthinksmall.wordpress.com/2010/01/04/points-inches-and-emus-measuring-units-in-office-open-xml/): ```ts -const image = Media.addImage({ - document: doc, +const image = new ImageRun({ data: buffer, transformation: { width: 903, @@ -126,8 +114,7 @@ const image = Media.addImage({ ``` ```ts -const image = Media.addImage({ - document: doc, +const image = new ImageRun({ data: buffer, transformation: { width: 903, @@ -192,8 +179,7 @@ wrap: { For example: ```ts -Media.addImage({ - document: doc, +const image = new ImageRun({ data: fs.readFileSync("./demo/images/pizza.gif"), transformation: { width: 200, @@ -241,8 +227,7 @@ margins: { For example: ```ts -Media.addImage({ - document: doc, +const image = new ImageRun({ data: fs.readFileSync("./demo/images/pizza.gif"), transformation: { width: 200, diff --git a/docs/usage/paragraph.md b/docs/usage/paragraph.md index 2e3ebc5e3d..e0b4e56599 100644 --- a/docs/usage/paragraph.md +++ b/docs/usage/paragraph.md @@ -72,7 +72,7 @@ This is the list of options for a paragraph. A detailed explanation is below: | indent | `IIndentAttributesProperties` | Optional | | | keepLines | `boolean` | Optional | | | keepNext | `boolean` | Optional | | -| children | `(TextRun or PictureRun or Hyperlink)[]` | Optional | | +| children | `(TextRun or ImageRun or Hyperlink)[]` | Optional | | | style | `string` | Optional | | | [tabStop](usage/tab-stops) | `{ left?: ITabStopOptions; right?: ITabStopOptions; maxRight?: { leader: LeaderType; }; center?: ITabStopOptions }` | Optional | | | [bullet](usage/bullet-points) | `{ level: number }` | Optional | | diff --git a/src/file/drawing/drawing.spec.ts b/src/file/drawing/drawing.spec.ts index d23377e674..b97b6ea11e 100644 --- a/src/file/drawing/drawing.spec.ts +++ b/src/file/drawing/drawing.spec.ts @@ -7,12 +7,10 @@ import { Drawing, IDrawingOptions } from "./drawing"; const imageBase64Data = `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`; function createDrawing(drawingOptions?: IDrawingOptions): Drawing { - const path = "./demo/images/image1.jpeg"; return new Drawing( { fileName: "test.jpg", stream: Buffer.from(imageBase64Data, "base64"), - path: path, transformation: { pixels: { x: 100, diff --git a/src/file/footer-wrapper.spec.ts b/src/file/footer-wrapper.spec.ts index 2a32ad7968..8978541d21 100644 --- a/src/file/footer-wrapper.spec.ts +++ b/src/file/footer-wrapper.spec.ts @@ -47,4 +47,12 @@ describe("FooterWrapper", () => { expect(spy.called).to.equal(true); }); }); + + describe("#Media", () => { + it("should get Media", () => { + const media = new Media(); + const file = new FooterWrapper(media, 1); + expect(file.Media).to.equal(media); + }); + }); }); diff --git a/src/file/header-wrapper.spec.ts b/src/file/header-wrapper.spec.ts index c6a7272d16..f224743470 100644 --- a/src/file/header-wrapper.spec.ts +++ b/src/file/header-wrapper.spec.ts @@ -47,4 +47,12 @@ describe("HeaderWrapper", () => { expect(spy.called).to.equal(true); }); }); + + describe("#Media", () => { + it("should get Media", () => { + const media = new Media(); + const file = new HeaderWrapper(media, 1); + expect(file.Media).to.equal(media); + }); + }); }); diff --git a/src/file/media/data.ts b/src/file/media/data.ts index 020317980d..eb5ae4629d 100644 --- a/src/file/media/data.ts +++ b/src/file/media/data.ts @@ -16,7 +16,6 @@ export interface IMediaDataTransformation { export interface IMediaData { readonly stream: Buffer | Uint8Array | ArrayBuffer; - readonly path?: string; readonly fileName: string; readonly transformation: IMediaDataTransformation; } diff --git a/src/file/media/media.spec.ts b/src/file/media/media.spec.ts index 3342bca29d..e8469c0c81 100644 --- a/src/file/media/media.spec.ts +++ b/src/file/media/media.spec.ts @@ -3,10 +3,7 @@ import { expect } from "chai"; import { SinonStub, stub } from "sinon"; import * as convenienceFunctions from "convenience-functions"; -import { Formatter } from "export/formatter"; -import { File } from "../file"; -import { Paragraph } from "../paragraph"; import { Media } from "./media"; describe("Media", () => { @@ -18,69 +15,6 @@ describe("Media", () => { (convenienceFunctions.uniqueId as SinonStub).restore(); }); - describe("#addImage", () => { - it("should add image", () => { - const file = new File(); - const image = Media.addImage({ - document: file, - data: "", - transformation: { - width: 100, - height: 100, - }, - }); - - let tree = new Formatter().format(new Paragraph(image)); - expect(tree["w:p"]).to.be.an.instanceof(Array); - - tree = new Formatter().format(image); - expect(tree["w:r"]).to.be.an.instanceof(Array); - }); - - it("should ensure the correct relationship id is used when adding image", () => { - // tslint:disable-next-line:no-any - - const file = new File(); - const image1 = Media.addImage({ - document: file, - data: "test", - transformation: { - width: 100, - height: 100, - }, - }); - const tree = new Formatter().format(new Paragraph(image1)); - const inlineElements = tree["w:p"][0]["w:r"][0]["w:drawing"][0]["wp:inline"]; - const graphicData = inlineElements.find((x) => x["a:graphic"]); - - expect(graphicData["a:graphic"][1]["a:graphicData"][1]["pic:pic"][2]["pic:blipFill"][0]["a:blip"]).to.deep.equal({ - _attr: { - "r:embed": `rId{test.png}`, - cstate: "none", - }, - }); - - const image2 = Media.addImage({ - document: file, - data: "test", - transformation: { - width: 100, - height: 100, - }, - }); - const tree2 = new Formatter().format(new Paragraph(image2)); - const inlineElements2 = tree2["w:p"][0]["w:r"][0]["w:drawing"][0]["wp:inline"]; - const graphicData2 = inlineElements2.find((x) => x["a:graphic"]); - - expect(graphicData2["a:graphic"][1]["a:graphicData"][1]["pic:pic"][2]["pic:blipFill"][0]["a:blip"]).to.deep.equal({ - _attr: { - "r:embed": `rId{test.png}`, - cstate: "none", - }, - }); - }); - }); - describe("#addMedia", () => { it("should add media", () => { const image = new Media().addMedia("", { @@ -129,35 +63,30 @@ describe("Media", () => { }); }); - describe("#getMedia", () => { - it("should get media", () => { + describe("#addImage", () => { + it("should add media", () => { const media = new Media(); media.addMedia("", { width: 100, height: 100, }); - const image = media.getMedia("test.png"); - - expect(image.fileName).to.equal("test.png"); - expect(image.transformation).to.deep.equal({ - pixels: { - x: 100, - y: 100, + media.addImage("test2.png", { + stream: Buffer.from(""), + fileName: "", + transformation: { + pixels: { + x: Math.round(1), + y: Math.round(1), + }, + emus: { + x: Math.round(1 * 9525), + y: Math.round(1 * 9525), + }, }, - flip: undefined, - emus: { - x: 952500, - y: 952500, - }, - rotation: undefined, }); - }); - it("Get media", () => { - const media = new Media(); - - expect(() => media.getMedia("test.png")).to.throw(); + expect(media.Array).to.be.lengthOf(2); }); }); diff --git a/src/file/media/media.ts b/src/file/media/media.ts index a73111849d..d71f4fc15a 100644 --- a/src/file/media/media.ts +++ b/src/file/media/media.ts @@ -1,12 +1,9 @@ import { uniqueId } from "convenience-functions"; -import { IFloating } from "../drawing"; -import { File } from "../file"; -import { PictureRun } from "../paragraph"; import { IMediaData } from "./data"; // import { Image } from "./image"; -interface IMediaTransformation { +export interface IMediaTransformation { readonly width: number; readonly height: number; readonly flip?: { @@ -17,48 +14,19 @@ interface IMediaTransformation { } export class Media { - public static addImage(options: { - readonly document: File; - readonly data: Buffer | string | Uint8Array | ArrayBuffer; - readonly transformation: IMediaTransformation; - readonly floating?: IFloating; - }): PictureRun { - // Workaround to expose id without exposing to API - const mediaData = options.document.Media.addMedia(options.data, options.transformation); - return new PictureRun(mediaData, { floating: options.floating }); - } - private readonly map: Map; constructor() { this.map = new Map(); } - public getMedia(key: string): IMediaData { - const data = this.map.get(key); + public addMedia(data: Buffer | string | Uint8Array | ArrayBuffer, transformation: IMediaTransformation): IMediaData { + const key = `${uniqueId()}.png`; - if (data === undefined) { - throw new Error(`Cannot find image with the key ${key}`); - } - - return data; - } - - public addMedia(buffer: Buffer | string | Uint8Array | ArrayBuffer, transformation: IMediaTransformation): IMediaData { - return this.createMedia(`${uniqueId()}.png`, transformation, buffer); - } - - private createMedia( - key: string, - transformation: IMediaTransformation, - data: Buffer | string | Uint8Array | ArrayBuffer, - filePath?: string, - ): IMediaData { const newData = typeof data === "string" ? this.convertDataURIToBinary(data) : data; const imageData: IMediaData = { stream: newData, - path: filePath, fileName: key, transformation: { pixels: { @@ -79,14 +47,12 @@ export class Media { return imageData; } + public addImage(key: string, mediaData: IMediaData): void { + this.map.set(key, mediaData); + } + public get Array(): readonly IMediaData[] { - const array = new Array(); - - this.map.forEach((data) => { - array.push(data); - }); - - return array; + return Array.from(this.map.values()); } private convertDataURIToBinary(dataURI: string): Uint8Array { diff --git a/src/file/paragraph/paragraph.ts b/src/file/paragraph/paragraph.ts index e707b499a7..c4a9c4ee60 100644 --- a/src/file/paragraph/paragraph.ts +++ b/src/file/paragraph/paragraph.ts @@ -10,11 +10,11 @@ import { PageBreak } from "./formatting/page-break"; import { Bookmark, ConcreteHyperlink, ExternalHyperlink, InternalHyperlink } from "./links"; import { Math } from "./math"; import { IParagraphPropertiesOptions, ParagraphProperties } from "./properties"; -import { PictureRun, Run, SequentialIdentifier, SymbolRun, TextRun } from "./run"; +import { ImageRun, Run, SequentialIdentifier, SymbolRun, TextRun } from "./run"; export type ParagraphChild = | TextRun - | PictureRun + | ImageRun | SymbolRun | Bookmark | PageBreak @@ -34,7 +34,7 @@ export interface IParagraphOptions extends IParagraphPropertiesOptions { export class Paragraph extends XmlComponent { private readonly properties: ParagraphProperties; - constructor(options: string | PictureRun | IParagraphOptions) { + constructor(options: string | IParagraphOptions) { super("w:p"); if (typeof options === "string") { @@ -44,13 +44,6 @@ export class Paragraph extends XmlComponent { return; } - if (options instanceof PictureRun) { - this.properties = new ParagraphProperties({}); - this.root.push(this.properties); - this.root.push(options); - return; - } - this.properties = new ParagraphProperties(options); this.root.push(this.properties); diff --git a/src/file/paragraph/run/image-run.spec.ts b/src/file/paragraph/run/image-run.spec.ts new file mode 100644 index 0000000000..a5572f48a9 --- /dev/null +++ b/src/file/paragraph/run/image-run.spec.ts @@ -0,0 +1,1035 @@ +import { expect } from "chai"; +import { SinonStub, stub } from "sinon"; + +import * as convenienceFunctions from "convenience-functions"; +import { Formatter } from "export/formatter"; +import { IViewWrapper } from "file/document-wrapper"; +import { File } from "file/file"; + +import { ImageRun } from "./image-run"; + +describe("ImageRun", () => { + before(() => { + stub(convenienceFunctions, "uniqueId").callsFake(() => { + return "test-unique-id"; + }); + }); + + after(() => { + (convenienceFunctions.uniqueId as SinonStub).restore(); + }); + + describe("#constructor()", () => { + it("should create with Buffer", () => { + const currentImageRun = new ImageRun({ + data: Buffer.from(""), + transformation: { + width: 200, + height: 200, + rotation: 45, + }, + floating: { + zIndex: 10, + horizontalPosition: { + offset: 1014400, + }, + verticalPosition: { + offset: 1014400, + }, + }, + }); + + const tree = new Formatter().format(currentImageRun, { + file: ({ + Media: { + // tslint:disable-next-line: no-empty + addImage: () => {}, + }, + } as unknown) as File, + viewWrapper: ({} as unknown) as IViewWrapper, + }); + 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: 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": "rId{test-unique-id.png}", + }, + }, + }, + { + "a:srcRect": {}, + }, + { + "a:stretch": [ + { + "a:fillRect": {}, + }, + ], + }, + ], + }, + { + "pic:spPr": [ + { + _attr: { + bwMode: "auto", + }, + }, + { + "a:xfrm": [ + { + _attr: { + rot: 2700000, + }, + }, + { + "a:ext": { + _attr: { + cx: 1905000, + cy: 1905000, + }, + }, + }, + { + "a:off": { + _attr: { + x: 0, + y: 0, + }, + }, + }, + ], + }, + { + "a:prstGeom": [ + { + _attr: { + prst: "rect", + }, + }, + { + "a:avLst": {}, + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }); + }); + + it("should create with string", () => { + const currentImageRun = new ImageRun({ + data: "", + transformation: { + width: 200, + height: 200, + rotation: 45, + }, + floating: { + zIndex: 10, + horizontalPosition: { + offset: 1014400, + }, + verticalPosition: { + offset: 1014400, + }, + }, + }); + + const tree = new Formatter().format(currentImageRun, { + file: ({ + Media: { + // tslint:disable-next-line: no-empty + addImage: () => {}, + }, + } as unknown) as File, + viewWrapper: ({} as unknown) as IViewWrapper, + }); + 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: 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": "rId{test-unique-id.png}", + }, + }, + }, + { + "a:srcRect": {}, + }, + { + "a:stretch": [ + { + "a:fillRect": {}, + }, + ], + }, + ], + }, + { + "pic:spPr": [ + { + _attr: { + bwMode: "auto", + }, + }, + { + "a:xfrm": [ + { + _attr: { + rot: 2700000, + }, + }, + { + "a:ext": { + _attr: { + cx: 1905000, + cy: 1905000, + }, + }, + }, + { + "a:off": { + _attr: { + x: 0, + y: 0, + }, + }, + }, + ], + }, + { + "a:prstGeom": [ + { + _attr: { + prst: "rect", + }, + }, + { + "a:avLst": {}, + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }); + }); + + it("should return UInt8Array if atob is present", () => { + global.atob = () => "atob result"; + + const currentImageRun = new ImageRun({ + data: "", + transformation: { + width: 200, + height: 200, + rotation: 45, + }, + floating: { + zIndex: 10, + horizontalPosition: { + offset: 1014400, + }, + verticalPosition: { + offset: 1014400, + }, + }, + }); + + const tree = new Formatter().format(currentImageRun, { + file: ({ + Media: { + // tslint:disable-next-line: no-empty + addImage: () => {}, + }, + } as unknown) as File, + viewWrapper: ({} as unknown) as IViewWrapper, + }); + + 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: 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": "rId{test-unique-id.png}", + }, + }, + }, + { + "a:srcRect": {}, + }, + { + "a:stretch": [ + { + "a:fillRect": {}, + }, + ], + }, + ], + }, + { + "pic:spPr": [ + { + _attr: { + bwMode: "auto", + }, + }, + { + "a:xfrm": [ + { + _attr: { + rot: 2700000, + }, + }, + { + "a:ext": { + _attr: { + cx: 1905000, + cy: 1905000, + }, + }, + }, + { + "a:off": { + _attr: { + x: 0, + y: 0, + }, + }, + }, + ], + }, + { + "a:prstGeom": [ + { + _attr: { + prst: "rect", + }, + }, + { + "a:avLst": {}, + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }); + + // tslint:disable-next-line: no-any + (global as any).atob = undefined; + }); + + it("should use data as is if its not a string", () => { + global.atob = () => "atob result"; + + const currentImageRun = new ImageRun({ + data: "", + transformation: { + width: 200, + height: 200, + rotation: 45, + }, + floating: { + zIndex: 10, + horizontalPosition: { + offset: 1014400, + }, + verticalPosition: { + offset: 1014400, + }, + }, + }); + + const tree = new Formatter().format(currentImageRun, { + file: ({ + Media: { + // tslint:disable-next-line: no-empty + addImage: () => {}, + }, + } as unknown) as File, + viewWrapper: ({} as unknown) as IViewWrapper, + }); + + 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: 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": "rId{test-unique-id.png}", + }, + }, + }, + { + "a:srcRect": {}, + }, + { + "a:stretch": [ + { + "a:fillRect": {}, + }, + ], + }, + ], + }, + { + "pic:spPr": [ + { + _attr: { + bwMode: "auto", + }, + }, + { + "a:xfrm": [ + { + _attr: { + rot: 2700000, + }, + }, + { + "a:ext": { + _attr: { + cx: 1905000, + cy: 1905000, + }, + }, + }, + { + "a:off": { + _attr: { + x: 0, + y: 0, + }, + }, + }, + ], + }, + { + "a:prstGeom": [ + { + _attr: { + prst: "rect", + }, + }, + { + "a:avLst": {}, + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }); + + // tslint:disable-next-line: no-any + (global as any).atob = undefined; + }); + }); +}); diff --git a/src/file/paragraph/run/image-run.ts b/src/file/paragraph/run/image-run.ts new file mode 100644 index 0000000000..64140cb665 --- /dev/null +++ b/src/file/paragraph/run/image-run.ts @@ -0,0 +1,68 @@ +import { uniqueId } from "convenience-functions"; + +import { Drawing, IFloating } from "../../drawing"; +import { IMediaTransformation } from "../../media"; +import { IMediaData } from "../../media/data"; +import { Run } from "../run"; +import { IContext, IXmlableObject } from "/file/xml-components"; + +export interface IImageOptions { + readonly data: Buffer | string | Uint8Array | ArrayBuffer; + readonly transformation: IMediaTransformation; + readonly floating?: IFloating; +} + +export class ImageRun extends Run { + private readonly key = `${uniqueId()}.png`; + private readonly imageData: IMediaData; + + constructor(options: IImageOptions) { + super({}); + const newData = typeof options.data === "string" ? this.convertDataURIToBinary(options.data) : options.data; + + this.imageData = { + stream: newData, + fileName: this.key, + transformation: { + pixels: { + x: Math.round(options.transformation.width), + y: Math.round(options.transformation.height), + }, + emus: { + x: Math.round(options.transformation.width * 9525), + y: Math.round(options.transformation.height * 9525), + }, + flip: options.transformation.flip, + rotation: options.transformation.rotation ? options.transformation.rotation * 60000 : undefined, + }, + }; + const drawing = new Drawing(this.imageData, { floating: options.floating }); + + this.root.push(drawing); + } + + public prepForXml(context: IContext): IXmlableObject | undefined { + context.file.Media.addImage(this.key, this.imageData); + + return super.prepForXml(context); + } + + private convertDataURIToBinary(dataURI: string): Uint8Array { + // https://gist.github.com/borismus/1032746 + // https://github.com/mafintosh/base64-to-uint8array + const BASE64_MARKER = ";base64,"; + + const base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length; + + if (typeof atob === "function") { + return new Uint8Array( + atob(dataURI.substring(base64Index)) + .split("") + .map((c) => c.charCodeAt(0)), + ); + } else { + const b = require("buf" + "fer"); + return new b.Buffer(dataURI, "base64"); + } + } +} diff --git a/src/file/paragraph/run/index.ts b/src/file/paragraph/run/index.ts index 3bf62d66cf..4179af7cfc 100644 --- a/src/file/paragraph/run/index.ts +++ b/src/file/paragraph/run/index.ts @@ -2,7 +2,7 @@ export * from "./run"; export * from "./properties"; export * from "./text-run"; export * from "./symbol-run"; -export * from "./picture-run"; +export * from "./image-run"; export * from "./run-fonts"; export * from "./sequential-identifier"; export * from "./underline"; diff --git a/src/file/paragraph/run/picture-run.ts b/src/file/paragraph/run/picture-run.ts deleted file mode 100644 index e98dba573a..0000000000 --- a/src/file/paragraph/run/picture-run.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Drawing } from "../../drawing"; -import { IDrawingOptions } from "../../drawing/drawing"; -import { IMediaData } from "../../media/data"; -import { Run } from "../run"; - -export class PictureRun extends Run { - constructor(imageData: IMediaData, drawingOptions?: IDrawingOptions) { - super({}); - - const drawing = new Drawing(imageData, drawingOptions); - - this.root.push(drawing); - } -}