Repository: kaliber5/ember-responsive-image
Pull request #314 (2021-07-23 13:16:10)

Support a custom quality setting for cloudinary and imgix providers


Patch:
diff --git a/addon/helpers/responsive-image-cloudinary-provider.ts b/addon/helpers/responsive-image-cloudinary-provider.ts
index 19337387..de7ec3d4 100644
--- a/addon/helpers/responsive-image-cloudinary-provider.ts
+++ b/addon/helpers/responsive-image-cloudinary-provider.ts
@@ -12,6 +12,7 @@ interface CloudinaryConfig {
 interface CloudinaryOptions {
   transformations?: string;
   formats?: ImageType[];
+  quality?: number;
 }
 
 const URL_REGEX = /https?:/;
@@ -43,7 +44,7 @@ export const provider = (
   return {
     imageTypes: options.formats ?? ['png', 'jpeg', 'webp', 'avif'],
     imageUrlFor(width: number, type: ImageType = 'jpeg'): string {
-      let resizeParams = `w_${width},c_limit,q_auto`;
+      let resizeParams = `w_${width},c_limit,q_${options.quality ?? 'auto'}`;
       if (deliveryType !== 'upload') {
         resizeParams += `,f_${type}`;
       }
diff --git a/addon/helpers/responsive-image-imgix-provider.ts b/addon/helpers/responsive-image-imgix-provider.ts
index 7ebd513f..6a5afee4 100644
--- a/addon/helpers/responsive-image-imgix-provider.ts
+++ b/addon/helpers/responsive-image-imgix-provider.ts
@@ -12,6 +12,7 @@ interface ImgixConfig {
 interface ImgixOptions {
   params?: Record<string, string | number>;
   formats?: ImageType[];
+  quality?: number;
 }
 
 const formatMap: Record<string, string> = {
@@ -36,6 +37,10 @@ export const provider = (
       params.set('w', String(width));
       params.set('fit', 'max');
 
+      if (options.quality) {
+        params.set('q', String(options.quality));
+      }
+
       if (options.params) {
         for (const [key, value] of Object.entries(options.params)) {
           params.set(key, String(value));
diff --git a/docs/providers/cloudinary.md b/docs/providers/cloudinary.md
index 35346424..05ca7d6f 100644
--- a/docs/providers/cloudinary.md
+++ b/docs/providers/cloudinary.md
@@ -16,6 +16,15 @@ you can add your own [Cloudinary transformations](https://cloudinary.com/documen
 <ResponsiveImage @src={{responsive-image-cloudinary-provider "path/to/uploaded/image.jpg" transformations="e_sharpen:400,e_grayscale"}}/>
 ```
 
+### Quality
+
+Use the `quality` parameter to pass a custom [quality](https://cloudinary.com/documentation/transformation_reference#q_quality) setting 
+instead of the default `auto`:
+
+```hbs
+<ResponsiveImage @src={{responsive-image-cloudinary-provider "path/to/uploaded/image.jpg" quality=50}}/>
+```
+
 ### Image formats
 
 By default, all supported image formats (PNG, JPEG, WEBP, AVIF) are referenced in the generated `<source>` tags.
diff --git a/docs/providers/imgix.md b/docs/providers/imgix.md
index ea583fb2..a78a7576 100644
--- a/docs/providers/imgix.md
+++ b/docs/providers/imgix.md
@@ -15,6 +15,14 @@ you can add your own [imgix parameters](https://docs.imgix.com/apis/rendering) b
 <ResponsiveImage @src={{responsive-image-imgix-provider "path/to/image.jpg" params=(hash monochrome="44768B" px=10)}}/>
 ```
 
+### Quality
+
+Use the `quality` parameter to pass a custom [quality](https://docs.imgix.com/apis/rendering/format/q) setting
+instead of the default of `75`:
+
+```hbs
+<ResponsiveImage @src={{responsive-image-imgix-provider "path/to/image.jpg" quality=50}}/>
+```
 
 ### Image formats
 


Test patch:
diff --git a/tests/integration/helpers/responsive-image-cloudinary-provider-test.ts b/tests/integration/helpers/responsive-image-cloudinary-provider-test.ts
index 59140dd4..b220aa35 100644
--- a/tests/integration/helpers/responsive-image-cloudinary-provider-test.ts
+++ b/tests/integration/helpers/responsive-image-cloudinary-provider-test.ts
@@ -80,6 +80,19 @@ module(
       assert.deepEqual(data.imageTypes, ['webp', 'avif']);
     });
 
+    test('it supports custom quality setting', async function (assert) {
+      await render(
+        hbs`{{dump (responsive-image-cloudinary-provider "samples/animals/three-dogs" quality=50)}}`
+      );
+
+      const data = getData() as ProviderResult;
+
+      assert.equal(
+        data.imageUrlFor(100, 'jpeg'),
+        'https://res.cloudinary.com/kaliber5/image/upload/w_100,c_limit,q_50/samples/animals/three-dogs.jpeg'
+      );
+    });
+
     test('it supports remote fetching', async function (assert) {
       await render(
         hbs`{{dump (responsive-image-cloudinary-provider "https://www.example.com/image.jpg")}}`
diff --git a/tests/integration/helpers/responsive-image-imgix-provider-test.ts b/tests/integration/helpers/responsive-image-imgix-provider-test.ts
index b54387be..8d970d3f 100644
--- a/tests/integration/helpers/responsive-image-imgix-provider-test.ts
+++ b/tests/integration/helpers/responsive-image-imgix-provider-test.ts
@@ -66,5 +66,18 @@ module(
 
       assert.deepEqual(data.imageTypes, ['webp', 'jpeg']);
     });
+
+    test('it supports custom quality setting', async function (assert) {
+      await render(
+        hbs`{{dump (responsive-image-imgix-provider "foo/bar.jpg" quality=50)}}`
+      );
+
+      const data = getData() as ProviderResult;
+
+      assert.equal(
+        data.imageUrlFor(100, 'jpeg'),
+        'https://kaliber5.imgix.net/foo/bar.jpg?fm=jpg&w=100&fit=max&q=50'
+      );
+    });
   }
 );