This commit is contained in:
2025-02-26 14:49:25 +07:00
commit 1c1d9c4474
6403 changed files with 1953774 additions and 0 deletions

View File

@@ -0,0 +1,191 @@
<!DOCTYPE html>
<html>
<head>
<title>DICOM Anonymiser</title>
<meta charset="UTF-8">
<script type="text/javascript" src="../../src/dicom/dicomParser.js"></script>
<script type="text/javascript" src="../../src/dicom/dicomWriter.js"></script>
<script type="text/javascript" src="../../src/dicom/dictionary.js"></script>
<script type="text/javascript">
// rules file
var _rulesFile = null;
// dicom file
var _dicomFile = null;
// DICOM elements
var _dicomElements = null;
// handle DICOM file load
function onLoadDICOMFile(event)
{
// parse DICOM
var parser = new dwv.dicom.DicomParser();
parser.parse(event.target.result);
// store elements
_dicomElements = parser.getRawDicomElements();
// activate generate button
var element = document.getElementById("generate");
element.className = "button button-active";
}
// generate DICOM data
function generate()
{
// check validity
if (!isValidRules()) {
return;
}
// create writer with textarea rules
var writer = new dwv.dicom.DicomWriter();
writer.rules = JSON.parse(document.getElementById('rules').value);
var dicomBuffer = null;
try {
dicomBuffer = writer.getBuffer(_dicomElements);
} catch (error) {
console.error(error);
alert(error.message);
}
// view as Blob to allow download
var blob = new Blob([dicomBuffer], {type: 'application/dicom'});
// update generate button
var element = document.getElementById("generate");
element.href = URL.createObjectURL(blob);
element.download = "anonym-" + _dicomFile.name;
}
// save the rules as a JSON file
function saveRules()
{
// check validity
if (!isValidRules()) {
return;
}
// get text from the textarea
var text = document.getElementById('rules').value;
// view as Blob to allow download
var blob = new Blob([text], {type:"text/plain"});
// update save button
var element = document.getElementById("save");
element.download = (_rulesFile === null ? "rules.json" : _rulesFile.name);
element.href = URL.createObjectURL(blob);
}
// is the JSON valid?
function isValidRules()
{
try {
JSON.parse(document.getElementById('rules').value);
}
catch (error) {
alert("The JSON is not valid, please check it with JSONLint.");
return false;
}
return true;
}
// open JSONLint to check the rules
function launchJSONLint()
{
var text = document.getElementById('rules').value;
var link = "http://jsonlint.com/?json=" + encodeURIComponent(text);
window.open(link);
}
// handle input DICOM file
function onInputDICOMFile(event)
{
if (event.target.files.length === 0) {
return;
}
_dicomFile = event.target.files[0];
var reader = new FileReader();
reader.onload = onLoadDICOMFile;
reader.readAsArrayBuffer(_dicomFile);
}
// handle input rules file
function onInputRulesFile(event)
{
if (event.target.files.length === 0) {
return;
}
_rulesFile = event.target.files[0];
var reader = new FileReader();
reader.onload = function (event) {
document.getElementById('rules').value = event.target.result;
};
reader.readAsText(_rulesFile);
}
</script>
<style>
body { font-family: Arial, Helvetica, sans-serif; }
textarea { width: 99%; margin: 2px; }
fieldset { background: whitesmoke; border: 1px solid grey; }
.button {
padding: 3px 7px 3px 7px;
text-align: center;
border-radius: 3px;
border: 1px solid grey;
text-decoration: none;
font: 80% sans-serif;
color: black;
background: #E3E3E3;
}
.button-active {
color: black;
background: #E3E3E3;
}
.button-disabled {
color: grey;
background: #F3F3F3;
}
.button:hover {
border: 1px solid black;
}
</style>
</head>
<body>
<h1>DWV DICOM Anonymiser</h1>
<p>Simple DICOM "anonymisation" tool. Available rules: <code>copy</code>,
<code>remove</code>, <code>clear</code>, <code>replace(value)</code>.</p>
<form name="genform">
<fieldset>
<label for="infile">DICOM file: </label>
<input id="infile" type="file" name="file" onchange="onInputDICOMFile(event);">
<br>&nbsp;
<br><label for="inrulesfile">JSON rules file: </label>
<input id="inrulesfile" type="file" name="file" onchange="onInputRulesFile(event);">
</fieldset>
<textarea id="rules" rows="25">
{
"default": {
"action": "remove", "value": null
},
"PatientName": {
"action": "replace", "value": "Anonymised"
},
"Meta Element": {
"action": "copy", "value": null
},
"Acquisition": {
"action": "copy", "value": null
},
"Image Presentation": {
"action": "copy", "value": null
},
"Procedure": {
"action": "copy", "value": null
},
"Pixel Data": {
"action": "copy", "value": null
}
}
</textarea>
<fieldset>
<a href="#" id="jsonlint" class="button" onclick="launchJSONLint();">JSONLint</a>
<a href="#" id="save" class="button" onclick="saveRules();">Save Rules</a>
<a href="#" id="generate" class="button button-disabled" onclick="generate();">Generate</a>
</fieldset>
</form>
</body>
</html>

View File

@@ -0,0 +1,216 @@
/**
* Tests for the 'dicom/dicomParser.js' file.
*/
/** @module tests/dicom */
// Do not warn if these variables were not defined before.
/* global QUnit */
QUnit.module("dicomParser");
// WARNING about PhantomJS 1.9
// ---------------------------
// TypedArray implementation seems incomplete, at least different than observed
// behavior in browsers...
// For a DICOM dataset, it was giving an:
// 'RangeError: ArrayBuffer length minus the byteOffset is not a multiple of the element size.'
// Which seem to originate from reading the data of first tag
// (FileMetaInformationGroupLength, Uint32 -> size=4)
// at offset 140 of a file of size 3070. 3070-140=2930; 2930/4=732.5...
//
// Error which, according to specs, should be thrown when the size of the data
// to read is not specified (see
// https://www.khronos.org/registry/typedarray/specs/latest/#7). But it is specified...
//
// So I updated the data to be of the correct size (in this case 3072)...
/**
* Tests for {@link dwv.dicom.DicomParser} using simple DICOM data.
* Using remote file for CI integration.
* @function module:tests/dicom~dicomParser
*/
QUnit.test("Test simple DICOM parsing.", function (assert) {
var done = assert.async();
var request = new XMLHttpRequest();
var urlRoot = "https://raw.githubusercontent.com/ivmartel/dwv/master";
var url = urlRoot + "/tests/data/dwv-test-simple.dcm";
request.open('GET', url, true);
request.responseType = "arraybuffer";
request.onerror = function (event) {
console.log(event);
};
request.onload = function (/*event*/) {
assert.ok((this.response.byteLength!==0), "Got a response.");
// parse DICOM
var dicomParser = new dwv.dicom.DicomParser();
dicomParser.parse(this.response);
var numRows = 32;
var numCols = 32;
// raw tags
var rawTags = dicomParser.getRawDicomElements();
// check values
assert.equal(rawTags.x00280010.value[0], numRows, "Number of rows (raw)");
assert.equal(rawTags.x00280011.value[0], numCols, "Number of columns (raw)");
// ReferencedImageSequence - ReferencedSOPInstanceUID
assert.equal(rawTags.x00081140.value[0].x00081155.value[0],
"1.3.12.2.1107.5.2.32.35162.2012021515511672669154094",
"ReferencedImageSequence SQ (raw)");
// wrapped tags
var tags = dicomParser.getDicomElements();
// wrong key
assert.equal(tags.getFromKey("x12345678"), null, "Wrong key");
assert.notOk(tags.getFromKey("x12345678"), "Wrong key fails if test" );
// empty key
assert.equal(tags.getFromKey("x00081050"), "", "Empty key");
assert.notOk(tags.getFromKey("x00081050"), "Empty key fails if test" );
// good key
assert.equal(tags.getFromKey("x00280010"), numRows, "Good key");
assert.ok(tags.getFromKey("x00280010"), "Good key passes if test" );
// zero value (passes test since it is a string)
assert.equal(tags.getFromKey("x00181318"), 0, "Good key, zero value");
assert.ok(tags.getFromKey("x00181318"), "Good key, zero value passes if test" );
// check values
assert.equal(tags.getFromName("Rows"), numRows, "Number of rows");
assert.equal(tags.getFromName("Columns"), numCols, "Number of columns");
// ReferencedImageSequence - ReferencedSOPInstanceUID
// only one item value -> returns the object directly
// (no need for tags.getFromName("ReferencedImageSequence")[0])
assert.equal(tags.getFromName("ReferencedImageSequence").x00081155.value[0],
"1.3.12.2.1107.5.2.32.35162.2012021515511672669154094",
"ReferencedImageSequence SQ");
// finish async test
done();
};
request.send(null);
});
/**
* Tests for {@link dwv.dicom.DicomParser} using sequence test DICOM data.
* Using remote file for CI integration.
* @function module:tests/dicom~dicomParser
*/
QUnit.test("Test sequence DICOM parsing.", function (assert) {
var done = assert.async();
var request = new XMLHttpRequest();
var urlRoot = "https://raw.githubusercontent.com/ivmartel/dwv/master";
var url = urlRoot + "/tests/data/dwv-test-sequence.dcm";
request.open('GET', url, true);
request.responseType = "arraybuffer";
request.onload = function (/*event*/) {
assert.ok((this.response.byteLength!==0), "Got a response.");
// parse DICOM
var dicomParser = new dwv.dicom.DicomParser();
dicomParser.parse(this.response);
// raw tags
var rawTags = dicomParser.getRawDicomElements();
assert.ok((Object.keys(rawTags).length!==0), "Got raw tags.");
// wrapped tags
var tags = dicomParser.getDicomElements();
assert.ok((tags.dumpToTable().length!==0), "Got wrapped tags.");
// ReferencedImageSequence: explicit sequence
var seq00 = tags.getFromName("ReferencedImageSequence");
assert.equal(seq00.length, 3, "ReferencedImageSequence length");
assert.equal(seq00[0].x00081155.value[0],
"1.3.12.2.1107.5.2.32.35162.2012021515511672669154094",
"ReferencedImageSequence - item0 - ReferencedSOPInstanceUID");
assert.equal(seq00[1].x00081155.value[0],
"1.3.12.2.1107.5.2.32.35162.2012021515511286933854090",
"ReferencedImageSequence - item1 - ReferencedSOPInstanceUID");
// SourceImageSequence: implicit sequence
var seq01 = tags.getFromName("SourceImageSequence");
assert.equal(seq01.length, 3, "SourceImageSequence length");
assert.equal(seq01[0].x00081155.value[0],
"1.3.12.2.1107.5.2.32.35162.2012021515511672669154094",
"SourceImageSequence - item0 - ReferencedSOPInstanceUID");
assert.equal(seq01[1].x00081155.value[0],
"1.3.12.2.1107.5.2.32.35162.2012021515511286933854090",
"SourceImageSequence - item1 - ReferencedSOPInstanceUID");
// ReferencedPatientSequence: explicit empty sequence
var seq10 = tags.getFromName("ReferencedPatientSequence");
assert.equal(seq10.length, 0, "ReferencedPatientSequence length");
// ReferencedOverlaySequence: implicit empty sequence
var seq11 = tags.getFromName("ReferencedOverlaySequence");
assert.equal(seq11.length, 0, "ReferencedOverlaySequence length");
// ReferringPhysicianIdentificationSequence: explicit empty item
var seq12 = tags.getFromName("ReferringPhysicianIdentificationSequence");
assert.equal(seq12.xFFFEE000.value.length, 0,
"ReferringPhysicianIdentificationSequence item length");
// ConsultingPhysicianIdentificationSequence: implicit empty item
var seq13 = tags.getFromName("ConsultingPhysicianIdentificationSequence");
assert.equal(seq13.xFFFEE000.value.length, 0,
"ConsultingPhysicianIdentificationSequence item length");
// ReferencedStudySequence: explicit sequence of sequence
var seq20 = tags.getFromName("ReferencedStudySequence");
// just one element
//assert.equal(seq20.length, 2, "ReferencedStudySequence length");
assert.equal(seq20.x0040A170.value[0].x00080100.value[0],
"123456",
"ReferencedStudySequence - seq - item0 - CodeValue");
// ReferencedSeriesSequence: implicit sequence of sequence
var seq21 = tags.getFromName("ReferencedSeriesSequence");
// just one element
//assert.equal(seq21.length, 2, "ReferencedSeriesSequence length");
assert.equal(seq21.x0040A170.value[0].x00080100.value[0],
"789101",
"ReferencedSeriesSequence - seq - item0 - CodeValue");
// ReferencedInstanceSequence: explicit empty sequence of sequence
var seq30 = tags.getFromName("ReferencedInstanceSequence");
assert.equal(seq30.x0040A170.value.length, 0,
"ReferencedInstanceSequence - seq - length");
// ReferencedVisitSequence: implicit empty sequence of sequence
var seq31 = tags.getFromName("ReferencedVisitSequence");
assert.equal(seq31.x0040A170.value.length, 0,
"ReferencedVisitSequence - seq - length");
// finish async test
done();
};
request.send(null);
});
/**
* Tests for {@link dwv.dicom.cleanString}.
* @function module:tests/dicom~cleanString
*/
QUnit.test("Test cleanString.", function (assert) {
// undefined
assert.equal(dwv.dicom.cleanString(), null, "Clean undefined");
// null
assert.equal(dwv.dicom.cleanString(null), null, "Clean null");
// empty
assert.equal(dwv.dicom.cleanString(""), "", "Clean empty");
// short
assert.equal(dwv.dicom.cleanString("a"), "a", "Clean short");
// special
var special = String.fromCharCode("u200B");
assert.equal(dwv.dicom.cleanString(special), "", "Clean just special");
// regular
var str = " El cielo azul ";
var refStr = "El cielo azul";
assert.equal(dwv.dicom.cleanString(str), refStr, "Clean regular");
// regular with special
str = " El cielo azul" + special;
refStr = "El cielo azul";
assert.equal(dwv.dicom.cleanString(str), refStr, "Clean regular with special");
// regular with special and ending space (not trimmed)
str = " El cielo azul " + special;
refStr = "El cielo azul ";
assert.equal(dwv.dicom.cleanString(str), refStr, "Clean regular with special 2");
});

View File

@@ -0,0 +1,283 @@
/**
* Tests for the 'dicom/dicomWriter.js' file.
*/
/** @module tests/dicom */
// Do not warn if these variables were not defined before.
/* global QUnit */
QUnit.module("dicomWriter");
var dwv = dwv || {};
dwv.utils = dwv.utils || {};
dwv.utils.test = dwv.utils.test || {};
/**
* Tests for {@link dwv.dicom.DicomWriter} using simple DICOM data.
* Using remote file for CI integration.
* @function module:tests/dicom~dicomWriter
*/
QUnit.test("Test multiframe writer support.", function (assert) {
var done = assert.async();
var request = new XMLHttpRequest();
var urlRoot = "https://raw.githubusercontent.com/ivmartel/dwv/master";
var url = urlRoot + "/tests/data/multiframe-test1.dcm";
request.open('GET', url, true);
request.responseType = "arraybuffer";
request.onerror = function (event) {
console.log(event);
};
request.onload = function (/*event*/) {
assert.ok((this.response.byteLength!==0), "Got a response.");
// parse DICOM
var dicomParser = new dwv.dicom.DicomParser();
dicomParser.parse(this.response);
var numFrames = 16;
// raw tags
var rawTags = dicomParser.getRawDicomElements();
// check values
assert.equal(rawTags.x00280008.value[0], numFrames, "Number of frames");
// length of value array for pixel data
assert.equal(rawTags.x7FE00010.value.length, numFrames, "Length of value array for pixel data");
var dicomWriter = new dwv.dicom.DicomWriter();
var buffer = dicomWriter.getBuffer(rawTags);
dicomParser = new dwv.dicom.DicomParser();
dicomParser.parse(buffer);
rawTags = dicomParser.getRawDicomElements();
// check values
assert.equal(rawTags.x00280008.value[0], numFrames, "Number of frames");
// length of value array for pixel data
assert.equal(rawTags.x7FE00010.value.length, numFrames, "Length of value array for pixel data");
// finish async test
done();
};
request.send(null);
});
QUnit.test("Test patient anonymisation", function (assert) {
var done = assert.async();
var request = new XMLHttpRequest();
var urlRoot = "https://raw.githubusercontent.com/ivmartel/dwv/master";
var url = urlRoot + "/tests/data/dwv-test-anonymise.dcm";
request.open('GET', url, true);
request.responseType = "arraybuffer";
request.onerror = function (event) {
console.log(event);
};
request.onload = function (/*event*/) {
assert.ok((this.response.byteLength!==0), "Got a response.");
// parse DICOM
var dicomParser = new dwv.dicom.DicomParser();
dicomParser.parse(this.response);
var patientsNameAnonymised = 'anonymise-name';
var patientsIdAnonymised = 'anonymise-id';
var rules = {
'default': {action: 'copy', value: null },
'x00100010' : {action: 'replace', value: patientsNameAnonymised }, // tag
'PatientID': {action: 'replace', value: patientsIdAnonymised}, // tag name 'x00100020'
'Patient' : {action: 'remove', value: null }, // group name 'x0010'
};
var patientsName = 'dwv-patient-test';
var patientID = 'dwv-patient-id123';
var patientsBirthDate = '19830101';
var patientsSex = 'M';
// raw tags
var rawTags = dicomParser.getRawDicomElements();
// check values
assert.equal(rawTags.x00100010.value[0], patientsName, "patientsName");
assert.equal(rawTags.x00100020.value[0], patientID, "patientID");
assert.equal(rawTags.x00100030.value[0], patientsBirthDate, "patientsBirthDate");
assert.equal(rawTags.x00100040.value[0], patientsSex, "patientsSex");
var dicomWriter = new dwv.dicom.DicomWriter();
dicomWriter.rules = rules;
var buffer = dicomWriter.getBuffer(rawTags);
dicomParser = new dwv.dicom.DicomParser();
dicomParser.parse(buffer);
rawTags = dicomParser.getRawDicomElements();
// check values
assert.equal(rawTags.x00100010.value[0], patientsNameAnonymised, "patientName");
assert.equal(rawTags.x00100020.value[0], patientsIdAnonymised, "patientID");
assert.notOk(rawTags.x00100030, "patientsBirthDate");
assert.notOk(rawTags.x00100040, "patientsSex");
// finish async test
done();
};
request.send(null);
});
/**
* Get a string representation of an object.
* TypedArray.toString can return '[object Uint8Array]' on old browsers
* (such as in PhantomJs).
* @param {Object} obj The input object
* @return {String} The string.
*/
dwv.utils.test.toString = function ( obj ) {
var res = obj.toString();
if ( res.substr(0,7) === "[object" &&
res.substr((res.length - 6),6) === "Array]") {
res = "";
for ( var i = 0; i < obj.length; ++i ) {
res += obj[i];
if ( i !== obj.length - 1 ) {
res += ",";
}
}
}
return res;
};
/**
* Compare JSON tags and DICOM elements
* @param {Object} jsonTags The JSON tags.
* @param {Object} dicomElements The DICOM elements
* @param {String} name The name of the test.
* @param {Object} comaprator An object with an equal function (such as Qunit assert).
*/
dwv.utils.test.compare = function ( jsonTags, dicomElements, name, comparator ) {
// check content
if (jsonTags === null || jsonTags === 0) {
return;
}
var keys = Object.keys(jsonTags);
for ( var k = 0; k < keys.length; ++k ) {
var tag = keys[k];
var tagGE = dwv.dicom.getGroupElementFromName(tag);
var tagKey = dwv.dicom.getGroupElementKey(tagGE.group, tagGE.element);
var element = dicomElements.getDEFromKey(tagKey);
var value = dicomElements.getFromKey(tagKey, true);
if ( element.vr !== "SQ" ) {
comparator.equal(dwv.utils.test.toString(value), jsonTags[tag], name + " - " + tag);
} else {
// check content
if (jsonTags[tag] === null || jsonTags[tag] === 0) {
continue;
}
// supposing same order of subkeys and indices...
var subKeys = Object.keys(jsonTags[tag]);
var index = 0;
for ( var sk = 0; sk < subKeys.length; ++sk ) {
if ( subKeys[sk] !== "explicitLength" ) {
var wrap = new dwv.dicom.DicomElementsWrapper(value[index]);
dwv.utils.test.compare(jsonTags[tag][subKeys[sk]], wrap, name, comparator);
++index;
}
}
}
}
};
/**
* Test a JSON config.
* @param {Object} config A JSON config representing DICOM tags.
* @param {Object} assert A Qunit assert.
*/
dwv.utils.test.testConfig = function (config, assert) {
// convert JSON to DICOM element object
var res = dwv.dicom.getElementsFromJSONTags(config.tags);
var dicomElements = res.elements;
// pixels: small gradient square
dicomElements.x7FE00010 = dwv.dicom.generatePixelDataFromJSONTags(config.tags, res.offset);
// create DICOM buffer
var writer = new dwv.dicom.DicomWriter();
var dicomBuffer = null;
try {
dicomBuffer = writer.getBuffer(dicomElements);
} catch (error) {
assert.ok(false, "Caught error: "+error);
return;
}
// parse the buffer
var dicomParser = new dwv.dicom.DicomParser();
dicomParser.parse(dicomBuffer);
var elements = dicomParser.getDicomElements();
// compare contents
dwv.utils.test.compare(config.tags, elements, config.name, assert);
};
QUnit.test("Test synthetic dicom explicit", function (assert) {
var done = assert.async();
// get the list of configs
var request = new XMLHttpRequest();
var urlRoot = "https://raw.githubusercontent.com/ivmartel/dwv/master";
var url = urlRoot + "/tests/dicom/synthetic-data_explicit.json";
request.open('GET', url, true);
request.onerror = function (event) {
console.error(event);
};
request.onload = function (/*event*/) {
var configs = JSON.parse(this.responseText);
for (var i = 0; i < configs.length; ++i ) {
dwv.utils.test.testConfig(configs[i], assert);
}
// finish async test
done();
};
request.send(null);
});
QUnit.test("Test synthetic dicom implicit", function (assert) {
var done = assert.async();
// get the list of configs
var request = new XMLHttpRequest();
var urlRoot = "https://raw.githubusercontent.com/ivmartel/dwv/master";
var url = urlRoot + "/tests/dicom/synthetic-data_implicit.json";
request.open('GET', url, true);
request.onerror = function (event) {
console.error(event);
};
request.onload = function (/*event*/) {
var configs = JSON.parse(this.responseText);
for (var i = 0; i < configs.length; ++i ) {
dwv.utils.test.testConfig(configs[i], assert);
}
// finish async test
done();
};
request.send(null);
});
QUnit.test("Test synthetic dicom explicit big endian", function (assert) {
var done = assert.async();
// get the list of configs
var request = new XMLHttpRequest();
var urlRoot = "https://raw.githubusercontent.com/ivmartel/dwv/master";
var url = urlRoot + "/tests/dicom/synthetic-data_explicit_big-endian.json";
request.open('GET', url, true);
request.onerror = function (event) {
console.error(event);
};
request.onload = function (/*event*/) {
var configs = JSON.parse(this.responseText);
for (var i = 0; i < configs.length; ++i ) {
dwv.utils.test.testConfig(configs[i], assert);
}
// finish async test
done();
};
request.send(null);
});

View File

@@ -0,0 +1,192 @@
<!DOCTYPE html>
<html>
<head>
<title>DICOM Generator</title>
<meta charset="UTF-8">
<script type="text/javascript" src="../../src/dicom/dicomParser.js"></script>
<script type="text/javascript" src="../../src/dicom/dicomWriter.js"></script>
<script type="text/javascript" src="../../src/dicom/dictionary.js"></script>
<script type="text/javascript">
// tags file
var _tagsFile = null;
// generate DICOM data
function generate()
{
// check validity
if (!isValidTags()) {
return;
}
// get tags from the textarea
var tags = JSON.parse(document.getElementById('tags').value);
// optional pixel generator (cannot be propagated)
var pixelGenerator = "gradSquare";
if ( typeof tags.PixelData !== "undefined" ) {
pixelGenerator = tags.PixelData;
delete tags.PixelData;
}
// convert JSON to DICOM element object
var res = dwv.dicom.getElementsFromJSONTags(tags);
var dicomElements = res.elements;
// pixels: small gradient square
dicomElements.x7FE00010 = null;
try {
dicomElements.x7FE00010 = dwv.dicom.generatePixelDataFromJSONTags(
tags, res.offset, pixelGenerator);
} catch (error) {
console.error(error);
alert(error.message);
}
// create writer
var writer = new dwv.dicom.DicomWriter();
var dicomBuffer = null;
try {
dicomBuffer = writer.getBuffer(dicomElements);
} catch (error) {
console.error(error);
alert(error.message);
}
// view as Blob to allow download
var blob = new Blob([dicomBuffer], {type: 'application/dicom'});
// update generate button
var element = document.getElementById("generate");
element.download = "dwv-generated.dcm";
element.href = URL.createObjectURL(blob);
}
// save the tags as a JSON file
function saveTags()
{
// check validity
if (!isValidTags()) {
return;
}
// get text from the textarea
var text = document.getElementById('tags').value;
// view as Blob to allow download
var blob = new Blob([text], {type:"text/plain"});
// update save button
var element = document.getElementById("save");
console.log(_tagsFile);
element.download = (_tagsFile === null ? "tags.json" : _tagsFile.name);
element.href = URL.createObjectURL(blob);
}
// is the JSON valid?
function isValidTags()
{
try {
JSON.parse(document.getElementById('tags').value);
}
catch (error) {
alert("The JSON is not valid, please check it with JSONLint.");
return false;
}
return true;
}
// open JSONLint to check the tags
function launchJSONlint()
{
var text = document.getElementById('tags').value;
var link = "http://jsonlint.com/?json=" + encodeURIComponent(text);
window.open(link);
}
// handle input tags file
function onInputTagsFile(event)
{
if (event.target.files.length === 0) {
return;
}
_tagsFile = event.target.files[0];
var reader = new FileReader();
reader.onload = function (event) {
document.getElementById('tags').value = event.target.result;
};
reader.readAsText(_tagsFile);
}
</script>
<style>
body { font-family: Arial, Helvetica, sans-serif; }
textarea { width: 99%; margin: 2px; }
fieldset { background: whitesmoke; border: 1px solid grey; }
.button {
padding: 3px 7px 3px 7px;
text-align: center;
border-radius: 3px;
border: 1px solid grey;
text-decoration: none;
font: 80% sans-serif;
color: black;
background: #E3E3E3;
}
.button-active {
color: black;
background: #E3E3E3;
}
.button-disabled {
color: grey;
background: #F3F3F3;
}
.button:hover {
border: 1px solid black;
}
</style>
</head>
<body>
<h1>DWV DICOM Generator</h1>
<p>Simple DICOM data generator from json tags.
Mainly used for generating test data, <b>use at your own risks!</b>
<br>No need for a 'FileMetaInformationGroupLength', it is calculated automatically.
Values should not be <code>null</code>...
<br>Sequences have an optional <code>explicitLength</code> boolean parameter to write them
and all their elements with implicit or explicit length. Its default value is <code>true</code>.
Set as <code>{}</code>, a sequence will
be written with explicit zero length, a <code>0</code> value will mean implicit length.
</p>
<form name="genform">
<fieldset>
<label for="intagsfile">JSON DICOM tags file: </label>
<input id="intagsfile" type="file" name="file" onchange="onInputTagsFile(event);">
</fieldset>
<textarea id="tags" rows="25">
{
"TransferSyntaxUID": "1.2.840.10008.1.2.1",
"Modality": "MR",
"PatientName": "dwv-patient-name",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PlanarConfiguration": 0,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11,
"ReferencedImageSequence": {
"explicitLength": true,
"item0": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511672669154094"
},
"item1": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511286933854090"
}
}
}
</textarea>
<fieldset>
<a href="#" id="jsonlint" class="button" onclick="launchJSONlint();">JSONLint</a>
<a href="#" id="save" class="button" onclick="saveTags();">Save Tags</a>
<a href="#" id="generate" class="button" onclick="generate();">Generate</a>
</fieldset>
</form>
</body>
</html>

View File

@@ -0,0 +1,93 @@
<!DOCTYPE html>
<html>
<head>
<title>DICOM synthetic data</title>
<meta charset="UTF-8">
<style>
body { font-family: Arial, Helvetica, sans-serif; }
</style>
<script type="text/javascript" src="../../src/dicom/dicomParser.js"></script>
<script type="text/javascript" src="../../src/dicom/dicomWriter.js"></script>
<script type="text/javascript" src="../../src/dicom/dictionary.js"></script>
<script type="text/javascript">
// Create an object url from (JSON) tags.
function getObjectUrlFromTags(tags) {
// convert JSON to DICOM element object
var res = dwv.dicom.getElementsFromJSONTags(tags);
var dicomElements = res.elements;
// pixels: small gradient square
dicomElements.x7FE00010 = dwv.dicom.generatePixelDataFromJSONTags(tags, res.offset);
// create DICOM buffer
var writer = new dwv.dicom.DicomWriter();
var dicomBuffer = null;
try {
dicomBuffer = writer.getBuffer(dicomElements);
} catch (error) {
console.error(error);
return;
}
// blob and then url
var blob = new Blob([dicomBuffer], {type: 'application/dicom'});
return URL.createObjectURL(blob);
}
// create list from configs
var getConfigsHtmlList = function (configs) {
var ul = document.createElement("ul");
for (var i = 0; i < configs.length; ++i ) {
// download link
var link = document.createElement("a");
link.href = getObjectUrlFromTags(configs[i].tags);
var fileName = "dwv-generated-" + configs[i].name + ".dcm";
link.download = fileName
link.appendChild( document.createTextNode( fileName ) );
// list element
var li = document.createElement("li");
li.append(link)
li.appendChild( document.createTextNode( ": " + configs[i].description ) );
// append to list
ul.append(li);
}
return ul;
}
// get the list of configs and display them with a download link
var getFileConfigsHtmlList = function (fileName) {
var urlRoot = "https://raw.githubusercontent.com/ivmartel/dwv/master";
var url = urlRoot + "/tests/dicom/" + fileName + ".json";
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.onerror = function (event) {
console.error(event);
};
request.onload = function (/*event*/) {
var content = document.getElementById("content");
var title = document.createElement("h2");
title.appendChild( document.createTextNode( fileName ) );
content.append(title);
var configs = JSON.parse(this.responseText);
content.append(getConfigsHtmlList(configs));
};
request.send(null);
}
// create lists
getFileConfigsHtmlList("synthetic-data_explicit");
getFileConfigsHtmlList("synthetic-data_implicit");
getFileConfigsHtmlList("synthetic-data_explicit_big-endian");
</script>
</head>
<body>
<h1>DWV DICOM synthetic data</h1>
<div id="content"></div>
</body>
</html>

View File

@@ -0,0 +1,193 @@
[
{
"name": "test00",
"description": "Little Endian Explicit test data.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2.1",
"Modality": "MR",
"PatientName": "dwv-patient-name-00",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11
}
},
{
"name": "test01",
"description": "Little Endian Explicit test data with PixelRepresentation=1.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2.1",
"Modality": "MR",
"PatientName": "dwv-patient-name-01",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PixelRepresentation": 1,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11
}
},
{
"name": "test02",
"description": "Little Endian Explicit 8bits RGB test data.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2.1",
"Modality": "MR",
"PatientName": "dwv-patient-name-02",
"PhotometricInterpretation": "RGB",
"SamplesPerPixel": 3,
"PlanarConfiguration": 1,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 8,
"BitsStored": 8,
"HighBit": 7
}
},
{
"name": "test03",
"description": "Little Endian Explicit test data with explicit length sequence.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2.1",
"Modality": "MR",
"PatientName": "dwv-patient-name-03",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11,
"ReferencedImageSequence": {
"explicitLength": true,
"item0": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511672669154094"
},
"item1": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511286933854090"
}
}
}
},
{
"name": "test04",
"description": "Little Endian Explicit test data with implicit length sequence.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2.1",
"Modality": "MR",
"PatientName": "dwv-patient-name-04",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11,
"ReferencedImageSequence": {
"explicitLength": false,
"item0": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511672669154094"
},
"item1": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511286933854090"
}
}
}
},
{
"name": "test05",
"description": "Little Endian Explicit test data with massive sequence.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2.1",
"Modality": "MR",
"PatientName": "dwv-patient-name-05",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11,
"ReferencedImageSequence": {
"explicitLength": true,
"item0": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511672669154094"
},
"item1": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511286933854090"
},
"item2": {}
},
"SourceImageSequence": {
"explicitLength": false,
"item0": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511672669154094"
},
"item1": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511286933854090"
},
"item2": 0
},
"ReferencedPatientSequence": {},
"ReferencedOverlaySequence": 0,
"ReferringPhysicianIdentificationSequence": {
"explicitLength": true,
"item0": {}
},
"ConsultingPhysicianIdentificationSequence": {
"explicitLength": false,
"item0": 0
},
"ReferencedStudySequence": {
"explicitLength": true,
"item0": {
"PurposeOfReferenceCodeSequence": {
"item0": {
"CodeValue": "123456"
}
}
}
},
"ReferencedSeriesSequence": {
"explicitLength": false,
"item0": {
"PurposeOfReferenceCodeSequence": {
"item0": {
"CodeValue": "789101"
}
}
}
},
"ReferencedInstanceSequence": {
"explicitLength": true,
"item0": {
"PurposeOfReferenceCodeSequence": {}
}
},
"ReferencedVisitSequence": {
"explicitLength": false,
"item0": {
"PurposeOfReferenceCodeSequence": 0
}
}
}
}
]

View File

@@ -0,0 +1,193 @@
[
{
"name": "test20",
"description": "Big Endian Explicit test data.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2.2",
"Modality": "MR",
"PatientName": "dwv-patient-name-20",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11
}
},
{
"name": "test21",
"description": "Big Endian Explicit test data with PixelRepresentation=1.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2.2",
"Modality": "MR",
"PatientName": "dwv-patient-name-21",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PixelRepresentation": 1,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11
}
},
{
"name": "test22",
"description": "Big Endian Explicit 8bits RGB test data.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2.2",
"Modality": "MR",
"PatientName": "dwv-patient-name-22",
"PhotometricInterpretation": "RGB",
"SamplesPerPixel": 3,
"PlanarConfiguration": 1,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 8,
"BitsStored": 8,
"HighBit": 7
}
},
{
"name": "test23",
"description": "Big Endian Explicit test data with explicit length sequence.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2.2",
"Modality": "MR",
"PatientName": "dwv-patient-name-23",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11,
"ReferencedImageSequence": {
"explicitLength": true,
"item0": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511672669154094"
},
"item1": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511286933854090"
}
}
}
},
{
"name": "test24",
"description": "Big Endian Explicit test data with implicit length sequence.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2.2",
"Modality": "MR",
"PatientName": "dwv-patient-name-24",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11,
"ReferencedImageSequence": {
"explicitLength": false,
"item0": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511672669154094"
},
"item1": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511286933854090"
}
}
}
},
{
"name": "test25",
"description": "Big Endian Explicit test data with massive sequence.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2.2",
"Modality": "MR",
"PatientName": "dwv-patient-name-25",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11,
"ReferencedImageSequence": {
"explicitLength": true,
"item0": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511672669154094"
},
"item1": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511286933854090"
},
"item2": {}
},
"SourceImageSequence": {
"explicitLength": false,
"item0": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511672669154094"
},
"item1": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511286933854090"
},
"item2": 0
},
"ReferencedPatientSequence": {},
"ReferencedOverlaySequence": 0,
"ReferringPhysicianIdentificationSequence": {
"explicitLength": true,
"item0": {}
},
"ConsultingPhysicianIdentificationSequence": {
"explicitLength": false,
"item0": 0
},
"ReferencedStudySequence": {
"explicitLength": true,
"item0": {
"PurposeOfReferenceCodeSequence": {
"item0": {
"CodeValue": "123456"
}
}
}
},
"ReferencedSeriesSequence": {
"explicitLength": false,
"item0": {
"PurposeOfReferenceCodeSequence": {
"item0": {
"CodeValue": "789101"
}
}
}
},
"ReferencedInstanceSequence": {
"explicitLength": true,
"item0": {
"PurposeOfReferenceCodeSequence": {}
}
},
"ReferencedVisitSequence": {
"explicitLength": false,
"item0": {
"PurposeOfReferenceCodeSequence": 0
}
}
}
}
]

View File

@@ -0,0 +1,193 @@
[
{
"name": "test10",
"description": "Little Endian Implicit test data.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2",
"Modality": "MR",
"PatientName": "dwv-patient-name-10",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11
}
},
{
"name": "test11",
"description": "Little Endian Implicit test data with PixelRepresentation=1.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2",
"Modality": "MR",
"PatientName": "dwv-patient-name-11",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PixelRepresentation": 1,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11
}
},
{
"name": "test12",
"description": "Little Endian Implicit 8bits RGB test data.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2",
"Modality": "MR",
"PatientName": "dwv-patient-name-12",
"PhotometricInterpretation": "RGB",
"SamplesPerPixel": 3,
"PlanarConfiguration": 1,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 8,
"BitsStored": 8,
"HighBit": 7
}
},
{
"name": "test13",
"description": "Little Endian Implicit test data with explicit length sequence.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2",
"Modality": "MR",
"PatientName": "dwv-patient-name-13",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11,
"ReferencedImageSequence": {
"explicitLength": true,
"item0": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511672669154094"
},
"item1": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511286933854090"
}
}
}
},
{
"name": "test14",
"description": "Little Endian Implicit test data with implicit length sequence.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2.1",
"Modality": "MR",
"PatientName": "dwv-patient-name-14",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11,
"ReferencedImageSequence": {
"explicitLength": false,
"item0": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511672669154094"
},
"item1": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511286933854090"
}
}
}
},
{
"name": "test15",
"description": "Little Endian Explicit test data with massive sequence.",
"tags": {
"TransferSyntaxUID": "1.2.840.10008.1.2.1",
"Modality": "MR",
"PatientName": "dwv-patient-name-15",
"PhotometricInterpretation": "MONOCHROME2",
"SamplesPerPixel": 1,
"PixelRepresentation": 0,
"Rows": 32,
"Columns": 32,
"BitsAllocated": 16,
"BitsStored": 12,
"HighBit": 11,
"ReferencedImageSequence": {
"explicitLength": true,
"item0": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511672669154094"
},
"item1": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511286933854090"
},
"item2": {}
},
"SourceImageSequence": {
"explicitLength": false,
"item0": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511672669154094"
},
"item1": {
"ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4",
"ReferencedSOPInstanceUID": "1.3.12.2.1107.5.2.32.35162.2012021515511286933854090"
},
"item2": 0
},
"ReferencedPatientSequence": {},
"ReferencedOverlaySequence": 0,
"ReferringPhysicianIdentificationSequence": {
"explicitLength": true,
"item0": {}
},
"ConsultingPhysicianIdentificationSequence": {
"explicitLength": false,
"item0": 0
},
"ReferencedStudySequence": {
"explicitLength": true,
"item0": {
"PurposeOfReferenceCodeSequence": {
"item0": {
"CodeValue": "123456"
}
}
}
},
"ReferencedSeriesSequence": {
"explicitLength": false,
"item0": {
"PurposeOfReferenceCodeSequence": {
"item0": {
"CodeValue": "789101"
}
}
}
},
"ReferencedInstanceSequence": {
"explicitLength": true,
"item0": {
"PurposeOfReferenceCodeSequence": {}
}
},
"ReferencedVisitSequence": {
"explicitLength": false,
"item0": {
"PurposeOfReferenceCodeSequence": 0
}
}
}
}
]