astrolicious / astro-tips.dev

The place for content that goes beyond the official docs, for all Astronauts!
https://astro-tips.dev
MIT License
76 stars 7 forks source link

Image Placeholders #52

Open OliverSpeir opened 5 months ago

OliverSpeir commented 5 months ago

Some inspiration:

OliverSpeir commented 1 week ago

https://discord.com/channels/830184174198718474/846469231176056853/1277731809467175014

---
import { getPixels } from "@unpic/pixels";
import type { UnresolvedImageTransform } from "astro";
import type { HTMLAttributes } from "astro/types";
import { getImage, type LocalImageProps } from "astro:assets";
import { readFile } from "node:fs/promises";
import sharp from "sharp";
import { rgbaToThumbHash, thumbHashToDataURL } from "thumbhash";

type Props = Omit<LocalImageProps, "src"> & {
  src: ImageMetadata;
};

const props = Astro.props;

if (typeof props.width === "string") {
  props.width = parseInt(props.width);
}

if (typeof props.height === "string") {
  props.height = parseInt(props.height);
}

const image = await getImage(props);

const opts: UnresolvedImageTransform = {
  src: Astro.props.src,
  format: "png",
};

const [w, h] = [image.attributes.width, image.attributes.height];

// if pic is 1:1 or wider than tall
if (w >= h) {
  opts.width = 100;
}

// if pic is 1:1 or taller than wide
if (h >= w) {
  opts.height = 100;
}
let buf = import.meta.env.PROD
  ? await sharp(await readFile(`./dist/${props.src.src}`))
    .resize({
      width: 100,
      height: 100,
      fit: "inside",
      withoutEnlargement: true,
    })
    .png()
    .modulate({ saturation: 1.2 })
    .toBuffer()
  : await getImage(opts)
    .then(_ => new URL(_.src, Astro.url));

const { height, width, data } = await getPixels(buf);
const hash = rgbaToThumbHash(width, height, data);
const src = thumbHashToDataURL(hash);

const additionalAttributes: HTMLAttributes<"img"> = {};
if (image.srcSet.values.length > 0) {
  additionalAttributes.srcset = image.srcSet.attribute;
}
---

<img
  src={src}
  data-src={image.src}
  data-srcset={additionalAttributes.srcset}
  {...additionalAttributes}
  {...image.attributes}
/>

<script>
import { lazyLoad } from "unlazy";

lazyLoad();
</script>
OliverSpeir commented 1 week ago

https://www.robinosborne.co.uk/2018/01/05/image-placeholders-do-it-right-or-dont-do-it-at-all-please/

sarah11918 commented 1 week ago

haha.. just came here to post that same article!

OliverSpeir commented 1 week ago

https://www.robinosborne.co.uk/2018/01/05/image-placeholders-do-it-right-or-dont-do-it-at-all-please/

Not sure I agree with this honestly

The main point of the article I got was don't do blurry LQIP (low quality image placeholders) instead just do a lower quality (but still recognizable) version of the original image

alexanderniebuhr commented 1 week ago

Thanks for all the information and context.. I need to block myself some time to go over this.