import * as dicomParser from "dicom-parser"; import * as cornerstone from "cornerstone-core"; import * as cornerstoneWADOImageLoader from "cornerstone-wado-image-loader"; cornerstoneWADOImageLoader.external.dicomParser = dicomParser; cornerstoneWADOImageLoader.external.cornerstone = cornerstone; import { convertBytes } from "@/utils/dicom-character-set"; import Vue from 'vue'; import { dcmUpload } from "@/utils/dcmUpload/dcmUpload"; let dicom = { PatientName: "x00100010", // 患者姓名 PatientId: "x00100020", // 患者ID PatientBirthDate: "x00100030", // 患者出生日期 PatientBirthTime: "x00100032", // 患者出生时间 PatientSex: "x00100040", // 患者性别 PatientWeight: "x00101030", // 患者体重 PregnancyStatus: "x001021c0", // 怀孕状态 PatientAge: "x00101010", // 患者年龄(做检查时刻的患者年龄,而不是此刻患者的真实年龄) AcquisitionTime: "x00080032", AcquisitionNumber: "x00200012", TriggerTime: "x00181060", AccessionNumber: "x00080050", // 检查号 StudyId: "x00200010", // 检查ID StudyInstanceUid: "x0020000d", // 检查实例号 StudyDate: "x00080020", // 检查日期 StudyTime: "x00080030", // 检查时间 Modalities: "x00080061", // 一个检查中含有的不同检查类型 BodyPartExamined: "x00080015", // 检查的部位 StudyDescription: "x00081030", // 检查的描述 InstitutionName: "x00080080", SeriesNumber: "x00200011", // 序列号 SeriesInstanceUid: "x0020000e", // 序列实例号 Modality: "x00080060", // 检查模态 SeriesDescription: "x0008103e", // 检查描述和说明 SeriesDate: "x00080021", // 检查日期 SeriesTime: "x00080031", // 检查时间 SequenceName: "x00180024", ProtocolName: "x00181030", ImagePosition: "x00200032", // 图像位置 ImageOrientation: "x00200037", // 图像方位 ImagePixelSpacing: "x00181164", SliceThickness: "x00180050", // 层厚 SpacingBetweenSlices: "x00180088", // 层间距 SliceLocation: "x00201041", // 相对位置 MRAcquisition: "x00180023", seriesBodyPartExamined: "x00180015", // 身体部位 ImageType: "x00080008", SopInstanceUid: "x00080018", // SOP实例UID ContentDate: "x00080023", // 影像拍摄日期 ContentTime: "x00080033", // 影像拍摄时间 ImageOrInstanceNumber: "x00200013", // 图像码 SamplesPerPixel: "x00280002", // 图像采样率 PhotometricInterpretation: "x00280004", // 光度计(对于CT图像,用两个枚举值MONOCHROME1,MONOCHROME2 用来判断图像是否是彩色的;MONOCHROME 1/2是灰度图,RGB则是真彩色图) Rows: "x00280010", // 行数 Columns: "x00280011", // 列数 NumberOfFrames: "x00280008", PixelSpacing: "x00280030", // 像素间距 BitsAllocated: "x00280100", // 分配的位数 BitsStored: "x00280101", // 存储的位数 HighBit: "x00280102", // 高位 PixelRepresentation: "x00280103", // 像素数据的表现类型(一个枚举值,分别为十六进制数0000和0001.0000H = 无符号整型,0001H = 2的补码) WindowCenter: "x00281050", // 窗位 WindowWidth: "x002811051", // 窗宽 RescaleIntercept: "x00281052", // 截距 RescaleSlope: "x00281053", // 斜率 RescaleType: "x00281054", // 输出值的单位 ParsingFormat: "x00080005", FrameOfReferenceUID: "x00200052", }; // 需要设置默认值 let defaultKey = ['Rows', 'Columns', 'SliceLocation', 'NumberOfFrames']; let uintKey = ['Rows', 'Columns']; let intStringKey = ['SliceLocation', 'NumberOfFrames']; // 需要格式解析 let pormatParseKey = ['PatientName', 'SeriesDescription', 'StudyDescription']; // 解析dicom文件 export const parseDicom = (file, name = false) => { return new Promise(function (resolve) { let reader = new FileReader(); reader.onload = function (e) { try { let data = dicomParser.parseDicom(new Uint8Array(e.target.result)); let res = {}; if (name && Array.isArray(name)) { name.forEach((item) => { if (dicom[item]) { res[item] = data.string(dicom[item]) || ''; } }); } else if (name) { if (dicom[name]) { res[name] = data.string(dicom[name]) || ''; } else { console.log("name is inexistence"); resolve(false) } } else { Object.keys(dicom).forEach((key) => { res[key] = data.string(dicom[key]) || ''; }); } pormatParseKey.forEach(key => { if (res[key]) { const Element = data.elements[dicom[key]]; const Bytes = new Uint8Array( data.byteArray.buffer, Element ? Element.dataOffset : 0, Element ? Element.length : 0 ); res[key] = convertBytes( res.ParsingFormat, Bytes ); } }) uintKey.forEach(key => { res[key] = data.uint16(dicom[key]) }) intStringKey.forEach(key => { res[key] = data.intString(dicom[key]) }) defaultKey.forEach(key => { if (!res[key] && res.hasOwnProperty(key)) { res[key] = 0; } }) resolve(res); } catch (error) { console.log(error) resolve(false); } }; reader.onerror = function (e) { console.log(e) resolve(false); }; reader.readAsArrayBuffer(file); }); }; // 影像上传 // 影像上传 export const dicomToOSS = async (file, path) => { try { let res = await dcmUpload(path, file); if (!res || !res.url) return false; return Vue.prototype.$getObjectName(res.url); } catch (err) { console.log(err); return false; } }; // 获取缩略图 export const getThumbnail = async (file, ossPath, dicomInfo) => { try { if (dicomInfo.modality !== "SR") { let fileId = cornerstoneWADOImageLoader.wadouri.fileManager.add(file); let blob = await dicomToPng( fileId, dicomInfo.Columns, dicomInfo.Rows ); if (!blob) return ""; let OSSclient = Vue.prototype.OSSclient; let seriesRes = await OSSclient.put(ossPath, blob); if (seriesRes && seriesRes.url) { return Vue.prototype.$getObjectName(seriesRes.url); } else { return ""; } } else { return ""; } } catch (err) { console.log(err); return ""; } }; const canvasToBlob = (canvas) => { return new Promise((resolve) => { canvas.toBlob((blob) => { resolve(blob); }); }); }; const dicomToPng = (imageId, width, height) => { return new Promise((resolve) => { cornerstone.loadImage(imageId).then(async (image) => { let canvas = document.createElement("canvas"); canvas.width = width; canvas.height = height; if (image) { cornerstone.renderToCanvas(canvas, image); // 将 Canvas 图像对象转换为 PNG 格式 let blob = await canvasToBlob(canvas); resolve(blob); } else { resolve(false); } }); }).catch((reason) => { reason(); }); };