File size: 1,992 Bytes
7e3630c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412f992
7e3630c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import { type Jimp } from "jimp";
import { useEffect, useState } from "react";
import { useImageCache } from "../InkPictureProvider.js";
import type { PixelData, PngData } from "../renderers/types.js";
import { fetchImage, getPngBuffer, getRawPixels } from "../utils/image.js";

export function useImage<T extends "pixels" | "png" = "pixels">(options: {
  src: Parameters<typeof Jimp.read>[0];
  pixelWidth: number;
  pixelHeight: number;
  mode?: T;
}): T extends "png"
  ? { imageData: PngData | undefined; error: boolean }
  : { imageData: PixelData | undefined; error: boolean } {
  const { src, pixelWidth, pixelHeight, mode = "pixels" } = options;
  const [imageData, setImageData] = useState<PngData | PixelData | undefined>(
    undefined,
  );
  const [error, setError] = useState(false);
  const cache = useImageCache();

  useEffect(() => {
    if (pixelWidth === 0 || pixelHeight === 0) return;

    let cancelled = false;

    const load = async () => {
      let image = typeof src === "string" ? cache?.get(src) : undefined;

      if (!image) {
        image = await fetchImage(src);
        if (cancelled) return;

        if (!image) {
          setError(true);
          setImageData(undefined);
          return;
        }

        if (typeof src === "string") {
          cache?.set(src, image);
        }
      }

      setError(false);
      image.cover({ w: pixelWidth, h: pixelHeight });

      if (mode === "png") {
        const result = await getPngBuffer(image);
        if (!cancelled) {
          setImageData(result);
        }
      } else {
        const result = await getRawPixels(image);
        if (!cancelled) {
          setImageData(result);
        }
      }
    };

    load();

    return () => {
      cancelled = true;
    };
  }, [src, pixelWidth, pixelHeight, mode, cache]);

  return { imageData, error } as T extends "png"
    ? { imageData: PngData | undefined; error: boolean }
    : { imageData: PixelData | undefined; error: boolean };
}