diff --git a/docs/content/3.providers/directus.md b/docs/content/3.providers/directus.md index 9e5f2321b..0c7c940b4 100644 --- a/docs/content/3.providers/directus.md +++ b/docs/content/3.providers/directus.md @@ -8,9 +8,7 @@ links: size: xs --- -Integration between [Directus](https://directus.io) and the image module. - -To use this provider you just need to specify the base URL of your project. +To use this provider you only need to specify the base URL of your Directus instance. ```ts [nuxt.config.ts] export default defineNuxtConfig({ @@ -23,51 +21,101 @@ export default defineNuxtConfig({ }) ``` -You can easily override default options: - -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - image: { - directus: { - baseURL: 'http://mydirectus-domain.com/assets', - modifiers: { - withoutEnlargement: 'true', - transforms: [['blur', 4], ['negate']] - } - } - } -}) -``` - -## Modifiers +## Props -All the default modifiers from [Directus documentation](https://docs.directus.io/reference/files.html#requesting-a-thumbnail) are available. +The NuxtImg Props map cleanly to the Directus Transforms. ```vue ``` -Since Directus exposes the full [sharp API](https://sharp.pixelplumbing.com/api-operation) through the `transforms` parameter, we can use it inside our `modifiers` prop: +### Modifiers + +The `modifiers` object is used for Directus specific features. All modifiers are optional. + +#### Examples of Modifiers + +::tabs{.w-full} +:::tabs-item{label="Modifiers"} ```vue ``` -::note -Note that the `transforms` parameter, as stated in the [Directus documentation](https://docs.directus.io/reference/files.html#advanced-transformations), is basically a list of lists. This is to facilitate the use of those sharp functions, like [`normalise`](https://sharp.pixelplumbing.com/api-operation#normalise), that would need multiple values in input: `transforms: [['normalise', 1, 99], ['blur', 4], ['negate']]`. +::: + +:::tabs-item{label="Keyed Modifier"} + +```vue + +``` + +::: +:: + +#### All Modifiers + +::field-group + +::field{name="withoutEnlargement" type="boolean"} +Disable automatically upscaling the image when true. +:: + +::field{name="transforms" type="['string', ...any][]"} +A pipeline of transforms to tell Directus how to modify the image before sending. +:::collapsible + +| **[Sharp Operation](https://sharp.pixelplumbing.com/api-operation/)**| **Options**| **Example Usage**| +|----------------------|--------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------| +| **rotate**| \[angle?: number, options?: \{ background: Color \} \]| \['rotate', 90\] or \['rotate', 90, \{ background: 'white' \} \]| +| **flip**| \[]| \['flip'\]| +| **flop**| \[]| \['flop'\]| +| **sharpen**| \[sigma?: number\] \| \[options?: \{ sigma?: number, m1?: number, m2?: number, x1?: number, y2?: number, y3?: number \} \]| \['sharpen', 1.5\] or \['sharpen', \{ sigma: 1.5, m1: 0.5 \} \]| +| **median**| \[size?: number\]| \['median', 5\]| +| **blur**| \[sigma?: number\] \| \[options?: \{ sigma?: number, precision?: 'integer' \| 'float' \| 'approximate', minAmplitude?: number \} \]| \['blur', 2\] or \['blur', \{ sigma: 2, precision: 'float' \} \]| +| **flatten**| \[options?: \{ background: Color \} \]| \['flatten', \{ background: 'black' \} \]| +| **unflatten**| \[]| \['unflatten'\]| +| **gamma**| \[gamma?: number, gammaOut?: number\]| \['gamma', 2.2\] or \['gamma', 2.2, 1.8\]| +| **negate**| \[options?: \{ alpha?: boolean \} \]| \['negate', \{ alpha: true \} \]| +| **normalize** or **normalise**| \[lower?: number, upper?: number\]| \['normalize', 0, 255\]| +| **clahe**| \[options?: \{ width: number, height: number, maxSlope?: number \} \]| \['clahe', \{ width: 8, height: 8 \} \]| +| **convolve**| \[kernel: \{ width: number, height: number, kernel: number\[], offset?: number \} \]| \['convolve', \{ width: 3, height: 3, kernel: [1, 1, 1, 1, 1, 1, 1, 1, 1], offset: 0 \} \]| +| **threshold**| \[value?: number, options?: \{ grayscale?: boolean \} \]| \['threshold', 128\] or \['threshold', 128, \{ grayscale: true \} \]| +| **linear**| \[a?: number \| number\[], b?: number \| number\[]\]| \['linear', 1.2, 0\] or \['linear', [1.2, 1.0], [0, 255]\]| +| **recomb**| \[matrix: number\[\]\[\]\]| \['recomb', \[\[0.5, 0.5, 0.5\], [0.5, 0.5, 0.5\], [0.5, 0.5, 0.5\]\] \]| +| **modulate**| \[options?: \{ brightness?: number, saturation?: number, hue?: number, lightness?: number \} \]| \['modulate', \{ brightness: 1.2, saturation: 1.5 \} \]| +| **tint**| \[color: Color\]| \['tint', 'red'\]| +| **grayscale** or **greyscale**| \[]| \['grayscale'\]| +| **pipelineColorspace** or **pipelineColourspace**| \[colorspace: SharpColorspace\]| \['pipelineColorspace', 'srgb'\]| +| **toColorspace** or **toColourspace**| \[colorspace: SharpColorspace\]| \['toColorspace', 'rgb'\]| +| **removeAlpha**| \[]| \['removeAlpha'\]| +| **ensureAlpha**| \[alpha?: number\]| \['ensureAlpha', 0.5\]| +| **extractChannel**| \[channel: 'red' \| 'green' \| 'blue' \| 'alpha'\]| \['extractChannel', 'red'\]| + +::: + +:::note +Directus defaults `ASSETS_TRANSFORM_MAX_OPERATIONS` to `5`. If you need more, it is recommended that you utilize a `key`ed transform. You can modify your [Directus Configuration](https://directus.io/docs/configuration/files#assets) to accommodate more transforms if necessary. +::: + +::field{name="key" type="string"} +Sets a unique identifier for allowing faster and easier image transformation requests. :: diff --git a/playground/app/providers.ts b/playground/app/providers.ts index 694dff051..b42b23a80 100644 --- a/playground/app/providers.ts +++ b/playground/app/providers.ts @@ -1297,11 +1297,11 @@ export const providers: Provider[] = [ name: 'directus', samples: [ { - src: 'ad514db1-eb90-4523-8183-46781437e7ee', - alt: 'Image 1', + src: '8f748634-d77b-4985-b27e-7e1f3559881a', + alt: 'Raw Image (no modifiers or transforms)', }, { - src: 'ad514db1-eb90-4523-8183-46781437e7ee.jpg', + src: '8f748634-d77b-4985-b27e-7e1f3559881a.jpg', alt: '1024px width', width: 1024, height: 256, @@ -1309,13 +1309,20 @@ export const providers: Provider[] = [ modifiers: { withoutEnlargement: 'true' }, }, { - src: 'ad514db1-eb90-4523-8183-46781437e7ee', + src: '8f748634-d77b-4985-b27e-7e1f3559881a', alt: '256px width, webp', width: 256, format: 'webp', }, { - src: 'ad514db1-eb90-4523-8183-46781437e7ee', + src: '8f748634-d77b-4985-b27e-7e1f3559881a', + alt: 'keyed transform (all other inputs ignored)', + format: 'tiff', + modifiers: { key: 'system-large-cover' }, + }, + + { + src: '8f748634-d77b-4985-b27e-7e1f3559881a', alt: '256px width, webp', width: 256, format: 'webp', diff --git a/playground/nuxt.config.ts b/playground/nuxt.config.ts index c4dbf392d..b6fb20f55 100644 --- a/playground/nuxt.config.ts +++ b/playground/nuxt.config.ts @@ -67,7 +67,7 @@ export default defineNuxtConfig({ apiVersion: 'v7', }, directus: { - baseURL: 'http://localhost:8055/assets/', + baseURL: 'https://sandbox.directus.io/assets/', }, fastly: { baseURL: 'https://www.fastly.io', diff --git a/src/runtime/providers/directus.ts b/src/runtime/providers/directus.ts index 2baffeb75..42d3bf168 100644 --- a/src/runtime/providers/directus.ts +++ b/src/runtime/providers/directus.ts @@ -2,29 +2,135 @@ import { joinURL } from 'ufo' import { createOperationsGenerator } from '../utils/index' import { defineProvider } from '../utils/provider' -const operationsGenerator = createOperationsGenerator() +type SharpOperationMap = { + // Image Operations https://sharp.pixelplumbing.com/api-operation/ + rotate: [angle?: number, options?: { background: Color }] + flip: [] + flop: [] + sharpen: [sigma?: number] | [options?: { sigma?: number, m1?: number, m2?: number, x1?: number, y2?: number, y3?: number }] + median: [size?: number] + blur: [sigma?: number] | [options?: { sigma?: number, precision?: 'integer' | 'float' | 'approximate', minAmplitude?: number }] + flatten: [options?: { background: Color }] + unflatten: [] + gamma: [gamma?: number, gammaOut?: number] + negate: [options?: { alpha?: boolean }] + normalize: [lower?: number, upper?: number] + normalise: [lower?: number, upper?: number] // Alias + clahe: [options?: { width: number, height: number, maxSlope?: number }] + convolve: [kernel: { width: number, height: number, kernel: number[], offset?: number }] + threshold: [value?: number, options?: { grayscale?: boolean }] + linear: [a?: number | number[], b?: number | number[]] + recomb: [matrix: number[][]] + modulate: [options?: { + brightness?: number + saturation?: number + hue?: number + lightness?: number + }] + + // Color Manipulation https://sharp.pixelplumbing.com/api-colour/ + tint: [color: Color] + grayscale: [] + greyscale: [] // Alias + pipelineColorspace: [colorspace: SharpColorspace] + pipelineColourspace: [colourspace: SharpColorspace] // Alias + toColorspace: [colorspace: SharpColorspace] + toColourspace: [colourspace: SharpColorspace] // Alias + + // Channel Manipulation https://sharp.pixelplumbing.com/api-channel/ + removeAlpha: [] + ensureAlpha: [alpha?: number] + extractChannel: [channel: 'red' | 'green' | 'blue' | 'alpha'] // Restricting to string channel extraction to avoid complexity. +} + +type SharpColorspace + = | 'srgb' + | 'rgb' + | 'scrgb' + | 'rgb16' + | 'cmyk' + | 'lab' + | 'b-w' + | string // retain advanced options for advanced users + +type Color + = | string + | { r: number, g: number, b: number, alpha?: number } + | { h: number, s: number, l: number, alpha?: number } + | { h: number, s: number, v: number, alpha?: number } + | { c: number, m: number, y: number, k: number, alpha?: number } + | { h: number, w: number, b: number } + | { l: number, c: number, h: number } + | { l: number, a: number, b: number } + | { h: number, c: number, g: number } + +type KnownSharpOperation + = { + [K in keyof SharpOperationMap]: + SharpOperationMap[K] extends [] + ? [K] + : [K, ...SharpOperationMap[K]] + }[keyof SharpOperationMap] + +type CustomSharpOperation + = K extends keyof SharpOperationMap + ? never + : [key: K, ...args: any[]] + +type SharpOperation + = | KnownSharpOperation + | CustomSharpOperation + +type DirectusModifiers + = | { key: string } + | { + key?: never + withoutEnlargement?: boolean + transforms?: SharpOperation[] + } interface DirectusOptions { baseURL: string - modifiers?: { - transforms?: string[] - withoutEnlargement?: boolean - } + width?: number + height?: number + quality?: number + format?: 'auto' | 'jpg' | 'png' | 'webp' | 'tiff' | 'avif' + fit?: 'cover' | 'contain' | 'inside' | 'outside' | 'fill' + modifiers?: DirectusModifiers +} + +// HACK: See Discussion #2206 +const operationsGenerator = createOperationsGenerator({ + valueMap: { + transforms(value: SharpOperation[]) { + return value.length > 0 + ? JSON.stringify( + Array.from(new Set(value.map(v => JSON.stringify(v)))) + .map(v => JSON.parse(v)), + ) + : undefined + }, + }, +}) + +function isKeyModifier( + mod: DirectusModifiers | undefined, +): mod is { key: string } { + return !!mod && 'key' in mod && typeof mod.key === 'string' } export default defineProvider({ getImage: (src, { modifiers, baseURL }) => { - // Separating the transforms from the rest of the modifiers - const transforms = modifiers.transforms && Array.isArray(modifiers.transforms) && modifiers.transforms.length > 0 - ? JSON.stringify(Array.from(new Set(modifiers.transforms.map(obj => JSON.stringify(obj)))).map(value => JSON.parse(value))) - : undefined - - const operations = operationsGenerator({ - ...modifiers, - transforms, - }) + if (isKeyModifier(modifiers)) { + return { + url: joinURL(baseURL, src + `?key=${modifiers.key}`), + } + } + + const operations = operationsGenerator(modifiers) + return { - url: joinURL(baseURL, src + (operations ? ('?' + operations.replace(/=+$/, '')) : '')), + url: joinURL(baseURL, src + (operations ? `?${operations}` : '')), } }, }) diff --git a/test/e2e/__snapshots__/directus.json5 b/test/e2e/__snapshots__/directus.json5 index 8dc47c7e1..b56885374 100644 --- a/test/e2e/__snapshots__/directus.json5 +++ b/test/e2e/__snapshots__/directus.json5 @@ -1,14 +1,16 @@ { "requests": [ - "http://localhost:8055/assets/ad514db1-eb90-4523-8183-46781437e7ee", - "http://localhost:8055/assets/ad514db1-eb90-4523-8183-46781437e7ee.jpg?withoutEnlargement=true&width=1024&height=256&fit=cover", - "http://localhost:8055/assets/ad514db1-eb90-4523-8183-46781437e7ee?width=256&format=webp", - "http://localhost:8055/assets/ad514db1-eb90-4523-8183-46781437e7ee?withoutEnlargement=true&transforms=%5B%5B%22blur%22%2C4%5D%2C%5B%22negate%22%5D%5D&width=256&format=webp", + "https://sandbox.directus.io/assets/8f748634-d77b-4985-b27e-7e1f3559881a", + "https://sandbox.directus.io/assets/8f748634-d77b-4985-b27e-7e1f3559881a.jpg?withoutEnlargement=true&width=1024&height=256&fit=cover", + "https://sandbox.directus.io/assets/8f748634-d77b-4985-b27e-7e1f3559881a?key=system-large-cover", + "https://sandbox.directus.io/assets/8f748634-d77b-4985-b27e-7e1f3559881a?width=256&format=webp", + "https://sandbox.directus.io/assets/8f748634-d77b-4985-b27e-7e1f3559881a?withoutEnlargement=true&transforms=%5B%5B%22blur%22%2C4%5D%2C%5B%22negate%22%5D%5D&width=256&format=webp", ], "sources": [ - "http://localhost:8055/assets/ad514db1-eb90-4523-8183-46781437e7ee", - "http://localhost:8055/assets/ad514db1-eb90-4523-8183-46781437e7ee.jpg?withoutEnlargement=true&width=1024&height=256&fit=cover", - "http://localhost:8055/assets/ad514db1-eb90-4523-8183-46781437e7ee?width=256&format=webp", - "http://localhost:8055/assets/ad514db1-eb90-4523-8183-46781437e7ee?withoutEnlargement=true&transforms=%5B%5B%22blur%22%2C4%5D%2C%5B%22negate%22%5D%5D&width=256&format=webp", + "https://sandbox.directus.io/assets/8f748634-d77b-4985-b27e-7e1f3559881a", + "https://sandbox.directus.io/assets/8f748634-d77b-4985-b27e-7e1f3559881a.jpg?withoutEnlargement=true&width=1024&height=256&fit=cover", + "https://sandbox.directus.io/assets/8f748634-d77b-4985-b27e-7e1f3559881a?width=256&format=webp", + "https://sandbox.directus.io/assets/8f748634-d77b-4985-b27e-7e1f3559881a?key=system-large-cover", + "https://sandbox.directus.io/assets/8f748634-d77b-4985-b27e-7e1f3559881a?withoutEnlargement=true&transforms=%5B%5B%22blur%22%2C4%5D%2C%5B%22negate%22%5D%5D&width=256&format=webp", ], } \ No newline at end of file diff --git a/test/nuxt/providers.test.ts b/test/nuxt/providers.test.ts index b7a284636..f78e4d916 100644 --- a/test/nuxt/providers.test.ts +++ b/test/nuxt/providers.test.ts @@ -5,41 +5,42 @@ import { images } from '../providers' import { useNuxtApp } from '#imports' import ipx from '../../dist/runtime/providers/ipx' import none from '../../dist/runtime/providers/none' -import weserv from '../../dist/runtime/providers/weserv' import aliyun from '../../dist/runtime/providers/aliyun' import awsAmplify from '../../dist/runtime/providers/awsAmplify' +import builderio from '../../dist/runtime/providers/builderio' import cloudflare from '../../dist/runtime/providers/cloudflare' import cloudflareimages from '../../dist/runtime/providers/cloudflareimages' +import cloudimage from '../../dist/runtime/providers/cloudimage' import cloudinary from '../../dist/runtime/providers/cloudinary' -import twicpics from '../../dist/runtime/providers/twicpics' +import contentful from '../../dist/runtime/providers/contentful' +import directus from '../../dist/runtime/providers/directus' import fastly from '../../dist/runtime/providers/fastly' -import picsum from '../../dist/runtime/providers/picsum' -import prepr from '../../dist/runtime/providers/prepr' +import flyimg from '../../dist/runtime/providers/flyimg' import glide from '../../dist/runtime/providers/glide' -import imgix from '../../dist/runtime/providers/imgix' import gumlet from '../../dist/runtime/providers/gumlet' +import hygraph from '../../dist/runtime/providers/hygraph' import imageengine from '../../dist/runtime/providers/imageengine' -import unsplash from '../../dist/runtime/providers/unsplash' import imagekit from '../../dist/runtime/providers/imagekit' +import imgix from '../../dist/runtime/providers/imgix' import netlifyImageCdn from '../../dist/runtime/providers/netlifyImageCdn' import netlifyLargeMedia from '../../dist/runtime/providers/netlifyLargeMedia' +import picsum from '../../dist/runtime/providers/picsum' +import prepr from '../../dist/runtime/providers/prepr' import prismic from '../../dist/runtime/providers/prismic' import sanity from '../../dist/runtime/providers/sanity' import shopify from '../../dist/runtime/providers/shopify' -import builderio from '../../dist/runtime/providers/builderio' -import contentful from '../../dist/runtime/providers/contentful' -import cloudimage from '../../dist/runtime/providers/cloudimage' +import sirv from '../../dist/runtime/providers/sirv' 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 twicpics from '../../dist/runtime/providers/twicpics' +import umbraco from '../../dist/runtime/providers/umbraco' +import unsplash from '../../dist/runtime/providers/unsplash' +import uploadcare from '../../dist/runtime/providers/uploadcare' import vercel from '../../dist/runtime/providers/vercel' import wagtail from '../../dist/runtime/providers/wagtail' -import uploadcare from '../../dist/runtime/providers/uploadcare' -import sirv from '../../dist/runtime/providers/sirv' -import hygraph from '../../dist/runtime/providers/hygraph' -import umbraco from '../../dist/runtime/providers/umbraco' -import flyimg from '../../dist/runtime/providers/flyimg' +import weserv from '../../dist/runtime/providers/weserv' function getEmptyContext() { return { @@ -546,6 +547,30 @@ describe('Providers', () => { } }) + it('directus', () => { + const providerOptions = { + baseURL: '/assets/', + } + for (const image of images) { + const [src, modifiers] = image.args + const generated = directus().getImage(src, { modifiers, ...providerOptions }, getEmptyContext()) + expect(generated).toMatchObject(image.directus) + } + }) + + it('directus w/ key modifier', () => { + const providerOptions = { + baseURL: '/assets/', + width: 200, + modifiers: { + key: 'system-small-cover', + allOtherModifiers: 'ignored', + }, + } + const generated = directus().getImage('uuid-example', { ...providerOptions }, getEmptyContext()) + expect(generated.url).toBe('/assets/uuid-example?key=system-small-cover') + }) + it('cloudimage', () => { const providerOptions = { token: 'demo', diff --git a/test/providers.ts b/test/providers.ts index bc276ebc3..395684f1d 100644 --- a/test/providers.ts +++ b/test/providers.ts @@ -32,7 +32,7 @@ export const images = [ supabase: { url: 'https://ovzjdhllnxrizgszqlsi.supabase.co/storage/v1/render/image/public/nuxt/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' }, + directus: { url: '/assets/test.png' }, uploadcare: { url: 'https://ucarecdn.com/c160afba-8b42-45a9-a46a-d393248b0072/' }, weserv: { url: 'https://wsrv.nl/?filename=test.png&we&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, flyimg: { url: 'https://demo.flyimg.io/upload/-/https://my-website.com/test.png' }, @@ -77,7 +77,7 @@ export const images = [ supabase: { url: 'https://ovzjdhllnxrizgszqlsi.supabase.co/storage/v1/render/image/public/nuxt/test.png?width=200' }, 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' }, + directus: { url: '/assets/test.png?width=200' }, uploadcare: { url: 'https://ucarecdn.com/c160afba-8b42-45a9-a46a-d393248b0072/-/resize/200x/' }, weserv: { url: 'https://wsrv.nl/?filename=test.png&we&w=200&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, flyimg: { url: 'https://demo.flyimg.io/upload/w_200/https://my-website.com/test.png' }, @@ -121,7 +121,7 @@ export const images = [ supabase: { url: 'https://ovzjdhllnxrizgszqlsi.supabase.co/storage/v1/render/image/public/nuxt/test.png?height=200' }, 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' }, + directus: { url: '/assets/test.png?height=200' }, uploadcare: { url: 'https://ucarecdn.com/c160afba-8b42-45a9-a46a-d393248b0072/-/resize/x200/' }, weserv: { url: 'https://wsrv.nl/?filename=test.png&we&h=200&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, flyimg: { url: 'https://demo.flyimg.io/upload/h_200/https://my-website.com/test.png' }, @@ -165,7 +165,7 @@ export const images = [ supabase: { url: 'https://ovzjdhllnxrizgszqlsi.supabase.co/storage/v1/render/image/public/nuxt/test.png?width=200&height=200' }, 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' }, + directus: { url: '/assets/test.png?width=200&height=200' }, uploadcare: { url: 'https://ucarecdn.com/c160afba-8b42-45a9-a46a-d393248b0072/-/resize/200x200/' }, weserv: { url: 'https://wsrv.nl/?filename=test.png&we&w=200&h=200&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, flyimg: { url: 'https://demo.flyimg.io/upload/w_200,h_200/https://my-website.com/test.png' }, @@ -209,7 +209,7 @@ export const images = [ supabase: { url: 'https://ovzjdhllnxrizgszqlsi.supabase.co/storage/v1/render/image/public/nuxt/test.png?width=200&height=200&resize=contain' }, 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' }, + directus: { url: '/assets/test.png?width=200&height=200&fit=contain' }, uploadcare: { url: 'https://ucarecdn.com/c160afba-8b42-45a9-a46a-d393248b0072/-/resize/200x200/-/stretch/off/' }, weserv: { url: 'https://wsrv.nl/?filename=test.png&we&w=200&h=200&fit=contain&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, flyimg: { url: 'https://demo.flyimg.io/upload/w_200,h_200/https://my-website.com/test.png' }, @@ -253,7 +253,7 @@ export const images = [ supabase: { url: 'https://ovzjdhllnxrizgszqlsi.supabase.co/storage/v1/render/image/public/nuxt/test.png?width=200&height=200&resize=contain&format=jpeg' }, 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' }, + directus: { url: '/assets/test.png?width=200&height=200&fit=contain&format=jpeg' }, uploadcare: { url: 'https://ucarecdn.com/c160afba-8b42-45a9-a46a-d393248b0072/-/format/jpeg/-/resize/200x200/-/stretch/off/' }, weserv: { url: 'https://wsrv.nl/?filename=test.png&we&w=200&h=200&fit=contain&output=jpg&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, flyimg: { url: 'https://demo.flyimg.io/upload/w_200,h_200,o_jpeg/https://my-website.com/test.png' },