diff --git a/docs/content/3.providers/edgeone-pages.md b/docs/content/3.providers/edgeone-pages.md new file mode 100644 index 000000000..8e02af1b4 --- /dev/null +++ b/docs/content/3.providers/edgeone-pages.md @@ -0,0 +1,143 @@ +--- +title: EdgeOne Pages +description: Use EdgeOne Pages imageMogr2 for image processing. +links: + - label: Source + icon: i-simple-icons-github + to: https://github.com/nuxt/image/blob/main/src/runtime/providers/edgeonePages.ts + size: xs +--- + +Integration with EdgeOne Pages image processing (`imageMogr2`). Supports resizing, cropping, rotation, format conversion, quality control, Gaussian blur, sharpening, and more. + +## Setup + +Set the site domain as `baseURL` in `nuxt.config.ts`: + +```ts [nuxt.config.ts] +export default defineNuxtConfig({ + image: { + edgeonePages: { + baseURL: 'https://.edgeone.app' + } + } +}) +``` + +::note +`baseURL` should point to a publicly accessible EdgeOne Pages domain. No trailing slash is needed. +:: + +## Basic Usage + +```vue + +``` + +## Standard Modifiers + +All 7 standard NuxtImg modifiers are mapped to imageMogr2: + +| Modifier | Mapping | Description | +|---|---|---| +| `width` / `height` | `/thumbnail/x` | Proportional scaling, affected by `fit` | +| `fit` | thumbnail suffix | `contain` → `x`, `cover` → `!xr`, `fill` → `x!` | +| `quality` | `/quality/` | Quality 1-100 | +| `format` | `/format/` | Output format, `jpeg` is auto-mapped to `jpg` | +| `background` | `/pad/1/color/` | Used with scaling, fills background color | +| `blur` | `/blur/x` | Gaussian blur | + +## Extended Modifiers + +Pass EdgeOne Pages-specific image processing parameters via the `:modifiers` prop: + +| Modifier | Mapping | Description | +|---|---|---| +| `crop` | `/crop/x` | Regular crop (independent of scaling) | +| `gravity` | `/gravity/` | Crop anchor: center, north, south, west, east, northwest, etc. | +| `dx` / `dy` | `/dx//dy/` | Crop offset | +| `iradius` | `/iradius/` | Inscribed circle crop radius | +| `scrop` | `/scrop/x` | Smart face crop | +| `rotate` | `/rotate/` | Clockwise rotation 0-360° | +| `autoOrient` | `/auto-orient` | Auto-rotate based on EXIF orientation | +| `sharpen` | `/sharpen/` | Sharpen | +| `strip` | `/strip` | Strip EXIF metadata | +| `interlace` | `/interlace/1` | Progressive JPEG/GIF | +| `pad` | `/pad/1` | Pad mode (used with background) | + +## Examples + +### Resize + Format + Quality + +```vue + +``` + +Generated URL: `?imageMogr2/thumbnail/!1200x500r/quality/85/format/webp` + +### Crop + Gravity + +```vue + +``` + +Generated URL: `?imageMogr2/crop/300x300/gravity/center` + +### Rotate + Sharpen + Strip Metadata + +```vue + +``` + +Generated URL: `?imageMogr2/rotate/90/sharpen/70/strip` + +### Gaussian Blur (Placeholder Effect) + +```vue + +``` + +Generated URL: `?imageMogr2/thumbnail/100x/quality/10/blur/20x20` + +### Smart Face Crop + +```vue + +``` + +Generated URL: `?imageMogr2/scrop/200x200` + +## References + +- [EdgeOne Pages Image Processing](https://edgeone.ai/document/162498) diff --git a/playground/app/pages/edgeone-pages.vue b/playground/app/pages/edgeone-pages.vue new file mode 100644 index 000000000..80ba1e0ac --- /dev/null +++ b/playground/app/pages/edgeone-pages.vue @@ -0,0 +1,393 @@ + + + + + diff --git a/playground/app/providers.ts b/playground/app/providers.ts index 6417d39fb..c66a42c79 100644 --- a/playground/app/providers.ts +++ b/playground/app/providers.ts @@ -1116,6 +1116,49 @@ export const providers: Provider[] = [ }, ], }, + // EdgeOne Pages + { + name: 'edgeonePages', + samples: [ + { + src: '/ssg-img.png', + width: 400, + height: 300, + fit: 'contain', + }, + { + src: '/ssg-img.png', + width: 400, + height: 300, + fit: 'cover', + }, + { + src: '/ssg-img.png', + width: 400, + height: 300, + fit: 'fill', + }, + { + src: '/ssg-img.png', + width: 300, + quality: 80, + format: 'webp', + }, + { + src: '/ssg-img.png', + modifiers: { + rotate: 90, + }, + }, + { + src: '/ssg-img.png', + modifiers: { + blur: 15, + quality: 50, + }, + }, + ], + }, // Unsplash { name: 'unsplash', diff --git a/playground/nuxt.config.ts b/playground/nuxt.config.ts index 9e9db4485..ca179808b 100644 --- a/playground/nuxt.config.ts +++ b/playground/nuxt.config.ts @@ -111,6 +111,9 @@ export default defineNuxtConfig({ supabase: { baseURL: 'https://ovzjdhllnxrizgszqlsi.supabase.co/storage/v1/render/image/public/nuxt', }, + edgeonePages: { + baseURL: 'https://nuxt-mix-template.edgeone.site', + }, unsplash: {}, vercel: { baseURL: 'https://image-component.nextjs.gallery/_next/image', diff --git a/src/provider.ts b/src/provider.ts index e41451151..9e8510a76 100644 --- a/src/provider.ts +++ b/src/provider.ts @@ -47,6 +47,7 @@ export const BuiltInProviders = [ 'strapi', 'strapi5', 'supabase', + 'edgeonePages', 'twicpics', 'unsplash', 'uploadcare', diff --git a/src/runtime/providers/edgeonePages.ts b/src/runtime/providers/edgeonePages.ts new file mode 100644 index 000000000..d996e441d --- /dev/null +++ b/src/runtime/providers/edgeonePages.ts @@ -0,0 +1,194 @@ +import { joinURL } from 'ufo' +import type { ImageModifiers } from '@nuxt/image' +import { defineProvider } from '../utils/provider' + +interface EdgeOnePagesModifiers extends ImageModifiers { + /** Regular crop: 'x' e.g. '300x400' */ + crop: string + /** Crop/scale gravity: center, north, south, west, east, northwest, northeast, southwest, southeast */ + gravity: string + /** Crop X offset */ + dx: number + /** Crop Y offset */ + dy: number + /** Inscribed circle crop radius */ + iradius: number + /** Smart face crop: 'x' */ + scrop: string + /** Clockwise rotation angle 0-360 */ + rotate: number + /** Auto-rotate based on EXIF orientation */ + autoOrient: boolean + /** Sharpen intensity */ + sharpen: number + /** Strip EXIF metadata */ + strip: boolean + /** Progressive display (JPEG/GIF) */ + interlace: boolean | number + /** Pad mode (used with thumbnail + background) 0 or 1 */ + pad: boolean | number +} + +/** Options for the EdgeOne Pages image provider. */ +export interface EdgeOnePagesOptions { + /** Base URL of the EdgeOne Pages site (e.g. `https://domain`). */ + baseURL: string + /** Optional image processing modifiers. */ + modifiers?: Partial +} + +const fitMap: Record = { + contain: '', // /thumbnail/x — scale to fit within bounds (default) + cover: 'r', // /thumbnail/!xr — scale to cover minimum bounds + fill: '!', // /thumbnail/x! — force stretch to exact dimensions + inside: '', // same as contain + outside: 'r', // same as cover +} + +/** Encode a hex color string to URL-safe Base64 for background fill. */ +function encodeColor(color: string): string { + const hex = color.startsWith('#') ? color : `#${color}` + if (typeof globalThis.btoa === 'function') { + return globalThis.btoa(hex).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '') + } + return Buffer.from(hex).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '') +} + +/** + * EdgeOne Pages image provider. + * + * Transforms images via the `imageMogr2` API, supporting resize, + * crop, rotate, blur, quality, format conversion and more. + * + * @see https://edgeone.ai/document/162498 + */ +export default defineProvider({ + getImage: (src, { modifiers = {}, baseURL }) => { + if (!baseURL) { + throw new Error('EdgeOne Pages provider requires baseURL to be set') + } + + const { + width, + height, + fit, + quality, + format, + background, + blur, + crop, + gravity, + dx, + dy, + iradius, + scrop, + rotate, + autoOrient, + sharpen, + strip, + interlace, + pad, + } = modifiers as Partial + + const operations: string[] = [] + + // --- Thumbnail (resize) --- + if (width || height) { + const w = width ?? '' + const h = height ?? '' + const fitSuffix = fit ? (fitMap[fit] ?? '') : '' + + if (fitSuffix === 'r') { + // cover / outside: !xr + operations.push(`thumbnail/!${w}x${h}r`) + } + else if (fitSuffix === '!') { + // fill: x! + operations.push(`thumbnail/${w}x${h}!`) + } + else { + // contain / inside / default: x + operations.push(`thumbnail/${w}x${h}`) + } + } + + // --- Pad + Color (background fill) --- + if (pad || (background && (width || height))) { + operations.push('pad/1') + if (background) { + operations.push(`color/${encodeColor(background)}`) + } + } + + // --- Crop (regular crop) --- + if (crop) { + operations.push(`crop/${crop}`) + if (gravity) { + operations.push(`gravity/${gravity}`) + } + if (typeof dx !== 'undefined') { + operations.push(`dx/${dx}`) + } + if (typeof dy !== 'undefined') { + operations.push(`dy/${dy}`) + } + } + + // --- iradius (inscribed circle crop) --- + if (typeof iradius !== 'undefined') { + operations.push(`iradius/${iradius}`) + } + + // --- scrop (smart face crop) --- + if (scrop) { + operations.push(`scrop/${scrop}`) + } + + // --- Rotate --- + if (typeof rotate !== 'undefined') { + operations.push(`rotate/${rotate}`) + } + + // --- Auto-orient --- + if (autoOrient) { + operations.push('auto-orient') + } + + // --- Quality --- + if (typeof quality !== 'undefined') { + operations.push(`quality/${quality}`) + } + + // --- Format --- + if (format) { + const mappedFormat = format === 'jpeg' ? 'jpg' : format + operations.push(`format/${mappedFormat}`) + } + + // --- Blur (Gaussian blur) --- + if (typeof blur !== 'undefined' && blur) { + operations.push(`blur/${blur}x${blur}`) + } + + // --- Sharpen --- + if (typeof sharpen !== 'undefined') { + operations.push(`sharpen/${sharpen}`) + } + + // --- Strip (remove metadata) --- + if (strip) { + operations.push('strip') + } + + // --- Interlace (progressive display) --- + if (interlace) { + operations.push(`interlace/${typeof interlace === 'number' ? interlace : 1}`) + } + + const query = operations.length ? `?imageMogr2/${operations.join('/')}` : '' + + return { + url: joinURL(baseURL, src + query), + } + }, +}) diff --git a/test/e2e/__snapshots__/edgeonePages.json5 b/test/e2e/__snapshots__/edgeonePages.json5 new file mode 100644 index 000000000..77d07de5f --- /dev/null +++ b/test/e2e/__snapshots__/edgeonePages.json5 @@ -0,0 +1,18 @@ +{ + "requests": [ + "https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/blur/15x15", + "https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/rotate/90", + "https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/!400x300r", + "https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/300x/quality/80/format/webp", + "https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/400x300", + "https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/400x300!", + ], + "sources": [ + "https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/400x300", + "https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/!400x300r", + "https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/400x300!", + "https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/300x/quality/80/format/webp", + "https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/rotate/90", + "https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/blur/15x15", + ], +} \ No newline at end of file diff --git a/test/nuxt/providers.test.ts b/test/nuxt/providers.test.ts index 21e7c6b25..0ab25d19c 100644 --- a/test/nuxt/providers.test.ts +++ b/test/nuxt/providers.test.ts @@ -32,6 +32,7 @@ import storyblok from '../../dist/runtime/providers/storyblok' import strapi from '../../dist/runtime/providers/strapi' import strapi5 from '../../dist/runtime/providers/strapi5' import supabase from '../../dist/runtime/providers/supabase' +import edgeonePages from '../../dist/runtime/providers/edgeonePages' import vercel from '../../dist/runtime/providers/vercel' import wagtail from '../../dist/runtime/providers/wagtail' import uploadcare from '../../dist/runtime/providers/uploadcare' @@ -558,6 +559,182 @@ describe('Providers', () => { } }) + it('edgeonePages', () => { + const providerOptions = { + baseURL: 'https://nuxt-mix-template.edgeone.site', + } + + for (const image of images) { + const [src, modifiers] = image.args + const generated = edgeonePages().getImage(src, { modifiers, ...providerOptions }, getEmptyContext()) + expect(generated).toMatchObject(image.edgeonePages) + } + + const src = '/ssg-img.png' + + // no modifiers + expect(edgeonePages().getImage(src, { modifiers: {}, ...providerOptions }, getEmptyContext())) + .toMatchObject({ url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png' }) + + // width only + expect(edgeonePages().getImage(src, { modifiers: { width: 200 }, ...providerOptions }, getEmptyContext())) + .toMatchObject({ url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/200x' }) + + // height only + expect(edgeonePages().getImage(src, { modifiers: { height: 200 }, ...providerOptions }, getEmptyContext())) + .toMatchObject({ url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/x200' }) + + // width + height + expect(edgeonePages().getImage(src, { modifiers: { width: 200, height: 200 }, ...providerOptions }, getEmptyContext())) + .toMatchObject({ url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/200x200' }) + + // width + height + fit contain + expect(edgeonePages().getImage(src, { modifiers: { width: 200, height: 200, fit: 'contain' }, ...providerOptions }, getEmptyContext())) + .toMatchObject({ url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/200x200' }) + + // width + height + fit contain + format + expect(edgeonePages().getImage(src, { modifiers: { width: 200, height: 200, fit: 'contain', format: 'jpeg' }, ...providerOptions }, getEmptyContext())) + .toMatchObject({ url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/200x200/format/jpg' }) + }) + + it('edgeonePages cover fit', () => { + const providerOptions = { + baseURL: 'https://nuxt-mix-template.edgeone.site', + } + const generated = edgeonePages().getImage('/ssg-img.png', { + modifiers: { width: 300, height: 200, fit: 'cover' }, + ...providerOptions, + }, getEmptyContext()) + expect(generated).toMatchObject({ + url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/!300x200r', + }) + }) + + it('edgeonePages fill fit', () => { + const providerOptions = { + baseURL: 'https://nuxt-mix-template.edgeone.site', + } + const generated = edgeonePages().getImage('/ssg-img.png', { + modifiers: { width: 300, height: 200, fit: 'fill' }, + ...providerOptions, + }, getEmptyContext()) + expect(generated).toMatchObject({ + url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/300x200!', + }) + }) + + it('edgeonePages blur', () => { + const providerOptions = { + baseURL: 'https://nuxt-mix-template.edgeone.site', + } + const generated = edgeonePages().getImage('/ssg-img.png', { + modifiers: { blur: 10 }, + ...providerOptions, + }, getEmptyContext()) + expect(generated).toMatchObject({ + url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/blur/10x10', + }) + }) + + it('edgeonePages rotate', () => { + const providerOptions = { + baseURL: 'https://nuxt-mix-template.edgeone.site', + } + const generated = edgeonePages().getImage('/ssg-img.png', { + modifiers: { rotate: 90 }, + ...providerOptions, + }, getEmptyContext()) + expect(generated).toMatchObject({ + url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/rotate/90', + }) + }) + + it('edgeonePages crop with gravity', () => { + const providerOptions = { + baseURL: 'https://nuxt-mix-template.edgeone.site', + } + const generated = edgeonePages().getImage('/ssg-img.png', { + modifiers: { crop: '300x400', gravity: 'center' }, + ...providerOptions, + }, getEmptyContext()) + expect(generated).toMatchObject({ + url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/crop/300x400/gravity/center', + }) + }) + + it('edgeonePages sharpen and strip', () => { + const providerOptions = { + baseURL: 'https://nuxt-mix-template.edgeone.site', + } + const generated = edgeonePages().getImage('/ssg-img.png', { + modifiers: { sharpen: 70, strip: true }, + ...providerOptions, + }, getEmptyContext()) + expect(generated).toMatchObject({ + url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/sharpen/70/strip', + }) + }) + + it('edgeonePages scrop (smart face crop)', () => { + const providerOptions = { + baseURL: 'https://nuxt-mix-template.edgeone.site', + } + const generated = edgeonePages().getImage('/ssg-img.png', { + modifiers: { scrop: '200x200' }, + ...providerOptions, + }, getEmptyContext()) + expect(generated).toMatchObject({ + url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/scrop/200x200', + }) + }) + + it('edgeonePages interlace and autoOrient', () => { + const providerOptions = { + baseURL: 'https://nuxt-mix-template.edgeone.site', + } + const generated = edgeonePages().getImage('/ssg-img.png', { + modifiers: { interlace: true, autoOrient: true }, + ...providerOptions, + }, getEmptyContext()) + expect(generated).toMatchObject({ + url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/auto-orient/interlace/1', + }) + }) + + it('edgeonePages iradius (circle crop)', () => { + const providerOptions = { + baseURL: 'https://nuxt-mix-template.edgeone.site', + } + const generated = edgeonePages().getImage('/ssg-img.png', { + modifiers: { iradius: 100 }, + ...providerOptions, + }, getEmptyContext()) + expect(generated).toMatchObject({ + url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/iradius/100', + }) + }) + + it('edgeonePages combined operations', () => { + const providerOptions = { + baseURL: 'https://nuxt-mix-template.edgeone.site', + } + const generated = edgeonePages().getImage('/ssg-img.png', { + modifiers: { + width: 800, + height: 600, + fit: 'cover', + quality: 85, + format: 'webp', + sharpen: 50, + interlace: true, + }, + ...providerOptions, + }, getEmptyContext()) + expect(generated).toMatchObject({ + url: 'https://nuxt-mix-template.edgeone.site/ssg-img.png?imageMogr2/thumbnail/!800x600r/quality/85/format/webp/sharpen/50/interlace/1', + }) + }) + it('strapi', () => { const test = { '': 'http://localhost:1337/uploads/test.png', diff --git a/test/providers.ts b/test/providers.ts index 122d0183e..a82aaae10 100644 --- a/test/providers.ts +++ b/test/providers.ts @@ -29,6 +29,7 @@ export const images = [ cloudimage: { url: 'https://demo.cloudimg.io/v7/_sl_/test.png' }, storyblok: { url: 'https://a.storyblok.com/test.png' }, supabase: { url: 'https://ovzjdhllnxrizgszqlsi.supabase.co/storage/v1/render/image/public/nuxt/test.png' }, + edgeonePages: { url: 'https://nuxt-mix-template.edgeone.site/test.png' }, vercel: { url: '/_vercel/image?url=%2Ftest.png&w=1536&q=100' }, wagtail: { url: '329944/original|format-webp|webpquality-70' }, directus: { url: '/assets/1ac73658-8b62-4dea-b6da-529fbc9d01a4' }, @@ -71,6 +72,7 @@ export const images = [ cloudimage: { url: 'https://demo.cloudimg.io/v7/_sl_/test.png?width=200' }, storyblok: { url: 'https://a.storyblok.com/test.png/m/200x0' }, supabase: { url: 'https://ovzjdhllnxrizgszqlsi.supabase.co/storage/v1/render/image/public/nuxt/test.png?width=200' }, + edgeonePages: { url: 'https://nuxt-mix-template.edgeone.site/test.png?imageMogr2/thumbnail/200x' }, vercel: { url: '/_vercel/image?url=%2Ftest.png&w=640&q=100' }, wagtail: { url: '329944/width-200|format-webp|webpquality-70' }, directus: { url: '/assets/1ac73658-8b62-4dea-b6da-529fbc9d01a4?width=200' }, @@ -112,6 +114,7 @@ export const images = [ cloudimage: { url: 'https://demo.cloudimg.io/v7/_sl_/test.png?height=200' }, storyblok: { url: 'https://a.storyblok.com/test.png/m/0x200' }, supabase: { url: 'https://ovzjdhllnxrizgszqlsi.supabase.co/storage/v1/render/image/public/nuxt/test.png?height=200' }, + edgeonePages: { url: 'https://nuxt-mix-template.edgeone.site/test.png?imageMogr2/thumbnail/x200' }, vercel: { url: '/_vercel/image?url=%2Ftest.png&w=1536&q=100' }, wagtail: { url: '329944/height-200|format-webp|webpquality-70' }, directus: { url: '/assets/1ac73658-8b62-4dea-b6da-529fbc9d01a4?height=200' }, @@ -153,6 +156,7 @@ export const images = [ cloudimage: { url: 'https://demo.cloudimg.io/v7/_sl_/test.png?width=200&height=200' }, storyblok: { url: 'https://a.storyblok.com/test.png/m/200x200' }, supabase: { url: 'https://ovzjdhllnxrizgszqlsi.supabase.co/storage/v1/render/image/public/nuxt/test.png?width=200&height=200' }, + edgeonePages: { url: 'https://nuxt-mix-template.edgeone.site/test.png?imageMogr2/thumbnail/200x200' }, vercel: { url: '/_vercel/image?url=%2Ftest.png&w=640&q=100' }, wagtail: { url: '329944/fill-200x200-c0|format-webp|webpquality-70' }, directus: { url: '/assets/1ac73658-8b62-4dea-b6da-529fbc9d01a4?width=200&height=200' }, @@ -194,6 +198,7 @@ export const images = [ cloudimage: { url: 'https://demo.cloudimg.io/v7/_sl_/test.png?width=200&height=200&func=fit' }, storyblok: { url: 'https://a.storyblok.com/test.png/m/fit-contain/200x200' }, supabase: { url: 'https://ovzjdhllnxrizgszqlsi.supabase.co/storage/v1/render/image/public/nuxt/test.png?width=200&height=200&resize=contain' }, + edgeonePages: { url: 'https://nuxt-mix-template.edgeone.site/test.png?imageMogr2/thumbnail/200x200' }, vercel: { url: '/_vercel/image?url=%2Ftest.png&w=640&q=100' }, wagtail: { url: '329944/fill-200x200-c0|format-webp|webpquality-70' }, directus: { url: '/assets/1ac73658-8b62-4dea-b6da-529fbc9d01a4?width=200&height=200&fit=contain' }, @@ -235,6 +240,7 @@ export const images = [ cloudimage: { url: 'https://demo.cloudimg.io/v7/_sl_/test.png?width=200&height=200&func=fit&force_format=jpeg' }, storyblok: { url: 'https://a.storyblok.com/test.png/m/fit-contain/200x200/filters:format(jpeg)' }, supabase: { url: 'https://ovzjdhllnxrizgszqlsi.supabase.co/storage/v1/render/image/public/nuxt/test.png?width=200&height=200&resize=contain&format=jpeg' }, + edgeonePages: { url: 'https://nuxt-mix-template.edgeone.site/test.png?imageMogr2/thumbnail/200x200/format/jpg' }, vercel: { url: '/_vercel/image?url=%2Ftest.png&w=640&q=100' }, wagtail: { url: '329944/fill-200x200-c0|format-jpeg|jpegquality-70' }, directus: { url: '/assets/1ac73658-8b62-4dea-b6da-529fbc9d01a4?width=200&height=200&fit=contain&format=jpg' },