File size: 2,784 Bytes
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import { fileURLToPath } from "node:url";
import { Jimp } from "jimp";

export type JimpImage = Awaited<ReturnType<typeof Jimp.read>>;

export interface ImageOutputInfo {
  width: number;
  height: number;
  channels: number;
  size?: number;
}

export async function fetchImage(
  src: Parameters<typeof Jimp.read>[0],
): Promise<JimpImage | undefined> {
  try {
    if (typeof src === "string" && src.startsWith("file://")) {
      return await Jimp.read(fileURLToPath(src));
    }
    return await Jimp.read(src);
  } catch {
    return undefined;
  }
}

export async function getRawPixels(
  image: JimpImage,
): Promise<{ data: Buffer; info: ImageOutputInfo }> {
  return {
    data: image.bitmap.data,
    info: {
      width: image.bitmap.width,
      height: image.bitmap.height,
      channels: 4,
    },
  };
}

export async function getPngBuffer(
  image: JimpImage,
): Promise<{ data: Buffer; info: ImageOutputInfo }> {
  const buffer = await image.getBuffer("image/png");
  return {
    data: buffer,
    info: {
      width: image.bitmap.width,
      height: image.bitmap.height,
      channels: 4,
      size: buffer.length,
    },
  };
}

export function calculateImageSize({
  maxWidth,
  maxHeight,
  originalAspectRatio,
  specifiedWidth,
  specifiedHeight,
}: {
  maxWidth: number;
  maxHeight: number;
  originalAspectRatio: number;
  specifiedWidth?: number;
  specifiedHeight?: number;
}): { width: number; height: number } {
  // Both width and height specified
  if (specifiedWidth && specifiedHeight) {
    const width = Math.min(specifiedWidth, maxWidth);
    const height = Math.min(specifiedHeight, maxHeight);
    return { width: Math.round(width), height: Math.round(height) };
  }

  // Only width specified
  if (specifiedWidth) {
    let width = Math.min(specifiedWidth, maxWidth);
    let height = width / originalAspectRatio;

    if (height > maxHeight) {
      height = maxHeight;
      width = height * originalAspectRatio;
    }

    return { width: Math.round(width), height: Math.round(height) };
  }

  // Only height specified
  if (specifiedHeight) {
    let height = Math.min(specifiedHeight, maxHeight);
    let width = height * originalAspectRatio;

    if (width > maxWidth) {
      width = maxWidth;
      height = width / originalAspectRatio;
    }

    return { width: Math.round(width), height: Math.round(height) };
  }

  // No dimensions specified - scale to fit while maintaining aspect ratio
  let height = maxHeight;
  let width = height * originalAspectRatio;

  if (width > maxWidth) {
    width = maxWidth;
    height = width / originalAspectRatio;
  }

  if (height > maxHeight) {
    height = maxHeight;
    width = height * originalAspectRatio;
  }

  return { width: Math.round(width), height: Math.round(height) };
}