From c3860ab30e8a48ffb085c11c14ff1dfaa3d23534 Mon Sep 17 00:00:00 2001 From: Konstantin Tarkus Date: Fri, 25 Sep 2020 11:33:57 +0300 Subject: [PATCH] Offset coordinates for cropping: x_5,y_5,w_80,h_60,c_crop (#1) --- README.md | 15 +++++++++--- lib/params.js | 18 ++++++++++++++ lib/params.js.map | 2 +- lib/transform.js | 4 +++- lib/transform.js.map | 2 +- lib/types.d.ts | 2 ++ package.json | 2 +- ...260-y-160-w-120-h-80-c-crop-png-1-snap.png | Bin 0 -> 50617 bytes src/params.ts | 12 ++++++++++ src/parse.test.ts | 22 ++++++++++++++++++ src/transform.test.ts | 17 ++++++++++++++ src/transform.ts | 8 ++++++- src/types.ts | 2 ++ 13 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 src/__image_snapshots__/transform-test-ts-x-260-y-160-w-120-h-80-c-crop-png-1-snap.png diff --git a/README.md b/README.md index ae659a1..697ae46 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ -# Image Resizing +# Cloud Image Resizing · [![npm package][npm-badge]][npm] + +[npm-badge]: https://img.shields.io/npm/v/image-resizing.svg?style=flat-square +[npm]: https://www.npmjs.org/package/image-resizing Node.js backend (middleware) for image manipulation needs (transform, resize, optimize) that can be hosted in a serverless environment such as Google Cloud @@ -8,6 +11,10 @@ Functions. Create a Google Cloud Function project that exports image transformation HTTP handler: +``` +$ npm install image-resizing --save +``` + ```js const { createHandler } = require("image-resizing"); @@ -24,7 +31,9 @@ module.exports.img = createHandler({ Deploy it to GCP using Node.js v12+ runtime and configure a CDN on top of it. ``` -https://example.com/w_80,h_60,c_fill/example.jpg +https://example.com/image.jpg - original image +https://example.com/w_80,h_60,c_fill/image.jpg - resized image (80x60) +https://example.com/x_10,y_10,w_80,h_60,c_crop/image.jpg - cropped image (80x60 at 10,10 offset) ``` ## References @@ -36,7 +45,7 @@ https://example.com/w_80,h_60,c_fill/example.jpg ## Contributing Contributions of any kind are welcome! If you're unsure about something or need -directions, don't hesitate to get in touch on[Discord](https://discord.com/invite/bSsv7XM). +directions, don't hesitate to get in touch on [Discord](https://discord.com/invite/bSsv7XM). ## License diff --git a/lib/params.js b/lib/params.js index 42d7213..ca2ebff 100644 --- a/lib/params.js +++ b/lib/params.js @@ -40,6 +40,24 @@ var params = { validate: function validate(value) { return ["crop", "fill"].includes(value); } + }, + x: { + key: "x", + parse: function parse(value) { + return parseInt(value, 10); + }, + validate: function validate(value) { + return !isNaN(value); + } + }, + y: { + key: "y", + parse: function parse(value) { + return parseInt(value, 10); + }, + validate: function validate(value) { + return !isNaN(value); + } } }; exports.params = params; diff --git a/lib/params.js.map b/lib/params.js.map index f679e42..08bba28 100644 --- a/lib/params.js.map +++ b/lib/params.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/params.ts"],"names":["params","width","key","parse","value","parseInt","validate","isNaN","height","crop","includes"],"mappings":";;;;;;;AAAA;;;;AAMA;;;;AAIO,IAAMA,MAAc,GAAG;AAC5BC,EAAAA,KAAK,EAAE;AACLC,IAAAA,GAAG,EAAE,GADA;AAELC,IAAAA,KAAK,EAAE,eAACC,KAAD;AAAA,aAAWC,QAAQ,CAACD,KAAD,EAAQ,EAAR,CAAnB;AAAA,KAFF;AAGLE,IAAAA,QAAQ,EAAE,kBAACF,KAAD;AAAA,aAAW,CAACG,KAAK,CAACH,KAAD,CAAN,IAAiBA,KAAK,IAAI,EAA1B,IAAgCA,KAAK,IAAI,IAApD;AAAA;AAHL,GADqB;AAO5BI,EAAAA,MAAM,EAAE;AACNN,IAAAA,GAAG,EAAE,GADC;AAENC,IAAAA,KAAK,EAAE,eAACC,KAAD;AAAA,aAAWC,QAAQ,CAACD,KAAD,EAAQ,EAAR,CAAnB;AAAA,KAFD;AAGNE,IAAAA,QAAQ,EAAE,kBAACF,KAAD;AAAA,aAAW,CAACG,KAAK,CAACH,KAAD,CAAN,IAAiBA,KAAK,IAAI,EAA1B,IAAgCA,KAAK,IAAI,IAApD;AAAA;AAHJ,GAPoB;AAa5BK,EAAAA,IAAI,EAAE;AACJP,IAAAA,GAAG,EAAE,GADD;AAEJC,IAAAA,KAAK,EAAE,eAACC,KAAD;AAAA,aAAWA,KAAX;AAAA,KAFH;AAGJE,IAAAA,QAAQ,EAAE,kBAACF,KAAD;AAAA,aAAW,CAAC,MAAD,EAAS,MAAT,EAAiBM,QAAjB,CAA0BN,KAA1B,CAAX;AAAA;AAHN;AAbsB,CAAvB","sourcesContent":["/**\n * Copyright (c) 2020-present Kriasoft | MIT License (https://git.io/JUgVL)\n */\n\nimport type { Param, Params } from \"./types\";\n\n/**\n * The list of supported image transformation options including parsing and\n * validation logic.\n */\nexport const params: Params = {\n width: {\n key: \"w\",\n parse: (value) => parseInt(value, 10),\n validate: (value) => !isNaN(value) && value >= 16 && value <= 3840,\n } as Param,\n\n height: {\n key: \"h\",\n parse: (value) => parseInt(value, 10),\n validate: (value) => !isNaN(value) && value >= 16 && value <= 2160,\n } as Param,\n\n crop: {\n key: \"c\",\n parse: (value) => value,\n validate: (value) => [\"crop\", \"fill\"].includes(value),\n } as Param<\"crop\" | \"fill\">,\n};\n"],"file":"params.js"} \ No newline at end of file +{"version":3,"sources":["../src/params.ts"],"names":["params","width","key","parse","value","parseInt","validate","isNaN","height","crop","includes","x","y"],"mappings":";;;;;;;AAAA;;;;AAMA;;;;AAIO,IAAMA,MAAc,GAAG;AAC5BC,EAAAA,KAAK,EAAE;AACLC,IAAAA,GAAG,EAAE,GADA;AAELC,IAAAA,KAAK,EAAE,eAACC,KAAD;AAAA,aAAWC,QAAQ,CAACD,KAAD,EAAQ,EAAR,CAAnB;AAAA,KAFF;AAGLE,IAAAA,QAAQ,EAAE,kBAACF,KAAD;AAAA,aAAW,CAACG,KAAK,CAACH,KAAD,CAAN,IAAiBA,KAAK,IAAI,EAA1B,IAAgCA,KAAK,IAAI,IAApD;AAAA;AAHL,GADqB;AAO5BI,EAAAA,MAAM,EAAE;AACNN,IAAAA,GAAG,EAAE,GADC;AAENC,IAAAA,KAAK,EAAE,eAACC,KAAD;AAAA,aAAWC,QAAQ,CAACD,KAAD,EAAQ,EAAR,CAAnB;AAAA,KAFD;AAGNE,IAAAA,QAAQ,EAAE,kBAACF,KAAD;AAAA,aAAW,CAACG,KAAK,CAACH,KAAD,CAAN,IAAiBA,KAAK,IAAI,EAA1B,IAAgCA,KAAK,IAAI,IAApD;AAAA;AAHJ,GAPoB;AAa5BK,EAAAA,IAAI,EAAE;AACJP,IAAAA,GAAG,EAAE,GADD;AAEJC,IAAAA,KAAK,EAAE,eAACC,KAAD;AAAA,aAAWA,KAAX;AAAA,KAFH;AAGJE,IAAAA,QAAQ,EAAE,kBAACF,KAAD;AAAA,aAAW,CAAC,MAAD,EAAS,MAAT,EAAiBM,QAAjB,CAA0BN,KAA1B,CAAX;AAAA;AAHN,GAbsB;AAmB5BO,EAAAA,CAAC,EAAE;AACDT,IAAAA,GAAG,EAAE,GADJ;AAEDC,IAAAA,KAAK,EAAE,eAACC,KAAD;AAAA,aAAWC,QAAQ,CAACD,KAAD,EAAQ,EAAR,CAAnB;AAAA,KAFN;AAGDE,IAAAA,QAAQ,EAAE,kBAACF,KAAD;AAAA,aAAW,CAACG,KAAK,CAACH,KAAD,CAAjB;AAAA;AAHT,GAnByB;AAyB5BQ,EAAAA,CAAC,EAAE;AACDV,IAAAA,GAAG,EAAE,GADJ;AAEDC,IAAAA,KAAK,EAAE,eAACC,KAAD;AAAA,aAAWC,QAAQ,CAACD,KAAD,EAAQ,EAAR,CAAnB;AAAA,KAFN;AAGDE,IAAAA,QAAQ,EAAE,kBAACF,KAAD;AAAA,aAAW,CAACG,KAAK,CAACH,KAAD,CAAjB;AAAA;AAHT;AAzByB,CAAvB","sourcesContent":["/**\n * Copyright (c) 2020-present Kriasoft | MIT License (https://git.io/JUgVL)\n */\n\nimport type { Param, Params } from \"./types\";\n\n/**\n * The list of supported image transformation options including parsing and\n * validation logic.\n */\nexport const params: Params = {\n width: {\n key: \"w\",\n parse: (value) => parseInt(value, 10),\n validate: (value) => !isNaN(value) && value >= 16 && value <= 3840,\n } as Param,\n\n height: {\n key: \"h\",\n parse: (value) => parseInt(value, 10),\n validate: (value) => !isNaN(value) && value >= 16 && value <= 2160,\n } as Param,\n\n crop: {\n key: \"c\",\n parse: (value) => value,\n validate: (value) => [\"crop\", \"fill\"].includes(value),\n } as Param<\"crop\" | \"fill\">,\n\n x: {\n key: \"x\",\n parse: (value) => parseInt(value, 10),\n validate: (value) => !isNaN(value),\n } as Param,\n\n y: {\n key: \"y\",\n parse: (value) => parseInt(value, 10),\n validate: (value) => !isNaN(value),\n } as Param,\n};\n"],"file":"params.js"} \ No newline at end of file diff --git a/lib/transform.js b/lib/transform.js index a00b861..5256243 100644 --- a/lib/transform.js +++ b/lib/transform.js @@ -24,7 +24,9 @@ function transform(imageStream, transforms) { var state = gm(imageStream); transforms.forEach(function (params) { if (params.width && params.height) { - if (params.crop === "fill") { + if (params.y !== undefined && params.y !== undefined && params.crop === "crop") { + state = state.crop(params.width, params.height, params.x, params.y); + } else if (params.crop === "fill") { state = state.resize(params.width, params.height, "^").gravity("Center").extent(params.width, params.height); } else { state = state.resize(params.width, params.height, "!"); diff --git a/lib/transform.js.map b/lib/transform.js.map index 180aad3..7fb3c74 100644 --- a/lib/transform.js.map +++ b/lib/transform.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/transform.ts"],"names":["gm","GraphicsMagick","subClass","imageMagick","transform","imageStream","transforms","state","forEach","params","width","height","crop","resize","gravity","extent","undefined"],"mappings":";;;;;;;AAIA;;;;AAJA;;;AAOA,IAAMA,EAAE,GAAGC,eAAeC,QAAf,CAAwB;AAAEC,EAAAA,WAAW,EAAE;AAAf,CAAxB,CAAX;AAEA;;;;;AAGO,SAASC,SAAT,CACLC,WADK,EAELC,UAFK,EAGiB;AACtB,MAAIC,KAAK,GAAGP,EAAE,CAACK,WAAD,CAAd;AAEAC,EAAAA,UAAU,CAACE,OAAX,CAAmB,UAACC,MAAD,EAAY;AAC7B,QAAIA,MAAM,CAACC,KAAP,IAAgBD,MAAM,CAACE,MAA3B,EAAmC;AACjC,UAAIF,MAAM,CAACG,IAAP,KAAgB,MAApB,EAA4B;AAC1BL,QAAAA,KAAK,GAAGA,KAAK,CACVM,MADK,CACEJ,MAAM,CAACC,KADT,EACgBD,MAAM,CAACE,MADvB,EAC+B,GAD/B,EAELG,OAFK,CAEG,QAFH,EAGLC,MAHK,CAGEN,MAAM,CAACC,KAHT,EAGgBD,MAAM,CAACE,MAHvB,CAAR;AAID,OALD,MAKO;AACLJ,QAAAA,KAAK,GAAGA,KAAK,CAACM,MAAN,CAAaJ,MAAM,CAACC,KAApB,EAA2BD,MAAM,CAACE,MAAlC,EAA0C,GAA1C,CAAR;AACD;AACF,KATD,MASO,IAAIF,MAAM,CAACC,KAAX,EAAkB;AACvBH,MAAAA,KAAK,GAAGA,KAAK,CAACM,MAAN,CAAaJ,MAAM,CAACC,KAApB,EAA2BM,SAA3B,CAAR;AACD,KAFM,MAEA,IAAIP,MAAM,CAACE,MAAX,EAAmB;AACxB;;AACA;AACAJ,MAAAA,KAAK,GAAGA,KAAK,CAACM,MAAN,CAAaG,SAAb,EAAwBP,MAAM,CAACE,MAA/B,CAAR;AACD;AACF,GAjBD;AAmBA,SAAOJ,KAAP;AACD","sourcesContent":["/**\n * Copyright (c) 2020-present Kriasoft | MIT License (https://git.io/JUgVL)\n */\n\nimport GraphicsMagick from \"gm\";\nimport type { Transform } from \"./types\";\n\nconst gm = GraphicsMagick.subClass({ imageMagick: true });\n\n/**\n * Transforms an image stream using {@link https://github.com/aheckmann/gm#readme|ImageMagick}.\n */\nexport function transform(\n imageStream: NodeJS.ReadableStream,\n transforms: Transform[],\n): GraphicsMagick.State {\n let state = gm(imageStream);\n\n transforms.forEach((params) => {\n if (params.width && params.height) {\n if (params.crop === \"fill\") {\n state = state\n .resize(params.width, params.height, \"^\")\n .gravity(\"Center\")\n .extent(params.width, params.height);\n } else {\n state = state.resize(params.width, params.height, \"!\");\n }\n } else if (params.width) {\n state = state.resize(params.width, undefined);\n } else if (params.height) {\n /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */\n /* @ts-ignore */\n state = state.resize(undefined, params.height);\n }\n });\n\n return state;\n}\n"],"file":"transform.js"} \ No newline at end of file +{"version":3,"sources":["../src/transform.ts"],"names":["gm","GraphicsMagick","subClass","imageMagick","transform","imageStream","transforms","state","forEach","params","width","height","y","undefined","crop","x","resize","gravity","extent"],"mappings":";;;;;;;AAIA;;;;AAJA;;;AAOA,IAAMA,EAAE,GAAGC,eAAeC,QAAf,CAAwB;AAAEC,EAAAA,WAAW,EAAE;AAAf,CAAxB,CAAX;AAEA;;;;;AAGO,SAASC,SAAT,CACLC,WADK,EAELC,UAFK,EAGiB;AACtB,MAAIC,KAAK,GAAGP,EAAE,CAACK,WAAD,CAAd;AAEAC,EAAAA,UAAU,CAACE,OAAX,CAAmB,UAACC,MAAD,EAAY;AAC7B,QAAIA,MAAM,CAACC,KAAP,IAAgBD,MAAM,CAACE,MAA3B,EAAmC;AACjC,UACEF,MAAM,CAACG,CAAP,KAAaC,SAAb,IACAJ,MAAM,CAACG,CAAP,KAAaC,SADb,IAEAJ,MAAM,CAACK,IAAP,KAAgB,MAHlB,EAIE;AACAP,QAAAA,KAAK,GAAGA,KAAK,CAACO,IAAN,CAAWL,MAAM,CAACC,KAAlB,EAAyBD,MAAM,CAACE,MAAhC,EAAwCF,MAAM,CAACM,CAA/C,EAAkDN,MAAM,CAACG,CAAzD,CAAR;AACD,OAND,MAMO,IAAIH,MAAM,CAACK,IAAP,KAAgB,MAApB,EAA4B;AACjCP,QAAAA,KAAK,GAAGA,KAAK,CACVS,MADK,CACEP,MAAM,CAACC,KADT,EACgBD,MAAM,CAACE,MADvB,EAC+B,GAD/B,EAELM,OAFK,CAEG,QAFH,EAGLC,MAHK,CAGET,MAAM,CAACC,KAHT,EAGgBD,MAAM,CAACE,MAHvB,CAAR;AAID,OALM,MAKA;AACLJ,QAAAA,KAAK,GAAGA,KAAK,CAACS,MAAN,CAAaP,MAAM,CAACC,KAApB,EAA2BD,MAAM,CAACE,MAAlC,EAA0C,GAA1C,CAAR;AACD;AACF,KAfD,MAeO,IAAIF,MAAM,CAACC,KAAX,EAAkB;AACvBH,MAAAA,KAAK,GAAGA,KAAK,CAACS,MAAN,CAAaP,MAAM,CAACC,KAApB,EAA2BG,SAA3B,CAAR;AACD,KAFM,MAEA,IAAIJ,MAAM,CAACE,MAAX,EAAmB;AACxB;;AACA;AACAJ,MAAAA,KAAK,GAAGA,KAAK,CAACS,MAAN,CAAaH,SAAb,EAAwBJ,MAAM,CAACE,MAA/B,CAAR;AACD;AACF,GAvBD;AAyBA,SAAOJ,KAAP;AACD","sourcesContent":["/**\n * Copyright (c) 2020-present Kriasoft | MIT License (https://git.io/JUgVL)\n */\n\nimport GraphicsMagick from \"gm\";\nimport type { Transform } from \"./types\";\n\nconst gm = GraphicsMagick.subClass({ imageMagick: true });\n\n/**\n * Transforms an image stream using {@link https://github.com/aheckmann/gm#readme|ImageMagick}.\n */\nexport function transform(\n imageStream: NodeJS.ReadableStream,\n transforms: Transform[],\n): GraphicsMagick.State {\n let state = gm(imageStream);\n\n transforms.forEach((params) => {\n if (params.width && params.height) {\n if (\n params.y !== undefined &&\n params.y !== undefined &&\n params.crop === \"crop\"\n ) {\n state = state.crop(params.width, params.height, params.x, params.y);\n } else if (params.crop === \"fill\") {\n state = state\n .resize(params.width, params.height, \"^\")\n .gravity(\"Center\")\n .extent(params.width, params.height);\n } else {\n state = state.resize(params.width, params.height, \"!\");\n }\n } else if (params.width) {\n state = state.resize(params.width, undefined);\n } else if (params.height) {\n /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */\n /* @ts-ignore */\n state = state.resize(undefined, params.height);\n }\n });\n\n return state;\n}\n"],"file":"transform.js"} \ No newline at end of file diff --git a/lib/types.d.ts b/lib/types.d.ts index f3eab16..d089560 100644 --- a/lib/types.d.ts +++ b/lib/types.d.ts @@ -6,6 +6,8 @@ export declare type Transform = { width?: number; height?: number; crop?: "crop" | "fill"; + x?: number; + y?: number; }; export declare type Param = { readonly key: string; diff --git a/package.json b/package.json index 36959f1..cd36e8c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "image-resizing", - "version": "0.1.0", + "version": "0.1.1", "description": "Node.js backend (middleware) for image manipulation needs (transform, resize, optimize).", "keywords": [ "cloud functions", diff --git a/src/__image_snapshots__/transform-test-ts-x-260-y-160-w-120-h-80-c-crop-png-1-snap.png b/src/__image_snapshots__/transform-test-ts-x-260-y-160-w-120-h-80-c-crop-png-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..cde5ef2312381c30e6bf4a2fddf28c4cc2801ba6 GIT binary patch literal 50617 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 rahGu@jX value, validate: (value) => ["crop", "fill"].includes(value), } as Param<"crop" | "fill">, + + x: { + key: "x", + parse: (value) => parseInt(value, 10), + validate: (value) => !isNaN(value), + } as Param, + + y: { + key: "y", + parse: (value) => parseInt(value, 10), + validate: (value) => !isNaN(value), + } as Param, }; diff --git a/src/parse.test.ts b/src/parse.test.ts index a8e7fda..24066fb 100644 --- a/src/parse.test.ts +++ b/src/parse.test.ts @@ -77,3 +77,25 @@ it("/img/w_80,h_60,c_fill/w_60,h_40/example.jpg", () => { } `); }); + +it("/img/x_10,y_5,w_80,h_60,c_crop/example.jpg", () => { + const result = parseUrlPath( + "/img/x_10,y_5,w_80,h_60,c_crop/example.jpg", + params, + ); + expect(result).toMatchInlineSnapshot(` + Object { + "source": "img/example.jpg", + "target": "img/example__x_10,y_5,w_80,h_60,c_crop.jpg", + "transforms": Array [ + Object { + "crop": "crop", + "height": 60, + "width": 80, + "x": 10, + "y": 5, + }, + ], + } + `); +}); diff --git a/src/transform.test.ts b/src/transform.test.ts index 62886c6..58c8ca6 100644 --- a/src/transform.test.ts +++ b/src/transform.test.ts @@ -96,3 +96,20 @@ it("h_60.png", (done) => { }, ); }); + +it("x_260,y_160,w_120,h_80,c_crop.png", (done) => { + const transforms: Transform[] = [ + { x: 260, y: 160, width: 120, height: 80, crop: "crop" }, + ]; + transform(fs.createReadStream("test.jpg"), transforms).toBuffer( + "png", + (err, image) => { + if (err) { + done(err); + } else { + expect(image).toMatchImageSnapshot(); + done(); + } + }, + ); +}); diff --git a/src/transform.ts b/src/transform.ts index d36e2a1..5487863 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -18,7 +18,13 @@ export function transform( transforms.forEach((params) => { if (params.width && params.height) { - if (params.crop === "fill") { + if ( + params.y !== undefined && + params.y !== undefined && + params.crop === "crop" + ) { + state = state.crop(params.width, params.height, params.x, params.y); + } else if (params.crop === "fill") { state = state .resize(params.width, params.height, "^") .gravity("Center") diff --git a/src/types.ts b/src/types.ts index 3f6eca8..d770e22 100644 --- a/src/types.ts +++ b/src/types.ts @@ -8,6 +8,8 @@ export type Transform = { width?: number; height?: number; crop?: "crop" | "fill"; + x?: number; + y?: number; }; export type Param = {