@cosyte/dicom 0.0.6 → 0.0.8

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/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.6";
12
+ var VERSION = "0.0.8";
13
13
 
14
14
  // src/dictionary/index.ts
15
15
  var dictionary_exports = {};
@@ -11733,6 +11733,12 @@ var WARNING_CODES = {
11733
11733
  // === Reserved by later phases (declared, not emitted in Phase 2) ===
11734
11734
  DICOM_BURNED_IN_ANNOTATION_NOT_REMOVED: "DICOM_BURNED_IN_ANNOTATION_NOT_REMOVED",
11735
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
11736
11742
  DICOM_PRIVATE_CREATOR_UNKNOWN: "DICOM_PRIVATE_CREATOR_UNKNOWN"
11737
11743
  // reserved by Phase 6 - not emitted in Phase 2
11738
11744
  };
@@ -11746,13 +11752,30 @@ var WARNING_MESSAGES = Object.freeze({
11746
11752
  DICOM_PRIVATE_TAG_NO_CREATOR: "Private element ({tag}) has no Private Creator registered for its block; treating as VR=UN.",
11747
11753
  DICOM_GROUP_LENGTH_IN_DATASET: "Retired Group Length element ({tag}) encountered in dataset; preserved as-is.",
11748
11754
  DICOM_NONZERO_RESERVED_BYTES: "Element ({tag}) has non-zero reserved bytes between VR and length (first byte {n}, second byte {n2}); ignoring.",
11749
- 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 or de-identification.",
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.",
11750
11756
  DICOM_UN_PARSED_AS_SQ: "Element ({tag}) has VR=UN with undefined length; descended as Implicit VR LE sequence per CP-246.",
11751
11757
  DICOM_EMPTY_ITEM_IN_SEQUENCE: "Sequence ({tag}) contains an empty item (length=0); tolerated.",
11752
11758
  DICOM_PIXEL_DATA_LENGTH_MISMATCH: "(7FE0,0010) PixelData declared length {n} does not match computed {n2} bytes.",
11753
11759
  DICOM_IMPLICIT_VR_FOR_PRIVATE_TAG_WITHOUT_VR: "Private element ({tag}) under Implicit VR LE has no VR override; falling back to UN.",
11754
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.",
11755
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.",
11756
11779
  DICOM_BOM_IN_TEXT_VR: "Element ({tag}) {vr} value begins with a UTF-8 BOM; stripped on decode.",
11757
11780
  DICOM_TRAILING_NULL_IN_TEXT_VR: "Element ({tag}) {vr} value has a trailing NULL pad where SPACE is expected; trimmed.",
11758
11781
  DICOM_UI_TRAILING_SPACE: "Element ({tag}) UI value is SPACE-padded; UI requires NULL padding (PS3.5 \xA76.2). Trimmed.",
@@ -11830,6 +11853,25 @@ function privateCreatorUnknown(position, tag) {
11830
11853
  function burnedInAnnotationNotRemoved(position) {
11831
11854
  return build(WARNING_CODES.DICOM_BURNED_IN_ANNOTATION_NOT_REMOVED, position);
11832
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
+ });
11874
+ }
11833
11875
  function bomInTextVR(position, tag, vr) {
11834
11876
  return build(WARNING_CODES.DICOM_BOM_IN_TEXT_VR, position, { tag, vr });
11835
11877
  }
@@ -14654,6 +14696,132 @@ function uidValueMultiplicity(rawBytes) {
14654
14696
  return raw.split("\\").length;
14655
14697
  }
14656
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
+
14657
14825
  // src/deident/types.ts
14658
14826
  var DEIDENTIFY_OPTIONS = Object.freeze([
14659
14827
  "CleanGraphics",
@@ -14725,6 +14893,9 @@ var BODY_ENCODING2 = {
14725
14893
  "1.2.840.10008.1.2.2": "explicitBE",
14726
14894
  "1.2.840.10008.1.2.1.99": "explicitLE"
14727
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));
14728
14899
  function validateRetain(retain) {
14729
14900
  const valid = new Set(DEIDENTIFY_OPTIONS);
14730
14901
  const active = /* @__PURE__ */ new Set();
@@ -14838,6 +15009,64 @@ function isPrivateCreatorElement(tag) {
14838
15009
  const { element } = splitTag(tag);
14839
15010
  return element >= 16 && element <= 255;
14840
15011
  }
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
+ }
14841
15070
  function creatorsInScope(source) {
14842
15071
  const byBlock = /* @__PURE__ */ new Map();
14843
15072
  for (const el of source) {
@@ -14864,21 +15093,26 @@ function processElements(source, ctx, contextPath) {
14864
15093
  const out = {
14865
15094
  elements: /* @__PURE__ */ new Map(),
14866
15095
  attributes: [],
14867
- removedPrivateTags: []
15096
+ removedPrivateTags: [],
15097
+ embeddedAttributes: [],
15098
+ unauditableSequences: [],
15099
+ undefinedVrElements: [],
15100
+ warnings: []
14868
15101
  };
14869
15102
  const creators = creatorsInScope(source);
14870
15103
  for (const el of source) {
14871
15104
  if (isPrivateTag(el.tag)) {
14872
- if (keepsPrivate(el, ctx, creators)) out.elements.set(el.tag, el);
15105
+ if (keepsPrivate(el, ctx, creators)) keepOrEmpty(el, ctx, contextPath, out);
14873
15106
  else out.removedPrivateTags.push(el.tag);
14874
15107
  continue;
14875
15108
  }
14876
15109
  const action = annexE(el.tag);
14877
15110
  if (action === void 0) {
14878
- if (el.vr === "SQ" && el.items !== void 0) {
14879
- out.elements.set(el.tag, descendSequence(el, ctx, contextPath, out));
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));
14880
15114
  } else {
14881
- out.elements.set(el.tag, el);
15115
+ keepOrEmpty(el, ctx, contextPath, out);
14882
15116
  }
14883
15117
  continue;
14884
15118
  }
@@ -14890,8 +15124,7 @@ function processElements(source, ctx, contextPath) {
14890
15124
  let applied;
14891
15125
  switch (resolved) {
14892
15126
  case "K":
14893
- out.elements.set(el.tag, el);
14894
- applied = "kept";
15127
+ applied = keepOrEmpty(el, ctx, contextPath, out) ? "kept" : "emptied";
14895
15128
  break;
14896
15129
  case "X":
14897
15130
  applied = "removed";
@@ -14933,6 +15166,10 @@ function descendSequence(el, ctx, contextPath, out) {
14933
15166
  const inner = processElements(item.elements(), ctx, childPath);
14934
15167
  out.attributes.push(...inner.attributes);
14935
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);
14936
15173
  newItems.push(new Item({ index, warnings: [], elements: inner.elements }));
14937
15174
  });
14938
15175
  return rebuildSequence(el, newItems, ctx.encoding);
@@ -14949,13 +15186,23 @@ function applySequenceAction(el, resolved, action, ctx, contextPath, out) {
14949
15186
  applied = "emptied";
14950
15187
  break;
14951
15188
  case "C":
14952
- out.elements.set(el.tag, descendSequence(el, ctx, contextPath, out));
14953
- applied = "cleaned";
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
+ }
14954
15196
  break;
14955
15197
  case "U":
14956
15198
  case "K":
14957
- out.elements.set(el.tag, descendSequence(el, ctx, contextPath, out));
14958
- applied = "kept";
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
+ }
14959
15206
  break;
14960
15207
  }
14961
15208
  out.attributes.push(auditAttribute(el.tag, action, resolved, applied, contextPath));
@@ -15001,8 +15248,18 @@ function deidentify(ds, options = {}) {
15001
15248
  active,
15002
15249
  remap,
15003
15250
  profile: options.profile,
15004
- encoding};
15005
- const { elements, attributes, removedPrivateTags } = processElements(ds.elements(), ctx, []);
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;
15006
15263
  elements.set(
15007
15264
  TAG_PATIENT_IDENTITY_REMOVED,
15008
15265
  insertedScalar(TAG_PATIENT_IDENTITY_REMOVED, "CS", Buffer.from("YES", "latin1"), littleEndian)
@@ -15012,7 +15269,7 @@ function deidentify(ds, options = {}) {
15012
15269
  TAG_DEIDENTIFICATION_METHOD,
15013
15270
  insertedScalar(TAG_DEIDENTIFICATION_METHOD, "LO", Buffer.from(method, "latin1"), littleEndian)
15014
15271
  );
15015
- const warnings = [];
15272
+ const warnings = [...processed.warnings];
15016
15273
  if (hasUncleanedBurnedIn(ds)) {
15017
15274
  const offset = ds.get(TAG_PIXEL_DATA)?.byteOffset ?? 0;
15018
15275
  warnings.push(burnedInAnnotationNotRemoved({ byteOffset: offset, fileMeta: false }));
@@ -15027,6 +15284,9 @@ function deidentify(ds, options = {}) {
15027
15284
  const report = {
15028
15285
  attributes,
15029
15286
  removedPrivateTags,
15287
+ embeddedAttributes,
15288
+ unauditableSequences,
15289
+ undefinedVrElements,
15030
15290
  uidMap: remap.cache,
15031
15291
  warnings,
15032
15292
  retained: [...active]