Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gatsby-plugin-utils): support aspect ratio for Image Service #35087

Merged
merged 7 commits into from
Mar 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ function parseSrcSet(
})
}

function base64Encode(s: string): string {
return Buffer.from(s).toString(`base64`)
}

describe(`gatsbyImageData`, () => {
const cacheDir = path.join(__dirname, `.cache`)

Expand Down Expand Up @@ -76,6 +80,66 @@ describe(`gatsbyImageData`, () => {
},
}

it(`should return proper image props for aspect ratio and automatically add "fit" prop`, async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay for adding tests!!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙌

const result = await gatsbyImageResolver(
portraitSource,
{
aspectRatio: 1.333333333,
layout: `fixed`,
width: 300,
placeholder: `none`,
},
actions
)

const parsedSrcSet = parseSrcSet(result.images.sources[0].srcSet)

expect(parsedSrcSet.length).toBe(2)

expect(parsedSrcSet[0].src).toEqual(
`/_gatsby/image/${base64Encode(portraitSource.url)}/${base64Encode(
`w=300&h=225&fm=avif&q=75`
)}/${portraitSource.basename}.avif`
)
expect(parsedSrcSet[0].descriptor).toEqual(`1x`)

expect(parsedSrcSet[1].src).toEqual(
`/_gatsby/image/${base64Encode(portraitSource.url)}/${base64Encode(
`w=600&h=450&fm=avif&q=75`
)}/${portraitSource.basename}.avif`
)
expect(parsedSrcSet[1].descriptor).toEqual(`2x`)
})

it(`should return proper image props for aspect ratio when "cropFocus" is also passed`, async () => {
const result = await gatsbyImageResolver(
portraitSource,
{
aspectRatio: 1.333333333,
layout: `fixed`,
width: 300,
placeholder: `none`,
cropFocus: [`entropy`],
},
actions
)
const parsedSrcSet = parseSrcSet(result.images.sources[0].srcSet)

expect(parsedSrcSet[0].src).toEqual(
`/_gatsby/image/${base64Encode(portraitSource.url)}/${base64Encode(
`w=300&h=225&fit=crop&crop=entropy&fm=avif&q=75`
)}/${portraitSource.basename}.avif`
)
expect(parsedSrcSet[0].descriptor).toEqual(`1x`)

expect(parsedSrcSet[1].src).toEqual(
`/_gatsby/image/${base64Encode(portraitSource.url)}/${base64Encode(
`w=600&h=450&fit=crop&crop=entropy&fm=avif&q=75`
)}/${portraitSource.basename}.avif`
)
expect(parsedSrcSet[1].descriptor).toEqual(`2x`)
})

it(`should return null when source is not an image`, async () => {
expect(
await gatsbyImageResolver(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ function calculateImageSizes(
fit,
outputPixelDensities,
breakpoints,
aspectRatio,
}: CalculateImageSizesArgs
): IImageSizes {
if (width && Number(width) <= 0) {
Expand All @@ -403,6 +404,7 @@ function calculateImageSizes(
fit,
sourceMetadata,
outputPixelDensities,
aspectRatio,
})
}
case `constrained`: {
Expand All @@ -414,6 +416,7 @@ function calculateImageSizes(
fit,
outputPixelDensities,
layout,
aspectRatio,
})
}
case `fullWidth`: {
Expand All @@ -426,6 +429,7 @@ function calculateImageSizes(
outputPixelDensities,
layout,
breakpoints,
aspectRatio,
})
}
}
Expand All @@ -437,8 +441,14 @@ function calculateFixedImageSizes({
height,
fit = `cover`,
outputPixelDensities,
aspectRatio: requestedAspectRatio,
}: Omit<ImageSizeArgs, "layout" | "breakpoints">): IImageSizes {
let aspectRatio = sourceMetadata.width / sourceMetadata.height
let aspectRatio
if (requestedAspectRatio) {
aspectRatio = requestedAspectRatio
} else {
aspectRatio = sourceMetadata.width / sourceMetadata.height
}

// make sure output outputPixelDensities has a value of 1
outputPixelDensities.push(1)
Expand All @@ -452,6 +462,7 @@ function calculateFixedImageSizes({
width,
height,
fit,
aspectRatio,
})
width = calculated.width
height = calculated.height
Expand Down Expand Up @@ -517,9 +528,15 @@ function calculateResponsiveImageSizes({
outputPixelDensities,
breakpoints,
layout,
aspectRatio: requestedAspectRatio,
}: ImageSizeArgs): IImageSizes {
let sizes: Array<number> = []
let aspectRatio = sourceMetadata.width / sourceMetadata.height
let aspectRatio
if (requestedAspectRatio) {
aspectRatio = requestedAspectRatio
} else {
aspectRatio = sourceMetadata.width / sourceMetadata.height
}
// Sort, dedupe and ensure there's a 1
const densities = new Set<number>(
outputPixelDensities.sort(sortNumeric).filter(Boolean)
Expand All @@ -531,6 +548,7 @@ function calculateResponsiveImageSizes({
width,
height,
fit,
aspectRatio,
})
width = calculated.width
height = calculated.height
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ interface IResizeArgs {
format: ImageFormat
cropFocus: Array<ImageCropFocus>
quality: number
aspectRatio: number
}

const DEFAULT_QUALITY = 75
Expand Down Expand Up @@ -124,6 +125,7 @@ export function generateResizeFieldConfig(
args: {
width: `Int`,
height: `Int`,
aspectRatio: `Float`,
fit: {
type: enums.fit.getTypeName(),
defaultValue: enums.fit.getField(`COVER`).value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,16 @@ export function calculateImageDimensions(
fit,
width: requestedWidth,
height: requestedHeight,
}: { fit: ImageFit } & WidthOrHeight
aspectRatio: requestedAspectRatio,
}: { fit: ImageFit; aspectRatio: number } & WidthOrHeight
): { width: number; height: number; aspectRatio: number } {
// Calculate the eventual width/height of the image.
const imageAspectRatio = originalDimensions.width / originalDimensions.height
let imageAspectRatio
if (requestedAspectRatio) {
imageAspectRatio = requestedAspectRatio
} else {
imageAspectRatio = originalDimensions.width / originalDimensions.height
}

let width = requestedWidth
let height = requestedHeight
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export type CalculateImageSizesArgs = {
layout: ImageLayout
outputPixelDensities: Array<number>
breakpoints?: Array<number>
aspectRatio?: number
} & WidthOrHeight

export function isImage(node: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ interface RemoteFile {
resize(
width: Int
height: Int
aspectRatio: Float
fit: RemoteFileFit = COVER

\\"\\"\\"
Expand Down Expand Up @@ -455,6 +456,7 @@ interface RemoteFile {
resize(
width: Int
height: Int
aspectRatio: Float
fit: RemoteFileFit = COVER

\\"\\"\\"
Expand Down Expand Up @@ -852,6 +854,7 @@ interface RemoteFile {
resize(
width: Int
height: Int
aspectRatio: Float
fit: RemoteFileFit = COVER

\\"\\"\\"
Expand Down