#815 Rotation and flipping images

This commit is contained in:
Dolan
2021-03-15 02:41:37 +00:00
parent a3febae8a3
commit bd40b11ce4
33 changed files with 615 additions and 126 deletions

View File

@ -1,4 +1,4 @@
export interface IMediaDataDimensions {
export interface IMediaDataTransformation {
readonly pixels: {
readonly x: number;
readonly y: number;
@ -7,13 +7,18 @@ export interface IMediaDataDimensions {
readonly x: number;
readonly y: number;
};
readonly flip?: {
readonly vertical?: boolean;
readonly horizontal?: boolean;
};
readonly rotation?: number;
}
export interface IMediaData {
readonly stream: Buffer | Uint8Array | ArrayBuffer;
readonly path?: string;
readonly fileName: string;
readonly dimensions: IMediaDataDimensions;
readonly transformation: IMediaDataTransformation;
}
// Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432

View File

@ -21,7 +21,14 @@ describe("Media", () => {
describe("#addImage", () => {
it("should add image", () => {
const file = new File();
const image = Media.addImage(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);
@ -34,7 +41,14 @@ describe("Media", () => {
// tslint:disable-next-line:no-any
const file = new File();
const image1 = Media.addImage(file, "test");
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"]);
@ -46,7 +60,14 @@ describe("Media", () => {
},
});
const image2 = Media.addImage(file, "test");
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"]);
@ -62,24 +83,32 @@ describe("Media", () => {
describe("#addMedia", () => {
it("should add media", () => {
const image = new Media().addMedia("");
const image = new Media().addMedia("", {
width: 100,
height: 100,
});
expect(image.fileName).to.equal("test.png");
expect(image.dimensions).to.deep.equal({
expect(image.transformation).to.deep.equal({
pixels: {
x: 100,
y: 100,
},
flip: undefined,
emus: {
x: 952500,
y: 952500,
},
rotation: undefined,
});
});
it("should return UInt8Array if atob is present", () => {
global.atob = () => "atob result";
const image = new Media().addMedia("");
const image = new Media().addMedia("", {
width: 100,
height: 100,
});
expect(image.stream).to.be.an.instanceof(Uint8Array);
// tslint:disable-next-line: no-any
@ -89,7 +118,10 @@ describe("Media", () => {
it("should use data as is if its not a string", () => {
global.atob = () => "atob result";
const image = new Media().addMedia(Buffer.from(""));
const image = new Media().addMedia(Buffer.from(""), {
width: 100,
height: 100,
});
expect(image.stream).to.be.an.instanceof(Uint8Array);
// tslint:disable-next-line: no-any
@ -100,20 +132,25 @@ describe("Media", () => {
describe("#getMedia", () => {
it("should get media", () => {
const media = new Media();
media.addMedia("");
media.addMedia("", {
width: 100,
height: 100,
});
const image = media.getMedia("test.png");
expect(image.fileName).to.equal("test.png");
expect(image.dimensions).to.deep.equal({
expect(image.transformation).to.deep.equal({
pixels: {
x: 100,
y: 100,
},
flip: undefined,
emus: {
x: 952500,
y: 952500,
},
rotation: undefined,
});
});
@ -127,7 +164,15 @@ describe("Media", () => {
describe("#Array", () => {
it("Get images as array", () => {
const media = new Media();
media.addMedia("");
media.addMedia("", {
width: 100,
height: 100,
flip: {
vertical: true,
horizontal: true,
},
rotation: 90,
});
const array = media.Array;
expect(array).to.be.an.instanceof(Array);
@ -135,15 +180,20 @@ describe("Media", () => {
const image = array[0];
expect(image.fileName).to.equal("test.png");
expect(image.dimensions).to.deep.equal({
expect(image.transformation).to.deep.equal({
pixels: {
x: 100,
y: 100,
},
flip: {
vertical: true,
horizontal: true,
},
emus: {
x: 952500,
y: 952500,
},
rotation: 5400000,
});
});
});

View File

@ -1,22 +1,31 @@
import { uniqueId } from "convenience-functions";
import { IDrawingOptions } from "../drawing";
import { IFloating } from "../drawing";
import { File } from "../file";
import { PictureRun } from "../paragraph";
import { IMediaData } from "./data";
// import { Image } from "./image";
interface IMediaTransformation {
readonly width: number;
readonly height: number;
readonly flip?: {
readonly vertical?: boolean;
readonly horizontal?: boolean;
};
readonly rotation?: number;
}
export class Media {
public static addImage(
file: File,
buffer: Buffer | string | Uint8Array | ArrayBuffer,
width?: number,
height?: number,
drawingOptions?: IDrawingOptions,
): PictureRun {
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 = file.Media.addMedia(buffer, width, height);
return new PictureRun(mediaData, drawingOptions);
const mediaData = options.document.Media.addMedia(options.data, options.transformation);
return new PictureRun(mediaData, { floating: options.floating });
}
private readonly map: Map<string, IMediaData>;
@ -35,22 +44,13 @@ export class Media {
return data;
}
public addMedia(buffer: Buffer | string | Uint8Array | ArrayBuffer, width: number = 100, height: number = 100): IMediaData {
const key = `${uniqueId()}.png`;
return this.createMedia(
key,
{
width: width,
height: height,
},
buffer,
);
public addMedia(buffer: Buffer | string | Uint8Array | ArrayBuffer, transformation: IMediaTransformation): IMediaData {
return this.createMedia(`${uniqueId()}.png`, transformation, buffer);
}
private createMedia(
key: string,
dimensions: { readonly width: number; readonly height: number },
transformation: IMediaTransformation,
data: Buffer | string | Uint8Array | ArrayBuffer,
filePath?: string,
): IMediaData {
@ -60,15 +60,17 @@ export class Media {
stream: newData,
path: filePath,
fileName: key,
dimensions: {
transformation: {
pixels: {
x: Math.round(dimensions.width),
y: Math.round(dimensions.height),
x: Math.round(transformation.width),
y: Math.round(transformation.height),
},
emus: {
x: Math.round(dimensions.width * 9525),
y: Math.round(dimensions.height * 9525),
x: Math.round(transformation.width * 9525),
y: Math.round(transformation.height * 9525),
},
flip: transformation.flip,
rotation: transformation.rotation ? transformation.rotation * 60000 : undefined,
},
};