@sylphx/image-reader-mcp 0.1.2 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,36 +1,51 @@
1
- import sharp from 'sharp';
1
+ /** Cheap local palette sample via optional sharp stats (not ML segmentation). */
2
2
 
3
- /** Cheap local palette sample via sharp stats (not ML segmentation). */
4
- export async function samplePalette(
5
- filePath: string,
6
- maxColors = 5
7
- ): Promise<Array<{ hex: string; approx_share: number }>> {
8
- const image = sharp(filePath, { failOn: 'none' }).resize(64, 64, { fit: 'inside' });
9
- const stats = await image.stats();
10
- const dominant = stats.dominant;
11
- if (!dominant) return [];
12
-
13
- const hex = (r: number, g: number, b: number) =>
14
- `#${[r, g, b]
15
- .map((v) =>
16
- Math.max(0, Math.min(255, Math.round(v)))
17
- .toString(16)
18
- .padStart(2, '0')
19
- )
20
- .join('')}`;
21
-
22
- const colors: Array<{ hex: string; approx_share: number }> = [
23
- { hex: hex(dominant.r, dominant.g, dominant.b), approx_share: 0.55 },
24
- ];
3
+ type SharpLike = (
4
+ input: string,
5
+ opts?: { failOn?: string }
6
+ ) => {
7
+ resize: (
8
+ w: number,
9
+ h: number,
10
+ opts: { fit: string }
11
+ ) => {
12
+ stats: () => Promise<{
13
+ dominant?: { r: number; g: number; b: number };
14
+ channels?: Array<{ mean?: number }>;
15
+ }>;
16
+ };
17
+ };
25
18
 
26
- // Channel means as a second honest swatch (not true multi-color clustering).
27
- const ch = stats.channels;
28
- if (ch && ch.length >= 3) {
29
- colors.push({
30
- hex: hex(ch[0]?.mean ?? dominant.r, ch[1]?.mean ?? dominant.g, ch[2]?.mean ?? dominant.b),
31
- approx_share: 0.45,
32
- });
19
+ export async function samplePalette(
20
+ filePath: string
21
+ ): Promise<Array<{ hex: string; approx_share: number }> | undefined> {
22
+ let sharp: SharpLike;
23
+ try {
24
+ const mod = await import('sharp');
25
+ const candidate = (mod as { default?: SharpLike }).default ?? (mod as unknown as SharpLike);
26
+ sharp = candidate;
27
+ } catch {
28
+ return undefined;
33
29
  }
34
30
 
35
- return colors.slice(0, maxColors);
31
+ try {
32
+ const image = sharp(filePath, { failOn: 'none' }).resize(64, 64, { fit: 'inside' });
33
+ const stats = await image.stats();
34
+ const channels = stats.channels ?? [];
35
+ if (stats.dominant) {
36
+ const { r, g, b } = stats.dominant;
37
+ const hex = `#${[r, g, b].map((n) => n.toString(16).padStart(2, '0')).join('')}`;
38
+ return [{ hex, approx_share: 1 }];
39
+ }
40
+ if (channels.length >= 3) {
41
+ const r = Math.round(channels[0]?.mean ?? 0);
42
+ const g = Math.round(channels[1]?.mean ?? 0);
43
+ const b = Math.round(channels[2]?.mean ?? 0);
44
+ const hex = `#${[r, g, b].map((n) => n.toString(16).padStart(2, '0')).join('')}`;
45
+ return [{ hex, approx_share: 1 }];
46
+ }
47
+ return undefined;
48
+ } catch {
49
+ return undefined;
50
+ }
36
51
  }
Binary file