@cosyte/dicom 0.0.13 → 0.0.14
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/CHANGELOG.md +178 -0
- package/README.md +5 -3
- package/dist/index.cjs +34 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +81 -22
- package/dist/index.d.ts +81 -22
- package/dist/index.mjs +34 -22
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -114,6 +114,18 @@ interface UidEntry {
|
|
|
114
114
|
* throw `TypeError` in strict mode (which all of `@cosyte/dicom`'s emitted code
|
|
115
115
|
* runs under, given `"use strict"` is implicit for ES modules).
|
|
116
116
|
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* import { Dictionary } from "@cosyte/dicom";
|
|
120
|
+
*
|
|
121
|
+
* // Tag or keyword, either way round, and `undefined` rather than a throw on a miss.
|
|
122
|
+
* Dictionary.lookup("00100020")?.name; // "Patient ID"
|
|
123
|
+
* Dictionary.byKeyword("Modality")?.tag; // "00080060"
|
|
124
|
+
*
|
|
125
|
+
* // UIDs resolve to their registered name, so nobody hard-codes a SOP Class table.
|
|
126
|
+
* Dictionary.uid("1.2.840.10008.5.1.4.1.1.2")?.name; // "CT Image Storage"
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
117
129
|
* @module
|
|
118
130
|
*/
|
|
119
131
|
|
|
@@ -317,8 +329,13 @@ interface ParseOptions {
|
|
|
317
329
|
*
|
|
318
330
|
* 🛑 **THE ESCALATED DIAGNOSTIC CARRIES SOURCE BYTES THAT THE WARNING DOES
|
|
319
331
|
* NOT.** A `DicomParseWarning.message` is a frozen registry string with only
|
|
320
|
-
* structural tokens filled in, so it is safe to log whole
|
|
321
|
-
*
|
|
332
|
+
* structural tokens filled in, so it is safe to log whole **on a well-formed
|
|
333
|
+
* file, and it is not unconditionally safe**: the `{tag}` slot is filled by a
|
|
334
|
+
* shape check, which cannot refuse a tag a lying Value Length composed out of
|
|
335
|
+
* somebody's value (measured, `PRE-EXISTING`, disclosed rather than guarded
|
|
336
|
+
* because withholding the tag would take it off every private element in every
|
|
337
|
+
* conformant file). The `DicomParseError` this option raises in its place is a
|
|
338
|
+
* different and larger surface: it also carries `snippet`,
|
|
322
339
|
* **16 raw bytes, unredacted** (D-10), read at the warning's own `byteOffset`.
|
|
323
340
|
* A message-only PHI review of the lenient path therefore does not transfer to
|
|
324
341
|
* the strict one. Log `err.code`, `err.byteOffset` and `err.message`; treat
|
|
@@ -921,6 +938,21 @@ declare class Element {
|
|
|
921
938
|
* `(0002,0102)` Private Information - is captured here as raw bytes (the
|
|
922
939
|
* on-wire value, even-length per PS3.5 §6.2) rather than dropped. `value` is a
|
|
923
940
|
* defensive copy, so the view never aliases the parsed input buffer.
|
|
941
|
+
*
|
|
942
|
+
* @example
|
|
943
|
+
* ```ts
|
|
944
|
+
* import { parseDicom } from "@cosyte/dicom";
|
|
945
|
+
* const ds = parseDicom(buf);
|
|
946
|
+
* // Anything the typed FileMeta fields do not model, in ascending tag order.
|
|
947
|
+
* for (const raw of ds.fileMeta?.extraElements ?? []) {
|
|
948
|
+
* raw.tag; // e.g. "00020017" Sending Application Entity Title
|
|
949
|
+
* raw.vr; // the VR the source wrote (File Meta is always Explicit VR LE)
|
|
950
|
+
* raw.value.length; // even, per PS3.5 2026c section 7.1.1
|
|
951
|
+
* }
|
|
952
|
+
* ```
|
|
953
|
+
*
|
|
954
|
+
* `(0002,0016)` Source Application Entity Title is deliberately NOT the example: it is one of the
|
|
955
|
+
* typed fields, so it never reaches this array.
|
|
924
956
|
*/
|
|
925
957
|
interface FileMetaRawElement {
|
|
926
958
|
/** 8-char uppercase hex tag, e.g. `"00020100"`. */
|
|
@@ -2448,15 +2480,29 @@ interface DeidentifiedAttribute {
|
|
|
2448
2480
|
* (PS3.15 §E.1 "all instances"; §E.3.5 is the standard's own precedent for
|
|
2449
2481
|
* removing identifying information embedded inside a string attribute).
|
|
2450
2482
|
*
|
|
2451
|
-
* `tag` and `vr` are the carrier's own and are structural. **`hidden`
|
|
2452
|
-
* and
|
|
2453
|
-
*
|
|
2454
|
-
*
|
|
2455
|
-
*
|
|
2456
|
-
* `
|
|
2457
|
-
*
|
|
2458
|
-
*
|
|
2459
|
-
*
|
|
2483
|
+
* `tag` and `vr` are the carrier's own and are structural. **`hidden` was not,
|
|
2484
|
+
* and it is bound now.** Every tag in an embedded run is composed from four
|
|
2485
|
+
* bytes that were sitting *inside* the carrier's value - that is the whole
|
|
2486
|
+
* reason this type exists - and a run needs only ONE actionable attribute to be
|
|
2487
|
+
* reported, so through `0.0.13` the rest of the run was listed beside it.
|
|
2488
|
+
* Measured: a `CS` carrier over-declaring across a fabricated `"SMIT"` header
|
|
2489
|
+
* beside a genuine `(0010,0020)` reported `hidden: ["4D535449", "00100020"]`,
|
|
2490
|
+
* and `4D535449` is `"SMIT"` in wire order.
|
|
2491
|
+
*
|
|
2492
|
+
* **An entry is now one of the 652 literal rows of PS3.15 Table E.1-1 that this
|
|
2493
|
+
* run's options left actionable.** That is a **membership** bound rather than a
|
|
2494
|
+
* shape one - the posture this package already takes for a VR and for a Private
|
|
2495
|
+
* Creator - so what survives names a published table entry rather than a
|
|
2496
|
+
* document byte, the same trade rendering a VR makes with the 34. **A
|
|
2497
|
+
* repeating-group mask hit is NOT in that set and is excluded**: `(50xx,xxxx)`
|
|
2498
|
+
* Curve Data leaves the whole 16-bit element number free, so a mask match proves
|
|
2499
|
+
* a rule exists without making the membership finite. A graded pass caught a
|
|
2500
|
+
* draft of this filter that admitted it.
|
|
2501
|
+
*
|
|
2502
|
+
* **🛑 THAT IS NOT AN ALL-CLEAR OVER THIS TYPE.** `contextPath` below is
|
|
2503
|
+
* unbound and unchanged, `hidden` is uncapped, and
|
|
2504
|
+
* {@link DeidentifyReport} names the report's other value-bearing fields. A
|
|
2505
|
+
* `DeidentifyReport` is still not safe to log whole.
|
|
2460
2506
|
*
|
|
2461
2507
|
* @example
|
|
2462
2508
|
* ```ts
|
|
@@ -2472,7 +2518,18 @@ interface EmbeddedAttributeFinding {
|
|
|
2472
2518
|
readonly tag: Tag;
|
|
2473
2519
|
/** The carrier's VR. Always one of the string VRs; binary VRs are not scanned. */
|
|
2474
2520
|
readonly vr: VR;
|
|
2475
|
-
/**
|
|
2521
|
+
/**
|
|
2522
|
+
* The tags found inside the carrier's value **that this run acts on and that a
|
|
2523
|
+
* published table names**, in wire order. **Not every tag in the run** - see
|
|
2524
|
+
* this type's own remarks.
|
|
2525
|
+
*
|
|
2526
|
+
* **🩺 IT MAY BE EMPTY, AND EMPTY DOES NOT MEAN "NOTHING WAS HIDDEN HERE".**
|
|
2527
|
+
* A run whose only actionable members are private attributes, Curve Data or
|
|
2528
|
+
* Overlay elements reports a finding with no tags: the carrier was still
|
|
2529
|
+
* emptied, and the accompanying `DICOM_DEIDENT_EMBEDDED_ATTRIBUTE_REMOVED`
|
|
2530
|
+
* warning still counts the whole run. The presence of the finding is the fact;
|
|
2531
|
+
* this list is the part of it that can be named.
|
|
2532
|
+
*/
|
|
2476
2533
|
readonly hidden: readonly Tag[];
|
|
2477
2534
|
/**
|
|
2478
2535
|
* Tag/index chain when the carrier is inside a sequence item; omitted at the
|
|
@@ -2697,13 +2754,6 @@ interface UndefinedVrFinding {
|
|
|
2697
2754
|
* and still answers it whenever the fabricated VR is outside the 34 PS3.5
|
|
2698
2755
|
* §6.2 defines. It cannot when the fabricated VR is one of them, because those
|
|
2699
2756
|
* two files are byte-identical.
|
|
2700
|
-
* - **`embeddedAttributes[].hidden`** - see {@link EmbeddedAttributeFinding}.
|
|
2701
|
-
* Each entry is a tag composed from four bytes that were sitting **inside**
|
|
2702
|
-
* a value, which is the position this type exists to distrust, so on a file
|
|
2703
|
-
* that populates the field at all they are document content by
|
|
2704
|
-
* construction. `PRE-EXISTING` and identical on every release that has
|
|
2705
|
-
* shipped the field; it is disclosed here and its remedy is its own slice,
|
|
2706
|
-
* alongside the cap that field is also missing.
|
|
2707
2757
|
* - **`contextPath`, on all four findings that carry one** - see
|
|
2708
2758
|
* {@link DeidentifiedAttribute.contextPath}, which holds the measurement. The
|
|
2709
2759
|
* segment tags come off the wire with no table behind them, so a fabricated
|
|
@@ -2714,8 +2764,18 @@ interface UndefinedVrFinding {
|
|
|
2714
2764
|
* same file the de-identified object itself re-emits the fabricated header, so
|
|
2715
2765
|
* redacting this field does not make the object safe.**
|
|
2716
2766
|
*
|
|
2767
|
+
* `embeddedAttributes[].hidden` **left that list** in
|
|
2768
|
+
* `DICOM-DIAGNOSTIC-PHI-RESIDUALS` - an entry is now a literal PS3.15 Table
|
|
2769
|
+
* E.1-1 row, so it is not value-bearing. Its own disclosure had been reworded
|
|
2770
|
+
* twice by then, and this repo deletes a disclosure at that point rather than
|
|
2771
|
+
* writing a third; what is true of the field is stated once, on
|
|
2772
|
+
* {@link EmbeddedAttributeFinding}. The field is **still uncapped**.
|
|
2773
|
+
*
|
|
2717
2774
|
* So "the report is safe to log apart from `uidMap`" is **not** an accurate
|
|
2718
2775
|
* description of this type, and was corrected rather than kept convenient.
|
|
2776
|
+
* **This is the only copy of that list.** Two others lived in module docstrings,
|
|
2777
|
+
* still naming `hidden` after it left and never naming `contextPath` at all; a
|
|
2778
|
+
* graded pass found them and they were deleted rather than resynced.
|
|
2719
2779
|
*
|
|
2720
2780
|
* @example
|
|
2721
2781
|
* ```ts
|
|
@@ -2994,9 +3054,8 @@ declare class DeidentifyError extends Error {
|
|
|
2994
3054
|
* action map ({@link annexE}). It is a **pure** function: the input {@link Dataset}
|
|
2995
3055
|
* is never mutated; a fresh `Dataset` (with a rebuilt element map and File Meta)
|
|
2996
3056
|
* is returned alongside a {@link DeidentifyReport} whose non-value-free fields
|
|
2997
|
-
* are named on that type
|
|
2998
|
-
*
|
|
2999
|
-
* there, never a count quoted elsewhere.
|
|
3057
|
+
* are named on that type. **The list is deliberately not copied here** - see
|
|
3058
|
+
* `./index.ts` for what a third copy of it cost.
|
|
3000
3059
|
*
|
|
3001
3060
|
* **What it does**
|
|
3002
3061
|
* - Resolves each attribute's action (basic profile, overridden by an active
|
package/dist/index.d.ts
CHANGED
|
@@ -114,6 +114,18 @@ interface UidEntry {
|
|
|
114
114
|
* throw `TypeError` in strict mode (which all of `@cosyte/dicom`'s emitted code
|
|
115
115
|
* runs under, given `"use strict"` is implicit for ES modules).
|
|
116
116
|
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* import { Dictionary } from "@cosyte/dicom";
|
|
120
|
+
*
|
|
121
|
+
* // Tag or keyword, either way round, and `undefined` rather than a throw on a miss.
|
|
122
|
+
* Dictionary.lookup("00100020")?.name; // "Patient ID"
|
|
123
|
+
* Dictionary.byKeyword("Modality")?.tag; // "00080060"
|
|
124
|
+
*
|
|
125
|
+
* // UIDs resolve to their registered name, so nobody hard-codes a SOP Class table.
|
|
126
|
+
* Dictionary.uid("1.2.840.10008.5.1.4.1.1.2")?.name; // "CT Image Storage"
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
117
129
|
* @module
|
|
118
130
|
*/
|
|
119
131
|
|
|
@@ -317,8 +329,13 @@ interface ParseOptions {
|
|
|
317
329
|
*
|
|
318
330
|
* 🛑 **THE ESCALATED DIAGNOSTIC CARRIES SOURCE BYTES THAT THE WARNING DOES
|
|
319
331
|
* NOT.** A `DicomParseWarning.message` is a frozen registry string with only
|
|
320
|
-
* structural tokens filled in, so it is safe to log whole
|
|
321
|
-
*
|
|
332
|
+
* structural tokens filled in, so it is safe to log whole **on a well-formed
|
|
333
|
+
* file, and it is not unconditionally safe**: the `{tag}` slot is filled by a
|
|
334
|
+
* shape check, which cannot refuse a tag a lying Value Length composed out of
|
|
335
|
+
* somebody's value (measured, `PRE-EXISTING`, disclosed rather than guarded
|
|
336
|
+
* because withholding the tag would take it off every private element in every
|
|
337
|
+
* conformant file). The `DicomParseError` this option raises in its place is a
|
|
338
|
+
* different and larger surface: it also carries `snippet`,
|
|
322
339
|
* **16 raw bytes, unredacted** (D-10), read at the warning's own `byteOffset`.
|
|
323
340
|
* A message-only PHI review of the lenient path therefore does not transfer to
|
|
324
341
|
* the strict one. Log `err.code`, `err.byteOffset` and `err.message`; treat
|
|
@@ -921,6 +938,21 @@ declare class Element {
|
|
|
921
938
|
* `(0002,0102)` Private Information - is captured here as raw bytes (the
|
|
922
939
|
* on-wire value, even-length per PS3.5 §6.2) rather than dropped. `value` is a
|
|
923
940
|
* defensive copy, so the view never aliases the parsed input buffer.
|
|
941
|
+
*
|
|
942
|
+
* @example
|
|
943
|
+
* ```ts
|
|
944
|
+
* import { parseDicom } from "@cosyte/dicom";
|
|
945
|
+
* const ds = parseDicom(buf);
|
|
946
|
+
* // Anything the typed FileMeta fields do not model, in ascending tag order.
|
|
947
|
+
* for (const raw of ds.fileMeta?.extraElements ?? []) {
|
|
948
|
+
* raw.tag; // e.g. "00020017" Sending Application Entity Title
|
|
949
|
+
* raw.vr; // the VR the source wrote (File Meta is always Explicit VR LE)
|
|
950
|
+
* raw.value.length; // even, per PS3.5 2026c section 7.1.1
|
|
951
|
+
* }
|
|
952
|
+
* ```
|
|
953
|
+
*
|
|
954
|
+
* `(0002,0016)` Source Application Entity Title is deliberately NOT the example: it is one of the
|
|
955
|
+
* typed fields, so it never reaches this array.
|
|
924
956
|
*/
|
|
925
957
|
interface FileMetaRawElement {
|
|
926
958
|
/** 8-char uppercase hex tag, e.g. `"00020100"`. */
|
|
@@ -2448,15 +2480,29 @@ interface DeidentifiedAttribute {
|
|
|
2448
2480
|
* (PS3.15 §E.1 "all instances"; §E.3.5 is the standard's own precedent for
|
|
2449
2481
|
* removing identifying information embedded inside a string attribute).
|
|
2450
2482
|
*
|
|
2451
|
-
* `tag` and `vr` are the carrier's own and are structural. **`hidden`
|
|
2452
|
-
* and
|
|
2453
|
-
*
|
|
2454
|
-
*
|
|
2455
|
-
*
|
|
2456
|
-
* `
|
|
2457
|
-
*
|
|
2458
|
-
*
|
|
2459
|
-
*
|
|
2483
|
+
* `tag` and `vr` are the carrier's own and are structural. **`hidden` was not,
|
|
2484
|
+
* and it is bound now.** Every tag in an embedded run is composed from four
|
|
2485
|
+
* bytes that were sitting *inside* the carrier's value - that is the whole
|
|
2486
|
+
* reason this type exists - and a run needs only ONE actionable attribute to be
|
|
2487
|
+
* reported, so through `0.0.13` the rest of the run was listed beside it.
|
|
2488
|
+
* Measured: a `CS` carrier over-declaring across a fabricated `"SMIT"` header
|
|
2489
|
+
* beside a genuine `(0010,0020)` reported `hidden: ["4D535449", "00100020"]`,
|
|
2490
|
+
* and `4D535449` is `"SMIT"` in wire order.
|
|
2491
|
+
*
|
|
2492
|
+
* **An entry is now one of the 652 literal rows of PS3.15 Table E.1-1 that this
|
|
2493
|
+
* run's options left actionable.** That is a **membership** bound rather than a
|
|
2494
|
+
* shape one - the posture this package already takes for a VR and for a Private
|
|
2495
|
+
* Creator - so what survives names a published table entry rather than a
|
|
2496
|
+
* document byte, the same trade rendering a VR makes with the 34. **A
|
|
2497
|
+
* repeating-group mask hit is NOT in that set and is excluded**: `(50xx,xxxx)`
|
|
2498
|
+
* Curve Data leaves the whole 16-bit element number free, so a mask match proves
|
|
2499
|
+
* a rule exists without making the membership finite. A graded pass caught a
|
|
2500
|
+
* draft of this filter that admitted it.
|
|
2501
|
+
*
|
|
2502
|
+
* **🛑 THAT IS NOT AN ALL-CLEAR OVER THIS TYPE.** `contextPath` below is
|
|
2503
|
+
* unbound and unchanged, `hidden` is uncapped, and
|
|
2504
|
+
* {@link DeidentifyReport} names the report's other value-bearing fields. A
|
|
2505
|
+
* `DeidentifyReport` is still not safe to log whole.
|
|
2460
2506
|
*
|
|
2461
2507
|
* @example
|
|
2462
2508
|
* ```ts
|
|
@@ -2472,7 +2518,18 @@ interface EmbeddedAttributeFinding {
|
|
|
2472
2518
|
readonly tag: Tag;
|
|
2473
2519
|
/** The carrier's VR. Always one of the string VRs; binary VRs are not scanned. */
|
|
2474
2520
|
readonly vr: VR;
|
|
2475
|
-
/**
|
|
2521
|
+
/**
|
|
2522
|
+
* The tags found inside the carrier's value **that this run acts on and that a
|
|
2523
|
+
* published table names**, in wire order. **Not every tag in the run** - see
|
|
2524
|
+
* this type's own remarks.
|
|
2525
|
+
*
|
|
2526
|
+
* **🩺 IT MAY BE EMPTY, AND EMPTY DOES NOT MEAN "NOTHING WAS HIDDEN HERE".**
|
|
2527
|
+
* A run whose only actionable members are private attributes, Curve Data or
|
|
2528
|
+
* Overlay elements reports a finding with no tags: the carrier was still
|
|
2529
|
+
* emptied, and the accompanying `DICOM_DEIDENT_EMBEDDED_ATTRIBUTE_REMOVED`
|
|
2530
|
+
* warning still counts the whole run. The presence of the finding is the fact;
|
|
2531
|
+
* this list is the part of it that can be named.
|
|
2532
|
+
*/
|
|
2476
2533
|
readonly hidden: readonly Tag[];
|
|
2477
2534
|
/**
|
|
2478
2535
|
* Tag/index chain when the carrier is inside a sequence item; omitted at the
|
|
@@ -2697,13 +2754,6 @@ interface UndefinedVrFinding {
|
|
|
2697
2754
|
* and still answers it whenever the fabricated VR is outside the 34 PS3.5
|
|
2698
2755
|
* §6.2 defines. It cannot when the fabricated VR is one of them, because those
|
|
2699
2756
|
* two files are byte-identical.
|
|
2700
|
-
* - **`embeddedAttributes[].hidden`** - see {@link EmbeddedAttributeFinding}.
|
|
2701
|
-
* Each entry is a tag composed from four bytes that were sitting **inside**
|
|
2702
|
-
* a value, which is the position this type exists to distrust, so on a file
|
|
2703
|
-
* that populates the field at all they are document content by
|
|
2704
|
-
* construction. `PRE-EXISTING` and identical on every release that has
|
|
2705
|
-
* shipped the field; it is disclosed here and its remedy is its own slice,
|
|
2706
|
-
* alongside the cap that field is also missing.
|
|
2707
2757
|
* - **`contextPath`, on all four findings that carry one** - see
|
|
2708
2758
|
* {@link DeidentifiedAttribute.contextPath}, which holds the measurement. The
|
|
2709
2759
|
* segment tags come off the wire with no table behind them, so a fabricated
|
|
@@ -2714,8 +2764,18 @@ interface UndefinedVrFinding {
|
|
|
2714
2764
|
* same file the de-identified object itself re-emits the fabricated header, so
|
|
2715
2765
|
* redacting this field does not make the object safe.**
|
|
2716
2766
|
*
|
|
2767
|
+
* `embeddedAttributes[].hidden` **left that list** in
|
|
2768
|
+
* `DICOM-DIAGNOSTIC-PHI-RESIDUALS` - an entry is now a literal PS3.15 Table
|
|
2769
|
+
* E.1-1 row, so it is not value-bearing. Its own disclosure had been reworded
|
|
2770
|
+
* twice by then, and this repo deletes a disclosure at that point rather than
|
|
2771
|
+
* writing a third; what is true of the field is stated once, on
|
|
2772
|
+
* {@link EmbeddedAttributeFinding}. The field is **still uncapped**.
|
|
2773
|
+
*
|
|
2717
2774
|
* So "the report is safe to log apart from `uidMap`" is **not** an accurate
|
|
2718
2775
|
* description of this type, and was corrected rather than kept convenient.
|
|
2776
|
+
* **This is the only copy of that list.** Two others lived in module docstrings,
|
|
2777
|
+
* still naming `hidden` after it left and never naming `contextPath` at all; a
|
|
2778
|
+
* graded pass found them and they were deleted rather than resynced.
|
|
2719
2779
|
*
|
|
2720
2780
|
* @example
|
|
2721
2781
|
* ```ts
|
|
@@ -2994,9 +3054,8 @@ declare class DeidentifyError extends Error {
|
|
|
2994
3054
|
* action map ({@link annexE}). It is a **pure** function: the input {@link Dataset}
|
|
2995
3055
|
* is never mutated; a fresh `Dataset` (with a rebuilt element map and File Meta)
|
|
2996
3056
|
* is returned alongside a {@link DeidentifyReport} whose non-value-free fields
|
|
2997
|
-
* are named on that type
|
|
2998
|
-
*
|
|
2999
|
-
* there, never a count quoted elsewhere.
|
|
3057
|
+
* are named on that type. **The list is deliberately not copied here** - see
|
|
3058
|
+
* `./index.ts` for what a third copy of it cost.
|
|
3000
3059
|
*
|
|
3001
3060
|
* **What it does**
|
|
3002
3061
|
* - Resolves each attribute's action (basic profile, overridden by an active
|
package/dist/index.mjs
CHANGED
|
@@ -9,7 +9,7 @@ var __export = (target, all) => {
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
// src/version.ts
|
|
12
|
-
var VERSION = "0.0.
|
|
12
|
+
var VERSION = "0.0.14";
|
|
13
13
|
|
|
14
14
|
// src/dictionary/index.ts
|
|
15
15
|
var dictionary_exports = {};
|
|
@@ -12206,7 +12206,11 @@ var WARNING_MESSAGES = Object.freeze({
|
|
|
12206
12206
|
DICOM_UNDEFINED_LENGTH_IN_EXPLICIT_VR: "Element ({tag}) uses undefined length (0xFFFFFFFF) under an Explicit VR transfer syntax.",
|
|
12207
12207
|
DICOM_ODD_LENGTH_VALUE_PADDED: "Element ({tag}) has odd declared length {n}; cursor advanced by one padding byte to maintain alignment.",
|
|
12208
12208
|
DICOM_VR_MISMATCH: "Element ({tag}) on-wire VR is {vr2}; dictionary lists {vr}. Trusting on-wire VR.",
|
|
12209
|
-
|
|
12209
|
+
// No tag, and the reason is the one `nonzeroReservedBytes` states: this code's
|
|
12210
|
+
// three siblings below fire only on an ODD group, and an odd group is the one
|
|
12211
|
+
// class of tag no closed table this library holds can ever vouch for. See
|
|
12212
|
+
// `privateTagNoCreator`.
|
|
12213
|
+
DICOM_PRIVATE_TAG_NO_CREATOR: "A private element has no Private Creator registered for its block; treating as VR=UN. Its tag is withheld; the byte offset identifies the element.",
|
|
12210
12214
|
DICOM_GROUP_LENGTH_IN_DATASET: "Retired Group Length element ({tag}) encountered in dataset; preserved as-is.",
|
|
12211
12215
|
// The tag is deliberately absent, and this is the only *parser* message where
|
|
12212
12216
|
// that is true. See `nonzeroReservedBytes`. Kept terse for the same reason the
|
|
@@ -12252,10 +12256,10 @@ var WARNING_MESSAGES = Object.freeze({
|
|
|
12252
12256
|
// `endLimit < buffer.length` conjunct bounds it by the buffer.
|
|
12253
12257
|
DICOM_ITEM_CROSSES_SEQUENCE_END: "Item ({tag}) declares a length reaching past its enclosing sequence's declared end, so it reads the enclosing Data Set's bytes; {n2} bytes remained inside the sequence. The file's two length fields disagree (PS3.5 7.5.1 and 7.5.2 govern them); the item's is used. The declared length is withheld; the byte offset locates the item.",
|
|
12254
12258
|
DICOM_PIXEL_DATA_LENGTH_MISMATCH: "(7FE0,0010) PixelData declared length {n} does not match computed {n2} bytes.",
|
|
12255
|
-
DICOM_IMPLICIT_VR_FOR_PRIVATE_TAG_WITHOUT_VR: "
|
|
12256
|
-
DICOM_PRIVATE_CREATOR_UNKNOWN: "
|
|
12259
|
+
DICOM_IMPLICIT_VR_FOR_PRIVATE_TAG_WITHOUT_VR: "A private element under Implicit VR LE has no VR override; falling back to UN. Its tag is withheld; the byte offset identifies the element.",
|
|
12260
|
+
DICOM_PRIVATE_CREATOR_UNKNOWN: "A private element has a Private Creator the active profile's private dictionary does not name; falling back to UN. The creator string is not reproduced here - read the (gggg,00EE) element if you need it. Its tag is withheld; the byte offset identifies the element.",
|
|
12257
12261
|
DICOM_BURNED_IN_ANNOTATION_NOT_REMOVED: "Pixel Data is present and Burned In Annotation is not 'NO'; this metadata-only de-identifier cannot inspect or clean pixels. Recognizable text may remain burned into the image.",
|
|
12258
|
-
DICOM_DEIDENT_EMBEDDED_ATTRIBUTE_REMOVED: "Element ({tag}) {vr} was kept by the action table, but its value ends with {n} whole Data Element(s) - an over-declared Value Length swallowed what followed it. Emptied rather than kept, because the action table cannot see an attribute encoded inside a value.
|
|
12262
|
+
DICOM_DEIDENT_EMBEDDED_ATTRIBUTE_REMOVED: "Element ({tag}) {vr} was kept by the action table, but its value ends with {n} whole Data Element(s) - an over-declared Value Length swallowed what followed it. Emptied rather than kept, because the action table cannot see an attribute encoded inside a value. report.embeddedAttributes names the ones this run acts on that also have a literal Table E.1-1 row, which may be none of them.",
|
|
12259
12263
|
// Deliberately short. One of these is raised per un-auditable element, so a
|
|
12260
12264
|
// long message is multiplied by an element count the input controls; the
|
|
12261
12265
|
// reasoning belongs in the docs, not in a string repeated thousands of times.
|
|
@@ -12318,8 +12322,8 @@ function oddLengthValuePadded(position, tag, declaredLength) {
|
|
|
12318
12322
|
function vrMismatch(position, tag, dictVR, fileVR) {
|
|
12319
12323
|
return build2(WARNING_CODES.DICOM_VR_MISMATCH, position, { tag, vr: dictVR, vr2: fileVR });
|
|
12320
12324
|
}
|
|
12321
|
-
function privateTagNoCreator(position
|
|
12322
|
-
return build2(WARNING_CODES.DICOM_PRIVATE_TAG_NO_CREATOR, position
|
|
12325
|
+
function privateTagNoCreator(position) {
|
|
12326
|
+
return build2(WARNING_CODES.DICOM_PRIVATE_TAG_NO_CREATOR, position);
|
|
12323
12327
|
}
|
|
12324
12328
|
function groupLengthInDataset(position, tag) {
|
|
12325
12329
|
return build2(WARNING_CODES.DICOM_GROUP_LENGTH_IN_DATASET, position, { tag });
|
|
@@ -12351,11 +12355,11 @@ function duplicateTagInDataSet(position) {
|
|
|
12351
12355
|
function duplicateFileMetaElement(position) {
|
|
12352
12356
|
return build2(WARNING_CODES.DICOM_DUPLICATE_FILE_META_ELEMENT, position);
|
|
12353
12357
|
}
|
|
12354
|
-
function implicitVRForPrivateTagWithoutVR(position
|
|
12355
|
-
return build2(WARNING_CODES.DICOM_IMPLICIT_VR_FOR_PRIVATE_TAG_WITHOUT_VR, position
|
|
12358
|
+
function implicitVRForPrivateTagWithoutVR(position) {
|
|
12359
|
+
return build2(WARNING_CODES.DICOM_IMPLICIT_VR_FOR_PRIVATE_TAG_WITHOUT_VR, position);
|
|
12356
12360
|
}
|
|
12357
|
-
function privateCreatorUnknown(position
|
|
12358
|
-
return build2(WARNING_CODES.DICOM_PRIVATE_CREATOR_UNKNOWN, position
|
|
12361
|
+
function privateCreatorUnknown(position) {
|
|
12362
|
+
return build2(WARNING_CODES.DICOM_PRIVATE_CREATOR_UNKNOWN, position);
|
|
12359
12363
|
}
|
|
12360
12364
|
function burnedInAnnotationNotRemoved(position) {
|
|
12361
12365
|
return build2(WARNING_CODES.DICOM_BURNED_IN_ANNOTATION_NOT_REMOVED, position);
|
|
@@ -12460,18 +12464,18 @@ function resolveImplicitVR(tag, ctx, emit, position) {
|
|
|
12460
12464
|
}
|
|
12461
12465
|
const creator = resolvePrivateCreator(tag, ctx);
|
|
12462
12466
|
if (creator === void 0) {
|
|
12463
|
-
emit(privateTagNoCreator(position
|
|
12464
|
-
emit(implicitVRForPrivateTagWithoutVR(position
|
|
12467
|
+
emit(privateTagNoCreator(position));
|
|
12468
|
+
emit(implicitVRForPrivateTagWithoutVR(position));
|
|
12465
12469
|
return "UN";
|
|
12466
12470
|
}
|
|
12467
12471
|
if (ctx.profile !== void 0) {
|
|
12468
12472
|
const def = resolvePrivateTag(ctx.profile, tag, creator);
|
|
12469
12473
|
if (def !== void 0) return def.vr;
|
|
12470
12474
|
if (!ctx.profile.privateDictionary.has(creator)) {
|
|
12471
|
-
emit(privateCreatorUnknown(position
|
|
12475
|
+
emit(privateCreatorUnknown(position));
|
|
12472
12476
|
}
|
|
12473
12477
|
}
|
|
12474
|
-
emit(implicitVRForPrivateTagWithoutVR(position
|
|
12478
|
+
emit(implicitVRForPrivateTagWithoutVR(position));
|
|
12475
12479
|
return "UN";
|
|
12476
12480
|
}
|
|
12477
12481
|
const direct = TAGS[tag];
|
|
@@ -15223,6 +15227,10 @@ function hasByteOutsideRepertoire(region, carrierVr) {
|
|
|
15223
15227
|
}
|
|
15224
15228
|
return false;
|
|
15225
15229
|
}
|
|
15230
|
+
function isTableBound(tag) {
|
|
15231
|
+
const action = annexE(tag);
|
|
15232
|
+
return action !== void 0 && action.repeatingGroup === void 0;
|
|
15233
|
+
}
|
|
15226
15234
|
function findEmbeddedAttributes(value, carrierVr, encoding, isActionable) {
|
|
15227
15235
|
if (!isScannableCarrier(carrierVr)) return void 0;
|
|
15228
15236
|
if (value.length < MIN_HEADER) return void 0;
|
|
@@ -15246,15 +15254,19 @@ function findEmbeddedAttributes(value, carrierVr, encoding, isActionable) {
|
|
|
15246
15254
|
for (let off = 0; off + MIN_HEADER <= n; off += 2) {
|
|
15247
15255
|
if (hit[off >> 1] !== 1) continue;
|
|
15248
15256
|
if (!hasByteOutsideRepertoire(window.subarray(off), carrierVr)) return void 0;
|
|
15249
|
-
const
|
|
15257
|
+
const hidden = [];
|
|
15258
|
+
let elementCount = 0;
|
|
15250
15259
|
let pos = off;
|
|
15251
15260
|
while (pos < n) {
|
|
15252
15261
|
const decoded = decodeAt(window, pos, encoding);
|
|
15253
15262
|
if (decoded === void 0) break;
|
|
15254
|
-
if (decoded.tag !== void 0)
|
|
15263
|
+
if (decoded.tag !== void 0) {
|
|
15264
|
+
elementCount += 1;
|
|
15265
|
+
if (isActionable(decoded.tag) && isTableBound(decoded.tag)) hidden.push(decoded.tag);
|
|
15266
|
+
}
|
|
15255
15267
|
pos = decoded.next;
|
|
15256
15268
|
}
|
|
15257
|
-
return
|
|
15269
|
+
return { hidden, elementCount };
|
|
15258
15270
|
}
|
|
15259
15271
|
return void 0;
|
|
15260
15272
|
}
|
|
@@ -15459,8 +15471,8 @@ function keepOrEmpty(el, ctx, contextPath, out) {
|
|
|
15459
15471
|
emptyUndefinedVrElement(el, ctx, contextPath, out);
|
|
15460
15472
|
return false;
|
|
15461
15473
|
}
|
|
15462
|
-
const
|
|
15463
|
-
if (
|
|
15474
|
+
const run = findEmbeddedAttributes(el.rawBytes, el.vr, ctx.encoding, (t) => actsOnTag(t, ctx));
|
|
15475
|
+
if (run === void 0) {
|
|
15464
15476
|
out.elements.set(el.tag, el);
|
|
15465
15477
|
return true;
|
|
15466
15478
|
}
|
|
@@ -15468,11 +15480,11 @@ function keepOrEmpty(el, ctx, contextPath, out) {
|
|
|
15468
15480
|
out.embeddedAttributes.push({
|
|
15469
15481
|
tag: el.tag,
|
|
15470
15482
|
vr: el.vr,
|
|
15471
|
-
hidden,
|
|
15483
|
+
hidden: run.hidden,
|
|
15472
15484
|
...contextPath.length > 0 ? { contextPath: [...contextPath] } : {}
|
|
15473
15485
|
});
|
|
15474
15486
|
out.warnings.push(
|
|
15475
|
-
embeddedAttributeRemoved({ byteOffset: el.byteOffset }, el.tag, el.vr,
|
|
15487
|
+
embeddedAttributeRemoved({ byteOffset: el.byteOffset }, el.tag, el.vr, run.elementCount)
|
|
15476
15488
|
);
|
|
15477
15489
|
return false;
|
|
15478
15490
|
}
|