@cosyte/dicom 0.0.5 → 0.0.7
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 +438 -31
- package/README.md +12 -7
- package/dist/index.cjs +548 -155
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +307 -12
- package/dist/index.d.ts +307 -12
- package/dist/index.mjs +549 -156
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Buffer } from 'buffer';
|
|
2
|
-
import {
|
|
2
|
+
import { inflateRawSync, deflateRawSync } from 'zlib';
|
|
3
3
|
import { createHash } from 'crypto';
|
|
4
4
|
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
@@ -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.7";
|
|
13
13
|
|
|
14
14
|
// src/dictionary/index.ts
|
|
15
15
|
var dictionary_exports = {};
|
|
@@ -11572,6 +11572,13 @@ var ByteCursor = class {
|
|
|
11572
11572
|
}
|
|
11573
11573
|
};
|
|
11574
11574
|
|
|
11575
|
+
// src/parser/tokens.ts
|
|
11576
|
+
var WITHHELD = "<withheld>";
|
|
11577
|
+
function safePrivateCreator(creator, profile) {
|
|
11578
|
+
if (profile === void 0) return WITHHELD;
|
|
11579
|
+
return profile.privateDictionary.has(creator) ? creator : WITHHELD;
|
|
11580
|
+
}
|
|
11581
|
+
|
|
11575
11582
|
// src/dataset/vr/charset.ts
|
|
11576
11583
|
var TERM_TO_LABEL = /* @__PURE__ */ new Map([
|
|
11577
11584
|
// Default repertoire (ISO 646 IRV / ASCII). Latin-1 is a lenient,
|
|
@@ -11624,7 +11631,7 @@ var MULTIBYTE_LABELS = /* @__PURE__ */ new Set([
|
|
|
11624
11631
|
]);
|
|
11625
11632
|
function parseSpecificCharacterSet(bytes) {
|
|
11626
11633
|
const raw = bytes.toString("latin1");
|
|
11627
|
-
return raw.split("\\").map((t) => t.replace(/[ ]+$/u, "").replace(/^[ ]+/u, ""));
|
|
11634
|
+
return raw.split("\\").map((t) => t.replace(/[ ]+$/u, "").replace(/^[ ]+/u, "")).map((t) => t === "" || TERM_TO_LABEL.has(t) ? t : WITHHELD);
|
|
11628
11635
|
}
|
|
11629
11636
|
function isKnownCharsetTerm(term) {
|
|
11630
11637
|
return TERM_TO_LABEL.has(term);
|
|
@@ -11653,6 +11660,48 @@ function decodeText(bytes, terms) {
|
|
|
11653
11660
|
}
|
|
11654
11661
|
}
|
|
11655
11662
|
|
|
11663
|
+
// src/parser/endian.ts
|
|
11664
|
+
var BE_VR_STRIDE = Object.freeze({
|
|
11665
|
+
// 2-byte swaps
|
|
11666
|
+
AT: 2,
|
|
11667
|
+
US: 2,
|
|
11668
|
+
SS: 2,
|
|
11669
|
+
OW: 2,
|
|
11670
|
+
// 4-byte swaps
|
|
11671
|
+
UL: 4,
|
|
11672
|
+
SL: 4,
|
|
11673
|
+
FL: 4,
|
|
11674
|
+
OF: 4,
|
|
11675
|
+
OL: 4,
|
|
11676
|
+
// 8-byte swaps (64-bit floats + 2018 64-bit integer additions)
|
|
11677
|
+
FD: 8,
|
|
11678
|
+
OD: 8,
|
|
11679
|
+
OV: 8,
|
|
11680
|
+
SV: 8,
|
|
11681
|
+
UV: 8,
|
|
11682
|
+
// No swap - byte streams (D-24) and ASCII / spec-defined VRs.
|
|
11683
|
+
OB: 0,
|
|
11684
|
+
UN: 0,
|
|
11685
|
+
AE: 0,
|
|
11686
|
+
AS: 0,
|
|
11687
|
+
CS: 0,
|
|
11688
|
+
DA: 0,
|
|
11689
|
+
DS: 0,
|
|
11690
|
+
DT: 0,
|
|
11691
|
+
IS: 0,
|
|
11692
|
+
LO: 0,
|
|
11693
|
+
LT: 0,
|
|
11694
|
+
PN: 0,
|
|
11695
|
+
SH: 0,
|
|
11696
|
+
ST: 0,
|
|
11697
|
+
TM: 0,
|
|
11698
|
+
UC: 0,
|
|
11699
|
+
UI: 0,
|
|
11700
|
+
UR: 0,
|
|
11701
|
+
UT: 0,
|
|
11702
|
+
SQ: 0
|
|
11703
|
+
});
|
|
11704
|
+
|
|
11656
11705
|
// src/parser/warnings.ts
|
|
11657
11706
|
var WARNING_CODES = {
|
|
11658
11707
|
// === Phase 2 actively emits (D-08 active list - alphabetical-within-prefix per CONTEXT specifics §) ===
|
|
@@ -11666,6 +11715,7 @@ var WARNING_CODES = {
|
|
|
11666
11715
|
DICOM_ODD_LENGTH_VALUE_PADDED: "DICOM_ODD_LENGTH_VALUE_PADDED",
|
|
11667
11716
|
DICOM_PIXEL_DATA_LENGTH_MISMATCH: "DICOM_PIXEL_DATA_LENGTH_MISMATCH",
|
|
11668
11717
|
DICOM_PRIVATE_TAG_NO_CREATOR: "DICOM_PRIVATE_TAG_NO_CREATOR",
|
|
11718
|
+
DICOM_SQ_NOT_DESCENDED: "DICOM_SQ_NOT_DESCENDED",
|
|
11669
11719
|
DICOM_UN_PARSED_AS_SQ: "DICOM_UN_PARSED_AS_SQ",
|
|
11670
11720
|
DICOM_UNDEFINED_LENGTH_IN_EXPLICIT_VR: "DICOM_UNDEFINED_LENGTH_IN_EXPLICIT_VR",
|
|
11671
11721
|
DICOM_VR_MISMATCH: "DICOM_VR_MISMATCH",
|
|
@@ -11683,162 +11733,168 @@ var WARNING_CODES = {
|
|
|
11683
11733
|
// === Reserved by later phases (declared, not emitted in Phase 2) ===
|
|
11684
11734
|
DICOM_BURNED_IN_ANNOTATION_NOT_REMOVED: "DICOM_BURNED_IN_ANNOTATION_NOT_REMOVED",
|
|
11685
11735
|
// reserved by Phase 7 - not emitted in Phase 2
|
|
11736
|
+
DICOM_DEIDENT_EMBEDDED_ATTRIBUTE_REMOVED: "DICOM_DEIDENT_EMBEDDED_ATTRIBUTE_REMOVED",
|
|
11737
|
+
// emitted by deidentify(), never by the parser
|
|
11738
|
+
DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE: "DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE",
|
|
11739
|
+
// emitted by deidentify(), never by the parser
|
|
11740
|
+
DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE: "DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE",
|
|
11741
|
+
// emitted by deidentify(), never by the parser
|
|
11686
11742
|
DICOM_PRIVATE_CREATOR_UNKNOWN: "DICOM_PRIVATE_CREATOR_UNKNOWN"
|
|
11687
11743
|
// reserved by Phase 6 - not emitted in Phase 2
|
|
11688
11744
|
};
|
|
11745
|
+
var WARNING_MESSAGES = Object.freeze({
|
|
11746
|
+
DICOM_MISSING_PREAMBLE: "No DICM magic at offset 128; falling back to offset-0 dataset.",
|
|
11747
|
+
DICOM_FILE_META_GROUP_LENGTH_MISSING: "(0002,0000) FileMetaInformationGroupLength missing; scanning forward to first non-(0002,xxxx) element.",
|
|
11748
|
+
DICOM_FILE_META_GROUP_LENGTH_MISMATCH: "(0002,0000) FileMetaInformationGroupLength declared {n} bytes; actual File Meta group size is {n2} bytes. Trusting actual.",
|
|
11749
|
+
DICOM_UNDEFINED_LENGTH_IN_EXPLICIT_VR: "Element ({tag}) uses undefined length (0xFFFFFFFF) under an Explicit VR transfer syntax.",
|
|
11750
|
+
DICOM_ODD_LENGTH_VALUE_PADDED: "Element ({tag}) has odd declared length {n}; cursor advanced by one padding byte to maintain alignment.",
|
|
11751
|
+
DICOM_VR_MISMATCH: "Element ({tag}) on-wire VR is {vr2}; dictionary lists {vr}. Trusting on-wire VR.",
|
|
11752
|
+
DICOM_PRIVATE_TAG_NO_CREATOR: "Private element ({tag}) has no Private Creator registered for its block; treating as VR=UN.",
|
|
11753
|
+
DICOM_GROUP_LENGTH_IN_DATASET: "Retired Group Length element ({tag}) encountered in dataset; preserved as-is.",
|
|
11754
|
+
DICOM_NONZERO_RESERVED_BYTES: "Element ({tag}) has non-zero reserved bytes between VR and length (first byte {n}, second byte {n2}); ignoring.",
|
|
11755
|
+
DICOM_SQ_NOT_DESCENDED: "Element ({tag}) resolved to VR=SQ from the dictionary but its defined-length value is not a valid item stream; kept as opaque bytes and NOT descended, so nothing nested inside it is visible to navigation, and deidentify() cannot audit it. See DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE.",
|
|
11756
|
+
DICOM_UN_PARSED_AS_SQ: "Element ({tag}) has VR=UN with undefined length; descended as Implicit VR LE sequence per CP-246.",
|
|
11757
|
+
DICOM_EMPTY_ITEM_IN_SEQUENCE: "Sequence ({tag}) contains an empty item (length=0); tolerated.",
|
|
11758
|
+
DICOM_PIXEL_DATA_LENGTH_MISMATCH: "(7FE0,0010) PixelData declared length {n} does not match computed {n2} bytes.",
|
|
11759
|
+
DICOM_IMPLICIT_VR_FOR_PRIVATE_TAG_WITHOUT_VR: "Private element ({tag}) under Implicit VR LE has no VR override; falling back to UN.",
|
|
11760
|
+
DICOM_PRIVATE_CREATOR_UNKNOWN: "Private element ({tag}) 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.",
|
|
11761
|
+
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.",
|
|
11762
|
+
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. Read report.embeddedAttributes for the tags that were hidden there.",
|
|
11763
|
+
// Deliberately short. One of these is raised per un-auditable element, so a
|
|
11764
|
+
// long message is multiplied by an element count the input controls; the
|
|
11765
|
+
// reasoning belongs in the docs, not in a string repeated thousands of times.
|
|
11766
|
+
DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE: "Element ({tag}) is VR=SQ with no parsed items, so its {n} value bytes could not be audited (PS3.15 E.1.1); emptied. See report.unauditableSequences.",
|
|
11767
|
+
// Deliberately short for the same reason as the code above: one per element,
|
|
11768
|
+
// and the element count is chosen by the input.
|
|
11769
|
+
//
|
|
11770
|
+
// NEITHER THE TAG NOR THE VR IS ECHOED, and that is specific to this code
|
|
11771
|
+
// rather than caution. Every other factory's {tag} is composed from a real
|
|
11772
|
+
// Data Element header; the condition that raises THIS one is that the header
|
|
11773
|
+
// was fabricated from bytes inside some element's value, so its four tag bytes
|
|
11774
|
+
// and its two VR bytes are document content. `renderTag` shape-checks a tag
|
|
11775
|
+
// and cannot refuse one, so the withholding has to happen at the call site.
|
|
11776
|
+
// The byte offset locates the element instead, and is a position this parser
|
|
11777
|
+
// counted rather than anything the document said.
|
|
11778
|
+
DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE: "An element at byte offset {n2} carries an on-wire VR that is not one of the 34 PS3.5 6.2 defines, so its {n} value bytes are not a Value Field this library decoded; emptied (PS3.15 E.1.1). Its tag and VR are withheld: an earlier under-declared length can make them fragments of some element's value. See report.undefinedVrElements.",
|
|
11779
|
+
DICOM_BOM_IN_TEXT_VR: "Element ({tag}) {vr} value begins with a UTF-8 BOM; stripped on decode.",
|
|
11780
|
+
DICOM_TRAILING_NULL_IN_TEXT_VR: "Element ({tag}) {vr} value has a trailing NULL pad where SPACE is expected; trimmed.",
|
|
11781
|
+
DICOM_UI_TRAILING_SPACE: "Element ({tag}) UI value is SPACE-padded; UI requires NULL padding (PS3.5 \xA76.2). Trimmed.",
|
|
11782
|
+
DICOM_NON_ASCII_IN_ASCII_VR: "Element ({tag}) {vr} is an ASCII-only VR but contains non-ASCII bytes; decoded as Latin-1 best-effort.",
|
|
11783
|
+
DICOM_IS_NONINTEGER_VALUE: "Element ({tag}) IS value is not a base-10 integer; surfaced as null with raw bytes preserved.",
|
|
11784
|
+
DICOM_DA_LEGACY_FORMAT: "Element ({tag}) DA value is not in canonical YYYYMMDD form; decoded best-effort, raw preserved.",
|
|
11785
|
+
DICOM_DT_NONSTANDARD_OFFSET: "Element ({tag}) DT value has a non-standard UTC offset; decoded best-effort, raw preserved.",
|
|
11786
|
+
DICOM_UNSUPPORTED_CHARSET: "(0008,0005) Specific Character Set value {n} names a defined term this build does not support; decoding text as UTF-8 best-effort. The term is not reproduced here - read the element if you need it.",
|
|
11787
|
+
DICOM_CHARSET_AMBIGUOUS_SEPARATOR: "(0008,0005) Specific Character Set value {n} is ambiguous under the active code extensions; decoding text as UTF-8 best-effort."
|
|
11788
|
+
});
|
|
11789
|
+
var KNOWN_VRS = new Set(Object.keys(BE_VR_STRIDE));
|
|
11790
|
+
var TAG_SHAPE = /^[0-9A-F]{8}$/u;
|
|
11791
|
+
function renderTag(tag) {
|
|
11792
|
+
return tag !== void 0 && TAG_SHAPE.test(tag) ? tag : WITHHELD;
|
|
11793
|
+
}
|
|
11794
|
+
function renderVr(vr) {
|
|
11795
|
+
return vr !== void 0 && KNOWN_VRS.has(vr) ? vr : WITHHELD;
|
|
11796
|
+
}
|
|
11797
|
+
function build(code, position, tokens = {}) {
|
|
11798
|
+
const message = WARNING_MESSAGES[code].replace("{tag}", renderTag(tokens.tag)).replace("{vr2}", renderVr(tokens.vr2)).replace("{vr}", renderVr(tokens.vr)).replace("{n2}", String(tokens.n2 ?? 0)).replace("{n}", String(tokens.n ?? 0));
|
|
11799
|
+
return { code, message, position };
|
|
11800
|
+
}
|
|
11689
11801
|
function missingPreamble(position) {
|
|
11690
|
-
return
|
|
11691
|
-
code: WARNING_CODES.DICOM_MISSING_PREAMBLE,
|
|
11692
|
-
message: "No DICM magic at offset 128; falling back to offset-0 dataset.",
|
|
11693
|
-
position
|
|
11694
|
-
};
|
|
11802
|
+
return build(WARNING_CODES.DICOM_MISSING_PREAMBLE, position);
|
|
11695
11803
|
}
|
|
11696
11804
|
function fileMetaGroupLengthMissing(position) {
|
|
11697
|
-
return
|
|
11698
|
-
code: WARNING_CODES.DICOM_FILE_META_GROUP_LENGTH_MISSING,
|
|
11699
|
-
message: "(0002,0000) FileMetaInformationGroupLength missing; scanning forward to first non-(0002,xxxx) element.",
|
|
11700
|
-
position
|
|
11701
|
-
};
|
|
11805
|
+
return build(WARNING_CODES.DICOM_FILE_META_GROUP_LENGTH_MISSING, position);
|
|
11702
11806
|
}
|
|
11703
11807
|
function fileMetaGroupLengthMismatch(position, declared, actual) {
|
|
11704
|
-
return {
|
|
11705
|
-
|
|
11706
|
-
|
|
11707
|
-
|
|
11708
|
-
};
|
|
11808
|
+
return build(WARNING_CODES.DICOM_FILE_META_GROUP_LENGTH_MISMATCH, position, {
|
|
11809
|
+
n: declared,
|
|
11810
|
+
n2: actual
|
|
11811
|
+
});
|
|
11709
11812
|
}
|
|
11710
11813
|
function undefinedLengthInExplicitVR(position, tag) {
|
|
11711
|
-
return {
|
|
11712
|
-
code: WARNING_CODES.DICOM_UNDEFINED_LENGTH_IN_EXPLICIT_VR,
|
|
11713
|
-
message: `Element (${tag}) uses undefined length (0xFFFFFFFF) under an Explicit VR transfer syntax.`,
|
|
11714
|
-
position
|
|
11715
|
-
};
|
|
11814
|
+
return build(WARNING_CODES.DICOM_UNDEFINED_LENGTH_IN_EXPLICIT_VR, position, { tag });
|
|
11716
11815
|
}
|
|
11717
11816
|
function oddLengthValuePadded(position, tag, declaredLength) {
|
|
11718
|
-
return {
|
|
11719
|
-
|
|
11720
|
-
|
|
11721
|
-
|
|
11722
|
-
};
|
|
11817
|
+
return build(WARNING_CODES.DICOM_ODD_LENGTH_VALUE_PADDED, position, {
|
|
11818
|
+
tag,
|
|
11819
|
+
n: declaredLength
|
|
11820
|
+
});
|
|
11723
11821
|
}
|
|
11724
11822
|
function vrMismatch(position, tag, dictVR, fileVR) {
|
|
11725
|
-
return {
|
|
11726
|
-
code: WARNING_CODES.DICOM_VR_MISMATCH,
|
|
11727
|
-
message: `Element (${tag}) on-wire VR is ${fileVR}; dictionary lists ${dictVR}. Trusting on-wire VR.`,
|
|
11728
|
-
position
|
|
11729
|
-
};
|
|
11823
|
+
return build(WARNING_CODES.DICOM_VR_MISMATCH, position, { tag, vr: dictVR, vr2: fileVR });
|
|
11730
11824
|
}
|
|
11731
11825
|
function privateTagNoCreator(position, tag) {
|
|
11732
|
-
return {
|
|
11733
|
-
code: WARNING_CODES.DICOM_PRIVATE_TAG_NO_CREATOR,
|
|
11734
|
-
message: `Private element (${tag}) has no Private Creator registered for its block; treating as VR=UN.`,
|
|
11735
|
-
position
|
|
11736
|
-
};
|
|
11826
|
+
return build(WARNING_CODES.DICOM_PRIVATE_TAG_NO_CREATOR, position, { tag });
|
|
11737
11827
|
}
|
|
11738
11828
|
function groupLengthInDataset(position, tag) {
|
|
11739
|
-
return {
|
|
11740
|
-
code: WARNING_CODES.DICOM_GROUP_LENGTH_IN_DATASET,
|
|
11741
|
-
message: `Retired Group Length element (${tag}) encountered in dataset; preserved as-is.`,
|
|
11742
|
-
position
|
|
11743
|
-
};
|
|
11829
|
+
return build(WARNING_CODES.DICOM_GROUP_LENGTH_IN_DATASET, position, { tag });
|
|
11744
11830
|
}
|
|
11745
|
-
function nonzeroReservedBytes(position, tag,
|
|
11746
|
-
return {
|
|
11747
|
-
|
|
11748
|
-
|
|
11749
|
-
|
|
11750
|
-
};
|
|
11831
|
+
function nonzeroReservedBytes(position, tag, first, second) {
|
|
11832
|
+
return build(WARNING_CODES.DICOM_NONZERO_RESERVED_BYTES, position, {
|
|
11833
|
+
tag,
|
|
11834
|
+
n: first,
|
|
11835
|
+
n2: second
|
|
11836
|
+
});
|
|
11751
11837
|
}
|
|
11752
11838
|
function unParsedAsSQ(position, tag) {
|
|
11753
|
-
return {
|
|
11754
|
-
|
|
11755
|
-
|
|
11756
|
-
|
|
11757
|
-
};
|
|
11839
|
+
return build(WARNING_CODES.DICOM_UN_PARSED_AS_SQ, position, { tag });
|
|
11840
|
+
}
|
|
11841
|
+
function sqNotDescended(position, tag) {
|
|
11842
|
+
return build(WARNING_CODES.DICOM_SQ_NOT_DESCENDED, position, { tag });
|
|
11758
11843
|
}
|
|
11759
11844
|
function emptyItemInSequence(position, tag) {
|
|
11760
|
-
return {
|
|
11761
|
-
code: WARNING_CODES.DICOM_EMPTY_ITEM_IN_SEQUENCE,
|
|
11762
|
-
message: `Sequence (${tag}) contains an empty item (length=0); tolerated.`,
|
|
11763
|
-
position
|
|
11764
|
-
};
|
|
11845
|
+
return build(WARNING_CODES.DICOM_EMPTY_ITEM_IN_SEQUENCE, position, { tag });
|
|
11765
11846
|
}
|
|
11766
11847
|
function implicitVRForPrivateTagWithoutVR(position, tag) {
|
|
11767
|
-
return {
|
|
11768
|
-
code: WARNING_CODES.DICOM_IMPLICIT_VR_FOR_PRIVATE_TAG_WITHOUT_VR,
|
|
11769
|
-
message: `Private element (${tag}) under Implicit VR LE has no VR override; falling back to UN.`,
|
|
11770
|
-
position
|
|
11771
|
-
};
|
|
11848
|
+
return build(WARNING_CODES.DICOM_IMPLICIT_VR_FOR_PRIVATE_TAG_WITHOUT_VR, position, { tag });
|
|
11772
11849
|
}
|
|
11773
|
-
function privateCreatorUnknown(position, tag
|
|
11774
|
-
return {
|
|
11775
|
-
code: WARNING_CODES.DICOM_PRIVATE_CREATOR_UNKNOWN,
|
|
11776
|
-
message: `Private element (${tag}) creator "${creator}" is not in the active profile's private dictionary; falling back to UN.`,
|
|
11777
|
-
position
|
|
11778
|
-
};
|
|
11850
|
+
function privateCreatorUnknown(position, tag) {
|
|
11851
|
+
return build(WARNING_CODES.DICOM_PRIVATE_CREATOR_UNKNOWN, position, { tag });
|
|
11779
11852
|
}
|
|
11780
11853
|
function burnedInAnnotationNotRemoved(position) {
|
|
11781
|
-
return
|
|
11782
|
-
|
|
11783
|
-
|
|
11784
|
-
|
|
11785
|
-
|
|
11854
|
+
return build(WARNING_CODES.DICOM_BURNED_IN_ANNOTATION_NOT_REMOVED, position);
|
|
11855
|
+
}
|
|
11856
|
+
function embeddedAttributeRemoved(position, tag, vr, count) {
|
|
11857
|
+
return build(WARNING_CODES.DICOM_DEIDENT_EMBEDDED_ATTRIBUTE_REMOVED, position, {
|
|
11858
|
+
tag,
|
|
11859
|
+
vr,
|
|
11860
|
+
n: count
|
|
11861
|
+
});
|
|
11862
|
+
}
|
|
11863
|
+
function sequenceNotAuditable(position, tag, byteLength) {
|
|
11864
|
+
return build(WARNING_CODES.DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE, position, {
|
|
11865
|
+
tag,
|
|
11866
|
+
n: byteLength
|
|
11867
|
+
});
|
|
11868
|
+
}
|
|
11869
|
+
function undefinedVrNotAuditable(position, byteLength) {
|
|
11870
|
+
return build(WARNING_CODES.DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE, position, {
|
|
11871
|
+
n: byteLength,
|
|
11872
|
+
n2: position.byteOffset
|
|
11873
|
+
});
|
|
11786
11874
|
}
|
|
11787
11875
|
function bomInTextVR(position, tag, vr) {
|
|
11788
|
-
return {
|
|
11789
|
-
code: WARNING_CODES.DICOM_BOM_IN_TEXT_VR,
|
|
11790
|
-
message: `Element (${tag}) ${vr} value begins with a UTF-8 BOM; stripped on decode.`,
|
|
11791
|
-
position
|
|
11792
|
-
};
|
|
11876
|
+
return build(WARNING_CODES.DICOM_BOM_IN_TEXT_VR, position, { tag, vr });
|
|
11793
11877
|
}
|
|
11794
11878
|
function trailingNullInTextVR(position, tag, vr) {
|
|
11795
|
-
return {
|
|
11796
|
-
code: WARNING_CODES.DICOM_TRAILING_NULL_IN_TEXT_VR,
|
|
11797
|
-
message: `Element (${tag}) ${vr} value has a trailing NULL pad where SPACE is expected; trimmed.`,
|
|
11798
|
-
position
|
|
11799
|
-
};
|
|
11879
|
+
return build(WARNING_CODES.DICOM_TRAILING_NULL_IN_TEXT_VR, position, { tag, vr });
|
|
11800
11880
|
}
|
|
11801
11881
|
function uiTrailingSpace(position, tag) {
|
|
11802
|
-
return {
|
|
11803
|
-
code: WARNING_CODES.DICOM_UI_TRAILING_SPACE,
|
|
11804
|
-
message: `Element (${tag}) UI value is SPACE-padded; UI requires NULL padding (PS3.5 \xA76.2). Trimmed.`,
|
|
11805
|
-
position
|
|
11806
|
-
};
|
|
11882
|
+
return build(WARNING_CODES.DICOM_UI_TRAILING_SPACE, position, { tag });
|
|
11807
11883
|
}
|
|
11808
11884
|
function nonAsciiInAsciiVR(position, tag, vr) {
|
|
11809
|
-
return {
|
|
11810
|
-
code: WARNING_CODES.DICOM_NON_ASCII_IN_ASCII_VR,
|
|
11811
|
-
message: `Element (${tag}) ${vr} is an ASCII-only VR but contains non-ASCII bytes; decoded as Latin-1 best-effort.`,
|
|
11812
|
-
position
|
|
11813
|
-
};
|
|
11885
|
+
return build(WARNING_CODES.DICOM_NON_ASCII_IN_ASCII_VR, position, { tag, vr });
|
|
11814
11886
|
}
|
|
11815
11887
|
function isNonintegerValue(position, tag) {
|
|
11816
|
-
return {
|
|
11817
|
-
code: WARNING_CODES.DICOM_IS_NONINTEGER_VALUE,
|
|
11818
|
-
message: `Element (${tag}) IS value is not a base-10 integer; surfaced as null with raw bytes preserved.`,
|
|
11819
|
-
position
|
|
11820
|
-
};
|
|
11888
|
+
return build(WARNING_CODES.DICOM_IS_NONINTEGER_VALUE, position, { tag });
|
|
11821
11889
|
}
|
|
11822
11890
|
function daLegacyFormat(position, tag) {
|
|
11823
|
-
return {
|
|
11824
|
-
code: WARNING_CODES.DICOM_DA_LEGACY_FORMAT,
|
|
11825
|
-
message: `Element (${tag}) DA value is not in canonical YYYYMMDD form; decoded best-effort, raw preserved.`,
|
|
11826
|
-
position
|
|
11827
|
-
};
|
|
11891
|
+
return build(WARNING_CODES.DICOM_DA_LEGACY_FORMAT, position, { tag });
|
|
11828
11892
|
}
|
|
11829
11893
|
function dtNonstandardOffset(position, tag) {
|
|
11830
|
-
return {
|
|
11831
|
-
code: WARNING_CODES.DICOM_DT_NONSTANDARD_OFFSET,
|
|
11832
|
-
message: `Element (${tag}) DT value has a non-standard UTC offset; decoded best-effort, raw preserved.`,
|
|
11833
|
-
position
|
|
11834
|
-
};
|
|
11894
|
+
return build(WARNING_CODES.DICOM_DT_NONSTANDARD_OFFSET, position, { tag });
|
|
11835
11895
|
}
|
|
11836
|
-
function unsupportedCharset(position,
|
|
11837
|
-
return {
|
|
11838
|
-
code: WARNING_CODES.DICOM_UNSUPPORTED_CHARSET,
|
|
11839
|
-
message: `Specific Character Set term "${term}" is not supported; decoding text as UTF-8 best-effort.`,
|
|
11840
|
-
position
|
|
11841
|
-
};
|
|
11896
|
+
function unsupportedCharset(position, valueIndex) {
|
|
11897
|
+
return build(WARNING_CODES.DICOM_UNSUPPORTED_CHARSET, position, { n: valueIndex });
|
|
11842
11898
|
}
|
|
11843
11899
|
|
|
11844
11900
|
// src/profiles/lookup.ts
|
|
@@ -11858,9 +11914,9 @@ var SPECIFIC_CHARACTER_SET_TAG = "00080005";
|
|
|
11858
11914
|
function applySpecificCharacterSet(tag, value, ctx, emit, position) {
|
|
11859
11915
|
if (tag !== SPECIFIC_CHARACTER_SET_TAG) return;
|
|
11860
11916
|
const terms = parseSpecificCharacterSet(value);
|
|
11861
|
-
|
|
11862
|
-
if (!isKnownCharsetTerm(term)) emit(unsupportedCharset(position,
|
|
11863
|
-
}
|
|
11917
|
+
terms.forEach((term, index) => {
|
|
11918
|
+
if (!isKnownCharsetTerm(term)) emit(unsupportedCharset(position, index + 1));
|
|
11919
|
+
});
|
|
11864
11920
|
ctx.currentCharset = terms;
|
|
11865
11921
|
}
|
|
11866
11922
|
var LONG_FORM_VRS = /* @__PURE__ */ new Set([
|
|
@@ -11896,7 +11952,7 @@ function resolveImplicitVR(tag, ctx, emit, position) {
|
|
|
11896
11952
|
const def = resolvePrivateTag(ctx.profile, tag, creator);
|
|
11897
11953
|
if (def !== void 0) return def.vr;
|
|
11898
11954
|
if (!ctx.profile.privateDictionary.has(creator)) {
|
|
11899
|
-
emit(privateCreatorUnknown(position, tag
|
|
11955
|
+
emit(privateCreatorUnknown(position, tag));
|
|
11900
11956
|
}
|
|
11901
11957
|
}
|
|
11902
11958
|
emit(implicitVRForPrivateTagWithoutVR(position, tag));
|
|
@@ -11921,6 +11977,9 @@ function resolvePrivateCreator(tag, ctx) {
|
|
|
11921
11977
|
if (blockId < 16 || blockId > 255) return void 0;
|
|
11922
11978
|
return ctx.creators.get(group)?.get(blockId);
|
|
11923
11979
|
}
|
|
11980
|
+
function safeModelCreator(creator, ctx) {
|
|
11981
|
+
return creator === void 0 ? void 0 : safePrivateCreator(creator, ctx.profile);
|
|
11982
|
+
}
|
|
11924
11983
|
function registerPrivateCreator(tag, value, ctx) {
|
|
11925
11984
|
const group = parseInt(tag.slice(0, 4), 16);
|
|
11926
11985
|
if (group % 2 === 0) return;
|
|
@@ -11980,8 +12039,7 @@ function readExplicitElementHeader(cursor, _ctx, emit) {
|
|
|
11980
12039
|
const reserved1 = cursor.buffer[cursor.position + 1];
|
|
11981
12040
|
cursor.position += 2;
|
|
11982
12041
|
if ((reserved0 ?? 0) !== 0 || (reserved1 ?? 0) !== 0) {
|
|
11983
|
-
|
|
11984
|
-
emit(nonzeroReservedBytes({ byteOffset: headerStart }, tag, observed));
|
|
12042
|
+
emit(nonzeroReservedBytes({ byteOffset: headerStart }, tag, reserved0 ?? 0, reserved1 ?? 0));
|
|
11985
12043
|
}
|
|
11986
12044
|
length = cursor.readUInt32();
|
|
11987
12045
|
headerLength = 12;
|
|
@@ -12617,6 +12675,13 @@ function parseSequence(buffer, valueStart, ctx, emit, opts) {
|
|
|
12617
12675
|
ctx.currentCharset = parentCharset;
|
|
12618
12676
|
}
|
|
12619
12677
|
};
|
|
12678
|
+
const parentCreators = ctx.creators;
|
|
12679
|
+
const restoreParentCreators = () => {
|
|
12680
|
+
ctx.creators = parentCreators;
|
|
12681
|
+
};
|
|
12682
|
+
const beginItemCreatorScope = () => {
|
|
12683
|
+
ctx.creators = /* @__PURE__ */ new Map();
|
|
12684
|
+
};
|
|
12620
12685
|
try {
|
|
12621
12686
|
const cursor = new ByteCursor(buffer, opts.littleEndian, valueStart);
|
|
12622
12687
|
const items = [];
|
|
@@ -12681,6 +12746,7 @@ function parseSequence(buffer, valueStart, ctx, emit, opts) {
|
|
|
12681
12746
|
continue;
|
|
12682
12747
|
}
|
|
12683
12748
|
restoreParentCharset();
|
|
12749
|
+
beginItemCreatorScope();
|
|
12684
12750
|
if (itemLength === UNDEFINED_LENGTH) {
|
|
12685
12751
|
const inner = opts.innerStrategy(buffer, cursor.position, ctx, emit, {
|
|
12686
12752
|
stopOnItemDelim: true
|
|
@@ -12708,9 +12774,39 @@ function parseSequence(buffer, valueStart, ctx, emit, opts) {
|
|
|
12708
12774
|
ctx.nestingDepth -= 1;
|
|
12709
12775
|
ctx.encodingContextStack.pop();
|
|
12710
12776
|
restoreParentCharset();
|
|
12777
|
+
restoreParentCreators();
|
|
12778
|
+
}
|
|
12779
|
+
}
|
|
12780
|
+
function isStrictEscalation(err) {
|
|
12781
|
+
if (!(err instanceof DicomParseError)) return false;
|
|
12782
|
+
return Object.values(WARNING_CODES).includes(err.code);
|
|
12783
|
+
}
|
|
12784
|
+
function tryParseDefinedLengthSQ(buffer, valueStart, valueLength, ctx, emit, implicitLeInner, tag) {
|
|
12785
|
+
const savedDepth = ctx.nestingDepth;
|
|
12786
|
+
const savedStackLen = ctx.encodingContextStack.length;
|
|
12787
|
+
const savedWarningsLen = ctx.warnings.length;
|
|
12788
|
+
try {
|
|
12789
|
+
const slice = buffer.subarray(valueStart, valueStart + valueLength);
|
|
12790
|
+
const result = parseSequence(slice, 0, ctx, emit, {
|
|
12791
|
+
explicitLength: valueLength,
|
|
12792
|
+
littleEndian: true,
|
|
12793
|
+
innerStrategy: implicitLeInner
|
|
12794
|
+
});
|
|
12795
|
+
return { success: true, items: result.items };
|
|
12796
|
+
} catch (err) {
|
|
12797
|
+
if (isStrictEscalation(err)) throw err;
|
|
12798
|
+
ctx.nestingDepth = savedDepth;
|
|
12799
|
+
while (ctx.encodingContextStack.length > savedStackLen) {
|
|
12800
|
+
ctx.encodingContextStack.pop();
|
|
12801
|
+
}
|
|
12802
|
+
while (ctx.warnings.length > savedWarningsLen) {
|
|
12803
|
+
ctx.warnings.pop();
|
|
12804
|
+
}
|
|
12805
|
+
emit(sqNotDescended({ byteOffset: valueStart }, tag));
|
|
12806
|
+
return { success: false, items: [] };
|
|
12711
12807
|
}
|
|
12712
12808
|
}
|
|
12713
|
-
function tryParseUnAsSQ(buffer, valueStart, valueLength, ctx, emit, implicitLeInner) {
|
|
12809
|
+
function tryParseUnAsSQ(buffer, valueStart, valueLength, ctx, emit, implicitLeInner, tag) {
|
|
12714
12810
|
const savedDepth = ctx.nestingDepth;
|
|
12715
12811
|
const savedStackLen = ctx.encodingContextStack.length;
|
|
12716
12812
|
const savedWarningsLen = ctx.warnings.length;
|
|
@@ -12723,18 +12819,15 @@ function tryParseUnAsSQ(buffer, valueStart, valueLength, ctx, emit, implicitLeIn
|
|
|
12723
12819
|
innerStrategy: implicitLeInner
|
|
12724
12820
|
};
|
|
12725
12821
|
const result = parseSequence(slice, 0, ctx, emit, opts);
|
|
12726
|
-
emit(unParsedAsSQ({ byteOffset: valueStart },
|
|
12822
|
+
emit(unParsedAsSQ({ byteOffset: valueStart }, tag));
|
|
12727
12823
|
return {
|
|
12728
12824
|
success: true,
|
|
12729
12825
|
items: result.items,
|
|
12730
12826
|
endOffset: valueStart + result.endOffset
|
|
12731
12827
|
};
|
|
12732
12828
|
} catch (err) {
|
|
12733
|
-
if (err
|
|
12734
|
-
|
|
12735
|
-
if (warningCodeValues.includes(err.code)) {
|
|
12736
|
-
throw err;
|
|
12737
|
-
}
|
|
12829
|
+
if (isStrictEscalation(err)) {
|
|
12830
|
+
throw err;
|
|
12738
12831
|
}
|
|
12739
12832
|
ctx.nestingDepth = savedDepth;
|
|
12740
12833
|
while (ctx.encodingContextStack.length > savedStackLen) {
|
|
@@ -12795,7 +12888,7 @@ function parseImplicitLE(buffer, datasetStart, ctx, emit, opts = {}) {
|
|
|
12795
12888
|
const valueRawStart = headerStart;
|
|
12796
12889
|
cursor.position = seq.endOffset;
|
|
12797
12890
|
const rawBytes = ctx.copyValues ? copyValueBytes(buffer.subarray(valueRawStart, cursor.position)) : buffer.subarray(valueRawStart, cursor.position);
|
|
12798
|
-
const privateCreator2 = resolvePrivateCreator(tag, ctx);
|
|
12891
|
+
const privateCreator2 = safeModelCreator(resolvePrivateCreator(tag, ctx), ctx);
|
|
12799
12892
|
elements.set(
|
|
12800
12893
|
tag,
|
|
12801
12894
|
new Element({
|
|
@@ -12812,6 +12905,40 @@ function parseImplicitLE(buffer, datasetStart, ctx, emit, opts = {}) {
|
|
|
12812
12905
|
);
|
|
12813
12906
|
continue;
|
|
12814
12907
|
}
|
|
12908
|
+
if (vr === "UN") {
|
|
12909
|
+
const cp246 = tryParseUnAsSQ(
|
|
12910
|
+
buffer,
|
|
12911
|
+
cursor.position,
|
|
12912
|
+
4294967295,
|
|
12913
|
+
ctx,
|
|
12914
|
+
emit,
|
|
12915
|
+
parseImplicitLE,
|
|
12916
|
+
tag
|
|
12917
|
+
);
|
|
12918
|
+
if (cp246.success) {
|
|
12919
|
+
const valueRawStart = headerStart;
|
|
12920
|
+
cursor.position = cp246.endOffset;
|
|
12921
|
+
const rawBytes = ctx.copyValues ? copyValueBytes(buffer.subarray(valueRawStart, cursor.position)) : buffer.subarray(valueRawStart, cursor.position);
|
|
12922
|
+
const privateCreator2 = safeModelCreator(resolvePrivateCreator(tag, ctx), ctx);
|
|
12923
|
+
elements.set(
|
|
12924
|
+
tag,
|
|
12925
|
+
new Element({
|
|
12926
|
+
tag,
|
|
12927
|
+
vr: "SQ",
|
|
12928
|
+
// Promoted, exactly as the Explicit-VR path promotes it.
|
|
12929
|
+
vm: cp246.items.length,
|
|
12930
|
+
length: 4294967295,
|
|
12931
|
+
rawBytes,
|
|
12932
|
+
byteOffset: headerStart,
|
|
12933
|
+
cp246Promoted: true,
|
|
12934
|
+
littleEndian: true,
|
|
12935
|
+
items: cp246.items,
|
|
12936
|
+
...privateCreator2 !== void 0 ? { privateCreator: privateCreator2 } : {}
|
|
12937
|
+
})
|
|
12938
|
+
);
|
|
12939
|
+
continue;
|
|
12940
|
+
}
|
|
12941
|
+
}
|
|
12815
12942
|
throw new DicomParseError(
|
|
12816
12943
|
FATAL_CODES.INVALID_FILE_META,
|
|
12817
12944
|
`Undefined length on non-SQ element ${tag} (vr=${vr}) under Implicit VR LE.`,
|
|
@@ -12831,6 +12958,35 @@ function parseImplicitLE(buffer, datasetStart, ctx, emit, opts = {}) {
|
|
|
12831
12958
|
const valueEnd = valueStart + length;
|
|
12832
12959
|
const valueSlice = ctx.copyValues ? copyValueBytes(buffer.subarray(valueStart, valueEnd)) : buffer.subarray(valueStart, valueEnd);
|
|
12833
12960
|
cursor.position = valueEnd;
|
|
12961
|
+
if (vr === "SQ") {
|
|
12962
|
+
const seq = tryParseDefinedLengthSQ(
|
|
12963
|
+
buffer,
|
|
12964
|
+
valueStart,
|
|
12965
|
+
length,
|
|
12966
|
+
ctx,
|
|
12967
|
+
emit,
|
|
12968
|
+
parseImplicitLE,
|
|
12969
|
+
tag
|
|
12970
|
+
);
|
|
12971
|
+
if (seq.success) {
|
|
12972
|
+
const privateCreator2 = safeModelCreator(resolvePrivateCreator(tag, ctx), ctx);
|
|
12973
|
+
elements.set(
|
|
12974
|
+
tag,
|
|
12975
|
+
new Element({
|
|
12976
|
+
tag,
|
|
12977
|
+
vr,
|
|
12978
|
+
vm: seq.items.length,
|
|
12979
|
+
length,
|
|
12980
|
+
rawBytes: valueSlice,
|
|
12981
|
+
byteOffset: headerStart,
|
|
12982
|
+
littleEndian: true,
|
|
12983
|
+
items: seq.items,
|
|
12984
|
+
...privateCreator2 !== void 0 ? { privateCreator: privateCreator2 } : {}
|
|
12985
|
+
})
|
|
12986
|
+
);
|
|
12987
|
+
continue;
|
|
12988
|
+
}
|
|
12989
|
+
}
|
|
12834
12990
|
if (element === 0 && group !== 2) {
|
|
12835
12991
|
emit(groupLengthInDataset(position, tag));
|
|
12836
12992
|
}
|
|
@@ -12838,7 +12994,7 @@ function parseImplicitLE(buffer, datasetStart, ctx, emit, opts = {}) {
|
|
|
12838
12994
|
registerPrivateCreator(tag, valueSlice, ctx);
|
|
12839
12995
|
}
|
|
12840
12996
|
applySpecificCharacterSet(tag, valueSlice, ctx, emit, position);
|
|
12841
|
-
const privateCreator = resolvePrivateCreator(tag, ctx);
|
|
12997
|
+
const privateCreator = safeModelCreator(resolvePrivateCreator(tag, ctx), ctx);
|
|
12842
12998
|
elements.set(
|
|
12843
12999
|
tag,
|
|
12844
13000
|
new Element({
|
|
@@ -12958,7 +13114,7 @@ function _parseExplicit(buffer, datasetStart, ctx, emit, mode, opts = {}) {
|
|
|
12958
13114
|
}
|
|
12959
13115
|
cursor.position = seqResult.endOffset;
|
|
12960
13116
|
const rawBytes = ctx.copyValues ? copyValueBytes(buffer.subarray(headerStart, cursor.position)) : buffer.subarray(headerStart, cursor.position);
|
|
12961
|
-
const privateCreator2 = resolvePrivateCreator(tag, ctx);
|
|
13117
|
+
const privateCreator2 = safeModelCreator(resolvePrivateCreator(tag, ctx), ctx);
|
|
12962
13118
|
elements.set(
|
|
12963
13119
|
tag,
|
|
12964
13120
|
new Element({
|
|
@@ -13010,12 +13166,13 @@ function _parseExplicit(buffer, datasetStart, ctx, emit, mode, opts = {}) {
|
|
|
13010
13166
|
UNDEFINED_LENGTH2,
|
|
13011
13167
|
ctx,
|
|
13012
13168
|
emit,
|
|
13013
|
-
parseImplicitLE
|
|
13169
|
+
parseImplicitLE,
|
|
13170
|
+
tag
|
|
13014
13171
|
);
|
|
13015
13172
|
if (cp246.success) {
|
|
13016
13173
|
cursor.position = cp246.endOffset;
|
|
13017
13174
|
const rawBytes = ctx.copyValues ? copyValueBytes(buffer.subarray(headerStart, cursor.position)) : buffer.subarray(headerStart, cursor.position);
|
|
13018
|
-
const privateCreator3 = resolvePrivateCreator(tag, ctx);
|
|
13175
|
+
const privateCreator3 = safeModelCreator(resolvePrivateCreator(tag, ctx), ctx);
|
|
13019
13176
|
elements.set(
|
|
13020
13177
|
tag,
|
|
13021
13178
|
new Element({
|
|
@@ -13034,7 +13191,7 @@ function _parseExplicit(buffer, datasetStart, ctx, emit, mode, opts = {}) {
|
|
|
13034
13191
|
);
|
|
13035
13192
|
continue;
|
|
13036
13193
|
}
|
|
13037
|
-
const privateCreator2 = resolvePrivateCreator(tag, ctx);
|
|
13194
|
+
const privateCreator2 = safeModelCreator(resolvePrivateCreator(tag, ctx), ctx);
|
|
13038
13195
|
const fallbackEnd = buffer.length;
|
|
13039
13196
|
const fallbackBytes = ctx.copyValues ? copyValueBytes(buffer.subarray(headerStart, fallbackEnd)) : buffer.subarray(headerStart, fallbackEnd);
|
|
13040
13197
|
elements.set(
|
|
@@ -13081,7 +13238,7 @@ function _parseExplicit(buffer, datasetStart, ctx, emit, mode, opts = {}) {
|
|
|
13081
13238
|
registerPrivateCreator(tag, valueSlice, ctx);
|
|
13082
13239
|
}
|
|
13083
13240
|
applySpecificCharacterSet(tag, valueSlice, ctx, emit, position);
|
|
13084
|
-
const privateCreator = resolvePrivateCreator(tag, ctx);
|
|
13241
|
+
const privateCreator = safeModelCreator(resolvePrivateCreator(tag, ctx), ctx);
|
|
13085
13242
|
const finalVr = vr;
|
|
13086
13243
|
elements.set(
|
|
13087
13244
|
tag,
|
|
@@ -13134,20 +13291,22 @@ function parseDeflatedLEWithCap(buffer, datasetStart, ctx, emit, maxInflatedByte
|
|
|
13134
13291
|
buildSnippet(buffer, datasetStart)
|
|
13135
13292
|
);
|
|
13136
13293
|
}
|
|
13294
|
+
const zlibCode = typeof code === "string" && code.length > 0 ? code : "unknown";
|
|
13137
13295
|
throw new DicomParseError(
|
|
13138
13296
|
FATAL_CODES.INVALID_FILE_META,
|
|
13139
|
-
`Failed to inflate Deflated TS payload: ${
|
|
13297
|
+
`Failed to inflate Deflated TS payload (zlib error code: ${zlibCode}).`,
|
|
13140
13298
|
datasetStart,
|
|
13141
13299
|
buildSnippet(buffer, datasetStart)
|
|
13142
13300
|
);
|
|
13143
13301
|
}
|
|
13144
13302
|
const innerCtx = { ...ctx, buffer: inflated };
|
|
13303
|
+
const innerChokepoint = makeEmitter(innerCtx);
|
|
13145
13304
|
const innerEmit = (w) => {
|
|
13146
13305
|
const wrapped = {
|
|
13147
13306
|
...w,
|
|
13148
13307
|
position: { ...w.position, deflated: true }
|
|
13149
13308
|
};
|
|
13150
|
-
|
|
13309
|
+
innerChokepoint(wrapped);
|
|
13151
13310
|
};
|
|
13152
13311
|
const result = parseExplicitLE(inflated, 0, innerCtx, innerEmit);
|
|
13153
13312
|
return { elements: result.elements, endOffset: buffer.length };
|
|
@@ -13174,6 +13333,7 @@ var TRANSFER_SYNTAX_PARSERS = Object.freeze({
|
|
|
13174
13333
|
});
|
|
13175
13334
|
|
|
13176
13335
|
// src/parser/index.ts
|
|
13336
|
+
var SUPPORTED_TRANSFER_SYNTAXES = Object.keys(TRANSFER_SYNTAX_PARSERS).join(", ");
|
|
13177
13337
|
function parseDicom(input, options = {}) {
|
|
13178
13338
|
if (rawInputIsEmpty(input)) {
|
|
13179
13339
|
throw new DicomParseError(FATAL_CODES.EMPTY_INPUT, "Input is empty.", 0, "");
|
|
@@ -13196,9 +13356,10 @@ function parseDicom(input, options = {}) {
|
|
|
13196
13356
|
const strategy = TRANSFER_SYNTAX_PARSERS[tsUid];
|
|
13197
13357
|
if (strategy === void 0) {
|
|
13198
13358
|
const tsName = uid(tsUid)?.name ?? "";
|
|
13359
|
+
const named = tsName.length > 0 ? `Transfer Syntax ${tsName}` : "The Transfer Syntax UID";
|
|
13199
13360
|
throw new DicomParseError(
|
|
13200
13361
|
FATAL_CODES.UNSUPPORTED_TRANSFER_SYNTAX,
|
|
13201
|
-
|
|
13362
|
+
`${named} in (0002,0010) is not supported by @cosyte/dicom v1 (supported: ${SUPPORTED_TRANSFER_SYNTAXES}).`,
|
|
13202
13363
|
fileMetaEnd,
|
|
13203
13364
|
tsName.length > 0 ? tsName : buildSnippet(buffer, fileMetaEnd)
|
|
13204
13365
|
);
|
|
@@ -13436,7 +13597,7 @@ function serializeDicom(ds) {
|
|
|
13436
13597
|
if (encoding === void 0) {
|
|
13437
13598
|
throw new DicomSerializeError(
|
|
13438
13599
|
SERIALIZE_ERROR_CODES.UNSUPPORTED_TRANSFER_SYNTAX,
|
|
13439
|
-
`Transfer Syntax UID
|
|
13600
|
+
`The Dataset's File Meta Transfer Syntax UID is not supported by the @cosyte/dicom v1 writer (supported: ${Object.keys(BODY_ENCODING).join(", ")}).`
|
|
13440
13601
|
);
|
|
13441
13602
|
}
|
|
13442
13603
|
const preamble = part10Preamble();
|
|
@@ -14535,6 +14696,132 @@ function uidValueMultiplicity(rawBytes) {
|
|
|
14535
14696
|
return raw.split("\\").length;
|
|
14536
14697
|
}
|
|
14537
14698
|
|
|
14699
|
+
// src/deident/embedded.ts
|
|
14700
|
+
var KNOWN_VRS2 = new Set(Object.keys(BE_VR_STRIDE));
|
|
14701
|
+
var UNDEFINED_LENGTH4 = 4294967295;
|
|
14702
|
+
var FFFE_GROUP = 65534;
|
|
14703
|
+
var SCANNABLE_CARRIER_VRS = /* @__PURE__ */ new Set([
|
|
14704
|
+
"AE",
|
|
14705
|
+
"AS",
|
|
14706
|
+
"CS",
|
|
14707
|
+
"DA",
|
|
14708
|
+
"DS",
|
|
14709
|
+
"DT",
|
|
14710
|
+
"IS",
|
|
14711
|
+
"LO",
|
|
14712
|
+
"LT",
|
|
14713
|
+
"PN",
|
|
14714
|
+
"SH",
|
|
14715
|
+
"ST",
|
|
14716
|
+
"TM",
|
|
14717
|
+
"UC",
|
|
14718
|
+
"UI",
|
|
14719
|
+
"UR",
|
|
14720
|
+
"UT"
|
|
14721
|
+
]);
|
|
14722
|
+
var ALLOWED_CONTROL_BYTES = /* @__PURE__ */ new Set([
|
|
14723
|
+
9,
|
|
14724
|
+
// TAB
|
|
14725
|
+
10,
|
|
14726
|
+
// LF
|
|
14727
|
+
12,
|
|
14728
|
+
// FF
|
|
14729
|
+
13,
|
|
14730
|
+
// CR
|
|
14731
|
+
27
|
|
14732
|
+
// ESC
|
|
14733
|
+
]);
|
|
14734
|
+
var CONTROL_TOLERANT_VRS = /* @__PURE__ */ new Set(["LT", "ST", "UT"]);
|
|
14735
|
+
var ESC_ONLY_VRS = /* @__PURE__ */ new Set(["LO", "SH", "UC", "PN"]);
|
|
14736
|
+
var MAX_SCAN_BYTES = 1 << 20;
|
|
14737
|
+
var MIN_HEADER = 8;
|
|
14738
|
+
function readU16(buf, off, littleEndian) {
|
|
14739
|
+
return littleEndian ? buf.readUInt16LE(off) : buf.readUInt16BE(off);
|
|
14740
|
+
}
|
|
14741
|
+
function readU32(buf, off, littleEndian) {
|
|
14742
|
+
return littleEndian ? buf.readUInt32LE(off) : buf.readUInt32BE(off);
|
|
14743
|
+
}
|
|
14744
|
+
function decodeAt(value, off, encoding) {
|
|
14745
|
+
if (off + MIN_HEADER > value.length) return void 0;
|
|
14746
|
+
const littleEndian = encoding !== "explicitBE";
|
|
14747
|
+
const group = readU16(value, off, littleEndian);
|
|
14748
|
+
const element = readU16(value, off + 2, littleEndian);
|
|
14749
|
+
if (group === FFFE_GROUP) {
|
|
14750
|
+
return { next: off + 8, tag: void 0 };
|
|
14751
|
+
}
|
|
14752
|
+
if (group === 0 && element === 0) return void 0;
|
|
14753
|
+
const tag = joinTag(group, element);
|
|
14754
|
+
if (encoding === "implicit") {
|
|
14755
|
+
const length2 = readU32(value, off + 4, littleEndian);
|
|
14756
|
+
if (length2 === UNDEFINED_LENGTH4 || length2 % 2 !== 0) return void 0;
|
|
14757
|
+
const next2 = off + 8 + length2;
|
|
14758
|
+
return next2 > value.length ? void 0 : { next: next2, tag };
|
|
14759
|
+
}
|
|
14760
|
+
const vr = value.toString("latin1", off + 4, off + 6);
|
|
14761
|
+
if (!KNOWN_VRS2.has(vr)) return void 0;
|
|
14762
|
+
if (LONG_FORM_VRS.has(vr)) {
|
|
14763
|
+
if (off + 12 > value.length) return void 0;
|
|
14764
|
+
if (value[off + 6] !== 0 || value[off + 7] !== 0) return void 0;
|
|
14765
|
+
const length2 = readU32(value, off + 8, littleEndian);
|
|
14766
|
+
if (length2 === UNDEFINED_LENGTH4 || length2 % 2 !== 0) return void 0;
|
|
14767
|
+
const next2 = off + 12 + length2;
|
|
14768
|
+
return next2 > value.length ? void 0 : { next: next2, tag };
|
|
14769
|
+
}
|
|
14770
|
+
const length = readU16(value, off + 6, littleEndian);
|
|
14771
|
+
if (length % 2 !== 0) return void 0;
|
|
14772
|
+
const next = off + 8 + length;
|
|
14773
|
+
return next > value.length ? void 0 : { next, tag };
|
|
14774
|
+
}
|
|
14775
|
+
function isScannableCarrier(vr) {
|
|
14776
|
+
return SCANNABLE_CARRIER_VRS.has(vr);
|
|
14777
|
+
}
|
|
14778
|
+
function hasByteOutsideRepertoire(region, carrierVr) {
|
|
14779
|
+
const allFive = CONTROL_TOLERANT_VRS.has(carrierVr);
|
|
14780
|
+
const escOnly = ESC_ONLY_VRS.has(carrierVr);
|
|
14781
|
+
for (const byte of region) {
|
|
14782
|
+
if (byte >= 32 && byte !== 127) continue;
|
|
14783
|
+
if (allFive && ALLOWED_CONTROL_BYTES.has(byte)) continue;
|
|
14784
|
+
if (escOnly && byte === 27) continue;
|
|
14785
|
+
return true;
|
|
14786
|
+
}
|
|
14787
|
+
return false;
|
|
14788
|
+
}
|
|
14789
|
+
function findEmbeddedAttributes(value, carrierVr, encoding, isActionable) {
|
|
14790
|
+
if (!isScannableCarrier(carrierVr)) return void 0;
|
|
14791
|
+
if (value.length < MIN_HEADER) return void 0;
|
|
14792
|
+
const windowStart = value.length > MAX_SCAN_BYTES ? value.length - MAX_SCAN_BYTES : 0;
|
|
14793
|
+
const window = value.subarray(windowStart);
|
|
14794
|
+
const n = window.length;
|
|
14795
|
+
const half = (n >> 1) + 1;
|
|
14796
|
+
const tiles = new Uint8Array(half);
|
|
14797
|
+
const hit = new Uint8Array(half);
|
|
14798
|
+
for (let off = n - MIN_HEADER & -2; off >= 0; off -= 2) {
|
|
14799
|
+
const decoded = decodeAt(window, off, encoding);
|
|
14800
|
+
if (decoded === void 0) continue;
|
|
14801
|
+
const atEnd = decoded.next === n;
|
|
14802
|
+
const onward = decoded.next < n ? tiles[decoded.next >> 1] === 1 : false;
|
|
14803
|
+
if (!atEnd && !onward) continue;
|
|
14804
|
+
tiles[off >> 1] = 1;
|
|
14805
|
+
const actionable = decoded.tag !== void 0 && isActionable(decoded.tag);
|
|
14806
|
+
const onwardHit = decoded.next < n ? hit[decoded.next >> 1] === 1 : false;
|
|
14807
|
+
if (actionable || onwardHit) hit[off >> 1] = 1;
|
|
14808
|
+
}
|
|
14809
|
+
for (let off = 0; off + MIN_HEADER <= n; off += 2) {
|
|
14810
|
+
if (hit[off >> 1] !== 1) continue;
|
|
14811
|
+
if (!hasByteOutsideRepertoire(window.subarray(off), carrierVr)) return void 0;
|
|
14812
|
+
const tags = [];
|
|
14813
|
+
let pos = off;
|
|
14814
|
+
while (pos < n) {
|
|
14815
|
+
const decoded = decodeAt(window, pos, encoding);
|
|
14816
|
+
if (decoded === void 0) break;
|
|
14817
|
+
if (decoded.tag !== void 0) tags.push(decoded.tag);
|
|
14818
|
+
pos = decoded.next;
|
|
14819
|
+
}
|
|
14820
|
+
return tags;
|
|
14821
|
+
}
|
|
14822
|
+
return void 0;
|
|
14823
|
+
}
|
|
14824
|
+
|
|
14538
14825
|
// src/deident/types.ts
|
|
14539
14826
|
var DEIDENTIFY_OPTIONS = Object.freeze([
|
|
14540
14827
|
"CleanGraphics",
|
|
@@ -14606,6 +14893,9 @@ var BODY_ENCODING2 = {
|
|
|
14606
14893
|
"1.2.840.10008.1.2.2": "explicitBE",
|
|
14607
14894
|
"1.2.840.10008.1.2.1.99": "explicitLE"
|
|
14608
14895
|
};
|
|
14896
|
+
var MAX_UNAUDITABLE_SEQUENCE_FINDINGS = 64;
|
|
14897
|
+
var MAX_UNDEFINED_VR_FINDINGS = 64;
|
|
14898
|
+
var KNOWN_VRS3 = new Set(Object.keys(BE_VR_STRIDE));
|
|
14609
14899
|
function validateRetain(retain) {
|
|
14610
14900
|
const valid = new Set(DEIDENTIFY_OPTIONS);
|
|
14611
14901
|
const active = /* @__PURE__ */ new Set();
|
|
@@ -14719,12 +15009,83 @@ function isPrivateCreatorElement(tag) {
|
|
|
14719
15009
|
const { element } = splitTag(tag);
|
|
14720
15010
|
return element >= 16 && element <= 255;
|
|
14721
15011
|
}
|
|
14722
|
-
function
|
|
15012
|
+
function actsOnTag(tag, ctx) {
|
|
15013
|
+
if (isPrivateTag(tag)) return true;
|
|
15014
|
+
const action = annexE(tag);
|
|
15015
|
+
if (action === void 0) return false;
|
|
15016
|
+
return resolveAction(effectiveCode(action, ctx.active)) !== "K";
|
|
15017
|
+
}
|
|
15018
|
+
function hasUndefinedVr(el) {
|
|
15019
|
+
return !KNOWN_VRS3.has(el.vr);
|
|
15020
|
+
}
|
|
15021
|
+
function keepOrEmpty(el, ctx, contextPath, out) {
|
|
15022
|
+
if (hasUndefinedVr(el)) {
|
|
15023
|
+
emptyUndefinedVrElement(el, ctx, contextPath, out);
|
|
15024
|
+
return false;
|
|
15025
|
+
}
|
|
15026
|
+
const hidden = findEmbeddedAttributes(el.rawBytes, el.vr, ctx.encoding, (t) => actsOnTag(t, ctx));
|
|
15027
|
+
if (hidden === void 0) {
|
|
15028
|
+
out.elements.set(el.tag, el);
|
|
15029
|
+
return true;
|
|
15030
|
+
}
|
|
15031
|
+
out.elements.set(el.tag, freshScalar(el, Buffer.alloc(0), 0));
|
|
15032
|
+
out.embeddedAttributes.push({
|
|
15033
|
+
tag: el.tag,
|
|
15034
|
+
vr: el.vr,
|
|
15035
|
+
hidden,
|
|
15036
|
+
...contextPath.length > 0 ? { contextPath: [...contextPath] } : {}
|
|
15037
|
+
});
|
|
15038
|
+
out.warnings.push(
|
|
15039
|
+
embeddedAttributeRemoved({ byteOffset: el.byteOffset }, el.tag, el.vr, hidden.length)
|
|
15040
|
+
);
|
|
15041
|
+
return false;
|
|
15042
|
+
}
|
|
15043
|
+
function emptyUndefinedVrElement(el, ctx, contextPath, out) {
|
|
15044
|
+
out.elements.set(el.tag, freshScalar(el, Buffer.alloc(0), 0));
|
|
15045
|
+
if (ctx.budget.undefinedVrElements >= MAX_UNDEFINED_VR_FINDINGS) return;
|
|
15046
|
+
ctx.budget.undefinedVrElements += 1;
|
|
15047
|
+
out.undefinedVrElements.push({
|
|
15048
|
+
byteOffset: el.byteOffset,
|
|
15049
|
+
byteLength: el.rawBytes.length,
|
|
15050
|
+
...contextPath.length > 0 ? { contextPath: [...contextPath] } : {}
|
|
15051
|
+
});
|
|
15052
|
+
out.warnings.push(undefinedVrNotAuditable({ byteOffset: el.byteOffset }, el.rawBytes.length));
|
|
15053
|
+
}
|
|
15054
|
+
function isUnauditableSequence(el) {
|
|
15055
|
+
return el.vr === "SQ" && el.items === void 0;
|
|
15056
|
+
}
|
|
15057
|
+
function emptyUnauditableSequence(el, ctx, contextPath, out) {
|
|
15058
|
+
out.elements.set(el.tag, rebuildSequence(el, [], ctx.encoding));
|
|
15059
|
+
if (ctx.budget.unauditableSequences >= MAX_UNAUDITABLE_SEQUENCE_FINDINGS) return;
|
|
15060
|
+
ctx.budget.unauditableSequences += 1;
|
|
15061
|
+
out.unauditableSequences.push({
|
|
15062
|
+
tag: el.tag,
|
|
15063
|
+
byteLength: el.rawBytes.length,
|
|
15064
|
+
...contextPath.length > 0 ? { contextPath: [...contextPath] } : {}
|
|
15065
|
+
});
|
|
15066
|
+
out.warnings.push(
|
|
15067
|
+
sequenceNotAuditable({ byteOffset: el.byteOffset }, el.tag, el.rawBytes.length)
|
|
15068
|
+
);
|
|
15069
|
+
}
|
|
15070
|
+
function creatorsInScope(source) {
|
|
15071
|
+
const byBlock = /* @__PURE__ */ new Map();
|
|
15072
|
+
for (const el of source) {
|
|
15073
|
+
if (!isPrivateTag(el.tag) || !isPrivateCreatorElement(el.tag)) continue;
|
|
15074
|
+
const { group, element } = splitTag(el.tag);
|
|
15075
|
+
byBlock.set(`${String(group)}:${String(element & 255)}`, decodeCreator(el));
|
|
15076
|
+
}
|
|
15077
|
+
return byBlock;
|
|
15078
|
+
}
|
|
15079
|
+
function creatorFor(tag, creators) {
|
|
15080
|
+
const { group, element } = splitTag(tag);
|
|
15081
|
+
return creators.get(`${String(group)}:${String(element >> 8 & 255)}`);
|
|
15082
|
+
}
|
|
15083
|
+
function keepsPrivate(el, ctx, creators) {
|
|
14723
15084
|
if (!ctx.active.has("RetainSafePrivate") || ctx.profile === void 0) return false;
|
|
14724
15085
|
if (isPrivateCreatorElement(el.tag)) {
|
|
14725
15086
|
return ctx.profile.privateDictionary.has(decodeCreator(el));
|
|
14726
15087
|
}
|
|
14727
|
-
const creator = el.
|
|
15088
|
+
const creator = creatorFor(el.tag, creators);
|
|
14728
15089
|
if (creator === void 0) return false;
|
|
14729
15090
|
return resolvePrivateTag(ctx.profile, el.tag, creator) !== void 0;
|
|
14730
15091
|
}
|
|
@@ -14732,20 +15093,26 @@ function processElements(source, ctx, contextPath) {
|
|
|
14732
15093
|
const out = {
|
|
14733
15094
|
elements: /* @__PURE__ */ new Map(),
|
|
14734
15095
|
attributes: [],
|
|
14735
|
-
removedPrivateTags: []
|
|
15096
|
+
removedPrivateTags: [],
|
|
15097
|
+
embeddedAttributes: [],
|
|
15098
|
+
unauditableSequences: [],
|
|
15099
|
+
undefinedVrElements: [],
|
|
15100
|
+
warnings: []
|
|
14736
15101
|
};
|
|
15102
|
+
const creators = creatorsInScope(source);
|
|
14737
15103
|
for (const el of source) {
|
|
14738
15104
|
if (isPrivateTag(el.tag)) {
|
|
14739
|
-
if (keepsPrivate(el, ctx))
|
|
15105
|
+
if (keepsPrivate(el, ctx, creators)) keepOrEmpty(el, ctx, contextPath, out);
|
|
14740
15106
|
else out.removedPrivateTags.push(el.tag);
|
|
14741
15107
|
continue;
|
|
14742
15108
|
}
|
|
14743
15109
|
const action = annexE(el.tag);
|
|
14744
15110
|
if (action === void 0) {
|
|
14745
|
-
if (el.vr === "SQ"
|
|
14746
|
-
|
|
15111
|
+
if (el.vr === "SQ") {
|
|
15112
|
+
if (isUnauditableSequence(el)) emptyUnauditableSequence(el, ctx, contextPath, out);
|
|
15113
|
+
else out.elements.set(el.tag, descendSequence(el, ctx, contextPath, out));
|
|
14747
15114
|
} else {
|
|
14748
|
-
|
|
15115
|
+
keepOrEmpty(el, ctx, contextPath, out);
|
|
14749
15116
|
}
|
|
14750
15117
|
continue;
|
|
14751
15118
|
}
|
|
@@ -14757,8 +15124,7 @@ function processElements(source, ctx, contextPath) {
|
|
|
14757
15124
|
let applied;
|
|
14758
15125
|
switch (resolved) {
|
|
14759
15126
|
case "K":
|
|
14760
|
-
|
|
14761
|
-
applied = "kept";
|
|
15127
|
+
applied = keepOrEmpty(el, ctx, contextPath, out) ? "kept" : "emptied";
|
|
14762
15128
|
break;
|
|
14763
15129
|
case "X":
|
|
14764
15130
|
applied = "removed";
|
|
@@ -14800,6 +15166,10 @@ function descendSequence(el, ctx, contextPath, out) {
|
|
|
14800
15166
|
const inner = processElements(item.elements(), ctx, childPath);
|
|
14801
15167
|
out.attributes.push(...inner.attributes);
|
|
14802
15168
|
out.removedPrivateTags.push(...inner.removedPrivateTags);
|
|
15169
|
+
out.embeddedAttributes.push(...inner.embeddedAttributes);
|
|
15170
|
+
out.unauditableSequences.push(...inner.unauditableSequences);
|
|
15171
|
+
out.undefinedVrElements.push(...inner.undefinedVrElements);
|
|
15172
|
+
out.warnings.push(...inner.warnings);
|
|
14803
15173
|
newItems.push(new Item({ index, warnings: [], elements: inner.elements }));
|
|
14804
15174
|
});
|
|
14805
15175
|
return rebuildSequence(el, newItems, ctx.encoding);
|
|
@@ -14816,13 +15186,23 @@ function applySequenceAction(el, resolved, action, ctx, contextPath, out) {
|
|
|
14816
15186
|
applied = "emptied";
|
|
14817
15187
|
break;
|
|
14818
15188
|
case "C":
|
|
14819
|
-
|
|
14820
|
-
|
|
15189
|
+
if (isUnauditableSequence(el)) {
|
|
15190
|
+
emptyUnauditableSequence(el, ctx, contextPath, out);
|
|
15191
|
+
applied = "emptied";
|
|
15192
|
+
} else {
|
|
15193
|
+
out.elements.set(el.tag, descendSequence(el, ctx, contextPath, out));
|
|
15194
|
+
applied = "cleaned";
|
|
15195
|
+
}
|
|
14821
15196
|
break;
|
|
14822
15197
|
case "U":
|
|
14823
15198
|
case "K":
|
|
14824
|
-
|
|
14825
|
-
|
|
15199
|
+
if (isUnauditableSequence(el)) {
|
|
15200
|
+
emptyUnauditableSequence(el, ctx, contextPath, out);
|
|
15201
|
+
applied = "emptied";
|
|
15202
|
+
} else {
|
|
15203
|
+
out.elements.set(el.tag, descendSequence(el, ctx, contextPath, out));
|
|
15204
|
+
applied = "kept";
|
|
15205
|
+
}
|
|
14826
15206
|
break;
|
|
14827
15207
|
}
|
|
14828
15208
|
out.attributes.push(auditAttribute(el.tag, action, resolved, applied, contextPath));
|
|
@@ -14868,8 +15248,18 @@ function deidentify(ds, options = {}) {
|
|
|
14868
15248
|
active,
|
|
14869
15249
|
remap,
|
|
14870
15250
|
profile: options.profile,
|
|
14871
|
-
encoding
|
|
14872
|
-
|
|
15251
|
+
encoding,
|
|
15252
|
+
budget: { unauditableSequences: 0, undefinedVrElements: 0 }
|
|
15253
|
+
};
|
|
15254
|
+
const processed = processElements(ds.elements(), ctx, []);
|
|
15255
|
+
const {
|
|
15256
|
+
elements,
|
|
15257
|
+
attributes,
|
|
15258
|
+
removedPrivateTags,
|
|
15259
|
+
embeddedAttributes,
|
|
15260
|
+
unauditableSequences,
|
|
15261
|
+
undefinedVrElements
|
|
15262
|
+
} = processed;
|
|
14873
15263
|
elements.set(
|
|
14874
15264
|
TAG_PATIENT_IDENTITY_REMOVED,
|
|
14875
15265
|
insertedScalar(TAG_PATIENT_IDENTITY_REMOVED, "CS", Buffer.from("YES", "latin1"), littleEndian)
|
|
@@ -14879,7 +15269,7 @@ function deidentify(ds, options = {}) {
|
|
|
14879
15269
|
TAG_DEIDENTIFICATION_METHOD,
|
|
14880
15270
|
insertedScalar(TAG_DEIDENTIFICATION_METHOD, "LO", Buffer.from(method, "latin1"), littleEndian)
|
|
14881
15271
|
);
|
|
14882
|
-
const warnings = [];
|
|
15272
|
+
const warnings = [...processed.warnings];
|
|
14883
15273
|
if (hasUncleanedBurnedIn(ds)) {
|
|
14884
15274
|
const offset = ds.get(TAG_PIXEL_DATA)?.byteOffset ?? 0;
|
|
14885
15275
|
warnings.push(burnedInAnnotationNotRemoved({ byteOffset: offset, fileMeta: false }));
|
|
@@ -14894,6 +15284,9 @@ function deidentify(ds, options = {}) {
|
|
|
14894
15284
|
const report = {
|
|
14895
15285
|
attributes,
|
|
14896
15286
|
removedPrivateTags,
|
|
15287
|
+
embeddedAttributes,
|
|
15288
|
+
unauditableSequences,
|
|
15289
|
+
undefinedVrElements,
|
|
14897
15290
|
uidMap: remap.cache,
|
|
14898
15291
|
warnings,
|
|
14899
15292
|
retained: [...active]
|