@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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<string, IMediaData>;
|
||||
|
||||
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;
|
||||
|
251
src/file/paragraph/image.spec.ts
Normal file
251
src/file/paragraph/image.spec.ts
Normal file
@ -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": [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
18
src/file/paragraph/image.ts
Normal file
18
src/file/paragraph/image.ts
Normal file
@ -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);
|
||||
}
|
||||
}
|
@ -3,3 +3,4 @@ export * from "./paragraph";
|
||||
export * from "./properties";
|
||||
export * from "./run";
|
||||
export * from "./links";
|
||||
export * from "./image";
|
||||
|
Reference in New Issue
Block a user