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 +54 -3
- package/index.d.ts +45 -11
- package/index.js +105 -0
- package/package.json +2 -2
- package/src/lib.rs +15 -0
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
|
-
|
|
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
|
-
* @
|
|
16
|
-
*
|
|
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
|
-
*
|
|
20
|
-
*
|
|
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
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* }
|
|
25
|
-
* ```
|
|
26
|
+
* @throws {TypeError}
|
|
27
|
+
* Thrown if `input` is not a Buffer.
|
|
26
28
|
*/
|
|
27
|
-
declare function
|
|
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
|
-
|
|
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.
|
|
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
|
+
}
|