@cosyte/dicom 0.1.6 → 0.1.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/dist/index.d.cts CHANGED
@@ -2794,7 +2794,11 @@ declare class DicomValueError extends Error {
2794
2794
  * carries an offset that is not zero and names no Directory Record the
2795
2795
  * `Dataset` holds, or is not one 32-bit unsigned integer (never written stale
2796
2796
  * or as zero), or `DIRECTORY_OFFSET_DEFLATED` when a DICOMDIR under Deflated
2797
- * Explicit VR LE carries a non-zero offset. Nothing is returned on a throw.
2797
+ * Explicit VR LE carries a non-zero offset, or `VALUE_TOO_LONG_FOR_VR` when a
2798
+ * Private Creator Data Element under an Explicit VR syntax, or a File Meta
2799
+ * Information element under any, has a value past 65,534 bytes in a VR with a
2800
+ * 16-bit Value Length Field (PS3.5 2026c section 6.2.2 forbids the `UN` such a
2801
+ * value is otherwise written as). Nothing is returned on a throw.
2798
2802
  *
2799
2803
  * @example
2800
2804
  * ```ts
@@ -2849,6 +2853,13 @@ declare function serializeDicom(ds: Dataset): Buffer;
2849
2853
  * not one 32-bit unsigned integer). A position inside a deflated stream
2850
2854
  * names no Item a reader can seek to, so no offset can be written for it.
2851
2855
  * A Deflated DICOMDIR whose offsets are all zero is written.
2856
+ * - `VALUE_TOO_LONG_FOR_VR` - a Private Creator Data Element `(gggg,00xx)`
2857
+ * under an Explicit VR Transfer Syntax, or a File Meta Information element
2858
+ * `(0002,xxxx)` under any, carries a value longer than 65,534 bytes in a VR
2859
+ * whose Explicit VR Value Length Field is 16 bits. PS3.5 2026c section 6.2.2
2860
+ * has such a value written with VR `UN`, which the writer does for every
2861
+ * other element, but says the `UN` VR "shall not be used" for these two, so
2862
+ * the value has no encoding and nothing is written.
2852
2863
  *
2853
2864
  * The message is built only from structural constants (never a decoded
2854
2865
  * attribute value, a Transfer Syntax UID, or a length or byte read from the
@@ -2872,6 +2883,7 @@ declare const SERIALIZE_ERROR_CODES: {
2872
2883
  readonly INVALID_ENCAPSULATED_PIXEL_DATA: "INVALID_ENCAPSULATED_PIXEL_DATA";
2873
2884
  readonly DIRECTORY_OFFSET_UNRESOLVED: "DIRECTORY_OFFSET_UNRESOLVED";
2874
2885
  readonly DIRECTORY_OFFSET_DEFLATED: "DIRECTORY_OFFSET_DEFLATED";
2886
+ readonly VALUE_TOO_LONG_FOR_VR: "VALUE_TOO_LONG_FOR_VR";
2875
2887
  };
2876
2888
  /**
2877
2889
  * Discriminant for {@link DicomSerializeError.code}, enabling exhaustive
@@ -2892,6 +2904,8 @@ declare const SERIALIZE_ERROR_CODES: {
2892
2904
  * return "a DICOMDIR offset names no Directory Record the dataset holds";
2893
2905
  * case "DIRECTORY_OFFSET_DEFLATED":
2894
2906
  * return "a Deflated DICOMDIR carries a non-zero Directory Record offset";
2907
+ * case "VALUE_TOO_LONG_FOR_VR":
2908
+ * return "a Private Creator or File Meta value is too long for its VR";
2895
2909
  * }
2896
2910
  * }
2897
2911
  * ```
@@ -2920,6 +2934,9 @@ type SerializeErrorCode = (typeof SERIALIZE_ERROR_CODES)[keyof typeof SERIALIZE_
2920
2934
  * if (err instanceof DicomSerializeError && err.code === "DIRECTORY_OFFSET_UNRESOLVED") {
2921
2935
  * // a DICOMDIR offset the writer cannot tie to a Directory Record
2922
2936
  * }
2937
+ * if (err instanceof DicomSerializeError && err.code === "VALUE_TOO_LONG_FOR_VR") {
2938
+ * // a Private Creator or File Meta value past 65,534 bytes, which UN may not carry
2939
+ * }
2923
2940
  * }
2924
2941
  * ```
2925
2942
  */
@@ -4679,6 +4696,13 @@ declare class DeidentifyError extends Error {
4679
4696
  * @throws {@link DeidentifyError} (`INVALID_OPTIONS`) for an unknown Retain option,
4680
4697
  * for both PS3.15 §E.3.6 temporal Options in one call, or for a malformed
4681
4698
  * `uidRoot`.
4699
+ * @throws `DicomSerializeError` (`VALUE_TOO_LONG_FOR_VR`) when the run
4700
+ * re-encodes a Sequence Item, under an Explicit VR syntax, that keeps a Private
4701
+ * Creator Data Element whose value is longer than 65,534 bytes. Only a
4702
+ * `RetainSafePrivate` run whose `Profile` names a creator that long keeps one;
4703
+ * PS3.5 2026c section 6.2.2 forbids the `UN` such a value is otherwise written
4704
+ * as, so the Item has no encoding. The same element at the root is returned,
4705
+ * and `serializeDicom` refuses it with the same code.
4682
4706
  *
4683
4707
  * @example
4684
4708
  * ```ts
package/dist/index.d.ts CHANGED
@@ -2794,7 +2794,11 @@ declare class DicomValueError extends Error {
2794
2794
  * carries an offset that is not zero and names no Directory Record the
2795
2795
  * `Dataset` holds, or is not one 32-bit unsigned integer (never written stale
2796
2796
  * or as zero), or `DIRECTORY_OFFSET_DEFLATED` when a DICOMDIR under Deflated
2797
- * Explicit VR LE carries a non-zero offset. Nothing is returned on a throw.
2797
+ * Explicit VR LE carries a non-zero offset, or `VALUE_TOO_LONG_FOR_VR` when a
2798
+ * Private Creator Data Element under an Explicit VR syntax, or a File Meta
2799
+ * Information element under any, has a value past 65,534 bytes in a VR with a
2800
+ * 16-bit Value Length Field (PS3.5 2026c section 6.2.2 forbids the `UN` such a
2801
+ * value is otherwise written as). Nothing is returned on a throw.
2798
2802
  *
2799
2803
  * @example
2800
2804
  * ```ts
@@ -2849,6 +2853,13 @@ declare function serializeDicom(ds: Dataset): Buffer;
2849
2853
  * not one 32-bit unsigned integer). A position inside a deflated stream
2850
2854
  * names no Item a reader can seek to, so no offset can be written for it.
2851
2855
  * A Deflated DICOMDIR whose offsets are all zero is written.
2856
+ * - `VALUE_TOO_LONG_FOR_VR` - a Private Creator Data Element `(gggg,00xx)`
2857
+ * under an Explicit VR Transfer Syntax, or a File Meta Information element
2858
+ * `(0002,xxxx)` under any, carries a value longer than 65,534 bytes in a VR
2859
+ * whose Explicit VR Value Length Field is 16 bits. PS3.5 2026c section 6.2.2
2860
+ * has such a value written with VR `UN`, which the writer does for every
2861
+ * other element, but says the `UN` VR "shall not be used" for these two, so
2862
+ * the value has no encoding and nothing is written.
2852
2863
  *
2853
2864
  * The message is built only from structural constants (never a decoded
2854
2865
  * attribute value, a Transfer Syntax UID, or a length or byte read from the
@@ -2872,6 +2883,7 @@ declare const SERIALIZE_ERROR_CODES: {
2872
2883
  readonly INVALID_ENCAPSULATED_PIXEL_DATA: "INVALID_ENCAPSULATED_PIXEL_DATA";
2873
2884
  readonly DIRECTORY_OFFSET_UNRESOLVED: "DIRECTORY_OFFSET_UNRESOLVED";
2874
2885
  readonly DIRECTORY_OFFSET_DEFLATED: "DIRECTORY_OFFSET_DEFLATED";
2886
+ readonly VALUE_TOO_LONG_FOR_VR: "VALUE_TOO_LONG_FOR_VR";
2875
2887
  };
2876
2888
  /**
2877
2889
  * Discriminant for {@link DicomSerializeError.code}, enabling exhaustive
@@ -2892,6 +2904,8 @@ declare const SERIALIZE_ERROR_CODES: {
2892
2904
  * return "a DICOMDIR offset names no Directory Record the dataset holds";
2893
2905
  * case "DIRECTORY_OFFSET_DEFLATED":
2894
2906
  * return "a Deflated DICOMDIR carries a non-zero Directory Record offset";
2907
+ * case "VALUE_TOO_LONG_FOR_VR":
2908
+ * return "a Private Creator or File Meta value is too long for its VR";
2895
2909
  * }
2896
2910
  * }
2897
2911
  * ```
@@ -2920,6 +2934,9 @@ type SerializeErrorCode = (typeof SERIALIZE_ERROR_CODES)[keyof typeof SERIALIZE_
2920
2934
  * if (err instanceof DicomSerializeError && err.code === "DIRECTORY_OFFSET_UNRESOLVED") {
2921
2935
  * // a DICOMDIR offset the writer cannot tie to a Directory Record
2922
2936
  * }
2937
+ * if (err instanceof DicomSerializeError && err.code === "VALUE_TOO_LONG_FOR_VR") {
2938
+ * // a Private Creator or File Meta value past 65,534 bytes, which UN may not carry
2939
+ * }
2923
2940
  * }
2924
2941
  * ```
2925
2942
  */
@@ -4679,6 +4696,13 @@ declare class DeidentifyError extends Error {
4679
4696
  * @throws {@link DeidentifyError} (`INVALID_OPTIONS`) for an unknown Retain option,
4680
4697
  * for both PS3.15 §E.3.6 temporal Options in one call, or for a malformed
4681
4698
  * `uidRoot`.
4699
+ * @throws `DicomSerializeError` (`VALUE_TOO_LONG_FOR_VR`) when the run
4700
+ * re-encodes a Sequence Item, under an Explicit VR syntax, that keeps a Private
4701
+ * Creator Data Element whose value is longer than 65,534 bytes. Only a
4702
+ * `RetainSafePrivate` run whose `Profile` names a creator that long keeps one;
4703
+ * PS3.5 2026c section 6.2.2 forbids the `UN` such a value is otherwise written
4704
+ * as, so the Item has no encoding. The same element at the root is returned,
4705
+ * and `serializeDicom` refuses it with the same code.
4682
4706
  *
4683
4707
  * @example
4684
4708
  * ```ts
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.1.6";
12
+ var VERSION = "0.1.7";
13
13
 
14
14
  // src/dictionary/index.ts
15
15
  var dictionary_exports = {};
@@ -14956,8 +14956,43 @@ function toDate(value, options) {
14956
14956
  const instant = new Date(utc.getTime() - offsetMinutes * 6e4);
14957
14957
  return Number.isNaN(instant.getTime()) ? void 0 : instant;
14958
14958
  }
14959
+
14960
+ // src/serialize/errors.ts
14961
+ var SERIALIZE_ERROR_CODES = {
14962
+ MISSING_TRANSFER_SYNTAX: "MISSING_TRANSFER_SYNTAX",
14963
+ UNSUPPORTED_TRANSFER_SYNTAX: "UNSUPPORTED_TRANSFER_SYNTAX",
14964
+ INVALID_ENCAPSULATED_PIXEL_DATA: "INVALID_ENCAPSULATED_PIXEL_DATA",
14965
+ DIRECTORY_OFFSET_UNRESOLVED: "DIRECTORY_OFFSET_UNRESOLVED",
14966
+ DIRECTORY_OFFSET_DEFLATED: "DIRECTORY_OFFSET_DEFLATED",
14967
+ VALUE_TOO_LONG_FOR_VR: "VALUE_TOO_LONG_FOR_VR"
14968
+ };
14969
+ var DicomSerializeError = class extends Error {
14970
+ code;
14971
+ /**
14972
+ * Construct a new `DicomSerializeError`. The `message` MUST be built only
14973
+ * from structural facts (never a decoded attribute value) so the error is
14974
+ * always safe to log.
14975
+ *
14976
+ * @internal
14977
+ */
14978
+ constructor(code, message) {
14979
+ super(`[${code}] ${message}`);
14980
+ this.name = "DicomSerializeError";
14981
+ this.code = code;
14982
+ }
14983
+ };
14984
+
14985
+ // src/serialize/element.ts
14959
14986
  var UNDEFINED_LENGTH4 = 4294967295;
14960
14987
  var MAX_SHORT_FORM_LENGTH = 65534;
14988
+ var PRIVATE_CREATOR_TOO_LONG_MESSAGE = "A Private Creator Data Element carries a value longer than 65,534 bytes under an Explicit VR Transfer Syntax, in a VR whose Value Length Field is 16 bits. PS3.5 section 6.2.2 has such a value written with VR UN, but says UN shall not be used for a Private Creator Data Element, so the value has no encoding and nothing is written.";
14989
+ var FILE_META_TOO_LONG_MESSAGE = "A File Meta Information element carries a value longer than 65,534 bytes in a VR whose Explicit VR Value Length Field is 16 bits. PS3.5 section 6.2.2 has such a value written with VR UN, but says UN shall not be used for a File Meta Information element, so the value has no encoding and nothing is written.";
14990
+ function refuseTooLongForVr(kind) {
14991
+ throw new DicomSerializeError(
14992
+ SERIALIZE_ERROR_CODES.VALUE_TOO_LONG_FOR_VR,
14993
+ kind === "privateCreator" ? PRIVATE_CREATOR_TOO_LONG_MESSAGE : FILE_META_TOO_LONG_MESSAGE
14994
+ );
14995
+ }
14961
14996
  var NULL_PAD_VRS = /* @__PURE__ */ new Set(["UI", "OB", "OW", "OF", "OD", "OL", "OV", "UN"]);
14962
14997
  function padValue(value, vr) {
14963
14998
  if (value.length % 2 === 0) return Buffer.from(value);
@@ -15020,7 +15055,9 @@ function encodeDatasetElement(el, encoding, rawBytes = el.rawBytes) {
15020
15055
  value
15021
15056
  ]);
15022
15057
  }
15023
- if (value.length > MAX_SHORT_FORM_LENGTH && !isPrivateCreator(group, element)) {
15058
+ if (value.length > MAX_SHORT_FORM_LENGTH) {
15059
+ if (isPrivateCreator(group, element)) refuseTooLongForVr("privateCreator");
15060
+ if (group === 2) refuseTooLongForVr("fileMeta");
15024
15061
  return Buffer.concat([
15025
15062
  uint16(group, littleEndian),
15026
15063
  uint16(element, littleEndian),
@@ -15039,30 +15076,6 @@ function encodeDatasetElement(el, encoding, rawBytes = el.rawBytes) {
15039
15076
  value
15040
15077
  ]);
15041
15078
  }
15042
-
15043
- // src/serialize/errors.ts
15044
- var SERIALIZE_ERROR_CODES = {
15045
- MISSING_TRANSFER_SYNTAX: "MISSING_TRANSFER_SYNTAX",
15046
- UNSUPPORTED_TRANSFER_SYNTAX: "UNSUPPORTED_TRANSFER_SYNTAX",
15047
- INVALID_ENCAPSULATED_PIXEL_DATA: "INVALID_ENCAPSULATED_PIXEL_DATA",
15048
- DIRECTORY_OFFSET_UNRESOLVED: "DIRECTORY_OFFSET_UNRESOLVED",
15049
- DIRECTORY_OFFSET_DEFLATED: "DIRECTORY_OFFSET_DEFLATED"
15050
- };
15051
- var DicomSerializeError = class extends Error {
15052
- code;
15053
- /**
15054
- * Construct a new `DicomSerializeError`. The `message` MUST be built only
15055
- * from structural facts (never a decoded attribute value) so the error is
15056
- * always safe to log.
15057
- *
15058
- * @internal
15059
- */
15060
- constructor(code, message) {
15061
- super(`[${code}] ${message}`);
15062
- this.name = "DicomSerializeError";
15063
- this.code = code;
15064
- }
15065
- };
15066
15079
  var UNDEFINED_LENGTH5 = 4294967295;
15067
15080
  var ITEM2 = 4294893568;
15068
15081
  var ITEM_DELIMITATION = 4294893581;
@@ -15507,6 +15520,7 @@ function encodeMetaElement(tag, vr, rawValue) {
15507
15520
  value
15508
15521
  ]);
15509
15522
  }
15523
+ if (value.length > MAX_SHORT_FORM_LENGTH) refuseTooLongForVr("fileMeta");
15510
15524
  const lengthBuf = Buffer.alloc(2);
15511
15525
  lengthBuf.writeUInt16LE(value.length, 0);
15512
15526
  return Buffer.concat([groupBuf, elementBuf, vrBuf, lengthBuf, value]);