202 lines
7.9 KiB
JavaScript
202 lines
7.9 KiB
JavaScript
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();
|
||
});
|
||
}; |