evanw / thumbhash

A very compact representation of an image placeholder
https://evanw.github.io/thumbhash/
MIT License
3.49k stars 69 forks source link

Aspect ratio isn't the same #31

Closed jamiechong closed 8 months ago

jamiechong commented 8 months ago

I'm testing this out and it seems like the generated thumbHash image has a different aspect ratio than my source image. Any ideas why?

The aspect ratio should be 67:100, but the hash image has an aspect ratio of 120:167 ~= 67:93.

Screenshot 2024-01-13 at 11 45 10 PM

I'm using this code:

  const image = await fetch(imageUri);
  const buffer = await image.arrayBuffer();
  const thumb = await sharp(buffer).resize(100, 100, { fit: "inside" });
  const { data, info } = await thumb.ensureAlpha().raw().toBuffer({ resolveWithObject: true });
  const thumbHash = rgbaToThumbHash(info.width, info.height, data);
  console.log(thumbHashToDataURL(thumbHash));

Here is my source image: image-39360735-0a5f-4320-86da-828b5dfef30a

evanw commented 8 months ago

This is not a bug. The aspect ratio is approximate, as is everything else about the resulting image (which is done for space-saving reasons). If you need an accurate aspect ratio then you'll have to store it along with the other data about the image.

jamiechong commented 8 months ago

That's too bad. I'm using thumbhash with expo-image, which doesn't provide a mechanism to utilize aspect ratio to size the placeholder image properly. To demonstrate, I've set a long transition time so you can see the placeholder fade into the source image and this is what it looks like.

Screenshot 2024-01-14 at 9 09 51 AM
evanw commented 8 months ago

A thumbnail is often not the exact same ratio as the input image anyway because of integer rounding when you scale down the dimensions. For example, consider a 1353x1000 image, which has an aspect ratio of 1.353. Shrinking it down by 20x gives a 68x50 image, which has an aspect ratio of 1.36, which is not the same aspect ratio. The only way to get the aspect ratio to be equal is for the image to have dimensions 67.65x50. But that can't happen because raster images always have a whole number of pixels in both dimensions. This has nothing to do with ThumbHash; this is just a reality of raster graphics.

If you want the images to line up exactly, you could consider requesting that expo-image add the ability to set the aspect ratio of the placeholder image.

jamiechong commented 8 months ago

Agreed - in the meantime I'll have to roll my own solution by using contentFit="cover". Thanks for replying.