main.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. const parser = require('dicom-parser');
  2. const fsp = require('fs-promise');
  3. const iconv = require("iconv-lite")
  4. const filePath = '/Users/fuyu/Desktop/MR/MR1912090041/1.2.392.200036.9125.2.138612190166.20191209000532/816190C2/8A40E178.dcm';
  5. // const filePath = '/Users/fuyu/Desktop/MR/MR1912090041/1.2.392.200036.9125.2.138612190166.20191209000532/517D6718/7F8E6EC3.dcm';
  6. // const filePath = '/Users/fuyu/Downloads/5805957747722467ffe1bbbf31e81a1c';
  7. // const filePath = '/Users/fuyu/Downloads/d1137941cbce83e442eb2978989d059c';
  8. // const filePath = '/Users/fuyu/Downloads/7380ed924937d0aee73be14f32f75706';
  9. let test = async url => {
  10. const fileBuffer = await fsp.readFile(url);
  11. const dataSet = parser.parseDicom(fileBuffer);
  12. // console.log(dataSet.string('x00080005'));
  13. [patientTag, studyTag, seriesTag, imageTag].forEach(tags => {
  14. for (let key in tags) {
  15. console.log(key, dataSet.string(tags[key]))
  16. }
  17. })
  18. // const charset = getCharSet(dataSet)
  19. // const originalString = dataSet.string;
  20. // dataSet.string = (tag, index) => {
  21. // let value = originalString.call(dataSet, tag, index);
  22. // if (value != null && value != 'undefined') {
  23. // console.log('charset', charset)
  24. // let _value = iconv.decode(value, 'UTF-8');
  25. // // console.log()
  26. // if (_value != null && _value != 'undefined') {
  27. // return _value.replace(/['^']+/g, '')
  28. // }
  29. // return _value;
  30. // } else {
  31. // return value;
  32. // }
  33. // };
  34. // let text = dataSet.string('x0008103e')
  35. // console.log(text, iconv.decode(text, 'ISO_IR 100'))
  36. }
  37. const chatSetMap = {
  38. 'ISO_IR 6': 'UTF-8',
  39. 'ISO_IR 192': 'UTF-8',
  40. 'ISO_IR 100': 'ISO-8859-1',
  41. 'ISO_IR 101': 'ISO-8859-2',
  42. 'ISO_IR 109': 'ISO-8859-3',
  43. 'ISO_IR 110': 'ISO-8859-4',
  44. 'ISO_IR 144': 'ISO-8859-5',
  45. 'ISO_IR 127': 'ISO-8859-6',
  46. 'ISO_IR 126': 'ISO-8859-7',
  47. 'ISO_IR 138': 'ISO-8859-8',
  48. 'ISO_IR 148': 'ISO-8859-9',
  49. }
  50. const getCharSet = dataSet => {
  51. let specificCharacterSet = dataSet.string('x00080005');
  52. let charset = 'GB2312'
  53. console.log('specificCharacterSet', specificCharacterSet)
  54. if (specificCharacterSet) {
  55. charset = chatSetMap[specificCharacterSet] || charset
  56. }
  57. return charset
  58. }
  59. // GB2312
  60. // //xml文件编码方式,以支持中文显示。
  61. // if (!csetString.empty())
  62. // encString = "GB2312";
  63. test(filePath)
  64. const patientTag = {
  65. 'patientName': 'x00100010', //患者姓名 PN
  66. 'patientId': 'x00100020', //患者ID LO
  67. 'birthDate': 'x00100030', //患者出生日期 DA
  68. 'birthTime': 'x00100032', //患者出生时间 TM
  69. 'patientSex': 'x00100040', //患者性别 CS
  70. 'pregnancy': 'x001021c0', //怀孕状态 US
  71. 'weight': 'x00101030', //患者体重 DS
  72. 'institutionName': 'x00080080', //生产厂家 US
  73. 'institutionCode': 'x00080082', //生产厂家代码 US
  74. 'patientAge': 'x00101010' //做检查时刻的患者年龄 AS
  75. };
  76. // 'patientName': {
  77. // 'tag': 'x00100010',
  78. // 'vr': 'PN',
  79. // 'description': 'Patient’s Name',
  80. // 'comment': '患者姓名'
  81. // }, //患者姓名 PN
  82. const studyTag = {
  83. 'accessionNumber': 'x00080050', //检查号(RIS的生成序号) SH
  84. 'studyId': 'x00200010', //检查ID SH
  85. 'studyUid': 'x0020000d', //检查实例号 唯一标记 UI
  86. 'studyDate': 'x00080020', //检查日期(检查开始的日期) DA
  87. 'studyTime': 'x00080030', //检查时间(检查开始的时间) TM
  88. 'modalities': 'x00080061', //一个检查中含有的不同检查类型 CS
  89. 'partExamined': 'x00080015', //检查的部位 CS
  90. 'description': 'x00081030', //检查的描述 LO
  91. 'patientAge': 'x00101010', //做检查时刻的患者年龄 AS
  92. 'institutionName': 'x00080080', //生产厂家 US
  93. 'institutionCode': 'x00080082', //生产厂家代码 US
  94. };
  95. const seriesTag = {
  96. 'seriesNumber': 'x00200011', //序列号:识别不同检查的号码.
  97. 'seriesUid': 'x0020000e', //序列实例号:唯一标记不同序列的号码.
  98. 'modality': 'x00080060', //检查模态(MRI/CT/CR/DR)
  99. 'description': 'x0008103e', //检查描述和说明
  100. 'seriesDate': 'x00080021', //检查日期
  101. 'seriesTime': 'x00080031', //检查时间
  102. 'imagePosition': 'x00200032', //图像位置:图像的左上角在空间坐标系中的x,y,z坐标,单位是毫米. 如果在检查中,则指该序列中第一张影像左上角的坐标.
  103. 'imageOrientation': 'x00200037', //图像方位:
  104. 'sliceThickness': 'x00180050', //层厚
  105. 'spacingSlices': 'x00180088', //层与层之间的间距,单位为mm
  106. 'sliceLocation': 'x00201041', //实际的相对位置,单位为mm.
  107. 'MRAcquisition': 'x00180023', //
  108. 'partExamined': 'x00180015', //身体部位.
  109. };
  110. const imageTag = {
  111. 'imageType': 'x00080008', //图片类型 CS
  112. 'imageId': 'x00080018', //实例UID
  113. 'contentDate': 'x00080023', //影像拍摄的日期 DA
  114. 'contentTime': 'x00080033', //影像拍摄的时间 TM
  115. 'imageNumber': 'x00200013', //图像码 IS
  116. 'pixel': 'x00280002', //图像上的采样率. US
  117. 'rows': 'x00280010', //图像的总行数,行分辨率 US
  118. 'columns': 'x00280011', //图像的总列数,列分辨率 US
  119. 'pixelSpacing': 'x00280030', //像素间距(像素中心之间的物理间距) DS
  120. 'bitsStored': 'x00280101', //存储的位数:有12到16列举值.存储每一个像素用的位数.每一个样本应该有相同值.
  121. 'highBit': 'x00280102', //高位. DS
  122. 'pixelRepresentation': 'x00280103', //像素数据的表现类型:这是一个枚举值,分别为十六进制数0000和0001.0000H = 无符号整数,0001H = 2的补码. DS
  123. 'windowCenter': 'x00281050', //窗位 DS
  124. 'windowWidth': 'x00281051', //窗宽 DS
  125. 'rescaleIntercept': 'x00281052', //截距:如果表明不同模态的LUT颜色对应表不存在时,则使用方程Units = m*SV + b,计算真实的像素值到呈现像素值。其中这个值为表达式中的b
  126. 'rescaleSlope': 'x00281053', //斜率.这个值为表达式中的m。
  127. 'rescaleType': 'x00281054', //输出值的单位.这是一个枚举值,
  128. 'imagePosition': 'x00200032', //图像位置 DS
  129. 'imageOrientation': 'x00200037', //图像方位 DS
  130. 'SOPInstanceUID': 'x00080018', //图像方位 DS
  131. 'numberOfFrames': 'x00280008', //图像frame张数 DS
  132. 'cineRate': 'x00180040' //图像播放速率
  133. }
  134. /** Image Tag*/
  135. //00080008 Image Type 图片类型 CS
  136. //00080018 SOP Instance UID SOP实例UID
  137. //00080023 Content Date 影像拍摄的日期 DA
  138. //00080033 Content Time 影像拍摄的时间. TM
  139. //00200013 Image/Instance Number 图像码(辨识图像的号码) IS
  140. //00280002 Samples Per Pixel 图像上的采样率. US
  141. /**
  142. * MONOCHROME1,MONOCHROME2.
  143. * 用来判断图像是否是彩色的,
  144. * MONOCHROME1/2是灰度图,
  145. * RGB则是真彩色图,还有其他.
  146. */
  147. //00280004 Photometric Interpretation: 光度计的解释,对于CT图像,用两个枚举值 CS
  148. //00280010 Rows 图像的总行数,行分辨率. US
  149. //00280011 Columns 图像的总列数,列分辨率. US
  150. //00280030 Pixel Spacing 像素间距(像素中心之间的物理间距) DS
  151. //00280100 Bits Allocated 分配的位数(存储每一个像素值时分配的位数) US
  152. //00280101 Bits Stored: 存储的位数(有12到16列举值 US
  153. //00280102 High Bit 高位 US
  154. //00280103 Pixel Representation 像素数据的表现类型(枚举值,分别为十六进制数0000和0001) US
  155. //00281050 Window Center 窗位 DS
  156. //00281051 Window Width 窗宽 DS
  157. //00281052 Rescale Intercept 截距 DS
  158. //00281053 Rescale Slope 斜率 DS
  159. //00281054 Rescale Type 输出值的单位 LO
  160. /**图像的左上角在空间坐标系中的x,y,z坐标,单位是毫米. 如果在检查中,则指该序列中第一张影像左上角的坐标*/
  161. //00200032 Image Position 图像位置 DS
  162. //00200037 Image Orientation 图像方位 DS
  163. //00180050 Slice Thickness 层厚 DS
  164. //00180088 Spacing Between Slices 层与层之间的间距,单位为mm DS
  165. //00201041 Slice Location 实际的相对位置,单位为mm. DS
  166. //00180023 MR Acquisition CS
  167. //00180015 Body Part Examined 身体部位 CS
  168. const patientWADO = {
  169. 'patientName': ['00100010', 'PN'], //患者姓名 PN
  170. 'patientId': ['00100020', 'LO'], //患者ID LO
  171. 'birthDate': ['00100030', 'DA'], //患者出生日期 DA
  172. 'birthTime': ['00100032', 'TM'], //患者出生时间 TM
  173. 'patientSex': ['00100040', 'CS'], //患者性别 CS
  174. 'pregnancy': ['001021c0', 'US'], //怀孕状态 US
  175. 'weight': ['00101030', 'DS'], //患者体重 DS
  176. 'institutionName': ['00080080', 'US'], //生产厂家 US
  177. 'institutionCode': ['00080082', 'US'], //生产厂家代码 US
  178. 'patientAge': ['00101010', 'AS'] //做检查时刻的患者年龄 AS
  179. }
  180. const studyWADO = {
  181. 'accessionNumber': ['00080050', 'SH'], //检查号(RIS的生成序号) SH
  182. 'studyId': ['00200010', 'SH'], //检查ID SH
  183. 'studyUid': ['0020000d', 'UI'], //检查实例号 唯一标记 UI
  184. 'studyDate': ['00080020', 'DA'], //检查日期(检查开始的日期) DA
  185. 'studyTime': ['00080030', 'TM'], //检查时间(检查开始的时间) TM
  186. 'modalities': ['00080061', 'CS'], //一个检查中含有的不同检查类型 CS
  187. 'partExamined': ['00080015', 'CS'], //检查的部位 CS
  188. 'description': ['00081030', 'LO'], //检查的描述 LO
  189. 'patientAge': ['00101010', 'AS'] //做检查时刻的患者年龄 AS
  190. }
  191. const seriesWADO = {
  192. 'seriesNumber': ['00200011', 'IS'], //序列号:识别不同检查的号码.
  193. 'seriesUid': ['0020000e', 'UI'], //序列实例号:唯一标记不同序列的号码.
  194. 'modality': ['00080060', 'CS'], //检查模态(MRI/CT/CR/DR)
  195. 'description': ['0008103e', 'LO'], //检查描述和说明
  196. 'seriesDate': ['00080021', 'DA'], //检查日期
  197. 'seriesTime': ['00080031', 'DA'], //检查时间
  198. 'imagePosition': ['00200032', 'DS'], //图像位置:图像的左上角在空间坐标系中的x,y,z坐标,单位是毫米. 如果在检查中,则指该序列中第一张影像左上角的坐标.
  199. 'imageOrientation': ['00200037', 'DS'], //图像方位:
  200. 'sliceThickness': ['00180050', 'DS'], //层厚
  201. 'spacingSlices': ['00180088', 'DS'], //层与层之间的间距,单位为mm
  202. 'sliceLocation': ['00201041', 'DS'], //实际的相对位置,单位为mm.
  203. 'MRAcquisition': ['00180023', 'CS'], //
  204. 'partExamined': ['00180015', 'CS'], //身体部位.
  205. };
  206. const imageWADO = {
  207. 'imageType': ['00080008', 'CS'], //图片类型 CS
  208. 'imageId': ['00080018', 'UI'], //实例UID UI
  209. 'contentDate': ['00080023', 'DA'], //影像拍摄的日期 DA
  210. 'contentTime': ['00080033', 'TM'], //影像拍摄的时间 TM
  211. 'imageNumber': ['00200013', 'IS'], //图像码 IS
  212. 'pixel': ['00280002', 'US'], //图像上的采样率. US
  213. 'rows': ['00280010', 'US'], //图像的总行数,行分辨率 US
  214. 'columns': ['00280011', 'US'], //图像的总列数,列分辨率 US
  215. 'pixelSpacing': ['00280030', 'DS'], //像素间距(像素中心之间的物理间距) DS
  216. 'bitsStored': ['00280101', 'US'], //存储的位数:有12到16列举值.存储每一个像素用的位数.每一个样本应该有相同值. US
  217. 'highBit': ['00280102', 'DS'], //高位. DS
  218. 'pixelRepresentation': ['00280103', 'DS'], //像素数据的表现类型:这是一个枚举值,分别为十六进制数0000和0001.0000H = 无符号整数,0001H = 2的补码. DS
  219. 'windowCenter': ['00281050', 'DS'], //窗位 DS
  220. 'windowWidth': ['00281051', 'DS'], //窗宽 DS
  221. 'rescaleIntercept': ['00281052', 'DS'], //截距:如果表明不同模态的LUT颜色对应表不存在时,则使用方程Units = m*SV + b,计算真实的像素值到呈现像素值。其中这个值为表达式中的b
  222. 'rescaleSlope': ['00281053', 'DS'], //斜率.这个值为表达式中的m。
  223. 'rescaleType': ['00281054', 'DS'], //输出值的单位.这是一个枚举值,
  224. 'imagePosition': ['00200032', 'DS'], //图像位置 DS
  225. 'imageOrientation': ['00200037', 'DS'], //图像方位 DS
  226. 'SOPInstanceUID': ['00080018', 'DS'], //图像方位
  227. 'numberOfFrames': ['00280008', 'IS'] //图像frame张数 DS
  228. }
  229. // export {
  230. // patientTag,
  231. // studyTag,
  232. // seriesTag,
  233. // imageTag,
  234. // patientWADO,
  235. // studyWADO,
  236. // seriesWADO,
  237. // imageWADO
  238. // }
  239. // tag VR VM Description
  240. // 00080005 CS 1-n SpecificCharacterSet
  241. // 00080020 DA 1-1 StudyDate
  242. // 00080030 TM 1-1 StudyTime
  243. // 00080050 SH 1-1 Accession​Numbe
  244. // 00080056 CS 1-1 Instance​Availability
  245. // 00080061 CS 1-n Modalities​In​Study
  246. // 00080090 PN 1-1 Referring​Physician​Name
  247. // 00081190 UR 1-1 Retrieve​URL
  248. // 00090010 LO 1-1 SpecificCharacterSet
  249. // 00091002 UN 1-1 SpecificCharacterSet
  250. // 00100010 PN 1-1 Patient​Name
  251. // 00100020 LO 1-1 Patient​Id
  252. // 00100021 LO 1-1 Issuer​Of​Patient​ID
  253. // 00100030 DT 1-1 Patient​Birth​Date
  254. // 00100040 CS 1-1 Patient​Sex
  255. // 00101002 SQ 1-1 Other​Patient​IDs​Sequence
  256. // 0020000D UI 1-1 Study​Instance​UID
  257. // 00200010 SH 1-1 Study​ID
  258. // 00201206 IS 1-1 Number​Of​Study​Related​Series
  259. // 00201208 IS 1-1 Number​Of​Study​Related​Instances
  260. // { // Result 1
  261. // "00080005": {
  262. // "vr": "CS",
  263. // "Value": [ "ISO_IR 192" ]
  264. // },
  265. // "00080020": {
  266. // "vr": "DT",
  267. // "Value": [ "20130409" ]
  268. // },
  269. // "00080030": {
  270. // "vr": "TM",
  271. // "Value": [ "131600.0000" ]
  272. // },
  273. // "00080050": {
  274. // "vr": "SH",
  275. // "Value": [ "11235813" ]
  276. // },
  277. // "00080056": {
  278. // "vr": "CS",
  279. // "Value": [ "ONLINE" ]
  280. // },
  281. // "00080061": {
  282. // "vr": "CS",
  283. // "Value": [
  284. // "CT",
  285. // "PET"
  286. // ]
  287. // },
  288. // "00080090": {
  289. // "vr": "PN",
  290. // "Value": [
  291. // {
  292. // "Alphabetic": "^Bob^^Dr."
  293. // }
  294. // ]
  295. // },
  296. // "00081190": {
  297. // "vr": "UR",
  298. // "Value": [ "http://wado.nema.org/studies/
  299. // 1.2.392.200036.9116.2.2.2.1762893313.1029997326.945873" ]
  300. // },
  301. // "00090010": {
  302. // "vr": "LO",
  303. // "Value": [ "Vendor A" ]
  304. // },
  305. // "00091002": {
  306. // "vr": "UN",
  307. // "InlineBinary": [ "z0x9c8v7" ]
  308. // },
  309. // "00100010": {
  310. // "vr": "PN",
  311. // "Value": [
  312. // {
  313. // "Alphabetic": "Wang^XiaoDong",
  314. // "Ideographic": "王^小東"
  315. // }
  316. // ]
  317. // },
  318. // "00100020": {
  319. // "vr": "LO",
  320. // "Value": [ "12345" ]
  321. // },
  322. // "00100021": {
  323. // "vr": "LO",
  324. // "Value": [ "Hospital A" ]
  325. // },
  326. // "00100030": {
  327. // "vr": "DT",
  328. // "Value": [ "19670701" ]
  329. // },
  330. // "00100040": {
  331. // "vr": "CS",
  332. // "Value": [ "M" ]
  333. // },
  334. // "00101002": {
  335. // "vr": "SQ",
  336. // "Value": [
  337. // {
  338. // "00100020": {
  339. // "vr": "LO",
  340. // "Value": [ "54321" ]
  341. // },
  342. // "00100021": {
  343. // "vr": "LO",
  344. // "Value": [ "Hospital B" ]
  345. // }
  346. // },
  347. // {
  348. // "00100020": {
  349. // "vr": "LO",
  350. // "Value": [ "24680" ]
  351. // },
  352. // "00100021": {
  353. // "vr": "LO",
  354. // "Value": [ "Hospital C" ]
  355. // }
  356. // }
  357. // ]
  358. // },
  359. // "0020000D": {
  360. // "vr": "UI",
  361. // "Value": [ "1.2.392.200036.9116.2.2.2.1762893313.1029997326.945873" ]
  362. // },
  363. // "00200010": {
  364. // "vr": "SH",
  365. // "Value": [ "11235813" ]
  366. // },
  367. // "00201206": {
  368. // "vr": "IS",
  369. // "Value": [ 4 ]
  370. // },
  371. // "00201208": {
  372. // "vr": "IS",
  373. // "Value": [ 942 ]
  374. // }
  375. // }