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.
Files changed (54) hide show
  1. package/README.md +72 -5
  2. package/lib/cjs/code-content-audio.d.ts +22 -0
  3. package/lib/cjs/code-content-audio.js +145 -0
  4. package/lib/cjs/code-content-audio.js.map +1 -0
  5. package/lib/cjs/code-content-image.d.ts +21 -0
  6. package/lib/cjs/code-content-image.js +121 -0
  7. package/lib/cjs/code-content-image.js.map +1 -0
  8. package/lib/cjs/code-content-text.d.ts +38 -0
  9. package/lib/cjs/code-content-text.js +72 -0
  10. package/lib/cjs/code-content-text.js.map +1 -0
  11. package/lib/cjs/code-content-video.d.ts +19 -0
  12. package/lib/cjs/code-content-video.js +328 -0
  13. package/lib/cjs/code-content-video.js.map +1 -0
  14. package/lib/cjs/codec.js +6 -7
  15. package/lib/cjs/codec.js.map +1 -1
  16. package/lib/cjs/constants.d.ts +10 -1
  17. package/lib/cjs/constants.js +25 -1
  18. package/lib/cjs/constants.js.map +1 -1
  19. package/lib/cjs/content-normalization.js +5 -9
  20. package/lib/cjs/content-normalization.js.map +1 -1
  21. package/lib/cjs/metacode.js +7 -14
  22. package/lib/cjs/metacode.js.map +1 -1
  23. package/lib/cjs/minhash.d.ts +34 -0
  24. package/lib/cjs/minhash.js +230 -0
  25. package/lib/cjs/minhash.js.map +1 -0
  26. package/lib/cjs/simhash.js +1 -2
  27. package/lib/cjs/simhash.js.map +1 -1
  28. package/lib/cjs/utils.js +9 -9
  29. package/lib/cjs/utils.js.map +1 -1
  30. package/lib/esm/code-content-audio.d.ts +22 -0
  31. package/lib/esm/code-content-audio.js +140 -0
  32. package/lib/esm/code-content-audio.js.map +1 -0
  33. package/lib/esm/code-content-image.d.ts +21 -0
  34. package/lib/esm/code-content-image.js +115 -0
  35. package/lib/esm/code-content-image.js.map +1 -0
  36. package/lib/esm/code-content-text.d.ts +38 -0
  37. package/lib/esm/code-content-text.js +67 -0
  38. package/lib/esm/code-content-text.js.map +1 -0
  39. package/lib/esm/code-content-video.d.ts +19 -0
  40. package/lib/esm/code-content-video.js +322 -0
  41. package/lib/esm/code-content-video.js.map +1 -0
  42. package/lib/esm/constants.d.ts +10 -1
  43. package/lib/esm/constants.js +24 -0
  44. package/lib/esm/constants.js.map +1 -1
  45. package/lib/esm/content-normalization.js +0 -3
  46. package/lib/esm/content-normalization.js.map +1 -1
  47. package/lib/esm/metacode.js +3 -9
  48. package/lib/esm/metacode.js.map +1 -1
  49. package/lib/esm/minhash.d.ts +34 -0
  50. package/lib/esm/minhash.js +223 -0
  51. package/lib/esm/minhash.js.map +1 -0
  52. package/lib/tsconfig-cjs.tsbuildinfo +1 -1
  53. package/lib/tsconfig.tsbuildinfo +1 -1
  54. 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.39.3
79
+ 0.40.1
14
80
  ```
15
81
  Install node 21
16
82
 
17
83
  ```sh
18
- nvm install 21
19
- v21.7.1 is already installed.
20
- Now using node v21.7.1 (npm v10.5.0)
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 {};