Skip to content

Commit 3f2bc25

Browse files
verysprywardpeet
andauthored
feat(gatsby-plugin-utils): support aspect ratio for Image Service (#35087)
* feat: add support for aspectRatio in image service resolver * refactor: remove todo * fix: pass aspectRatio to all the stuff that needs it * feat: pass apsectRatio to calculateImageDimensions * feat: add aspectRatio to generateResizeFieldConfig * fix(image cdn): do not pass aspect ratio in with image args * update snapshot Co-authored-by: Ward Peeters <[email protected]>
1 parent 6454eed commit 3f2bc25

File tree

6 files changed

+98
-4
lines changed

6 files changed

+98
-4
lines changed

packages/gatsby-plugin-utils/src/polyfill-remote-file/__tests__/gatsby-image-resolver.ts

+64
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ function parseSrcSet(
3535
})
3636
}
3737

38+
function base64Encode(s: string): string {
39+
return Buffer.from(s).toString(`base64`)
40+
}
41+
3842
describe(`gatsbyImageData`, () => {
3943
const cacheDir = path.join(__dirname, `.cache`)
4044

@@ -76,6 +80,66 @@ describe(`gatsbyImageData`, () => {
7680
},
7781
}
7882

83+
it(`should return proper image props for aspect ratio and automatically add "fit" prop`, async () => {
84+
const result = await gatsbyImageResolver(
85+
portraitSource,
86+
{
87+
aspectRatio: 1.333333333,
88+
layout: `fixed`,
89+
width: 300,
90+
placeholder: `none`,
91+
},
92+
actions
93+
)
94+
95+
const parsedSrcSet = parseSrcSet(result.images.sources[0].srcSet)
96+
97+
expect(parsedSrcSet.length).toBe(2)
98+
99+
expect(parsedSrcSet[0].src).toEqual(
100+
`/_gatsby/image/${base64Encode(portraitSource.url)}/${base64Encode(
101+
`w=300&h=225&fm=avif&q=75`
102+
)}/${portraitSource.basename}.avif`
103+
)
104+
expect(parsedSrcSet[0].descriptor).toEqual(`1x`)
105+
106+
expect(parsedSrcSet[1].src).toEqual(
107+
`/_gatsby/image/${base64Encode(portraitSource.url)}/${base64Encode(
108+
`w=600&h=450&fm=avif&q=75`
109+
)}/${portraitSource.basename}.avif`
110+
)
111+
expect(parsedSrcSet[1].descriptor).toEqual(`2x`)
112+
})
113+
114+
it(`should return proper image props for aspect ratio when "cropFocus" is also passed`, async () => {
115+
const result = await gatsbyImageResolver(
116+
portraitSource,
117+
{
118+
aspectRatio: 1.333333333,
119+
layout: `fixed`,
120+
width: 300,
121+
placeholder: `none`,
122+
cropFocus: [`entropy`],
123+
},
124+
actions
125+
)
126+
const parsedSrcSet = parseSrcSet(result.images.sources[0].srcSet)
127+
128+
expect(parsedSrcSet[0].src).toEqual(
129+
`/_gatsby/image/${base64Encode(portraitSource.url)}/${base64Encode(
130+
`w=300&h=225&fit=crop&crop=entropy&fm=avif&q=75`
131+
)}/${portraitSource.basename}.avif`
132+
)
133+
expect(parsedSrcSet[0].descriptor).toEqual(`1x`)
134+
135+
expect(parsedSrcSet[1].src).toEqual(
136+
`/_gatsby/image/${base64Encode(portraitSource.url)}/${base64Encode(
137+
`w=600&h=450&fit=crop&crop=entropy&fm=avif&q=75`
138+
)}/${portraitSource.basename}.avif`
139+
)
140+
expect(parsedSrcSet[1].descriptor).toEqual(`2x`)
141+
})
142+
79143
it(`should return null when source is not an image`, async () => {
80144
expect(
81145
await gatsbyImageResolver(

packages/gatsby-plugin-utils/src/polyfill-remote-file/graphql/gatsby-image-resolver.ts

+20-2
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ function calculateImageSizes(
381381
fit,
382382
outputPixelDensities,
383383
breakpoints,
384+
aspectRatio,
384385
}: CalculateImageSizesArgs
385386
): IImageSizes {
386387
if (width && Number(width) <= 0) {
@@ -403,6 +404,7 @@ function calculateImageSizes(
403404
fit,
404405
sourceMetadata,
405406
outputPixelDensities,
407+
aspectRatio,
406408
})
407409
}
408410
case `constrained`: {
@@ -414,6 +416,7 @@ function calculateImageSizes(
414416
fit,
415417
outputPixelDensities,
416418
layout,
419+
aspectRatio,
417420
})
418421
}
419422
case `fullWidth`: {
@@ -426,6 +429,7 @@ function calculateImageSizes(
426429
outputPixelDensities,
427430
layout,
428431
breakpoints,
432+
aspectRatio,
429433
})
430434
}
431435
}
@@ -437,8 +441,14 @@ function calculateFixedImageSizes({
437441
height,
438442
fit = `cover`,
439443
outputPixelDensities,
444+
aspectRatio: requestedAspectRatio,
440445
}: Omit<ImageSizeArgs, "layout" | "breakpoints">): IImageSizes {
441-
let aspectRatio = sourceMetadata.width / sourceMetadata.height
446+
let aspectRatio
447+
if (requestedAspectRatio) {
448+
aspectRatio = requestedAspectRatio
449+
} else {
450+
aspectRatio = sourceMetadata.width / sourceMetadata.height
451+
}
442452

443453
// make sure output outputPixelDensities has a value of 1
444454
outputPixelDensities.push(1)
@@ -452,6 +462,7 @@ function calculateFixedImageSizes({
452462
width,
453463
height,
454464
fit,
465+
aspectRatio,
455466
})
456467
width = calculated.width
457468
height = calculated.height
@@ -517,9 +528,15 @@ function calculateResponsiveImageSizes({
517528
outputPixelDensities,
518529
breakpoints,
519530
layout,
531+
aspectRatio: requestedAspectRatio,
520532
}: ImageSizeArgs): IImageSizes {
521533
let sizes: Array<number> = []
522-
let aspectRatio = sourceMetadata.width / sourceMetadata.height
534+
let aspectRatio
535+
if (requestedAspectRatio) {
536+
aspectRatio = requestedAspectRatio
537+
} else {
538+
aspectRatio = sourceMetadata.width / sourceMetadata.height
539+
}
523540
// Sort, dedupe and ensure there's a 1
524541
const densities = new Set<number>(
525542
outputPixelDensities.sort(sortNumeric).filter(Boolean)
@@ -531,6 +548,7 @@ function calculateResponsiveImageSizes({
531548
width,
532549
height,
533550
fit,
551+
aspectRatio,
534552
})
535553
width = calculated.width
536554
height = calculated.height

packages/gatsby-plugin-utils/src/polyfill-remote-file/graphql/resize-resolver.ts

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ interface IResizeArgs {
2525
format: ImageFormat
2626
cropFocus: Array<ImageCropFocus>
2727
quality: number
28+
aspectRatio: number
2829
}
2930

3031
const DEFAULT_QUALITY = 75
@@ -124,6 +125,7 @@ export function generateResizeFieldConfig(
124125
args: {
125126
width: `Int`,
126127
height: `Int`,
128+
aspectRatio: `Float`,
127129
fit: {
128130
type: enums.fit.getTypeName(),
129131
defaultValue: enums.fit.getField(`COVER`).value,

packages/gatsby-plugin-utils/src/polyfill-remote-file/graphql/utils.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,16 @@ export function calculateImageDimensions(
2929
fit,
3030
width: requestedWidth,
3131
height: requestedHeight,
32-
}: { fit: ImageFit } & WidthOrHeight
32+
aspectRatio: requestedAspectRatio,
33+
}: { fit: ImageFit; aspectRatio: number } & WidthOrHeight
3334
): { width: number; height: number; aspectRatio: number } {
3435
// Calculate the eventual width/height of the image.
35-
const imageAspectRatio = originalDimensions.width / originalDimensions.height
36+
let imageAspectRatio
37+
if (requestedAspectRatio) {
38+
imageAspectRatio = requestedAspectRatio
39+
} else {
40+
imageAspectRatio = originalDimensions.width / originalDimensions.height
41+
}
3642

3743
let width = requestedWidth
3844
let height = requestedHeight

packages/gatsby-plugin-utils/src/polyfill-remote-file/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export type CalculateImageSizesArgs = {
6565
layout: ImageLayout
6666
outputPixelDensities: Array<number>
6767
breakpoints?: Array<number>
68+
aspectRatio?: number
6869
} & WidthOrHeight
6970

7071
export function isImage(node: {

packages/gatsby/src/schema/__tests__/__snapshots__/print.js.snap

+3
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ interface RemoteFile {
6868
resize(
6969
width: Int
7070
height: Int
71+
aspectRatio: Float
7172
fit: RemoteFileFit = COVER
7273
7374
\\"\\"\\"
@@ -455,6 +456,7 @@ interface RemoteFile {
455456
resize(
456457
width: Int
457458
height: Int
459+
aspectRatio: Float
458460
fit: RemoteFileFit = COVER
459461
460462
\\"\\"\\"
@@ -852,6 +854,7 @@ interface RemoteFile {
852854
resize(
853855
width: Int
854856
height: Int
857+
aspectRatio: Float
855858
fit: RemoteFileFit = COVER
856859
857860
\\"\\"\\"

0 commit comments

Comments
 (0)