File size: 3,841 Bytes
3530df7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import { JimpClass } from "@jimp/types";
import anyBase from "any-base";

import ImagePHash from "./phash.js";

// an array storing the maximum string length of hashes at various bases
// 0 and 1 do not exist as possible hash lengths
// prettier-ignore
const alphabet =
  "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_";

// an array storing the maximum string length of hashes at various bases
// 0 and 1 do not exist as possible hash lengths
const maxHashLength = [NaN, NaN];

for (let i = 2; i < 65; i++) {
  const maxHash = anyBase(
    anyBase.BIN,
    alphabet.slice(0, i),
  )(new Array(64 + 1).join("1"));
  maxHashLength.push(maxHash.length);
}

export const methods = {
  /**
   * Calculates the perceptual hash
   * @returns the perceptual hash
   * @example
   * ```ts
   * import { Jimp } from "jimp";
   *
   * const image = await Jimp.read("test/image.png");
   *
   * image.hash();
   * ```
   */
  pHash<I extends JimpClass>(image: I) {
    const pHash = new ImagePHash();
    return pHash.getHash(image);
  },

  /**
   * Generates a perceptual hash of the image <https://en.wikipedia.org/wiki/Perceptual_hashing>. And pads the string. Can configure base.
   * @param base A number between 2 and 64 representing the base for the hash (e.g. 2 is binary, 10 is decimal, 16 is hex, 64 is base 64). Defaults to 64.
   * @example
   * ```ts
   * import { Jimp } from "jimp";
   *
   * const image = await Jimp.read("test/image.png");
   *
   * image.hash(2); // binary
   * image.hash(64); // base 64
   * ```
   */
  hash<I extends JimpClass>(image: I, base = 64) {
    if (base < 2 || base > 64) {
      throw new Error("base must be a number between 2 and 64");
    }

    const subAlphabet = alphabet.slice(0, base);
    const pHash = this.pHash(image);
    const maxLength = maxHashLength[base]!;

    return anyBase(anyBase.BIN, subAlphabet)(pHash).padStart(maxLength, "0");
  },

  /**
   * Calculates the hamming distance of the current image and a hash based on their perceptual hash
   * @param compareHash hash to compare to
   * @returns  a number ranging from 0 to 1, 0 means they are believed to be identical
   * @example
   * ```ts
   * import { Jimp } from "jimp";
   *
   * const image = await Jimp.read("test/image.png");
   *
   * image.distanceFromHash(image.pHash());
   * ```
   */
  distanceFromHash<I extends JimpClass>(image: I, compareHash: string) {
    const pHash = new ImagePHash();
    const currentHash = pHash.getHash(image);

    return pHash.distance(currentHash, compareHash);
  },
};

/**
 * Calculates the hamming distance of two images based on their perceptual hash
 * @param img1 A Jimp image to compare
 * @param img2 A Jimp image to compare
 * @returns A number ranging from 0 to 1, 0 means they are believed to be identical
 * @example
 * ```ts
 * import { Jimp, distance } from "jimp";
 *
 * const image1 = await Jimp.read("test/image.png");
 * const image2 = await Jimp.read("test/image.png");
 *
 * distance(image1, image2); // 0.5
 * ```
 */
export function distance<I extends JimpClass>(img1: I, img2: I) {
  const phash = new ImagePHash();
  const hash1 = phash.getHash(img1);
  const hash2 = phash.getHash(img2);

  return phash.distance(hash1, hash2);
}

/**
 * Calculates the hamming distance of two images based on their perceptual hash
 * @param hash1 A pHash
 * @param hash2 A pHash
 * @returns A number ranging from 0 to 1, 0 means they are believed to be identical
 * @example
 * ```ts
 * import { Jimp, compareHashes } from "jimp";
 *
 * const image1 = await Jimp.read("test/image.png");
 * const image2 = await Jimp.read("test/image.png");
 *
 * compareHashes(image1.pHash(), image2.pHash()); // 0.5
 * ```
 */
export function compareHashes(hash1: string, hash2: string) {
  const phash = new ImagePHash();
  return phash.distance(hash1, hash2);
}