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

Lack of control/flexibility with SanityImage params #89

Open
fvieira opened this issue Aug 24, 2020 · 4 comments
Open

Lack of control/flexibility with SanityImage params #89

fvieira opened this issue Aug 24, 2020 · 4 comments

Comments

@fvieira
Copy link

fvieira commented Aug 24, 2020

In order to explain why I think the current SanityImage params are not flexible enough, I'm going to give an example.

Let's say I have a 400x400 div in my website that I want to fill with an image that comes from Sanity. If I was building the image url by hand, I'd use the following params: w=400&h=400&fit=min. This always gives me a square image (perfect for my square div), shrinks large images as needed, and doesn't scale up small images (CSS can do that if needed).
Now, using a fluid query (and yes, I know that in this specific example I could use a fixed query, but I simplified for sake of brevity), all I can say is (maxwidth: 400, maxHeight: 400). If the image that I have in Sanity has more that 400 width and height, I get the same image as if using the params w=400&h=400&fit=min, but if one size of the image is smaller, let's say 500x200, it results in these params w=400&h=200&fit=crop, which gives me an image that is not square (and thus wastes bandwidth by fetching an image where half of it is never shown, and also results in a stretched image if seen on a browser that doesn't support object-fit).

What I'd like is to have more control over the final url, first by being able to set the fit parameter (in my case, to min), second by not having the lib changing the aspect ratio of the values I give it (if I give it a maxWidth and maxHeight of 400, the url shouldn't have a width of 400 and height of 200, independent of the size of the image being fetched).

I know there must be a million reasons for things to be the way they are that I'm not aware of, but the way they are now is also limiting, so I was hoping to start a discussion on how we could improve things.

@aidan-rypens
Copy link

Yes, more control would be great. For example, define the quality somewhere of the images that are been resolved. The compression is driving me mad!

@bradley
Copy link

bradley commented Oct 27, 2020

I know this is a terrible thing to do but Im just slammed and didn't have time to contribute to the project accounting for tests, so essentially pulled out https://github.com/sanity-io/gatsby-source-sanity/blob/main/src/images/getGatsbyImageProps.ts and hacked it within my project to support extra Sanity image arguments.

I was cautious about breaking anything that had to do with image sizes so only allowed my own hack to support a subset of those options in the form of:

export type SanityImageArgs = {
  bg?: string,
  blur?: number,
  fm?: string,
  invert?: boolean,
  q?: number,
  sat?: number,
  sharpen?: number
}

And then added that argument to the two functions, getFixedGatsbyImage and getFluidGatsbyImage in the form of:

export function getFluidGatsbyImage(
  image: ImageNode,
  args: FluidArgs,
  sanityArgs: SanityImageArgs,
  loc: SanityLocation,
): GatsbyFluidImageProps | null {

...

const sanityParams = Object.keys(sanityArgs || {}).map(key => key + '=' + sanityArgs[key]).join('&')

const baseSrc =
    isOriginalSize(maxWidth, maxHeight) ||
    (maxWidth >= dimensions.width && maxHeight >= dimensions.height)
      ? `${url}?${sanityParams}`
      : `${url}?w=${maxWidth}&h=${maxHeight}&fit=crop&${sanityParams}`

...

  const srcSets = widths
    .filter((currentWidth) => currentWidth <= dimensions.width)
    .reduce((acc, currentWidth) => {
      const currentHeight = Math.round(currentWidth / desiredAspectRatio)
      const imgUrl = isOriginalSize(currentWidth, currentHeight)
        ? `${url}?${sanityParams}`
        : `${url}?w=${currentWidth}&h=${currentHeight}&fit=crop&${sanityParams}`

      const webpUrl = convertToFormat(imgUrl, 'webp')
      const baseUrl = convertToFormat(imgUrl, forceConvert || props.extension)
      acc.webp.push(`${webpUrl} ${currentWidth}w`)
      acc.base.push(`${baseUrl} ${currentWidth}w`)
      return acc
    }, initial)

...

This is then used as:

const fluid = getGatsbyImageProps.getFluidGatsbyImage(
    banner.asset.id,
    {
      maxHeight: 2400,
      maxWidth: 2400
    },
    {
      q: 30
    }
    sanityConfig
  );

Maybe this will help inspire a nice update to this package if anything. Here is a gist.

@bradley
Copy link

bradley commented Nov 12, 2020

Ok ended up making a pull request for this: #95

@AllanPooley
Copy link

For anyone else struggling with this, there's a Gatsby plugin that might help: https://www.sanity.io/plugins/gatsby-plugin-sanity-image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants