Skip to content
Open
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
3d8f679
chore refactored proper location of dictionaries and removed redundan…
Aug 19, 2025
b2fa72d
chore refactored the logic for switching to target decoder such that …
Aug 19, 2025
4d55daf
chore Forgot to pass the ignoreErrors flag.
Aug 19, 2025
6b70b60
chore Moved the decoder logic to the base BufferStream class since it…
Aug 19, 2025
5596de1
chore Refactored core encoding decoding logic to be in its own class …
Aug 19, 2025
50327d2
chore Added docstrings to new class to clarify usage and expectations.
Aug 19, 2025
8164601
Merge branch 'master' into 454_incorrect_decoding_of_iso_ir_100
luissantosHCIT Mar 6, 2026
89b7498
chore moving constants into their own files.
luissantosHCIT Mar 6, 2026
b4e15c7
chore removing duplicated constant => encodingMapping
luissantosHCIT Mar 6, 2026
da8812e
chore cleaned up usage of constants and adding new constant file impo…
luissantosHCIT Mar 6, 2026
c91b13a
chore cleaned up class exports.
luissantosHCIT Mar 6, 2026
f2e2b17
chore imported the encodingMapping constant and removed logic directl…
luissantosHCIT Mar 6, 2026
6ff636f
chore refactored the encoding selection logic for clarity and to make…
luissantosHCIT Mar 6, 2026
3bce05a
chore moved the DicomBufferCODEC into its own file and made the encod…
luissantosHCIT Mar 6, 2026
0c60c55
chore converting structs into Maps and Sets.
luissantosHCIT Mar 6, 2026
daa7276
chore changing vars into const and lets for clarity.
luissantosHCIT Mar 6, 2026
d1f03b5
chore moved the log.js source to utilities.
luissantosHCIT Mar 6, 2026
46ec4bf
chore moved a few constants to constants/dicom, switched a few checks…
luissantosHCIT Mar 6, 2026
d1383aa
chore moved selectEncoding to utilities
luissantosHCIT Mar 6, 2026
16ed19c
chore changed vars to consts and lets.
luissantosHCIT Mar 6, 2026
011cdd0
chore checked for key in constant encodingMapping.
luissantosHCIT Mar 6, 2026
591806b
chore changed the ES version to 11 in JSHints to kill false positive …
luissantosHCIT Mar 6, 2026
067783a
fix bug introduced by accidentally setting variables to const.
luissantosHCIT Mar 6, 2026
1ae8d7a
fix added parameter guard check in selectEncoding
luissantosHCIT Mar 6, 2026
46e8d4a
fix added missing has check.
luissantosHCIT Mar 6, 2026
e25344f
fix restored removed new keyword when I was cleaning the project. Oops.
luissantosHCIT Mar 6, 2026
5654097
fix reverted some of the linter suggested changes to const and equali…
luissantosHCIT Mar 6, 2026
39e2fb4
fix reverted some of the linter suggested changes to const and equali…
luissantosHCIT Mar 6, 2026
5f3c70e
chore moved out encoding function into selectEncoding source.
luissantosHCIT Mar 6, 2026
8442409
fix(BufferStream) corrected issues with encoding due to changing stru…
luissantosHCIT Mar 7, 2026
134b3c9
chore(selectEncoding) added note.
luissantosHCIT Mar 7, 2026
c0012d4
fix(DicomMetaDictionary) generation of struct sopClassUIDsByName prop…
luissantosHCIT Mar 7, 2026
690ece8
chore(DicomMetaDictionary) added addEncoding method to allow external…
luissantosHCIT Mar 9, 2026
db96bf6
chore(BufferStream) consolidated the encoding methods into a singular…
luissantosHCIT Mar 9, 2026
487fa4a
chore(Tag) pass through encoding option upon initialization of a writ…
luissantosHCIT Mar 9, 2026
fc7a36e
chore(DicomDict) pass through encoding option upon initialization of …
luissantosHCIT Mar 9, 2026
b565467
fix(BufferStream) missing default endianness for ReadBufferStream.
luissantosHCIT Mar 9, 2026
0e501c2
chore(Tag) const correctness
luissantosHCIT Mar 10, 2026
e09fb64
fix(DicomMessage) calling wrong encoding method (was renamed today in…
luissantosHCIT Mar 10, 2026
b0c8c73
chore(ValueRepresentation) moving common formatting/value filtering l…
luissantosHCIT Mar 10, 2026
f30cc2f
fix(ValueRepresentation) reverted initial changes to ValueRepresentat…
luissantosHCIT Mar 10, 2026
1843eca
fix(tests) renamed the encoding method to the new one.
luissantosHCIT Mar 10, 2026
b140d6a
feature(tests) added basic tests tracking encoded write/reads of Dico…
luissantosHCIT Mar 10, 2026
7f8f808
chore(encodings) renamed latin1 to iso-8859-1 for consistency.
luissantosHCIT Mar 12, 2026
942620c
chore(encodings) added the other two Ox VRs in AsyncDicomReader.
luissantosHCIT Mar 12, 2026
c1a87ac
chore(encodings) renamed DicomBufferCODEC to DicomTextTranscode for a…
luissantosHCIT Mar 12, 2026
b0e8b67
chore(encodings) renamed codec to textTranscoder for consistency with…
luissantosHCIT Mar 12, 2026
4ff3ca4
chore(encodings) forced littleEndian and simplified constructor of de…
luissantosHCIT Mar 13, 2026
f4e7e8e
chore(encodings) corrected the fact that the DicomDataReadBufferStrea…
luissantosHCIT Mar 13, 2026
3d59ff3
chore(encodings) refactored the constructor of WriteStreamBuffer to a…
luissantosHCIT Mar 13, 2026
49d957c
chore(encodings) refactored the tests making use of WriteStreamBuffer…
luissantosHCIT Mar 13, 2026
a1bfa85
chore(encodings) removed options improperly added during the original…
luissantosHCIT Mar 13, 2026
baab404
docs(BufferStream) Added documentation notes on the constructor chang…
luissantosHCIT Mar 15, 2026
608fd52
chore removed unused imports
luissantosHCIT Mar 17, 2026
2e07a30
chore corrected function doc string
luissantosHCIT Mar 17, 2026
df6eabd
chore(sopClassUIDs) moved the name-uid set into the constants source …
luissantosHCIT Mar 18, 2026
133ddf6
chore(sopClassUIDs) Removed the generation of sopClassUIDsByName and …
luissantosHCIT Mar 18, 2026
5e1913a
chore(style) fixed code style with yarn prettier
luissantosHCIT Mar 18, 2026
f44ed90
Merge branch 'master' into 454_incorrect_decoding_of_iso_ir_100
luissantosHCIT May 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .jshintrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"esversion": 6
"esversion": 11
}
16 changes: 8 additions & 8 deletions src/AsyncDicomReader.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ import {
VM_DELIMITER,
UNDEFINED_LENGTH,
TagHex,
encodingMapping,
UNDEFINED_LENGTH_FIX,
VALID_VRS,
singleVRs,
isVideoTransferSyntax
} from "./constants/dicom";
import { encodingMapping } from "./constants/encodings";
import { Tag } from "./Tag";
import { DicomMessage, singleVRs } from "./DicomMessage";
import { DicomMessage } from "./DicomMessage";
import { DicomMetaDictionary } from "./DicomMetaDictionary";
import { DicomMetadataListener } from "./utilities/DicomMetadataListener.js";
import { log } from "./log.js";
import { log } from "./utilities/log.js";

const readLog = log.getLogger("AsyncDicomReader");

Expand Down Expand Up @@ -720,13 +721,13 @@ export class AsyncDicomReader {
}
} else {
const value = vr.read(stream, length, syntax)?.value;
if (!vr.isBinary() && singleVRs.indexOf(vr.type) == -1) {
if (!vr.isBinary() && !singleVRs.has(vr.type)) {
values = value;
if (typeof value === "string") {
const delimiterChar = String.fromCharCode(VM_DELIMITER);
values = vr.dropPadByte(value.split(delimiterChar));
}
} else if (vr.type == "OW" || vr.type == "OB") {
} else if (vr.type === "OW" || vr.type === "OB") {
Comment thread
luissantosHCIT marked this conversation as resolved.
Outdated
values = value;
} else {
Array.isArray(value) ? (values = value) : values.push(value);
Expand All @@ -737,9 +738,8 @@ export class AsyncDicomReader {
if (values.length > 0) {
let [coding] = values;
coding = coding.replace(/[_ ]/g, "-").toLowerCase();
if (coding in encodingMapping) {
coding = encodingMapping[coding];
this.stream.setDecoder(new TextDecoder(coding));
if (encodingMapping.has(coding)) {
this.stream.setEncoding(coding);
} else if (options?.ignoreErrors) {
log.warn(
`Unsupported character set: ${coding}, using default character set`
Expand Down
75 changes: 75 additions & 0 deletions src/BufferCODEC.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { DicomMetaDictionary } from "./DicomMetaDictionary";

Check failure on line 1 in src/BufferCODEC.js

View workflow job for this annotation

GitHub Actions / lint-and-format

'DicomMetaDictionary' is defined but never used
import { defaultEncoding } from "./constants/encodings";
import { selectNativeEncoding } from "./utilities/selectEncoding";

/**
* Facilitates the conversion of binary buffers from a DICOM encoding scheme to
* a web supported string encoding scheme and vice versa.
*/
export class DicomBufferCODEC {
Comment thread
luissantosHCIT marked this conversation as resolved.
Outdated
encoder = new TextEncoder(defaultEncoding);
decoder = new TextDecoder(defaultEncoding);

/**
* Use this method if you want to change the decoder directly and do not
* need to have the encoding scheme name translated to one of the encoding
* schemes supported by web browsers.
*
* For example, instead of passing ISO 2022 IR 100, you have to pass latin1.
* Passing an incorrect encoding scheme name will result in an exception.
*
* @param {string} webEncoding
*/
setNativeDecoder(webEncoding) {
this.decoder = new TextDecoder(webEncoding);
}

/**
* Unused since we typically default to utf-8. This method is provided for
* convenience in case someone needs to encode a buffer in something else
* before storing in a DICOM header.
*
* @param {string} webEncoding
*/
setNativeEncoder(webEncoding) {
this.decoder = new TextEncoder(webEncoding);
}

/**
* Main method for changing encoder.
*
* Given a DICOM encoding scheme like ISO 2022 IR 100, generate the correct
* string to store to disk.
*
* Optionally, include whether to ignore or throw an exception if dicom to
* web encoding is not found in our mapping
*
* @param {string} dicomEncoding
* @param {boolean} ignoreErrors
*/
setEncoding(dicomEncoding, ignoreErrors = false) {
let coding = selectNativeEncoding(dicomEncoding, ignoreErrors);
this.setNativeEncoder(coding);
this.setNativeDecoder(coding);
}

/**
* Convenience method as would be found in TextEncoder and TextDecoder APIs.
*
* @param data
* @returns {string}
*/
decode(data) {
return this.decoder.decode(data);
}

/**
* Convenience method as would be found in TextEncoder and TextDecoder APIs.
*
* @param {string} data
* @returns {Uint8Array}
*/
encode(data) {
return this.encoder.encode(data);
}
}
42 changes: 27 additions & 15 deletions src/BufferStream.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import pako from "pako";
import SplitDataView from "./SplitDataView";
import { toFloat } from "./utilities/toFloat";
import { toInt } from "./utilities/toInt";
import { DicomBufferCODEC } from "./BufferCODEC";
import { defaultDICOMEncoding } from "./constants/encodings";

export class BufferStream {
offset = 0;
Expand All @@ -18,12 +20,14 @@ export class BufferStream {
/** A flag to set to indicate to clear buffers as they get consumed */
clearBuffers = false;

encoder = new TextEncoder("utf-8");
codec = new DicomBufferCODEC();

constructor(options = null) {
this.isLittleEndian = options?.littleEndian || this.isLittleEndian;
this.view.defaultSize = options?.defaultSize ?? this.view.defaultSize;
this.clearBuffers = options.clearBuffers || false;

this.setEncoding(options?.encoding || defaultDICOMEncoding);
}

/**
Expand Down Expand Up @@ -68,8 +72,20 @@ export class BufferStream {
return true;
}

setEndian(isLittle) {
this.isLittleEndian = isLittle;
setEncoding(dicomEncoding, ignoreErrors) {
this.codec.setEncoding(dicomEncoding, ignoreErrors);
}

setEndian(isLittleEndian = true) {
this.isLittleEndian = isLittleEndian;
}

setLittleEndian() {
this.isLittleEndian = true;
}

setBigEndian() {
this.isLittleEndian = false;
}

slice(start = this.startOffset, end = this.endOffset) {
Expand Down Expand Up @@ -169,7 +185,7 @@ export class BufferStream {
}

writeUTF8String(value) {
const encodedString = this.encoder.encode(value);
const encodedString = this.codec.encode(value);
this.checkSize(encodedString.byteLength);
this.view.writeBuffer(encodedString, this.offset);
return this.increment(encodedString.byteLength);
Expand Down Expand Up @@ -300,7 +316,7 @@ export class BufferStream {
const view = new DataView(
this.slice(this.offset, this.offset + length)
);
const result = this.decoder.decode(view);
const result = this.codec.decode(view);
this.increment(length);
return result;
}
Expand Down Expand Up @@ -453,16 +469,16 @@ export class BufferStream {
export class ReadBufferStream extends BufferStream {
constructor(
buffer,
littleEndian,
littleEndian = false,
Comment thread
luissantosHCIT marked this conversation as resolved.
Outdated
options = {
start: null,
stop: null,
noCopy: false
}
},
encoding = defaultDICOMEncoding
) {
super({ ...options, littleEndian });
super({ ...options, littleEndian, encoding });
this.noCopy = options.noCopy;
this.decoder = new TextDecoder("latin1");

if (buffer instanceof BufferStream) {
this.view.from(buffer.view, options);
Expand All @@ -478,10 +494,6 @@ export class ReadBufferStream extends BufferStream {
this.endOffset = this.size;
}

setDecoder(decoder) {
this.decoder = decoder;
}

reset() {
this.offset = this.startOffset;
return this;
Expand Down Expand Up @@ -564,8 +576,8 @@ export class DeflatedReadBufferStream extends ReadBufferStream {
}

export class WriteBufferStream extends BufferStream {
constructor(defaultSize, littleEndian) {
super({ defaultSize, littleEndian });
constructor(defaultSize, littleEndian, encoding = defaultDICOMEncoding) {
Comment thread
luissantosHCIT marked this conversation as resolved.
Outdated
super({ defaultSize, littleEndian, encoding });
this.size = 0;
}
}
26 changes: 21 additions & 5 deletions src/DicomDict.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { WriteBufferStream } from "./BufferStream";
import { ValueRepresentation } from "./ValueRepresentation";
import { TagHex } from "./constants/dicom";
import { defaultDICOMEncoding } from "./constants/encodings";

const EXPLICIT_LITTLE_ENDIAN = "1.2.840.10008.1.2.1";

Expand All @@ -22,13 +23,28 @@ class DicomDict {
}
}

write(writeOptions = { allowInvalidVRLength: false }) {
var metaSyntax = EXPLICIT_LITTLE_ENDIAN;
var fileStream = new WriteBufferStream(4096, true);
write(
Comment thread
luissantosHCIT marked this conversation as resolved.
writeOptions = {
allowInvalidVRLength: false,
encoding: defaultDICOMEncoding,
littleEndian: true
}
) {
const metaSyntax = EXPLICIT_LITTLE_ENDIAN;
const fileStream = new WriteBufferStream(
4096,
writeOptions.littleEndian,
writeOptions.encoding
);

fileStream.writeUint8Repeat(0, 128);
fileStream.writeAsciiString("DICM");

var metaStream = new WriteBufferStream(1024);
const metaStream = new WriteBufferStream(
Comment thread
luissantosHCIT marked this conversation as resolved.
Outdated
1024,
writeOptions.littleEndian,
writeOptions.encoding
);
if (!this.meta[TagHex.TransferSyntaxUID]) {
this.meta[TagHex.TransferSyntaxUID] = {
vr: "UI",
Expand All @@ -46,7 +62,7 @@ class DicomDict {
);
fileStream.concat(metaStream);

var useSyntax = this.meta[TagHex.TransferSyntaxUID].Value[0];
const useSyntax = this.meta[TagHex.TransferSyntaxUID].Value[0];
DicomMessage.write(this.dict, fileStream, useSyntax, writeOptions);
return fileStream.getBuffer();
}
Expand Down
Loading
Loading