main.js 18 KB

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