From ac8979bbe3fa9b2c838cb5092f9dae2fda548318 Mon Sep 17 00:00:00 2001 From: Martin Skec Date: Mon, 20 Nov 2023 07:37:11 +0100 Subject: [PATCH] feat(preserveAspectRatio): added option to preserve aspect ratio (#193) * feat(preserveAspectRatio): added option to preserve aspect ratio When set to true and both width and height are specified, they are interpreted as the minimum width and minimum height, respectively. If set to true with only the width specified, the height will be automatically determined while preserving the aspect ratio, and vice versa. fixes #88, #189 --- readme.md | 21 ++++++------ src/graphics.ts | 13 ++++++-- src/pdf2picCore.ts | 1 + src/types/options.ts | 1 + src/utils/defaultOptions.ts | 1 + test/graphics.test.ts | 19 +++++++++++ test/index.test.ts | 66 +++++++++++++++++++++++++++++++++++++ 7 files changed, 110 insertions(+), 12 deletions(-) diff --git a/readme.md b/readme.md index 6eb05e3..8968ae9 100644 --- a/readme.md +++ b/readme.md @@ -174,16 +174,17 @@ Functions same as `fromPath(filePath, options).setGMClass(subClass)` only input ### options Following are the options that can be passed on the pdf2pic api: -| option | default value | description | -|--------------|--------------- |------------------------------| -| quality | `0` | Image compression level. Value depends on `format`, usually from `0` to `100` ([more info](http://www.graphicsmagick.org/GraphicsMagick.html#details-quality)) | -| format | `'png'` | Formatted image characteristics / image format ([image characteristics](http://www.graphicsmagick.org/GraphicsMagick.html#details-format), [image format](http://www.graphicsmagick.org/formats.html)) | -| width | `768` | Output width | -| height | `512` | Output height | -| density | `72` | Output DPI (dots per inch) ([more info](http://www.graphicsmagick.org/GraphicsMagick.html#details-density)) | -| savePath | `'./'` | Path where to save the output | -| saveFilename | `'untitled'` | Output filename | -| compression | `'jpeg'` | Compression method ([more info](http://www.graphicsmagick.org/GraphicsMagick.html#details-compress)) | +| option | default value | description | +|---------------------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| quality | `0` | Image compression level. Value depends on `format`, usually from `0` to `100` ([more info](http://www.graphicsmagick.org/GraphicsMagick.html#details-quality)) | +| format | `'png'` | Formatted image characteristics / image format ([image characteristics](http://www.graphicsmagick.org/GraphicsMagick.html#details-format), [image format](http://www.graphicsmagick.org/formats.html)) | +| width | `768` | Output width | +| height | `512` | Output height | +| preserveAspectRatio | `false` | Maintains the aspect ratio of the image. When set to `true` and both `width` and `height` are specified, they are interpreted as the minimum width and minimum height, respectively. If set to `true` with only the `width` specified, the `height` will be automatically determined while preserving the aspect ratio, and vice versa. | +| density | `72` | Output DPI (dots per inch) ([more info](http://www.graphicsmagick.org/GraphicsMagick.html#details-density)) | +| savePath | `'./'` | Path where to save the output | +| saveFilename | `'untitled'` | Output filename | +| compression | `'jpeg'` | Compression method ([more info](http://www.graphicsmagick.org/GraphicsMagick.html#details-compress)) | ### convertOptions diff --git a/src/graphics.ts b/src/graphics.ts index d42019a..b7c7d68 100644 --- a/src/graphics.ts +++ b/src/graphics.ts @@ -13,6 +13,8 @@ export class Graphics { private height = 512; + private preserveAspectRatio = false; + private density = 72; private savePath = "./"; @@ -39,7 +41,7 @@ export class Graphics { public gmBaseCommand(stream: fs.ReadStream, filename: string): gm.State { return this.gm(stream, filename) .density(this.density, this.density) - .resize(this.width, this.height, "!") + .resize(this.width, this.height, this.preserveAspectRatio ? '^' : '!') .quality(this.quality) .compress(this.compression) } @@ -136,7 +138,13 @@ export class Graphics { public setSize(width: number, height?: number): Graphics { this.width = width; - this.height = !!height ? height : width; + this.height = this.preserveAspectRatio || !!height ? height : width; + + return this; + } + + public setPreserveAspectRatio(preserveAspectRatio: boolean): Graphics { + this.preserveAspectRatio = preserveAspectRatio; return this; } @@ -189,6 +197,7 @@ export class Graphics { format: this.format, width: this.width, height: this.height, + preserveAspectRatio: this.preserveAspectRatio, density: this.density, savePath: this.savePath, saveFilename: this.saveFilename, diff --git a/src/pdf2picCore.ts b/src/pdf2picCore.ts index eb203c3..45ce00b 100644 --- a/src/pdf2picCore.ts +++ b/src/pdf2picCore.ts @@ -73,6 +73,7 @@ export function pdf2picCore(source: string, data: string | Buffer, options = def function setGMOptions(gm: Graphics, options: Options): void { gm.setQuality(options.quality) .setFormat(options.format) + .setPreserveAspectRatio(options.preserveAspectRatio) .setSize(options.width, options.height) .setDensity(options.density) .setSavePath(options.savePath) diff --git a/src/types/options.ts b/src/types/options.ts index deb75dc..28fada4 100644 --- a/src/types/options.ts +++ b/src/types/options.ts @@ -3,6 +3,7 @@ export type Options = { format?: string; width?: number; height?: number; + preserveAspectRatio?: boolean; density?: number; savePath?: string; saveFilename?: string; diff --git a/src/utils/defaultOptions.ts b/src/utils/defaultOptions.ts index 4e3924a..e17417d 100644 --- a/src/utils/defaultOptions.ts +++ b/src/utils/defaultOptions.ts @@ -6,6 +6,7 @@ export const defaultOptions: Options = { width: 768, height: 512, density: 72, + preserveAspectRatio: false, savePath: "./", saveFilename: "untitled", compression: "jpeg" diff --git a/test/graphics.test.ts b/test/graphics.test.ts index 672bba8..e7455ed 100644 --- a/test/graphics.test.ts +++ b/test/graphics.test.ts @@ -72,6 +72,7 @@ describe("graphics", () => { gm.setQuality(100); gm.setFormat("jpg"); + gm.setPreserveAspectRatio(true); gm.setSize(100, 100); gm.setDensity(100); gm.setSavePath("./test/data"); @@ -92,6 +93,9 @@ describe("graphics", () => { expect(options).to.haveOwnProperty("height"); expect(options.height).to.be.equal(100); + expect(options).to.haveOwnProperty("preserveAspectRatio"); + expect(options.preserveAspectRatio).to.be.equal(true); + expect(options).to.haveOwnProperty("density"); expect(options.density).to.be.equal(100); @@ -119,6 +123,21 @@ describe("graphics", () => { expect(options.height).to.be.equal(200); }); + it("should by not set height if preserveAspectRatio is `true`", () => { + const gm = new Graphics(); + + gm.setPreserveAspectRatio(true); + gm.setSize(200); + + const options = gm.getOptions(); + + expect(options).to.haveOwnProperty("width"); + expect(options.width).to.be.equal(200); + + expect(options).to.haveOwnProperty("height"); + expect(options.height).to.be.equal(undefined); + }); + it("should save first page as image file", async () => { const gm = new Graphics(); diff --git a/test/index.test.ts b/test/index.test.ts index 43bd26a..f8c173d 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -364,4 +364,70 @@ describe("PDF2Pic Core", () => { } }).timeout(7000); }); + + describe('preserveAspectRatio', () => { + it('should preserve aspect ratio of pages', async () => { + const gm = new Graphics(); + const options = { + ...baseOptions, + format: "png", + width: undefined, + height: undefined, + preserveAspectRatio: true, + saveFilename: "test-aspect-ratio-1" + } + + const convert = fromPath("./test/data/pdf1.pdf", options); + const imageResponse = await convert.bulk([1, 2], { responseType: 'image' }); + + expect(imageResponse).to.be.an('array').that.has.lengthOf(2) + + + expectImageResponseToBeValid(imageResponse[0], options) + const page1Info = await gm.identify(`./dump/fromfiletest/${options.saveFilename}.1.png`) as gm.ImageInfo; + expectInfoToBeValid(page1Info, { ...options, width: 842, height: 595 }) + + expectImageResponseToBeValid(imageResponse[1], options) + const page2Info = await gm.identify(`./dump/fromfiletest/${options.saveFilename}.2.png`) as gm.ImageInfo; + expectInfoToBeValid(page2Info, { ...options, width: 1684, height: 595 }) + }); + + it('should set height automatically', async () => { + const gm = new Graphics(); + const options = { + ...baseOptions, + format: "png", + width: 600, + height: undefined, + preserveAspectRatio: true, + saveFilename: "test-aspect-ratio-2" + } + + const convert = fromPath("./test/data/pdf1.pdf", options); + const imageResponse = await convert(1, { responseType: 'image' }); + + expectImageResponseToBeValid(imageResponse, options) + const page1Info = await gm.identify(`./dump/fromfiletest/${options.saveFilename}.1.png`) as gm.ImageInfo; + expectInfoToBeValid(page1Info, { ...options, height: 424 }) + }); + + it('should set width automatically', async () => { + const gm = new Graphics(); + const options = { + ...baseOptions, + format: "png", + width: undefined, + height: 600, + preserveAspectRatio: true, + saveFilename: "test-aspect-ratio-3" + } + + const convert = fromPath("./test/data/pdf1.pdf", options); + const imageResponse = await convert(1, { responseType: 'image' }); + + expectImageResponseToBeValid(imageResponse, options) + const page1Info = await gm.identify(`./dump/fromfiletest/${options.saveFilename}.1.png`) as gm.ImageInfo; + expectInfoToBeValid(page1Info, { ...options, width: 849 }) + }); + }) });