Skip to content

Commit

Permalink
feat: add ImageEngine provider (#456)
Browse files Browse the repository at this point in the history
  • Loading branch information
kamermans committed Jan 31, 2022
1 parent ad7c74c commit 3f00cf3
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 2 deletions.
82 changes: 82 additions & 0 deletions docs/content/en/4.providers/imageengine.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
title: ImageEngine Provider
description: 'Nuxt Image has first class integration with ImageEngine'
navigation:
title: ImageEngine
---

Integration between [ImageEngine](https://imageengine.io/) and the image module.

At a minimum, you must configure the `imageengine` provider with the `baseURL` set to your ImageEngine Delivery Address:

```js{}[nuxt.config.js]
export default {
image: {
imageengine: {
baseURL: 'https://xxxxx.imgeng.in'
}
}
}
```

## ImageEngine `fit` values

The [standard values for `fit` property](/components/nuxt-img#fit) map onto [ImageEngine Directives](https://imageengine.io/docs/directives) as follows:

* `cover`: `m_cropbox`
* `contain`: `m_letterbox`
* `fill`: `m_stretch`
* `inside`: `m_box`, this is the default fit method for the ImageEngine provider.
* `outside`: This fit method is not supported and functions the same as `inside`.

## ImageEngine modifiers

In addition to the [standard modifiers](/components/nuxt-img#modifiers), you can also use all [ImageEngine Directives](https://imageengine.io/docs/directives) by adding them to the `modifiers` property with the following attribute names:

* `format`: `f` directive
* `fit`: `m` directive
* `passThrough`: `pass` directive
* `sharpen`: `s` directive
* `rotate`: `r` directive
* `screenPercent`: `pc` directive
* `crop`: `cr` directive
* `inline`: `in` directive
* `metadata`: `meta` directive

> Note that the standard `quality` attribute is converted to the ImageEngine `cmpr` compression directive. `quality` is the opposite of compression, so 80% quality equals 20% compression. Since ImageEngine automatically adapts image quality the visitor's device, browser and network quality, it is recommended that you do not explicitly set the quality. If you want to completely disable all optimizations to an image, you should use `:modifiers="{ passThrough: 'true' }"`, which will serve the unaltered image.
Example 1: Cropping an image to a width and height of 100x80, starting 10 pixels from the top and 20 pixels from the left:

```html
<nuxt-img
provider="imageengine"
src="/some-image.jpg"
width="100"
height="80"
:modifiers="{ cr: '100,80,10,20' }"
/>
```

Example 2: Instruct ImageEngine to keep the image's EXIF metadata (which is normally removed to reduce the image byte size):

```html
<nuxt-img
provider="imageengine"
src="/some-image.jpg"
width="100"
height="80"
:modifiers="{ meta: 'true' }"
/>
```

## ImageEngine best practices

### Automatic format and quality detection

ImageEngine automatically detects the best format and quality for your image based on the characteristics of the specific device that requested it.

This feature is very effective and it is not recommended that you disable it, but if you must, you can manually specify the format (ex: `format='webp'`) and quality (`quality='80'`).

### ImageEngine settings

ImageEngine allows you to set all of the modifiers/directives in the ImageEngine control panel under advanced settings. This is a good place to set default adjustments since you can modify them without having to make changes to your Nuxt codebase. If a directive is set in both Nuxt and the ImageEngine User-Adjustable Settings, the value in Nuxt takes priority.
3 changes: 3 additions & 0 deletions playground/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ export default <NuxtConfig> {
vercel: {
baseURL: 'https://image-component.nextjs.gallery/_next/image'
},
imageengine: {
baseURL: 'https://abc123.imgeng.in'
},
providers: {
custom: {
provider: '~/providers/custom',
Expand Down
13 changes: 13 additions & 0 deletions playground/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,19 @@ export const providers: Provider[] = [
}
]
},
// imageengine
{
name: 'imageengine',
samples: [
{
src: '/images/image.jpg',
width: 300,
height: 300,
fit: 'inside',
modifiers: { metadata: 'true', sharpen: 10 }
}
]
},
// Glide
{
name: 'glide',
Expand Down
3 changes: 2 additions & 1 deletion src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ const BuiltInProviders = [
'twicpics',
'storyblok',
'unsplash',
'vercel'
'vercel',
'imageengine'
]

export const providerSetup: Record<string, ProviderSetup> = {
Expand Down
53 changes: 53 additions & 0 deletions src/runtime/providers/imageengine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { joinURL } from 'ufo'
import type { ProviderGetImage } from 'src'
import { createOperationsGenerator } from '~image'

export const operationsGenerator = createOperationsGenerator({
keyMap: {
width: 'w',
height: 'h',
quality: 'cmpr',
format: 'f',
fit: 'm',
passThrough: 'pass',
sharpen: 's',
rotate: 'r',
screenPercent: 'pc',
crop: 'cr',
inline: 'in',
metadata: 'meta'
},
valueMap: {
fit: {
cover: 'cropbox',
contain: 'letterbox',
fill: 'stretch',
inside: 'box',
outside: 'box'
},
format: {
jpeg: 'jpg'
},
quality (value: string) {
// ImageEngine uses compression, which is the opposite of quality,
// so quality 90 == compression 10. Convert using: compression = 100 - quality
let compression = (100 - parseInt(value, 10))

// ImageEngine's values are 0-99 (100 values), whereas Nuxt uses 0-100 (101 values)
// so we clip the upper bound at 99 if 100 was requested.
if (compression === 100) {
compression = 99
}
return compression.toString()
}
},
joinWith: '/',
formatter: (key, value) => `${key}_${value}`
})

export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL = '/' } = {}) => {
const operations = operationsGenerator(modifiers)
return {
url: joinURL(baseURL, src + (operations ? ('?imgeng=/' + operations) : ''))
}
}
3 changes: 2 additions & 1 deletion src/types/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ export interface ImageProviders {
imgix?: any
prismic?: any
twicpics?: any
storyblok?: any,
storyblok?: any
imageengine?: any,
ipx?: Partial<IPXOptions>
static?: Partial<IPXOptions>
}
Expand Down
6 changes: 6 additions & 0 deletions test/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const images = [
fastly: { url: '/test.png' },
glide: { url: '/test.png' },
imgix: { url: '/test.png' },
imageengine: { url: '/test.png' },
unsplash: { url: '/test.png' },
imagekit: { url: '/test.png' },
netlify: { url: '/test.png' },
Expand All @@ -22,6 +23,7 @@ export const images = [
fastly: { url: '/test.png?width=200' },
glide: { url: '/test.png?w=200' },
imgix: { url: '/test.png?w=200' },
imageengine: { url: '/test.png?imgeng=/w_200' },
unsplash: { url: '/test.png?w=200' },
imagekit: { url: '/test.png?tr=w-200' },
netlify: { url: '/test.png?w=200&nf_resize=fit' },
Expand All @@ -37,6 +39,7 @@ export const images = [
fastly: { url: '/test.png?height=200' },
glide: { url: '/test.png?h=200' },
imgix: { url: '/test.png?h=200' },
imageengine: { url: '/test.png?imgeng=/h_200' },
unsplash: { url: '/test.png?h=200' },
imagekit: { url: '/test.png?tr=h-200' },
netlify: { url: '/test.png?h=200&nf_resize=fit' },
Expand All @@ -52,6 +55,7 @@ export const images = [
fastly: { url: '/test.png?width=200&height=200' },
glide: { url: '/test.png?w=200&h=200' },
imgix: { url: '/test.png?w=200&h=200' },
imageengine: { url: '/test.png?imgeng=/w_200/h_200' },
unsplash: { url: '/test.png?w=200&h=200' },
imagekit: { url: '/test.png?tr=w-200,h-200' },
netlify: { url: '/test.png?w=200&h=200&nf_resize=fit' },
Expand All @@ -67,6 +71,7 @@ export const images = [
fastly: { url: '/test.png?width=200&height=200&fit=bounds' },
glide: { url: '/test.png?w=200&h=200&fit=contain' },
imgix: { url: '/test.png?w=200&h=200&fit=fill' },
imageengine: { url: '/test.png?imgeng=/w_200/h_200/m_letterbox' },
unsplash: { url: '/test.png?w=200&h=200&fit=fill' },
imagekit: { url: '/test.png?tr=w-200,h-200,cm-pad_resize' },
netlify: { url: '/test.png?w=200&h=200&nf_resize=fit' },
Expand All @@ -82,6 +87,7 @@ export const images = [
fastly: { url: '/test.png?width=200&height=200&fit=bounds&format=jpeg' },
glide: { url: '/test.png?w=200&h=200&fit=contain&fm=jpeg' },
imgix: { url: '/test.png?w=200&h=200&fit=fill&fm=jpeg' },
imageengine: { url: '/test.png?imgeng=/w_200/h_200/m_letterbox/f_jpg' },
unsplash: { url: '/test.png?w=200&h=200&fit=fill&fm=jpeg' },
imagekit: { url: '/test.png?tr=w-200,h-200,cm-pad_resize,f-jpeg' },
netlify: { url: '/test.png?w=200&h=200&nf_resize=fit' },
Expand Down
32 changes: 32 additions & 0 deletions test/unit/providers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as twicpics from '~/runtime/providers/twicpics'
import * as fastly from '~/runtime/providers/fastly'
import * as glide from '~/runtime/providers/glide'
import * as imgix from '~/runtime/providers/imgix'
import * as imageengine from '~/runtime/providers/imageengine'
import * as unsplash from '~/runtime/providers/unsplash'
import * as imagekit from '~/runtime/providers/imagekit'
import * as netlify from '~/runtime/providers/netlify'
Expand Down Expand Up @@ -137,6 +138,37 @@ describe('Providers', () => {
}
})

test('imageengine', () => {
const providerOptions = {
baseURL: ''
}

for (const image of images) {
const [src, modifiers] = image.args
const generated = imageengine.getImage(src, { modifiers, ...providerOptions }, emptyContext)
expect(generated).toMatchObject(image.imageengine)
}
})

test('imageengine compression', () => {
const providerOptions = {
baseURL: 'https://foo.bar.com'
}
const generated = imageengine.getImage(
'/test.jpg',
{
modifiers: {
width: 150,
quality: 0
},
...providerOptions
}, emptyContext
)
expect(generated).toMatchObject({
url: 'https://foo.bar.com/test.jpg?imgeng=/w_150/cmpr_99'
})
})

test('unsplash', () => {
const providerOptions = {
baseURL: ''
Expand Down

0 comments on commit 3f00cf3

Please sign in to comment.