pdqhash-node 1.0.0 → 1.1.0

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.
package/README.md CHANGED
@@ -8,16 +8,67 @@ A minimal Node.js wrapper around the Cargo crate [pdqhash](https://github.com/da
8
8
  ## Install
9
9
  ```
10
10
  yarn add pdqhash-node
11
- yarn build
12
11
  ```
13
12
 
14
13
  ## Usage
15
14
 
16
15
  ```js
17
16
  import { readFileSync } from 'fs';
18
- import { pdqhash } from 'pdqhash-node';
17
+ import { pdqhash, pdqhashBuffer } from 'pdqhash-node';
19
18
 
20
19
  const buf = readFileSync('image.jpg');
21
- const hashHex = pdqhash(buf); // string | null
20
+ var hashHex = pdqhash(buf); // string | null
21
+ // or
22
+ var hashBuf = pdqhashBuffer(buf); // Buffer | null
22
23
  console.log(hashHex);
23
24
  ```
25
+
26
+ ## API
27
+
28
+ - `pdqhash(input: Buffer): string | null`
29
+ - Hex string PDQ hash. Returns `null` if hashing fails.
30
+ - `pdqhashBuffer(input: Buffer): Buffer | null`
31
+ - Raw PDQ hash bytes as a `Buffer`. Returns `null` if hashing fails.
32
+ - `pdqhashWithQuality(input: Buffer): { hash: string; quality: number } | null`
33
+ - Hex string PDQ hash plus the quality score. Returns `null` if hashing fails.
34
+ - `hammingDistance(a: Buffer, b: Buffer): number`
35
+ - Computes Hamming distance between two PDQ hash Buffers.
36
+
37
+ ### Examples
38
+
39
+ Compute hash in hex and Buffer:
40
+
41
+ ```js
42
+ import { readFileSync } from 'fs';
43
+ import { pdqhash, pdqhashBuffer } from 'pdqhash-node';
44
+
45
+ const buf = readFileSync('image.jpg');
46
+ console.log(pdqhash(buf)); // hex string
47
+ console.log(pdqhashBuffer(buf)?.toString('hex')); // same hash from Buffer
48
+ ```
49
+
50
+ Get hash with quality:
51
+
52
+ ```js
53
+ import { readFileSync } from 'fs';
54
+ import { pdqhashWithQuality } from 'pdqhash-node';
55
+
56
+ const buf = readFileSync('image.jpg');
57
+ const result = pdqhashWithQuality(buf);
58
+ if (result) {
59
+ console.log(result.hash, result.quality);
60
+ }
61
+ ```
62
+
63
+ Compute Hamming distance:
64
+
65
+ ```js
66
+ import { readFileSync } from 'fs';
67
+ import { pdqhashBuffer, hammingDistance } from 'pdqhash-node';
68
+
69
+ const a = pdqhashBuffer(readFileSync('image1.jpg'));
70
+ const b = pdqhashBuffer(readFileSync('image2.jpg'));
71
+ if (a && b) {
72
+ console.log(hammingDistance(a, b));
73
+ }
74
+ ```
package/index.d.ts CHANGED
@@ -11,23 +11,57 @@
11
11
  *
12
12
  * @throws {TypeError}
13
13
  * Thrown if `input` is not a Buffer.
14
+ */
15
+ declare function pdqhash(input: Buffer): string | null;
16
+
17
+ /**
18
+ * Generate a PDQ perceptual hash from a binary buffer.
14
19
  *
15
- * @example
16
- * ```ts
17
- * import { pdqhash } from "pdqhash-node";
20
+ * This function accepts a {@link Buffer} and returns the raw PDQ
21
+ * hash as a {@link Buffer}.
18
22
  *
19
- * const buf = fs.readFileSync("image.jpg");
20
- * const hash = pdqhash(buf);
23
+ * @param input - A Buffer containing the binary data to hash.
24
+ * @returns A Buffer containing the PDQ hash, or `null` if a hash could not be generated.
21
25
  *
22
- * if (hash) {
23
- * console.log(hash);
24
- * }
25
- * ```
26
+ * @throws {TypeError}
27
+ * Thrown if `input` is not a Buffer.
26
28
  */
27
- declare function pdqhash(input: Buffer): string | null;
29
+ declare function pdqhashBuffer(input: Buffer): Buffer | null;
30
+
31
+ /**
32
+ * Generate a PDQ hash with quality metadata from a binary buffer.
33
+ *
34
+ * Returns an object containing the PDQ hash in hex string form and
35
+ * the computed quality score.
36
+ *
37
+ * @param input - A Buffer containing the binary data to hash.
38
+ * @returns An object `{ hash: string, quality: number }`, or `null` if a hash could not be generated.
39
+ *
40
+ * @throws {TypeError}
41
+ * Thrown if `input` is not a Buffer.
42
+ */
43
+ declare function pdqhashWithQuality(input: Buffer): { hash: string; quality: number } | null;
44
+
45
+ /**
46
+ * Compute Hamming distance between two PDQ hashes.
47
+ *
48
+ * Accepts two PDQ hash Buffers and returns their Hamming distance
49
+ * as a number.
50
+ *
51
+ * @param a - First PDQ hash as a Buffer.
52
+ * @param b - Second PDQ hash as a Buffer.
53
+ * @returns The Hamming distance between `a` and `b`.
54
+ *
55
+ * @throws {TypeError}
56
+ * Thrown if either argument is not a Buffer.
57
+ */
58
+ declare function hammingDistance(a: Buffer, b: Buffer): number;
28
59
 
29
60
  declare const _default: {
30
- pdqhash: typeof pdqhash;
61
+ pdqhash: typeof pdqhash;
62
+ pdqhashBuffer: typeof pdqhashBuffer;
63
+ pdqhashWithQuality: typeof pdqhashWithQuality;
64
+ hammingDistance: typeof hammingDistance;
31
65
  };
32
66
 
33
67
  export = _default;
package/index.js CHANGED
@@ -33,6 +33,111 @@ function pdqhash(input) {
33
33
  return Buffer.from(res.hash).toString('hex');
34
34
  }
35
35
 
36
+ /**
37
+ * Generate a PDQ perceptual hash from a binary buffer.
38
+ *
39
+ * This function accepts a {@link Buffer} and returns the raw PDQ
40
+ * hash as a {@link Buffer}.
41
+ *
42
+ * @param input - A Buffer containing the binary data to hash.
43
+ * @returns A Buffer containing the PDQ hash, or `null` if a hash could not be generated.
44
+ *
45
+ * @throws {TypeError}
46
+ * Thrown if `input` is not a Buffer.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * import { pdqhashBuffer } from "pdqhash-node";
51
+ *
52
+ * const buf = fs.readFileSync("image.jpg");
53
+ * const hashBuf = pdqhashBuffer(buf);
54
+ *
55
+ * if (hashBuf) {
56
+ * console.log(hashBuf.toString('hex'));
57
+ * }
58
+ * ```
59
+ */
60
+ function pdqhashBuffer(input) {
61
+ if (!Buffer.isBuffer(input)) {
62
+ throw new TypeError('pdqhashBuffer(input): input must be a Buffer');
63
+ }
64
+ const res = addon.generatePdqFromBuffer(input);
65
+ if (!res) return null;
66
+ return Buffer.from(res.hash);
67
+ }
68
+
69
+ /**
70
+ * Generate a PDQ hash with quality metadata from a binary buffer.
71
+ *
72
+ * Returns an object containing the PDQ hash in hex string form and
73
+ * the computed quality score.
74
+ *
75
+ * @param input - A Buffer containing the binary data to hash.
76
+ * @returns An object `{ hash: string, quality: number }`, or `null` if a hash could not be generated.
77
+ *
78
+ * @throws {TypeError}
79
+ * Thrown if `input` is not a Buffer.
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * import { pdqhashWithQuality } from "pdqhash-node";
84
+ *
85
+ * const buf = fs.readFileSync("image.jpg");
86
+ * const result = pdqhashWithQuality(buf);
87
+ *
88
+ * if (result) {
89
+ * console.log(result.hash, result.quality);
90
+ * }
91
+ * ```
92
+ */
93
+ function pdqhashWithQuality(input) {
94
+ if (!Buffer.isBuffer(input)) {
95
+ throw new TypeError('pdqhashWithQuality(input): input must be a Buffer');
96
+ }
97
+ const res = addon.generatePdqFromBuffer(input);
98
+ if (!res) return null;
99
+ return {
100
+ hash: Buffer.from(res.hash).toString('hex'),
101
+ quality: res.quality,
102
+ };
103
+ }
104
+
105
+ /**
106
+ * Compute Hamming distance between two PDQ hashes.
107
+ *
108
+ * Accepts two PDQ hash Buffers and returns their Hamming distance
109
+ * as a number.
110
+ *
111
+ * @param a - First PDQ hash as a Buffer.
112
+ * @param b - Second PDQ hash as a Buffer.
113
+ * @returns The Hamming distance between `a` and `b`.
114
+ *
115
+ * @throws {TypeError}
116
+ * Thrown if either argument is not a Buffer.
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * import { pdqhashBuffer, hammingDistance } from "pdqhash-node";
121
+ *
122
+ * const a = pdqhashBuffer(fs.readFileSync("image1.jpg"));
123
+ * const b = pdqhashBuffer(fs.readFileSync("image2.jpg"));
124
+ *
125
+ * if (a && b) {
126
+ * console.log(hammingDistance(a, b));
127
+ * }
128
+ * ```
129
+ */
130
+ function hammingDistance(a, b) {
131
+ if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
132
+ throw new TypeError('hammingDistance(a, b): arguments must be Buffers');
133
+ }
134
+ return addon.hammingDistance(a, b);
135
+ }
136
+
36
137
  module.exports = {
37
138
  pdqhash,
139
+ pdqhashBuffer,
140
+ pdqhashWithQuality,
141
+ hammingDistance
38
142
  };
143
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdqhash-node",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "main": "index.js",
5
5
  "types": "index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "repository": {
16
16
  "type": "git",
17
- "url": "https://github.com/dispherical/pdqhash-node.git"
17
+ "url": "git+https://github.com/dispherical/pdqhash-node.git"
18
18
  },
19
19
  "keywords": [
20
20
  "pdq",
package/src/lib.rs CHANGED
@@ -22,3 +22,18 @@ pub fn generate_pdq_from_buffer(input: Buffer) -> Result<Option<PdqResult>> {
22
22
  None => Ok(None),
23
23
  }
24
24
  }
25
+
26
+ #[napi]
27
+ pub fn hamming_distance(a: Buffer, b: Buffer) -> Result<u32> {
28
+ if a.len() != b.len() {
29
+ return Err(Error::new(
30
+ Status::InvalidArg,
31
+ "Buffers must be the same length",
32
+ ));
33
+ }
34
+
35
+ Ok(a.iter()
36
+ .zip(b.iter())
37
+ .map(|(x, y)| (x ^ y).count_ones())
38
+ .sum())
39
+ }