File size: 1,188 Bytes
39309b1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
/* pixels.mjs: look at what a browser actually drew.
 *   const img = decodePng(await page.screenshot({ clip }))
 *   px(img, 10, 20)            -> [r, g, b, a]
 *   stats(img, x, y, w, h)     -> { mean:[r,g,b], variance, lit, n }  (lit = pixels brighter than the floor)
 */
import { PNG } from 'pngjs';

export const decodePng = (buf) => PNG.sync.read(buf);

export const px = (img, x, y) => {
  const i = (Math.round(y) * img.width + Math.round(x)) * 4;
  return [img.data[i], img.data[i + 1], img.data[i + 2], img.data[i + 3]];
};

/** colour distance (0..441) */
export const dist = (a, b) => Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]);

export function stats(img, x0, y0, w, h, floor = 40) {
  let n = 0, lit = 0, sr = 0, sg = 0, sb = 0, ssq = 0;
  for (let y = y0; y < y0 + h && y < img.height; y++) for (let x = x0; x < x0 + w && x < img.width; x++) {
    const [r, g, b] = px(img, x, y);
    n++; sr += r; sg += g; sb += b;
    const l = (r + g + b) / 3;
    ssq += l * l;
    if (l > floor) lit++;
  }
  const mr = sr / n, mg = sg / n, mb = sb / n, ml = (mr + mg + mb) / 3;
  return { mean: [mr, mg, mb].map((v) => Math.round(v)), variance: ssq / n - ml * ml, lit, n };
}