asset-utils
asset-utils copied to clipboard
[getImageDimensions] Account for cropping
Hey @rexxars 👋
I caught a bug in that stems from dimensions calculated wrongly with getImageDimensions
if an image has a crop. Basically, if an image's _id
includes 2304x1400
but its crop results in something like 400x400
, getImageDimensions returns width: 2304, height: 1400, aspectRatio: 2304/1400
, where the aspectRatio is actually 1
. This makes the padding hack in front-ends unpredictable and broken.
AFAIK, it's doable to get the proper values if an image object with hotspot/crop is provided through some simple-ish math, the question is whether this should be considered by getImageDimensions or if we need a new API. I'm thinking a new property cropped?: { width: number; height: number; aspectRatio: number }
would be the best approach as modifying the original width and height would break existing code and adding a new API could get more confusing and laborious.
Any strong opinions? Should I write a PR or is this something we're not looking for?
Hey Henrique - thanks for filing this!
I suppose we could add a method that takes a SanityImageObjectStub as the only valid input - getImageDimensionsWithCrop
, or similar?
Alternatively a second argument to the getImageDimensions
(useCrop?: boolean
), perhaps?
Thanks for the quick answer 😄
A potential issue with having SanityImageObjectStub as the only valid input is that if you process images that could be resolved or not you'd have to manually set the systems for dealing with that. Particularly in the Sanity.io site this is a very common situation but maybe it's an edge case we don't need to care about?
Anywho, happy to go with what you think best, you're light-years ahead of me here.
I'll try to work on the PR for this late next week :)
Hello. 3 years later, I chime in. Any snippet/PR @hdoro?
With Google penalizing CLS, it's more important than ever to know beforehand the dimensions of the image that we want to display. Unfortunately getImageDimensions
from @sanity/asset-utils
only gives the original dimensions.
Here you go @thobas-dnvgl :
import type { SanityImageObject } from '@sanity/image-url/lib/types/types'
export function getImageDimensions(
image: SanityImageObject,
): { width: number; height: number; aspectRatio: number } | undefined {
if (!image?.asset?._ref) {
return
}
// example asset._ref:
// image-7558c4a4d73dac0398c18b7fa2c69825882e6210-366x96-png
// When splitting by '-' we can extract the dimensions, id and extension
const dimensions = image.asset._ref.split('-')[2]
const [width, height] = dimensions.split('x').map(Number)
if (!width || !height || Number.isNaN(width) || Number.isNaN(height)) {
return
}
if (image.crop) {
const croppedWidth =
width * (1 - (image.crop?.right || 0) - (image.crop?.left || 0))
const croppedHeight =
height * (1 - (image.crop?.top || 0) - (image.crop?.bottom || 0))
return {
width: croppedWidth,
height: croppedHeight,
aspectRatio: croppedWidth / croppedHeight,
}
}
return {
width,
height,
aspectRatio: width / height,
}
}