File size: 2,159 Bytes
9fa1f67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import sharp from 'sharp'

const SAMPLE_SIZE = 32

const initSQRT = (N) => {
  const c = new Array(N)
  for (let i = 1; i < N; i++) {
    c[i] = 1
  }
  c[0] = 1 / Math.sqrt(2.0)
  return c
}

const SQRT = initSQRT(SAMPLE_SIZE)

const initCOS = (N) => {
  const cosines = new Array(N)
  for (let k = 0; k < N; k++) {
    cosines[k] = new Array(N)
    for (let n = 0; n < N; n++) {
      cosines[k][n] = Math.cos(((2 * k + 1) / (2.0 * N)) * n * Math.PI)
    }
  }
  return cosines
}

const COS = initCOS(SAMPLE_SIZE)

const applyDCT = (f, size) => {
  var N = size

  var F = new Array(N)
  for (var u = 0; u < N; u++) {
    F[u] = new Array(N)
    for (var v = 0; v < N; v++) {
      var sum = 0
      for (var i = 0; i < N; i++) {
        for (var j = 0; j < N; j++) {
          sum += COS[i][u] * COS[j][v] * f[i][j]
        }
      }
      sum *= (SQRT[u] * SQRT[v]) / 4
      F[u][v] = sum
    }
  }
  return F
}

const LOW_SIZE = 8

export const phash = async (image, options) => {
  const data = await sharp(image, options)
    .greyscale()
    .resize(SAMPLE_SIZE, SAMPLE_SIZE, { fit: 'fill' })
    .rotate()
    .raw()
    .toBuffer()
  // copy signal
  const s = new Array(SAMPLE_SIZE)
  for (let x = 0; x < SAMPLE_SIZE; x++) {
    s[x] = new Array(SAMPLE_SIZE)
    for (let y = 0; y < SAMPLE_SIZE; y++) {
      s[x][y] = data[SAMPLE_SIZE * y + x]
    }
  }

  // apply 2D DCT II
  const dct = applyDCT(s, SAMPLE_SIZE)

  // get AVG on high frequencies
  let totalSum = 0
  for (let x = 0; x < LOW_SIZE; x++) {
    for (let y = 0; y < LOW_SIZE; y++) {
      totalSum += dct[x + 1][y + 1]
    }
  }

  const avg = totalSum / (LOW_SIZE * LOW_SIZE)

  // compute hash
  let fingerprint = []

  for (let x = 0; x < LOW_SIZE; x++) {
    for (let y = 0; y < LOW_SIZE; y++) {
      fingerprint.push(dct[x + 1][y + 1] > avg ? 1 : 0)
    }
  }
  return parseInt(fingerprint.join(''), 2).toString(16)
}

export const distance = (a, b) => {
  let count = 0
  for (let i = 0; i < a.length; i++) {
    if (a[i] !== b[i]) {
      count++
    }
  }
  return count
}