Skip to content

Commit

Permalink
feat(paragraph): set width and height of an image (#37)
Browse files Browse the repository at this point in the history
Fixes #36
  • Loading branch information
connium authored May 20, 2018
1 parent 19a4206 commit c5bf9a2
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.


## [Unreleased] (2018-??-??)
### Added
- **paragraph:** Set width and height of an image, closes [#36](https://github.com/connium/simple-odf/issues/36)

## [0.4.0] (2018-05-19)
### Added
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ const simpleOdf = require("simple-odf");

const document = new simpleOdf.TextDocument();

document.addParagraph().addImage("/home/homer/myself.png");
const image = document.addParagraph().addImage("/home/homer/myself.png");
image.setSize(29.4, 36.5);

document.addHeading("Welcome to simple-odf");

Expand Down
3 changes: 3 additions & 0 deletions src/OdfAttributeName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ export enum OdfAttributeName {
StylePosition = "style:position",
StyleType = "style:type",

SvgHeight = "svg:height",
SvgWidth = "svg:width",

TextAnchorType = "text:anchor-type",
TextOutlineLevel = "text:outline-level",
TextStyleName = "text:style-name",
Expand Down
96 changes: 90 additions & 6 deletions src/draw/Image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { OdfAttributeName } from "../OdfAttributeName";
import { OdfElement } from "../OdfElement";
import { OdfElementName } from "../OdfElementName";

const MINIMAL_SIZE = 1;
const DEFAULT_ANCHOR_TYPE = "paragraph";
const ENCODING = "base64";

Expand All @@ -12,6 +13,9 @@ const ENCODING = "base64";
* @since 0.3.0
*/
export class Image extends OdfElement {
private height: number | undefined;
private width: number | undefined;

/**
* Creates an image
*
Expand All @@ -22,16 +26,98 @@ export class Image extends OdfElement {
super();
}

/**
* Sets the target height of the image.
*
* @param {number} height The target height of the image in millimeter
* @since 0.5.0
*/
public setHeight(height: number): void {
this.height = Math.max(height, MINIMAL_SIZE);
}

/**
* Returns the target height of the image or `undefined` if no height was set.
*
* @returns {number | undefined} The target height of the image in millimeter or `undefined` if no height was set
* @since 0.5.0
*/
public getHeight(): number | undefined {
return this.height;
}

/**
* Sets the target width of the image.
*
* @param {number} width The target width of the image in millimeter
* @since 0.5.0
*/
public setWidth(width: number): void {
this.width = Math.max(width, MINIMAL_SIZE);
}

/**
* Returns the target width of the image or `undefined` if no width was set.
*
* @returns {number | undefined} The target width of the image in millimeter or `undefined` if no width was set
* @since 0.5.0
*/
public getWidth(): number | undefined {
return this.width;
}

/**
* Sets the target size of the image.
*
* @param {number} width The target width of the image in millimeter
* @param {number} height The target height of the image in millimeter
* @since 0.5.0
*/
public setSize(width: number, height: number): void {
this.setWidth(width);
this.setHeight(height);
}

/** @inheritDoc */
protected toXml(document: Document, parent: Element): void {
(document.firstChild as Element).setAttribute("xmlns:draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0");

const frame = document.createElement(OdfElementName.DrawFrame);
parent.appendChild(frame);
frame.setAttribute(OdfAttributeName.TextAnchorType, DEFAULT_ANCHOR_TYPE);
const frameElement = document.createElement(OdfElementName.DrawFrame);
parent.appendChild(frameElement);

this.setFrameAttributes(frameElement);

this.embedImage(document, frameElement);

super.toXml(document, frameElement);
}

/**
* Sets the attributes for the image frame.
*
* @param {Element} frameElement The element which will take the attribute
*/
private setFrameAttributes(frameElement: Element): void {
frameElement.setAttribute(OdfAttributeName.TextAnchorType, DEFAULT_ANCHOR_TYPE);

if (this.width !== undefined) {
frameElement.setAttribute(OdfAttributeName.SvgWidth, + this.width + "mm");
}

if (this.height !== undefined) {
frameElement.setAttribute(OdfAttributeName.SvgHeight, + this.height + "mm");
}
}

/**
* Creates the image element and embeds the denoted image base64 encoded binary data.
*
* @param {Document} document The XML document
* @param {Element} frameElement The parent node in the DOM (`draw:frame`)
*/
private embedImage(document: Document, frameElement: Element): void {
const image = document.createElement(OdfElementName.DrawImage);
frame.appendChild(image);
frameElement.appendChild(image);

const binaryData = document.createElement(OdfElementName.OfficeBinaryData);
image.appendChild(binaryData);
Expand All @@ -40,7 +126,5 @@ export class Image extends OdfElement {
const base64Image = rawImage.toString(ENCODING);
const textNode = document.createTextNode(base64Image);
binaryData.appendChild(textNode);

super.toXml(document, frame);
}
}
79 changes: 77 additions & 2 deletions test/draw/Image.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { join } from "path";
import { Image } from "../../src/draw/Image";
import { TextDocument } from "../../src/TextDocument";

describe(Image.name, () => {
Expand All @@ -8,9 +9,71 @@ describe(Image.name, () => {
document = new TextDocument();
});

describe("#addImage", () => {
describe("#setHeight", () => {
it("set a minimum height", () => {
const image = new Image("somePath");
image.setHeight(-23);

expect(image.getHeight()).toBe(1);
});
});

describe("#getHeight", () => {
it("return `undefined` as default", () => {
const image = new Image("somePath");

expect(image.getHeight()).toBeUndefined();
});

it("return the current height", () => {
const image = new Image("somePath");

image.setHeight(23);

expect(image.getHeight()).toBe(23);
});
});

describe("#setWidth", () => {
it("set a minimum width", () => {
const image = new Image("somePath");
image.setWidth(-42);

expect(image.getWidth()).toBe(1);
});
});

describe("#getWidth", () => {
it("return `undefined` as default", () => {
const image = new Image("somePath");

expect(image.getWidth()).toBeUndefined();
});

it("return the current width", () => {
const image = new Image("somePath");

image.setWidth(42);

expect(image.getWidth()).toBe(42);
});
});

describe("#setSize", () => {
it("set width and height", () => {
const image = new Image("somePath");
image.setSize(42, 23);

expect(image.getWidth()).toBe(42);
expect(image.getHeight()).toBe(23);
});
});

describe("#toXml", () => {
let image: Image;

beforeEach(() => {
document.addParagraph().addImage(join(__dirname, "..", "data", "ODF.png"));
image = document.addParagraph().addImage(join(__dirname, "..", "data", "ODF.png"));
});

it("add draw namespace", () => {
Expand All @@ -27,5 +90,17 @@ describe(Image.name, () => {
+ "</draw:frame>");
expect(document.toString()).toMatch(regex);
});

it("set the height", () => {
image.setHeight(23);

expect(document.toString()).toMatch(/<draw:frame text:anchor-type="paragraph" svg:height="23mm">/);
});

it("set the width", () => {
image.setWidth(42);

expect(document.toString()).toMatch(/<draw:frame text:anchor-type="paragraph" svg:width="42mm">/);
});
});
});
3 changes: 2 additions & 1 deletion test/integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ xdescribe("integration", () => {
});

it("image", () => {
document.addParagraph().addImage(join(__dirname, "data", "ODF.png"));
const image = document.addParagraph().addImage(join(__dirname, "data", "ODF.png"));
image.setSize(29.4, 36.5);
});

it("add heading", () => {
Expand Down

0 comments on commit c5bf9a2

Please sign in to comment.