From 71c8c4cc2c9bfd73296c5df2a51b414dad5faade Mon Sep 17 00:00:00 2001 From: Pyll Gomez <57198612+workatease@users.noreply.github.com> Date: Mon, 22 Mar 2021 20:08:44 -0400 Subject: [PATCH] Assets quality parameter #4557 (#4620) * Rotate JPG image on upload #4206 * fixes #3949 width/height generated for gif and tif * API hooks for event added for auth.login #4079 * updated doc for api hooks for new auth.login event * Style tweaks * Update docs * Tweak docs some more * Spelling error * Allow non-required flags and pass to hook * SDK - Persistent login refresh fixes #4113 * Fixed #4145 SDK, Token Expired error * Spell check * Docs Spell check * Docs Spell check * Docs Spell check * update docs for sdk-js * To delete all expired session from db on login * corrected the condition for the delete * changed the from Date.now to new date . * Move it inline * fixes issue 4557 for asset quality for thumbnail * asset documentation is updated Co-authored-by: rijkvanzanten --- api/src/constants.ts | 2 +- api/src/controllers/assets.ts | 6 ++++++ api/src/services/assets.ts | 11 +++++++---- api/src/types/assets.ts | 1 + docs/reference/api/assets.md | 8 +++++--- 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/api/src/constants.ts b/api/src/constants.ts index 4cbeb82794..81bd626842 100644 --- a/api/src/constants.ts +++ b/api/src/constants.ts @@ -36,7 +36,7 @@ export const SYSTEM_ASSET_ALLOW_LIST: Transformation[] = [ }, ]; -export const ASSET_TRANSFORM_QUERY_KEYS = ['key', 'width', 'height', 'fit', 'withoutEnlargement']; +export const ASSET_TRANSFORM_QUERY_KEYS = ['key', 'width', 'height', 'fit', 'withoutEnlargement', 'quality']; export const FILTER_VARIABLES = ['$NOW', '$CURRENT_USER', '$CURRENT_ROLE']; diff --git a/api/src/controllers/assets.ts b/api/src/controllers/assets.ts index 9a3dcb6980..7a501cb461 100644 --- a/api/src/controllers/assets.ts +++ b/api/src/controllers/assets.ts @@ -63,6 +63,12 @@ router.get( if (transformation.hasOwnProperty('key') && Object.keys(transformation).length > 1) { throw new InvalidQueryException(`You can't combine the "key" query parameter with any other transformation.`); } + if ( + transformation.hasOwnProperty('quality') && + (Number(transformation.quality) < 1 || Number(transformation.quality) > 100) + ) { + throw new InvalidQueryException(`"quality" Parameter has to between 1 to 100`); + } const systemKeys = SYSTEM_ASSET_ALLOW_LIST.map((transformation) => transformation.key); const allKeys: string[] = [ diff --git a/api/src/services/assets.ts b/api/src/services/assets.ts index 88c6b87430..3caf069b88 100644 --- a/api/src/services/assets.ts +++ b/api/src/services/assets.ts @@ -47,7 +47,7 @@ export class AssetsService { const assetFilename = path.basename(file.filename_disk, path.extname(file.filename_disk)) + - this.getAssetSuffix(resizeOptions) + + this.getAssetSuffix(transformation) + path.extname(file.filename_disk); const { exists } = await storage.disk(file.storage).exists(assetFilename); @@ -62,6 +62,9 @@ export class AssetsService { const readStream = storage.disk(file.storage).getStream(file.filename_disk, range); const transformer = sharp().rotate().resize(resizeOptions); + if (transformation.quality) { + transformer.toFormat(type.substring(6), { quality: Number(transformation.quality) }); + } await storage.disk(file.storage).put(assetFilename, readStream.pipe(transformer)); @@ -89,12 +92,12 @@ export class AssetsService { return resizeOptions; } - private getAssetSuffix(resizeOptions: ResizeOptions) { - if (Object.keys(resizeOptions).length === 0) return ''; + private getAssetSuffix(transformation: Transformation) { + if (Object.keys(transformation).length === 0) return ''; return ( '__' + - Object.entries(resizeOptions) + Object.entries(transformation) .sort((a, b) => (a[0] > b[0] ? 1 : -1)) .map((e) => e.join('_')) .join(',') diff --git a/api/src/types/assets.ts b/api/src/types/assets.ts index 920acc6137..8fa6718c59 100644 --- a/api/src/types/assets.ts +++ b/api/src/types/assets.ts @@ -4,6 +4,7 @@ export type Transformation = { height?: number; // height fit?: 'cover' | 'contain' | 'inside' | 'outside'; // fit withoutEnlargement?: boolean; // Without Enlargement + quality?: number; }; // @NOTE Keys used in Transformation should match ASSET_GENERATION_QUERY_KEYS in constants.ts diff --git a/docs/reference/api/assets.md b/docs/reference/api/assets.md index d9cf366ac8..ce111641e0 100644 --- a/docs/reference/api/assets.md +++ b/docs/reference/api/assets.md @@ -26,7 +26,7 @@ permissions and other built-in features. Fetching thumbnails is as easy as adding query parameters to the original file's URL. If a requested thumbnail doesn't yet exist, it is dynamically generated and immediately returned. When requesting a thumbnail, the following parameters -are all required. +are all required, supports thumbnail for `jpeg`,`png` and `webp` - **`fit`** — The **fit** of the thumbnail while always preserving the aspect ratio, can be any of the following options: @@ -38,7 +38,7 @@ are all required. and height - **`width`** — The **width** of the thumbnail in pixels - **`height`** — The **height** of the thumbnail in pixels -- **`quality`** — The **quality** of the thumbnail (`0` to `100`) +- **`quality`** — The **quality** of the thumbnail (`1` to `100`) is `Optional` - **`withoutEnlargement`** — Disable image up-scaling - **`download`** — Add `Content-Disposition` header and force browser to download file @@ -86,7 +86,9 @@ four possible qualities (200x200 cover) to visually compare the balance between ## Downloading a File To download an asset with the correct filename, you need to add the `?download` query parameter to the request and the -`download` attribute to your anchor tag. This will ensure the appropriate [Content-Disposition](https://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html) headers are added. Without this, the download will work on the _same_ domain, however it will have the file's "id" as the filename for cross-origin requests. +`download` attribute to your anchor tag. This will ensure the appropriate +[Content-Disposition](https://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html) headers are added. Without this, the +download will work on the _same_ domain, however it will have the file's "id" as the filename for cross-origin requests. Example: