iscc-core-ts 0.0.7 → 0.0.9
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 +72 -5
- package/lib/cjs/code-content-audio.d.ts +22 -0
- package/lib/cjs/code-content-audio.js +145 -0
- package/lib/cjs/code-content-audio.js.map +1 -0
- package/lib/cjs/code-content-image.d.ts +21 -0
- package/lib/cjs/code-content-image.js +121 -0
- package/lib/cjs/code-content-image.js.map +1 -0
- package/lib/cjs/code-content-text.d.ts +38 -0
- package/lib/cjs/code-content-text.js +72 -0
- package/lib/cjs/code-content-text.js.map +1 -0
- package/lib/cjs/code-content-video.d.ts +19 -0
- package/lib/cjs/code-content-video.js +328 -0
- package/lib/cjs/code-content-video.js.map +1 -0
- package/lib/cjs/codec.js +6 -7
- package/lib/cjs/codec.js.map +1 -1
- package/lib/cjs/constants.d.ts +10 -1
- package/lib/cjs/constants.js +25 -1
- package/lib/cjs/constants.js.map +1 -1
- package/lib/cjs/content-normalization.js +5 -9
- package/lib/cjs/content-normalization.js.map +1 -1
- package/lib/cjs/metacode.js +7 -14
- package/lib/cjs/metacode.js.map +1 -1
- package/lib/cjs/minhash.d.ts +34 -0
- package/lib/cjs/minhash.js +230 -0
- package/lib/cjs/minhash.js.map +1 -0
- package/lib/cjs/simhash.js +1 -2
- package/lib/cjs/simhash.js.map +1 -1
- package/lib/cjs/utils.js +9 -9
- package/lib/cjs/utils.js.map +1 -1
- package/lib/esm/code-content-audio.d.ts +22 -0
- package/lib/esm/code-content-audio.js +140 -0
- package/lib/esm/code-content-audio.js.map +1 -0
- package/lib/esm/code-content-image.d.ts +21 -0
- package/lib/esm/code-content-image.js +115 -0
- package/lib/esm/code-content-image.js.map +1 -0
- package/lib/esm/code-content-text.d.ts +38 -0
- package/lib/esm/code-content-text.js +67 -0
- package/lib/esm/code-content-text.js.map +1 -0
- package/lib/esm/code-content-video.d.ts +19 -0
- package/lib/esm/code-content-video.js +322 -0
- package/lib/esm/code-content-video.js.map +1 -0
- package/lib/esm/constants.d.ts +10 -1
- package/lib/esm/constants.js +24 -0
- package/lib/esm/constants.js.map +1 -1
- package/lib/esm/content-normalization.js +0 -3
- package/lib/esm/content-normalization.js.map +1 -1
- package/lib/esm/metacode.js +3 -9
- package/lib/esm/metacode.js.map +1 -1
- package/lib/esm/minhash.d.ts +34 -0
- package/lib/esm/minhash.js +223 -0
- package/lib/esm/minhash.js.map +1 -0
- package/lib/tsconfig-cjs.tsbuildinfo +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -6
package/README.md
CHANGED
|
@@ -1,5 +1,71 @@
|
|
|
1
1
|
# iscc-core-ts
|
|
2
|
-
Iscc core TypeScript implementation of iscc-core reference
|
|
2
|
+
Iscc core TypeScript implementation of [iscc-core python reference](https://github.com/iscc/iscc-core)
|
|
3
|
+
|
|
4
|
+
# Project summary
|
|
5
|
+
|
|
6
|
+
The “ISCC-CORE typescript implementation library” goal is to implement core functions of the new [ISCC standard ISO 24138:2024](https://www.iso.org/fr/standard/77899.html) in Typescript programming language.
|
|
7
|
+
This typescript core library will be useful for the javascript ecosystem and developers ( frontend, backend ) to use and work with this new standard in their project.
|
|
8
|
+
|
|
9
|
+
The ISCC stands for “International Standard Content Code”. More detail at [https://iscc.codes/](https://iscc.codes/)
|
|
10
|
+
|
|
11
|
+
The ISCC is a similarity preserving fingerprint and identifier for digital media assets.
|
|
12
|
+
|
|
13
|
+
ISCCs are generated algorithmically from digital content, just like cryptographic hashes. However, instead of using a single cryptographic hash function to identify data only, the ISCC uses various algorithms to create a composite identifier that exhibits similarity-preserving properties (soft hash).
|
|
14
|
+
|
|
15
|
+
The component-based structure of the ISCC identifies content at multiple levels of abstraction. Each component is self-describing, modular, and can be used separately or with others to aid in various content identification tasks. The algorithmic design supports content deduplication, database synchronization, indexing, integrity verification, timestamping, versioning, data provenance, similarity clustering, anomaly detection, usage tracking, allocation of royalties, fact-checking and general digital asset management use-cases.
|
|
16
|
+
|
|
17
|
+
# Work In progress
|
|
18
|
+
|
|
19
|
+
This library is under development. It is not ready for production. The current development planning can be check [here](https://github.com/users/branciard/projects/1)
|
|
20
|
+
|
|
21
|
+
| Functions | Implementation | test coverage
|
|
22
|
+
| ---------- | -------------- | -------- |
|
|
23
|
+
| gen_meta_code_v0 | Done | ☑ test_0001_title_only
|
|
24
|
+
| | | ☑ test_0002_title_extra
|
|
25
|
+
| | | ☑ test_0003_96_bits
|
|
26
|
+
| | | ☑ test_0004_128_bits
|
|
27
|
+
| | | ☑ test_0005_160_bits
|
|
28
|
+
| | | ☑ test_0006_192_bits
|
|
29
|
+
| | | ☑ test_0007_224_bits
|
|
30
|
+
| | | ☑ test_0008_256_bits
|
|
31
|
+
| | | ☑ test_0009_i18n
|
|
32
|
+
| | | ☑ test_0010_normalizeation
|
|
33
|
+
| | | ☑ test_0011_trim
|
|
34
|
+
| | | ☑ test_0012_trim_i18n
|
|
35
|
+
| | | ☐ test_0013_norm_i18n_256
|
|
36
|
+
| | | ☑ test_0014_meta_object_json
|
|
37
|
+
| | | ☑ test_0015_meta_object_json_ld
|
|
38
|
+
| | | ☑ test_0016_meta_data_url
|
|
39
|
+
| gen_text_code_v0 | Done | ☑ test_0000_empty_str
|
|
40
|
+
| | | ☑ test_0001_hello_world
|
|
41
|
+
| | | ☑ test_0002_hello_world_256_bits
|
|
42
|
+
| | | ☑ test_0003_i18n
|
|
43
|
+
| | | ☑ test_0004_more
|
|
44
|
+
| gen_image_code_v0 | Done | ☑ test_0000_all_black_64
|
|
45
|
+
| | | ☑ test_0001_all_white_128
|
|
46
|
+
| | | ☑ test_0003_img_256
|
|
47
|
+
| gen_audio_code_v0 | Done | ☑ test_0000_empty_64
|
|
48
|
+
| | | ☑ test_0001_one_128
|
|
49
|
+
| | | ☑ test_0002_two_256
|
|
50
|
+
| | | ☑ test_0003_test_neg_256
|
|
51
|
+
| | | ☑ test_0004_cv_256
|
|
52
|
+
| gen_video_code_v0 | Done | ☑ test_0000_one_zero_frame_64
|
|
53
|
+
| | | ☑ test_0001_multiple_frames_128
|
|
54
|
+
| | | ☑ test_0003_range_256
|
|
55
|
+
| gen_mixed_code_v0 | TODO | ☐ test_0000_std_64
|
|
56
|
+
| | | ☐ test_0001_128_truncated
|
|
57
|
+
| gen_data_code_v0 | TODO | ☐ test_0000_two_bytes_64
|
|
58
|
+
| | | ☐ test_0001_empty_64
|
|
59
|
+
| | | ☐ test_0002_zero_128
|
|
60
|
+
| | | ☐ test_0003_static_256
|
|
61
|
+
| gen_instance_code_v0 | TODO | ☐ test_0000_empty_64
|
|
62
|
+
| | | ☐ test_0001_zero_128
|
|
63
|
+
| | | ☐ test_0002_static_256
|
|
64
|
+
| gen_iscc_code_v0 | TODO | ☐ test_0000_standard
|
|
65
|
+
| | | ☐ test_0001_no_meta
|
|
66
|
+
| | | ☐ test_0002_no_meta_content_256
|
|
67
|
+
| | | ☐ test_0003_no_meta_content_128
|
|
68
|
+
| | | ☐ test_0004_ordering
|
|
3
69
|
|
|
4
70
|
|
|
5
71
|
|
|
@@ -10,14 +76,15 @@ We recomand to use [nvm](https://github.com/nvm-sh/nvm) to install and target no
|
|
|
10
76
|
Nvm version used:
|
|
11
77
|
```sh
|
|
12
78
|
nvm --version
|
|
13
|
-
0.
|
|
79
|
+
0.40.1
|
|
14
80
|
```
|
|
15
81
|
Install node 21
|
|
16
82
|
|
|
17
83
|
```sh
|
|
18
|
-
nvm install
|
|
19
|
-
|
|
20
|
-
|
|
84
|
+
nvm install --lts
|
|
85
|
+
Installing latest LTS version.
|
|
86
|
+
v20.18.0 is already installed.
|
|
87
|
+
Now using node v22.11.0 (npm v10.9.0)
|
|
21
88
|
```
|
|
22
89
|
|
|
23
90
|
# Install and build
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
*The Content-Code Audio is generated from a Chromaprint fingerprint provided as a vector of 32-bit
|
|
4
|
+
signed integers. The [iscc-sdk](https://github.com/iscc/iscc-sdk) uses
|
|
5
|
+
[fpcalc](https://acoustid.org/chromaprint) to extract Chromaprint vectors with the following
|
|
6
|
+
command line parameters:
|
|
7
|
+
|
|
8
|
+
`$ fpcalc -raw -json -signed -length 0 myaudiofile.mp3`
|
|
9
|
+
*/
|
|
10
|
+
export declare function gen_audio_code(chromaprint: number[], bits?: number, version?: number): {
|
|
11
|
+
iscc: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
* @param name
|
|
16
|
+
* @param description
|
|
17
|
+
* @returns
|
|
18
|
+
*/
|
|
19
|
+
export declare function gen_audio_code_v0(chromaprint: number[], bits?: number): {
|
|
20
|
+
iscc: string;
|
|
21
|
+
};
|
|
22
|
+
export declare function soft_hash_audio_v0(cv: Iterable<number>, bits?: number): Uint8Array;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.gen_audio_code = gen_audio_code;
|
|
4
|
+
exports.gen_audio_code_v0 = gen_audio_code_v0;
|
|
5
|
+
exports.soft_hash_audio_v0 = soft_hash_audio_v0;
|
|
6
|
+
const codec_1 = require("./codec");
|
|
7
|
+
const constants_1 = require("./constants");
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
*The Content-Code Audio is generated from a Chromaprint fingerprint provided as a vector of 32-bit
|
|
11
|
+
signed integers. The [iscc-sdk](https://github.com/iscc/iscc-sdk) uses
|
|
12
|
+
[fpcalc](https://acoustid.org/chromaprint) to extract Chromaprint vectors with the following
|
|
13
|
+
command line parameters:
|
|
14
|
+
|
|
15
|
+
`$ fpcalc -raw -json -signed -length 0 myaudiofile.mp3`
|
|
16
|
+
*/
|
|
17
|
+
function gen_audio_code(chromaprint, bits, version) {
|
|
18
|
+
if (!version) {
|
|
19
|
+
version = 0;
|
|
20
|
+
}
|
|
21
|
+
if (version == 0) {
|
|
22
|
+
return gen_audio_code_v0(chromaprint, bits);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
throw new Error('Only ISCC version 0 is supported');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* @param name
|
|
31
|
+
* @param description
|
|
32
|
+
* @returns
|
|
33
|
+
*/
|
|
34
|
+
function gen_audio_code_v0(chromaprint, bits) {
|
|
35
|
+
const digest = Buffer.from(soft_hash_audio_v0(chromaprint, bits ? bits : 64)).toString('hex');
|
|
36
|
+
const audio_code = (0, codec_1.encode_component)(constants_1.MainTypes.CONTENT, constants_1.SubTypes.AUDIO, constants_1.Version.V0, bits ? bits : 64,
|
|
37
|
+
// fix bug https://github.com/nodejs/node/issues/21242 https://github.com/merkletreejs/merkletreejs/pull/91
|
|
38
|
+
digest.length % 2 ? '0' + digest : digest);
|
|
39
|
+
const iscc = 'ISCC:' + audio_code;
|
|
40
|
+
return {
|
|
41
|
+
iscc: iscc
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function soft_hash_audio_v0(cv, bits = 64) {
|
|
45
|
+
/**
|
|
46
|
+
* Create audio similarity hash from a chromaprint vector.
|
|
47
|
+
*
|
|
48
|
+
* @param cv - Chromaprint vector
|
|
49
|
+
* @param bits - Bit-length resulting similarity hash (multiple of 32)
|
|
50
|
+
* @return Audio-Hash digest
|
|
51
|
+
*/
|
|
52
|
+
// Convert chromaprint vector into list of 4 byte digests
|
|
53
|
+
const digests = Array.from(cv).map(intFeature => new Uint8Array(new Int32Array([intFeature]).buffer).reverse());
|
|
54
|
+
// Return identity hash if we have 0 digests
|
|
55
|
+
if (digests.length === 0) {
|
|
56
|
+
return new Uint8Array(32);
|
|
57
|
+
}
|
|
58
|
+
// Calculate simhash of digests as first 32-bit chunk of the hash
|
|
59
|
+
const parts = [algSimhash(digests)];
|
|
60
|
+
let bitLength = 32;
|
|
61
|
+
// Calculate separate 32-bit simhashes for each quarter of features (original order)
|
|
62
|
+
for (const bucket of divide(4, digests)) {
|
|
63
|
+
const features = Array.from(bucket);
|
|
64
|
+
if (features.length > 0) {
|
|
65
|
+
parts.push(algSimhash(features));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
parts.push(new Uint8Array(4));
|
|
69
|
+
}
|
|
70
|
+
bitLength += 32;
|
|
71
|
+
if (bitLength === bits) {
|
|
72
|
+
return concatenateUint8Arrays(parts);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Calculate separate simhashes for each third of features (ordered by int value)
|
|
76
|
+
const cvs = Array.from(cv).sort((a, b) => a - b);
|
|
77
|
+
const sortedDigests = cvs.map(intFeature => new Uint8Array(new Int32Array([intFeature]).buffer).reverse());
|
|
78
|
+
for (const bucket of divide(3, sortedDigests)) {
|
|
79
|
+
const features = Array.from(bucket);
|
|
80
|
+
if (features.length > 0) {
|
|
81
|
+
parts.push(algSimhash(features));
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
parts.push(new Uint8Array(4));
|
|
85
|
+
}
|
|
86
|
+
bitLength += 32;
|
|
87
|
+
if (bitLength === bits) {
|
|
88
|
+
return concatenateUint8Arrays(parts);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return concatenateUint8Arrays(parts);
|
|
92
|
+
}
|
|
93
|
+
function algSimhash(hashDigests) {
|
|
94
|
+
/**
|
|
95
|
+
* Creates a similarity preserving hash from a sequence of equal sized hash digests.
|
|
96
|
+
*
|
|
97
|
+
* @param hashDigests - A sequence of equally sized byte-hashes.
|
|
98
|
+
* @returns Similarity byte-hash
|
|
99
|
+
*/
|
|
100
|
+
const nBytes = hashDigests[0].length;
|
|
101
|
+
const nBits = nBytes * 8;
|
|
102
|
+
const vector = new Array(nBits).fill(0);
|
|
103
|
+
for (const digest of hashDigests) {
|
|
104
|
+
for (let i = 0; i < nBits; i++) {
|
|
105
|
+
const byteIndex = Math.floor(i / 8);
|
|
106
|
+
const bitIndex = i % 8;
|
|
107
|
+
vector[i] += (digest[byteIndex] & (1 << (7 - bitIndex))) !== 0 ? 1 : 0;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const minFeatures = hashDigests.length / 2;
|
|
111
|
+
let shash = BigInt(0);
|
|
112
|
+
for (let i = 0; i < nBits; i++) {
|
|
113
|
+
if (vector[i] >= minFeatures) {
|
|
114
|
+
shash |= BigInt(1) << BigInt(nBits - 1 - i);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return bigIntToUint8Array(shash, nBytes);
|
|
118
|
+
}
|
|
119
|
+
function* divide(n, iterable) {
|
|
120
|
+
const arr = Array.from(iterable);
|
|
121
|
+
const chunkSize = Math.ceil(arr.length / n);
|
|
122
|
+
for (let i = 0; i < n; i++) {
|
|
123
|
+
yield arr.slice(i * chunkSize, (i + 1) * chunkSize);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function concatenateUint8Arrays(arrays) {
|
|
127
|
+
const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
|
|
128
|
+
const result = new Uint8Array(totalLength);
|
|
129
|
+
let offset = 0;
|
|
130
|
+
for (const arr of arrays) {
|
|
131
|
+
result.set(arr, offset);
|
|
132
|
+
offset += arr.length;
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
function bigIntToUint8Array(bigInt, byteLength) {
|
|
137
|
+
const result = new Uint8Array(byteLength);
|
|
138
|
+
let tempBigInt = BigInt(bigInt); // Create a copy to avoid modifying the original
|
|
139
|
+
for (let i = 0; i < byteLength; i++) {
|
|
140
|
+
result[byteLength - 1 - i] = Number(tempBigInt & 255n);
|
|
141
|
+
tempBigInt = tempBigInt >> 8n;
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=code-content-audio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-content-audio.js","sourceRoot":"","sources":["../../src/code-content-audio.ts"],"names":[],"mappings":"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","sourcesContent":["\nimport { encode_component } from './codec';\nimport {\n MainTypes,\n SubTypes,\n Version\n} from './constants';\n\n/**\n * \n*The Content-Code Audio is generated from a Chromaprint fingerprint provided as a vector of 32-bit\nsigned integers. The [iscc-sdk](https://github.com/iscc/iscc-sdk) uses\n[fpcalc](https://acoustid.org/chromaprint) to extract Chromaprint vectors with the following\ncommand line parameters:\n\n`$ fpcalc -raw -json -signed -length 0 myaudiofile.mp3`\n */\n\n\nexport function gen_audio_code(\n chromaprint: number[],\n bits?: number,\n version?: number\n): {\n iscc: string\n}{\n if (!version) {\n version = 0;\n }\n if (version == 0) {\n return gen_audio_code_v0(chromaprint, bits);\n } else {\n throw new Error('Only ISCC version 0 is supported');\n }\n}\n\n/**\n*\n* @param name\n* @param description\n* @returns\n*/\n\nexport function gen_audio_code_v0(\n chromaprint: number[],\n bits?: number\n): {\n iscc: string\n} {\n\n\n const digest = Buffer.from(soft_hash_audio_v0(chromaprint,bits ? bits : 64)).toString('hex');\n const audio_code = encode_component(\n MainTypes.CONTENT,\n SubTypes.AUDIO,\n Version.V0,\n bits ? bits : 64,\n // fix bug https://github.com/nodejs/node/issues/21242 https://github.com/merkletreejs/merkletreejs/pull/91\n digest.length % 2 ? '0' + digest : digest\n );\n\n const iscc = 'ISCC:' + audio_code;\n return {\n iscc: iscc\n };\n}\n\n\nexport function soft_hash_audio_v0(cv: Iterable<number>, bits: number = 64): Uint8Array {\n /**\n * Create audio similarity hash from a chromaprint vector.\n *\n * @param cv - Chromaprint vector\n * @param bits - Bit-length resulting similarity hash (multiple of 32)\n * @return Audio-Hash digest\n */\n\n // Convert chromaprint vector into list of 4 byte digests\n const digests = Array.from(cv).map(intFeature => \n new Uint8Array(new Int32Array([intFeature]).buffer).reverse()\n );\n\n // Return identity hash if we have 0 digests\n if (digests.length === 0) {\n return new Uint8Array(32);\n }\n\n // Calculate simhash of digests as first 32-bit chunk of the hash\n const parts: Uint8Array[] = [algSimhash(digests)];\n\n let bitLength = 32;\n\n // Calculate separate 32-bit simhashes for each quarter of features (original order)\n for (const bucket of divide(4, digests)) {\n const features = Array.from(bucket);\n if (features.length > 0) {\n parts.push(algSimhash(features));\n } else {\n parts.push(new Uint8Array(4));\n }\n bitLength += 32;\n if (bitLength === bits) {\n return concatenateUint8Arrays(parts);\n }\n }\n\n // Calculate separate simhashes for each third of features (ordered by int value)\n const cvs = Array.from(cv).sort((a, b) => a - b);\n const sortedDigests = cvs.map(intFeature => \n new Uint8Array(new Int32Array([intFeature]).buffer).reverse()\n );\n for (const bucket of divide(3, sortedDigests)) {\n const features = Array.from(bucket);\n if (features.length > 0) {\n parts.push(algSimhash(features));\n } else {\n parts.push(new Uint8Array(4));\n }\n bitLength += 32;\n if (bitLength === bits) {\n return concatenateUint8Arrays(parts);\n }\n }\n\n return concatenateUint8Arrays(parts);\n}\n\nfunction algSimhash(hashDigests: Uint8Array[]): Uint8Array {\n /**\n * Creates a similarity preserving hash from a sequence of equal sized hash digests.\n *\n * @param hashDigests - A sequence of equally sized byte-hashes.\n * @returns Similarity byte-hash\n */\n\n const nBytes = hashDigests[0].length;\n const nBits = nBytes * 8;\n const vector = new Array(nBits).fill(0);\n for (const digest of hashDigests) {\n for (let i = 0; i < nBits; i++) {\n const byteIndex = Math.floor(i / 8);\n const bitIndex = i % 8;\n vector[i] += (digest[byteIndex] & (1 << (7 - bitIndex))) !== 0 ? 1 : 0;\n }\n }\n\n const minFeatures = hashDigests.length / 2;\n let shash = BigInt(0);\n\n for (let i = 0; i < nBits; i++) {\n if (vector[i] >= minFeatures) {\n shash |= BigInt(1) << BigInt(nBits - 1 - i);\n }\n }\n\n return bigIntToUint8Array(shash, nBytes);\n}\n\nfunction* divide<T>(n: number, iterable: Iterable<T>): Generator<T[]> {\n const arr = Array.from(iterable);\n const chunkSize = Math.ceil(arr.length / n);\n for (let i = 0; i < n; i++) {\n yield arr.slice(i * chunkSize, (i + 1) * chunkSize);\n }\n}\n\nfunction concatenateUint8Arrays(arrays: Uint8Array[]): Uint8Array {\n const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const arr of arrays) {\n result.set(arr, offset);\n offset += arr.length;\n }\n return result;\n}\n\nfunction bigIntToUint8Array(bigInt: bigint, byteLength: number): Uint8Array {\n const result = new Uint8Array(byteLength);\n let tempBigInt = BigInt(bigInt); // Create a copy to avoid modifying the original\n for (let i = 0; i < byteLength; i++) {\n result[byteLength - 1 - i] = Number(tempBigInt & 255n);\n tempBigInt = tempBigInt >> 8n;\n }\n return result;\n}"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare function gen_image_code(pixels: number[], bits?: number, version?: number): {
|
|
2
|
+
iscc: string;
|
|
3
|
+
};
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param name
|
|
7
|
+
* @param description
|
|
8
|
+
* @returns
|
|
9
|
+
*/
|
|
10
|
+
export declare function gen_image_code_v0(pixels: number[], bits?: number): {
|
|
11
|
+
iscc: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Calculate image hash from normalized grayscale pixel sequence of length 1024.
|
|
15
|
+
*
|
|
16
|
+
* @param pixels - Normalized image pixels
|
|
17
|
+
* @param bits - Bit-length of image hash (default 64).
|
|
18
|
+
* @return Similarity preserving Image-Hash digest.
|
|
19
|
+
*/
|
|
20
|
+
export declare function soft_hash_image_v0(pixels: number[], bits: number): Uint8Array;
|
|
21
|
+
export declare function algDct(v: number[]): number[];
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.gen_image_code = gen_image_code;
|
|
4
|
+
exports.gen_image_code_v0 = gen_image_code_v0;
|
|
5
|
+
exports.soft_hash_image_v0 = soft_hash_image_v0;
|
|
6
|
+
exports.algDct = algDct;
|
|
7
|
+
const codec_1 = require("./codec");
|
|
8
|
+
const constants_1 = require("./constants");
|
|
9
|
+
function gen_image_code(pixels, bits, version) {
|
|
10
|
+
if (!version) {
|
|
11
|
+
version = 0;
|
|
12
|
+
}
|
|
13
|
+
if (version == 0) {
|
|
14
|
+
return gen_image_code_v0(pixels, bits);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
throw new Error('Only ISCC version 0 is supported');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
* @param name
|
|
23
|
+
* @param description
|
|
24
|
+
* @returns
|
|
25
|
+
*/
|
|
26
|
+
function gen_image_code_v0(pixels, bits) {
|
|
27
|
+
const digest = Buffer.from(soft_hash_image_v0(pixels, bits ? bits : constants_1.IMAGE_BITS)).toString('hex');
|
|
28
|
+
const image_code = (0, codec_1.encode_component)(constants_1.MainTypes.CONTENT, constants_1.SubTypes.IMAGE, constants_1.Version.V0, bits ? bits : constants_1.IMAGE_BITS,
|
|
29
|
+
// fix bug https://github.com/nodejs/node/issues/21242 https://github.com/merkletreejs/merkletreejs/pull/91
|
|
30
|
+
digest.length % 2 ? '0' + digest : digest);
|
|
31
|
+
const iscc = 'ISCC:' + image_code;
|
|
32
|
+
return {
|
|
33
|
+
iscc: iscc
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Calculate image hash from normalized grayscale pixel sequence of length 1024.
|
|
38
|
+
*
|
|
39
|
+
* @param pixels - Normalized image pixels
|
|
40
|
+
* @param bits - Bit-length of image hash (default 64).
|
|
41
|
+
* @return Similarity preserving Image-Hash digest.
|
|
42
|
+
*/
|
|
43
|
+
function soft_hash_image_v0(pixels, bits) {
|
|
44
|
+
if (bits > 256) {
|
|
45
|
+
throw new Error(`${bits} bits exceeds max length 256 for soft_hash_image`);
|
|
46
|
+
}
|
|
47
|
+
// DCT per row
|
|
48
|
+
const dctRowLists = [];
|
|
49
|
+
for (let i = 0; i < pixels.length; i += 32) {
|
|
50
|
+
dctRowLists.push(algDct(pixels.slice(i, i + 32)));
|
|
51
|
+
}
|
|
52
|
+
// DCT per col
|
|
53
|
+
const dctRowListsT = dctRowLists[0].map((_, colIndex) => dctRowLists.map(row => row[colIndex]));
|
|
54
|
+
const dctColListsT = dctRowListsT.map(algDct);
|
|
55
|
+
const dctMatrix = dctColListsT[0].map((_, rowIndex) => dctColListsT.map(col => col[rowIndex]));
|
|
56
|
+
function flatten(m, x, y) {
|
|
57
|
+
return m.slice(y, y + 8).flatMap(row => row.slice(x, x + 8));
|
|
58
|
+
}
|
|
59
|
+
let bitstring = "";
|
|
60
|
+
const slices = [[0, 0], [1, 0], [0, 1], [1, 1]];
|
|
61
|
+
for (const [x, y] of slices) {
|
|
62
|
+
// Extract 8 x 8 slice
|
|
63
|
+
const flatList = flatten(dctMatrix, x, y);
|
|
64
|
+
// Calculate median
|
|
65
|
+
const med = median(flatList);
|
|
66
|
+
// Append 64-bit digest by comparing to median
|
|
67
|
+
for (const value of flatList) {
|
|
68
|
+
bitstring += value > med ? "1" : "0";
|
|
69
|
+
}
|
|
70
|
+
const bl = bitstring.length;
|
|
71
|
+
if (bl >= bits) {
|
|
72
|
+
const hashDigest = new Uint8Array(Math.floor(bl / 8));
|
|
73
|
+
for (let i = 0; i < bl; i += 8) {
|
|
74
|
+
hashDigest[i / 8] = parseInt(bitstring.substr(i, 8), 2);
|
|
75
|
+
}
|
|
76
|
+
return hashDigest;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
throw new Error("Failed to generate hash digest");
|
|
80
|
+
}
|
|
81
|
+
function median(numbers) {
|
|
82
|
+
const sorted = numbers.slice().sort((a, b) => a - b);
|
|
83
|
+
const middle = Math.floor(sorted.length / 2);
|
|
84
|
+
if (sorted.length % 2 === 0) {
|
|
85
|
+
return (sorted[middle - 1] + sorted[middle]) / 2;
|
|
86
|
+
}
|
|
87
|
+
return sorted[middle];
|
|
88
|
+
}
|
|
89
|
+
function algDct(v) {
|
|
90
|
+
/**
|
|
91
|
+
* Discrete cosine transform.
|
|
92
|
+
*
|
|
93
|
+
* See: [nayuki.io](https://www.nayuki.io/page/fast-discrete-cosine-transform-algorithms).
|
|
94
|
+
*
|
|
95
|
+
* @param v - Input vector for DCT calculation.
|
|
96
|
+
* @return DCT Transformed vector.
|
|
97
|
+
*/
|
|
98
|
+
const n = v.length;
|
|
99
|
+
if (n === 1) {
|
|
100
|
+
return [...v];
|
|
101
|
+
}
|
|
102
|
+
else if (n === 0 || n % 2 !== 0) {
|
|
103
|
+
throw new Error("Invalid input length");
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
const half = Math.floor(n / 2);
|
|
107
|
+
const alpha = Array.from({ length: half }, (_, i) => v[i] + v[n - 1 - i]);
|
|
108
|
+
const beta = Array.from({ length: half }, (_, i) => (v[i] - v[n - 1 - i]) / (Math.cos((i + 0.5) * Math.PI / n) * 2.0));
|
|
109
|
+
const alphaTransformed = algDct(alpha);
|
|
110
|
+
const betaTransformed = algDct(beta);
|
|
111
|
+
const result = [];
|
|
112
|
+
for (let i = 0; i < half - 1; i++) {
|
|
113
|
+
result.push(alphaTransformed[i]);
|
|
114
|
+
result.push(betaTransformed[i] + betaTransformed[i + 1]);
|
|
115
|
+
}
|
|
116
|
+
result.push(alphaTransformed[half - 1]);
|
|
117
|
+
result.push(betaTransformed[half - 1]);
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=code-content-image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-content-image.js","sourceRoot":"","sources":["../../src/code-content-image.ts"],"names":[],"mappings":"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","sourcesContent":["import { encode_component } from './codec';\nimport {\n MainTypes,\n SubTypes,\n IMAGE_BITS,\n Version\n} from './constants';\n\n\nexport function gen_image_code(\n pixels: number[],\n bits?: number,\n version?: number\n): {\n iscc: string\n}{\n if (!version) {\n version = 0;\n }\n if (version == 0) {\n return gen_image_code_v0(pixels, bits);\n } else {\n throw new Error('Only ISCC version 0 is supported');\n }\n}\n\n/**\n*\n* @param name\n* @param description\n* @returns\n*/\n\nexport function gen_image_code_v0(\n pixels: number[],\n bits?: number\n): {\n iscc: string\n} {\n\n\n const digest = Buffer.from(soft_hash_image_v0(pixels,bits ? bits : IMAGE_BITS)).toString('hex');\n const image_code = encode_component(\n MainTypes.CONTENT,\n SubTypes.IMAGE,\n Version.V0,\n bits ? bits : IMAGE_BITS,\n // fix bug https://github.com/nodejs/node/issues/21242 https://github.com/merkletreejs/merkletreejs/pull/91\n digest.length % 2 ? '0' + digest : digest\n );\n\n const iscc = 'ISCC:' + image_code;\n return {\n iscc: iscc\n };\n}\n\n\n /**\n * Calculate image hash from normalized grayscale pixel sequence of length 1024.\n *\n * @param pixels - Normalized image pixels\n * @param bits - Bit-length of image hash (default 64).\n * @return Similarity preserving Image-Hash digest.\n */\nexport function soft_hash_image_v0(\n pixels: number[],\n bits: number\n): Uint8Array {\n if (bits > 256) {\n throw new Error(`${bits} bits exceeds max length 256 for soft_hash_image`);\n }\n \n // DCT per row\n const dctRowLists: number[][] = [];\n for (let i = 0; i < pixels.length; i += 32) {\n dctRowLists.push(algDct(pixels.slice(i, i + 32)));\n }\n\n // DCT per col\n const dctRowListsT = dctRowLists[0].map((_, colIndex) => dctRowLists.map(row => row[colIndex]));\n const dctColListsT = dctRowListsT.map(algDct);\n\n const dctMatrix = dctColListsT[0].map((_, rowIndex) => dctColListsT.map(col => col[rowIndex]));\n\n function flatten(m: number[][], x: number, y: number): number[] {\n return m.slice(y, y + 8).flatMap(row => row.slice(x, x + 8));\n }\n\n let bitstring = \"\";\n const slices = [[0, 0], [1, 0], [0, 1], [1, 1]];\n\n for (const [x, y] of slices) {\n // Extract 8 x 8 slice\n const flatList = flatten(dctMatrix, x, y);\n\n // Calculate median\n const med = median(flatList);\n\n // Append 64-bit digest by comparing to median\n for (const value of flatList) {\n bitstring += value > med ? \"1\" : \"0\";\n }\n \n const bl = bitstring.length;\n if (bl >= bits) {\n const hashDigest = new Uint8Array(Math.floor(bl / 8));\n for (let i = 0; i < bl; i += 8) {\n hashDigest[i / 8] = parseInt(bitstring.substr(i, 8), 2);\n }\n return hashDigest;\n }\n }\n\n throw new Error(\"Failed to generate hash digest\");\n}\n\n\n\nfunction median(numbers: number[]): number {\n const sorted = numbers.slice().sort((a, b) => a - b);\n const middle = Math.floor(sorted.length / 2);\n\n if (sorted.length % 2 === 0) {\n return (sorted[middle - 1] + sorted[middle]) / 2;\n }\n\n return sorted[middle];\n}\n\n\n\nexport function algDct(v: number[]): number[] {\n /**\n * Discrete cosine transform.\n *\n * See: [nayuki.io](https://www.nayuki.io/page/fast-discrete-cosine-transform-algorithms).\n *\n * @param v - Input vector for DCT calculation.\n * @return DCT Transformed vector.\n */\n\n const n = v.length;\n if (n === 1) {\n return [...v];\n } else if (n === 0 || n % 2 !== 0) {\n throw new Error(\"Invalid input length\");\n } else {\n const half = Math.floor(n / 2);\n const alpha = Array.from({ length: half }, (_, i) => v[i] + v[n - 1 - i]);\n const beta = Array.from({ length: half }, (_, i) => \n (v[i] - v[n - 1 - i]) / (Math.cos((i + 0.5) * Math.PI / n) * 2.0)\n );\n \n const alphaTransformed = algDct(alpha);\n const betaTransformed = algDct(beta);\n \n const result: number[] = [];\n for (let i = 0; i < half - 1; i++) {\n result.push(alphaTransformed[i]);\n result.push(betaTransformed[i] + betaTransformed[i + 1]);\n }\n result.push(alphaTransformed[half - 1]);\n result.push(betaTransformed[half - 1]);\n \n return result;\n }\n}"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export declare function gen_text_code(text: string, bits?: number, version?: number): {
|
|
2
|
+
iscc: string;
|
|
3
|
+
characters: number;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param name
|
|
8
|
+
* @param description
|
|
9
|
+
* @returns
|
|
10
|
+
*/
|
|
11
|
+
export declare function gen_text_code_v0(text: string, bits?: number): {
|
|
12
|
+
iscc: string;
|
|
13
|
+
characters: number;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
*
|
|
17
|
+
*
|
|
18
|
+
* Creates a 256-bit similarity preserving hash for text input with algorithm v0.
|
|
19
|
+
|
|
20
|
+
- Slide over text with a
|
|
21
|
+
[`text_ngram_size`][iscc_core.options.CoreOptions.text_ngram_size] wide window
|
|
22
|
+
and create [`xxh32`](https://cyan4973.github.io/xxHash/) hashes
|
|
23
|
+
- Create a [`minhash_256`][iscc_core.minhash.alg_minhash_256] from the hashes generated
|
|
24
|
+
in the previous step.
|
|
25
|
+
|
|
26
|
+
!!! note
|
|
27
|
+
|
|
28
|
+
Before passing text to this function it must be:
|
|
29
|
+
|
|
30
|
+
- stripped of markup
|
|
31
|
+
- normalized
|
|
32
|
+
- stripped of whitespace
|
|
33
|
+
- lowercased
|
|
34
|
+
|
|
35
|
+
* @param text
|
|
36
|
+
* @returns
|
|
37
|
+
*/
|
|
38
|
+
export declare function soft_hash_text_v0(text: string): Uint8Array;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.gen_text_code = gen_text_code;
|
|
4
|
+
exports.gen_text_code_v0 = gen_text_code_v0;
|
|
5
|
+
exports.soft_hash_text_v0 = soft_hash_text_v0;
|
|
6
|
+
const constants_1 = require("./constants");
|
|
7
|
+
const content_normalization_1 = require("./content-normalization");
|
|
8
|
+
const utils_1 = require("./utils");
|
|
9
|
+
const minhash_1 = require("./minhash");
|
|
10
|
+
const js_xxhash_1 = require("js-xxhash");
|
|
11
|
+
const codec_1 = require("./codec");
|
|
12
|
+
const constants_2 = require("./constants");
|
|
13
|
+
function gen_text_code(text, bits, version) {
|
|
14
|
+
if (!version) {
|
|
15
|
+
version = 0;
|
|
16
|
+
}
|
|
17
|
+
if (version == 0) {
|
|
18
|
+
return gen_text_code_v0(text, bits);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
throw new Error('Only ISCC version 0 is supported');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
* @param name
|
|
27
|
+
* @param description
|
|
28
|
+
* @returns
|
|
29
|
+
*/
|
|
30
|
+
function gen_text_code_v0(text, bits) {
|
|
31
|
+
text = (0, content_normalization_1.text_collapse)(text);
|
|
32
|
+
const characters = text ? text.length : 0;
|
|
33
|
+
const digest = Buffer.from(soft_hash_text_v0(text)).toString('hex');
|
|
34
|
+
const text_code = (0, codec_1.encode_component)(constants_2.MainTypes.CONTENT, constants_2.SubTypes.TEXT, constants_2.Version.V0, bits ? bits : constants_2.TEXT_BITS,
|
|
35
|
+
// fix bug https://github.com/nodejs/node/issues/21242 https://github.com/merkletreejs/merkletreejs/pull/91
|
|
36
|
+
digest.length % 2 ? '0' + digest : digest);
|
|
37
|
+
const iscc = 'ISCC:' + text_code;
|
|
38
|
+
return {
|
|
39
|
+
iscc: iscc,
|
|
40
|
+
characters: characters
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
*
|
|
45
|
+
*
|
|
46
|
+
* Creates a 256-bit similarity preserving hash for text input with algorithm v0.
|
|
47
|
+
|
|
48
|
+
- Slide over text with a
|
|
49
|
+
[`text_ngram_size`][iscc_core.options.CoreOptions.text_ngram_size] wide window
|
|
50
|
+
and create [`xxh32`](https://cyan4973.github.io/xxHash/) hashes
|
|
51
|
+
- Create a [`minhash_256`][iscc_core.minhash.alg_minhash_256] from the hashes generated
|
|
52
|
+
in the previous step.
|
|
53
|
+
|
|
54
|
+
!!! note
|
|
55
|
+
|
|
56
|
+
Before passing text to this function it must be:
|
|
57
|
+
|
|
58
|
+
- stripped of markup
|
|
59
|
+
- normalized
|
|
60
|
+
- stripped of whitespace
|
|
61
|
+
- lowercased
|
|
62
|
+
|
|
63
|
+
* @param text
|
|
64
|
+
* @returns
|
|
65
|
+
*/
|
|
66
|
+
function soft_hash_text_v0(text) {
|
|
67
|
+
const ngrams = (0, utils_1.sliding_window)(text, constants_1.TEXT_NGRAM_SIZE);
|
|
68
|
+
const features = ngrams.map(s => BigInt((0, js_xxhash_1.xxHash32)(s) >>> 0));
|
|
69
|
+
const hash_digest = (0, minhash_1.algMinhash256)(features);
|
|
70
|
+
return hash_digest;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=code-content-text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-content-text.js","sourceRoot":"","sources":["../../src/code-content-text.ts"],"names":[],"mappings":";;AAeA,sCAgBC;AASD,4CA2BC;AA0BD,8CAQC;AApGD,2CAA8C;AAC9C,mEAAwD;AACxD,mCAAyC;AACzC,uCAA0C;AAC1C,yCAAqC;AACrC,mCAA2C;AAC3C,2CAKqB;AAGrB,SAAgB,aAAa,CACzB,IAAY,EACZ,IAAa,EACb,OAAgB;IAKhB,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,OAAO,GAAG,CAAC,CAAC;IAChB,CAAC;IACD,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;QACf,OAAO,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACxC,CAAC;SAAM,CAAC;QACJ,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACxD,CAAC;AACL,CAAC;AAED;;;;;EAKE;AAEF,SAAgB,gBAAgB,CAC7B,IAAY,EACZ,IAAa;IAQZ,IAAI,GAAG,IAAA,qCAAa,EAAC,IAAI,CAAC,CAAC;IAC3B,MAAM,UAAU,GAAG,IAAI,CAAA,CAAC,CAAA,IAAI,CAAC,MAAM,CAAA,CAAC,CAAA,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACpE,MAAM,SAAS,GAAG,IAAA,wBAAgB,EAC9B,qBAAS,CAAC,OAAO,EACjB,oBAAQ,CAAC,IAAI,EACb,mBAAO,CAAC,EAAE,EACV,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,qBAAS;IACvB,2GAA2G;IAC3G,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAC5C,CAAC;IAEF,MAAM,IAAI,GAAG,OAAO,GAAG,SAAS,CAAC;IACjC,OAAO;QACH,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,UAAU;KACzB,CAAC;AACN,CAAC;AAGD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,SAAgB,iBAAiB,CAC7B,IAAY;IAGZ,MAAM,MAAM,GAAG,IAAA,sBAAc,EAAC,IAAI,EAAE,2BAAe,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,IAAA,oBAAQ,EAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,WAAW,GAAG,IAAA,uBAAa,EAAC,QAAQ,CAAC,CAAC;IAC5C,OAAO,WAAW,CAAC;AACvB,CAAC","sourcesContent":["\nimport { TEXT_NGRAM_SIZE } from './constants';\nimport { text_collapse } from './content-normalization';\nimport { sliding_window } from './utils';\nimport { algMinhash256 } from './minhash';\nimport { xxHash32 } from 'js-xxhash';\nimport { encode_component } from './codec';\nimport {\n MainTypes,\n SubTypes,\n TEXT_BITS,\n Version\n} from './constants';\n\n\nexport function gen_text_code(\n text: string,\n bits?: number,\n version?: number\n): { \n iscc: string;\n characters: number;\n } {\n if (!version) {\n version = 0;\n }\n if (version == 0) {\n return gen_text_code_v0(text, bits);\n } else {\n throw new Error('Only ISCC version 0 is supported');\n }\n}\n\n/**\n*\n* @param name\n* @param description\n* @returns\n*/\n\nexport function gen_text_code_v0(\n text: string,\n bits?: number\n):{ \niscc: string;\ncharacters: number;\n} {\n\n\n \n text = text_collapse(text);\n const characters = text?text.length:0;\n const digest = Buffer.from(soft_hash_text_v0(text)).toString('hex');\n const text_code = encode_component(\n MainTypes.CONTENT,\n SubTypes.TEXT,\n Version.V0,\n bits ? bits : TEXT_BITS,\n // fix bug https://github.com/nodejs/node/issues/21242 https://github.com/merkletreejs/merkletreejs/pull/91\n digest.length % 2 ? '0' + digest : digest\n );\n\n const iscc = 'ISCC:' + text_code;\n return {\n iscc: iscc,\n characters: characters\n };\n}\n\n\n/**\n * \n * \n * Creates a 256-bit similarity preserving hash for text input with algorithm v0.\n\n - Slide over text with a\n [`text_ngram_size`][iscc_core.options.CoreOptions.text_ngram_size] wide window\n and create [`xxh32`](https://cyan4973.github.io/xxHash/) hashes\n - Create a [`minhash_256`][iscc_core.minhash.alg_minhash_256] from the hashes generated\n in the previous step.\n\n !!! note\n\n Before passing text to this function it must be:\n\n - stripped of markup\n - normalized\n - stripped of whitespace\n - lowercased\n\n * @param text \n * @returns \n */\nexport function soft_hash_text_v0(\n text: string\n): Uint8Array {\n\n const ngrams = sliding_window(text, TEXT_NGRAM_SIZE);\n const features = ngrams.map(s => BigInt(xxHash32(s) >>> 0));\n const hash_digest = algMinhash256(features);\n return hash_digest;\n}\n\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
*The Content-Code Audio is generated from a Chromaprint fingerprint provided as a vector of 32-bit
|
|
4
|
+
signed integers. The [iscc-sdk](https://github.com/iscc/iscc-sdk) uses
|
|
5
|
+
[fpcalc](https://acoustid.org/chromaprint) to extract Chromaprint vectors with the following
|
|
6
|
+
command line parameters:
|
|
7
|
+
|
|
8
|
+
`$ fpcalc -raw -json -signed -length 0 myaudiofile.mp3`
|
|
9
|
+
*/
|
|
10
|
+
type FrameSig = number[];
|
|
11
|
+
export declare const WTA_VIDEO_ID_PERMUTATIONS: [number, number][];
|
|
12
|
+
export declare function gen_video_code(frame_sigs: FrameSig[], bits?: number, version?: number): {
|
|
13
|
+
iscc: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function gen_video_code_v0(frameSigs: FrameSig[], bits?: number): {
|
|
16
|
+
iscc: string;
|
|
17
|
+
};
|
|
18
|
+
export declare function soft_hash_video_v0(frameSigs: FrameSig[], bits?: number): Uint8Array;
|
|
19
|
+
export {};
|