//功能名称 const functionNames = [ "Magnify", "Pan", "Zoom", "ZoomMouseWheel", "Wwwc", "ScaleOverlay", "OrientationMarkers", "WwwcRegion", "Rotate", "Angle", "ArrowAnnotate", "Bidirectional", "CobbAngle", "EllipticalRoi", "FreehandRoi", "Length", "Probe", "RectangleRoi", "TextMarker", "StackScroll", "StackScrollMouseWheel" ] //标尺和方向显示可与其他状态同时启用 const displayFunctions = ["ScaleOverlay", "OrientationMarkers"] //不能同时启用的功能 const notNeedDisableFunctions = ["WwwcRegion", "Rotate", "Angle", "ArrowAnnotate", "Bidirectional", "CobbAngle", "EllipticalRoi", "FreehandRoi", "Length", "Probe", "RectangleRoi", "TextMarker"] //状态数据 var stateData = { rowCount: 1, columnCount: 1, imgIndex: 0, element: {}, dicomInfo: {}, showMapping: new Map() } /*切换工具*/ function switchAction(tagName, flag, btn) { //btn btn-primary var isSelected = $(btn).hasClass('selected'); if (isSelected) { $(btn).removeClass("btn-primary") $(btn).removeClass("selected") $(btn).addClass("btn-default") disableFunctions(tagName); } else { disableFunctions(tagName); $(btn).removeClass("btn-default") $(btn).addClass("btn-primary") $(btn).addClass("selected") } if (!isSelected) { cornerstoneTools.setToolActive(tagName, { mouseButtonMask: 1 }) } } function reload() { var data = cornerstoneTools.getToolState(stateData.element, "stack").data[0]; var index = data.currentImageIdIndex; var imgId = data.imageIds[index]; data.currentImageIdIndex = index; cornerstone.loadAndCacheImage(imgId).then(function (image) { cornerstone.enable(stateData.element); cornerstone.displayImage(stateData.element, image); }); } //下一张 function next(imgId) { if (imgId && stateData.element != imgId) { return; } var data = cornerstoneTools.getToolState(stateData.element, "stack").data[0]; var index = data.currentImageIdIndex; if (index == data.imageIds.length - 1) { return; } else { index += 1; } var imgId = data.imageIds[index]; data.currentImageIdIndex = index; cornerstone.loadAndCacheImage(imgId).then(function (image) { cornerstone.enable(stateData.element); cornerstone.displayImage(stateData.element, image); renderTagText(stateData.element,image) }); for (var i = 0; i < 10; i++) { if (index + i == data.imageIds.length - 1) { break; } cornerstone.loadImage(data.imageIds[index + i]).then((image) => { console.log("loaded ok " + data.imageIds[index + i]); }) } setSliderValue(stateData.element.id) } //读取文件中的标签信息 function getDicomInfo(image) { var imageInfo = {}; imageInfo.seriesNumber = image.data.string('x00200011');//图像序列号 imageInfo.imageNum = image.data.string('x00200013');//图像位置 imageInfo.imageDate = image.data.string("x00080021");//拍摄日期 imageInfo.sliceThickness = image.data.string('x00180050');//层厚 imageInfo.patientId = image.data.string('x00100020');//病理号 // 判断窗宽窗位是否合法 imageInfo.pixelR = image.data.uint16('x00280103'); imageInfo.heightBit = image.data.uint16('x00280102') || ''; // 病人基本信息 imageInfo.patientName = image.data.string('x00100010'); imageInfo.patientBirthDate = image.data.string('x00100030'); imageInfo.patientGender = image.data.string('x00100040'); imageInfo.sID = image.data.string('x00200011'); // 像素间距 imageInfo.pixelSpacing = image.data.string('x00280030'); imageInfo.height = image.data.uint16('x00280010'); imageInfo.width = image.data.uint16('x00280011'); imageInfo.height = image.data.uint16('x00280010'); imageInfo.windowCenter = image.data.string('x00281050'); imageInfo.windowWidth = image.data.string('x00281051'); imageInfo.imagePixelSpacing = image.data.string('x00181164') || ''; imageInfo.rowPixelSpacing = image.rowPixelSpacing; // 放射放大系数 imageInfo.magnification = Number(image.data.string('x00181114')); // 放射源到面板的距离 imageInfo.sourceTOdetector = image.data.string('x00181110'); // 放射源到病人的距离 imageInfo.sourceTOpatient = image.data.string('x00181111'); //this.modalityLUT = cornerstone.metaData.get('modalityLutModule', image.imageId).modalityLUTSequence; imageInfo.voiContent = cornerstone.metaData.get('voiLutModule', image.imageId); // 斜率截距 imageInfo.rescaleIntercept = Number(image.data.string('x00281052')); imageInfo.rescaleSlope = Number(image.data.string('x00281053')); return imageInfo; } //上一张 function last(imgId) { if (imgId && stateData.element != imgId) { return; } var data = cornerstoneTools.getToolState(stateData.element, "stack").data[0]; var index = data.currentImageIdIndex; if (index == 0) { return; } else { index -= 1; } var imgId = data.imageIds[index]; data.currentImageIdIndex = index; cornerstone.loadAndCacheImage(imgId).then(function (image) { cornerstone.enable(stateData.element); cornerstone.displayImage(stateData.element, image); renderTagText(stateData.element, image) }); setSliderValue(stateData.element.id) } //进度条更新 function setAllSliderValue() { //获取所有已经加载的图片区映射关系 if (stateData.showMapping) { stateData.showMapping.forEach((value, key) => { setSliderValue(key); }); } } //标签文本更新 function setAllTagsValue() { if (stateData.showMapping) { stateData.showMapping.forEach((value, key) => { var element = document.getElementById(key) var image = cornerstone.getImage(element); //TODO 缺少获取图片对象信息 renderTagText(element, image) }); } } //重置画布 function resetRenderCanvase() { var element = stateData.element; const enabledElement = cornerstone.getEnabledElement(element); enabledElement.renderingTools.colormapId = undefined; enabledElement.renderingTools.colorLut = undefined; const renderCanvas = enabledElement.renderingTools.renderCanvas; const canvasContext = renderCanvas.getContext('2d'); // NOTE - we need to fill the render canvas with white pixels since we // control the luminance using the alpha channel to improve rendering performance. canvasContext.fillStyle = 'white'; canvasContext.fillRect(0, 0, renderCanvas.width, renderCanvas.height); const renderCanvasData = canvasContext.getImageData(0, 0, renderCanvas.width, renderCanvas.height); enabledElement.renderingTools.renderCanvasContext = canvasContext; enabledElement.renderingTools.renderCanvasData = renderCanvasData; cornerstone.updateImage(stateData.element); } //重置按钮状态 function resetBtnState(id) { if ($("#" + id).hasClass("selected")) { $("#" + id).removeClass("btn-primary") $("#" + id).removeClass("selected") $("#" + id).addClass("btn-default") } } function disableFunctions(currentFun) { functionNames.forEach(function (fname) { resetBtnState(fname) if (currentFun != fname && (notNeedDisableFunctions.includes(fname) || displayFunctions.includes(fname))) { return; } cornerstoneTools.setToolDisabled(fname, { mouseButtonMask: 1 }) }) } //辅助工具 const toolFunction = ["ScaleOverlay", "OrientationMarkers"] const wheelFunction = ["ZoomMouseWheel"] //撤销所有改动 function resetTool() { //反转色 //invert(null, $("#invert"), true) //changColor(0, $("#changeColor"), true) functionNames.forEach(function (fname) { if (notNeedDisableFunctions.includes(fname)) { cornerstoneTools.clearToolState(stateData.element, fname); } }) cornerstone.reset(stateData.element); cornerstone.updateImage(stateData.element); } //反转颜色 function invert(flag, btn, reset) { //btn btn-primary var isSelected = $(btn).hasClass('selected'); if (isSelected || reset) { $(btn).removeClass("btn-primary") $(btn).removeClass("selected") $(btn).addClass("btn-default") } else { $(btn).removeClass("btn-default") $(btn).addClass("btn-primary") $(btn).addClass("selected") } //反转颜色 var viewport = { invert: !isSelected ? true : false } cornerstone.setViewport(stateData.element, viewport); } //彩色 function changColor(flag, btn, reset) { var element = stateData.element; //btn btn-primary var isSelected = $(btn).hasClass('selected'); if (isSelected || reset) { $(btn).removeClass("btn-primary") $(btn).removeClass("selected") $(btn).addClass("btn-default") } else { $(btn).removeClass("btn-default") $(btn).addClass("btn-primary") $(btn).addClass("selected") } resetRenderCanvase(); const b = cornerstone.getEnabledElement(element) const v = cornerstone.getDefaultViewport(b.canvas, b.image) var vp = cornerstone.getViewport(element); vp.colormap = !isSelected ? "hsv" : undefined; if (!flag) { cornerstone.setViewport(element, v) } else { cornerstone.setViewport(element, vp) } } //重置cornerstone function reset() { cornerstone.reset(stateData.element); } function initConerstone(element) { // 注册并挂载cornerstone及其cornerstoneTools,固定操作 cornerstoneTools.external.cornerstone = cornerstone; cornerstoneTools.external.cornerstoneMath = cornerstoneMath; cornerstoneTools.external.Hammer = Hammer; cornerstoneWADOImageLoader.external.dicomParser = dicomParser; cornerstoneWADOImageLoader.external.cornerstone = cornerstone; // imageId就是cornerstone要求的.dcm图片地址,例如:var imageId = "wadouri:http://127.0.0.1:6699/ctdcm1.dcm"; //var imageId = "wadouri:./1.dcm"; // 初始化cornerstoneTools工具 cornerstoneTools.init(); //// 获取要用于加载图片的div区域 //element = document.getElementById('dicomImage'); ////激活获取到的用于图片加载的区域 cornerstone.enable(element); // 从cornerstoneTools库中获取窗宽,窗高工具 const WwwcTool = cornerstoneTools.WwwcTool; //添加获取到的窗宽,窗高工具 cornerstoneTools.addTool(WwwcTool); //放大 const MagnifyTool = cornerstoneTools.MagnifyTool; cornerstoneTools.addTool(MagnifyTool) //平移 const PanTool = cornerstoneTools.PanTool; cornerstoneTools.addTool(PanTool) const ZoomTool = cornerstoneTools.ZoomTool; cornerstoneTools.addTool(ZoomTool, { // Optional configuration configuration: { invert: false, preventZoomOutsideImage: false, minScale: .1, maxScale: 20.0, } }); const ZoomMouseWheelTool = cornerstoneTools.ZoomMouseWheelTool; cornerstoneTools.addTool(ZoomMouseWheelTool) const WwwcRegionTool = cornerstoneTools.WwwcRegionTool; cornerstoneTools.addTool(WwwcRegionTool) const ScaleOverlayTool = cornerstoneTools.ScaleOverlayTool; cornerstoneTools.addTool(ScaleOverlayTool) //旋转 const RotateTool = cornerstoneTools.RotateTool; cornerstoneTools.addTool(RotateTool) const OrientationMarkersTool = cornerstoneTools.OrientationMarkersTool; cornerstoneTools.addTool(OrientationMarkersTool) const AngleTool = cornerstoneTools.AngleTool; cornerstoneTools.addTool(AngleTool) const ArrowAnnotateTool = cornerstoneTools.ArrowAnnotateTool; cornerstoneTools.addTool(ArrowAnnotateTool) const BidirectionalTool = cornerstoneTools.BidirectionalTool; cornerstoneTools.addTool(BidirectionalTool) const CobbAngleTool = cornerstoneTools.CobbAngleTool; cornerstoneTools.addTool(CobbAngleTool) const EllipticalRoiTool = cornerstoneTools.EllipticalRoiTool; cornerstoneTools.addTool(EllipticalRoiTool) const FreehandRoiTool = cornerstoneTools.FreehandRoiTool; cornerstoneTools.addTool(FreehandRoiTool) const LengthTool = cornerstoneTools.LengthTool; cornerstoneTools.addTool(LengthTool) const ProbeTool = cornerstoneTools.ProbeTool; cornerstoneTools.addTool(ProbeTool) const RectangleRoiTool = cornerstoneTools.RectangleRoiTool; cornerstoneTools.addTool(RectangleRoiTool) const TextMarkerTool = cornerstoneTools.TextMarkerTool // set up the markers configuration const configuration = { markers: ['F5', 'F4', 'F3', 'F2', 'F1'], current: 'F5', ascending: true, loop: true, } cornerstoneTools.addTool(TextMarkerTool, { configuration }) const StackScrollTool = cornerstoneTools.StackScrollTool cornerstoneTools.addTool(StackScrollTool) const StackScrollMouseWheelTool = cornerstoneTools.StackScrollMouseWheelTool cornerstoneTools.addTool(StackScrollMouseWheelTool) cornerstoneTools.setToolActive('StackScrollMouseWheel', {}) } function initConerstoneAndData() { var series = stateData.dicomInfo.seriesList[stateData.imgIndex].instanceList const scheme = 'wadouri' const baseUrl = '' const imageIds = series.map(seriesImage => `${scheme}:${baseUrl}${seriesImage.imageid}`) //define the stack const stack = { currentImageIdIndex: 0, imageIds: imageIds } cornerstone.enable(stateData.element); // load images and set the stack cornerstone.loadImage(imageIds[0]).then((image) => { initSlider(stateData.element); cornerstone.displayImage(stateData.element, image) cornerstoneTools.addStackStateManager(stateData.element, ['stack']) cornerstoneTools.addToolState(stateData.element, 'stack', stack) renderTagText(stateData.element, image) }) } //页面加载完成,执行初始化 $(document).ready(function () { createElements(1, 1,true); //激活获取到的用于图片加载的区域 stateData.element = document.getElementById('dicomImage_0_0'); stateData.showMapping.set('dicomImage_0_0',0); //cornerstone.enable(stateData.element); initConerstone(stateData.element); //初始化数据 initData(); //鼠标滚轮事件 document.addEventListener('mousewheel', function (event) { // 处理事件 setAllSliderValue(); setAllTagsValue(); }); //鼠标移动事件 document.addEventListener('mousemove', function (event) { // 处理事件 setAllSliderValue(); setAllTagsValue(); }); }) //初始化右侧图片列表 function initImgList(data) { $("#dicom-list").empty(); for (var i = 0; i < data.seriesList.length; i++) { var className = "series_img"; if (stateData.imgIndex == i) { className += "_active"; } $("#dicom-list").append(''); } } //修改序列 function changeIndex(i) { if (stateData.imgIndex == i && stateData.showMapping.get(stateData.element.id) == i) { return; } $("#img_" + stateData.imgIndex).removeClass("series_img_active"); $("#img_" + stateData.imgIndex).addClass("series_img") $("#img_" + i).removeClass("series_img") $("#img_" + i).addClass("series_img_active") stateData.imgIndex = i initConerstone(stateData.element) initConerstoneAndData(); stateData.showMapping.set(stateData.element.id, i); } //获取数据 Handler/Service.ashx idx: idx, no: localData.no, orgId: localData.orgId, method: "getSeries" function initData() { var idx = GetQueryString("idx"); var localStorage = window.localStorage; var localData = JSON.parse(localStorage.data); var data= JSON.parse(localData.do); console.log("网页接受到数据"+data) stateData.dicomInfo = data; initImgList(stateData.dicomInfo); initConerstoneAndData(); /* alert(localData.regid) */ /* $.getJSON("http://127.0.0.1:5000/get-data", { }, function (data) { if ("failed" == data.status) { alert("获取数据失败") } else { console.log(data) stateData.dicomInfo = data; initImgList(stateData.dicomInfo); initConerstoneAndData(); } }); */ } //初始化滚动条 function initSlider(element) { var idx = stateData.showMapping.get(element.id); var size = stateData.dicomInfo.seriesList[idx].instanceList.length; //当前索引 var index = 0; try { var data = cornerstoneTools.getToolState(element, "stack").data[0]; index = data.currentImageIdIndex; } catch (err) { console.log('err',err) } $("#" + element.id + "-slider").attr("min", 1) $("#" + element.id + "-slider").attr("max", size) $("#" + element.id + "-slider").val(index + 1) } //选中元素 function changeElement(b) { //滚动条和上下翻页禁用 $(".operator").attr("disabled", "true"); $("#" + b.id + "-btn-next").removeAttr("disabled"); $("#" + b.id + "-btn-last").removeAttr("disabled"); $("#" + b.id + "-slider").removeAttr("disabled"); if (stateData.element == b) { $(b).parent().removeClass("dicom-img-box"); $(b).parent().addClass("dicom-img-box-active"); return; } $(b).parent().removeClass("dicom-img-box"); $(b).parent().addClass("dicom-img-box-active"); $(stateData.element).parent().removeClass("dicom-img-box-active"); $(stateData.element).parent().addClass("dicom-img-box"); stateData.element = b; } //获取URL参数 function GetQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); var r = window.location.search.substr(1).match(reg); if (r != null) return unescape(r[2]); return null; } //设置滑动条值 function setSliderValue(imgId) { //获取被选中胶片区域元素 var element = document.getElementById(imgId) var data = cornerstoneTools.getToolState(element, "stack").data[0]; var index = data.currentImageIdIndex; $("#" + imgId + "-slider").val(index+1); } function changeSlider(imgId, slider) { var sliderValue = $(slider).val(); var data = cornerstoneTools.getToolState(stateData.element, "stack").data[0]; index = sliderValue - 1; var imgId = data.imageIds[index]; data.currentImageIdIndex = index; cornerstone.loadAndCacheImage(imgId).then(function (image) { cornerstone.enable(stateData.element); cornerstone.displayImage(stateData.element, image); renderTagText(stateData.element,image) }); for (var i = 0; i < 10; i++) { if (index + i == data.imageIds.length - 1) { break; } cornerstone.loadImage(data.imageIds[index + i]).then((image) => { console.log("loaded ok " + data.imageIds[index + i]); }) } } //渲染标签文本 function renderTagText(e, i) { var tagsInfo = getDicomInfo(i); var element = $(e).parent()[0]; var boxId = element.id; //判断文本是否已经显示 if (!$("#" + boxId + "_left-top").length) { var infoElement = '
' + '
' + '
' + '
'; $(element).children().first().before(infoElement); } //左上角 var leftTop = $("#" + boxId + "_left-top"); leftTop.empty(); leftTop.append("
" + tagsInfo.patientId + "
");//体检编号 leftTop.append("
姓名:" + stateData.dicomInfo.patientname + "
");//患者姓名 leftTop.append("
" + tagsInfo.patientBirthDate + " " + (tagsInfo.patientGender == 'F' ? "男":"女") + "
"); leftTop.append("
" + tagsInfo.imageDate + "
"); //左下角 var leftBottom = $("#" + boxId + "_left-bottom"); leftBottom.empty(); leftBottom.append("
" + stateData.dicomInfo.hospital +"
"); //右上角 var rightTop = $("#" + boxId + "_right-top"); rightTop.empty(); rightTop.append("
序列:" + tagsInfo.seriesNumber + " 图像:" + tagsInfo.imageNum + "
"); //右下角 var vp = cornerstone.getViewport(e); var rightBottom = $("#" + boxId + "_right-bottom"); rightBottom.empty(); rightBottom.append("
缩放:" + vp.scale.toFixed(2) + "
"); rightBottom.append("
" + tagsInfo.width + "x" + tagsInfo.height + "
"); rightBottom.append("
窗宽:" + tagsInfo.windowWidth + " 窗位:" + tagsInfo.windowCenter + "
"); } //创建视图元素 function createElements(rowCount, columnCount,isInit) { var container = document.getElementById('dicom-continer'); if (!isInit) { clearChildren(container); } for (var i = 0; i < rowCount; i++) { //生成行 var rowDom = document.createElement('div') rowDom.setAttribute("class", "flex-row"); for (var j = 0; j < columnCount; j++) { var columnDom = document.createElement('div'); columnDom.setAttribute("class", "dicom-img-box"); columnDom.setAttribute("id", 'dicom-img-box_' + i + '_' + j) var imgId = 'dicomImage_' + i + '_' + j; $(columnDom).append('
' +'
' + '' + '' + '' + '
'); rowDom.appendChild(columnDom); } container.appendChild(rowDom); } } //清理元素 function clearChildren(element) { if (element && element.children.length > 0) { for (var i = 0; i < element.children.length; i++) { element.removeChild(element.children[i]); i--; } } } //创建视图入口 function doCreate() { let rowCount = parseInt(document.getElementById('row-count').value); let columnCount = parseInt(document.getElementById('column-count').value); if (stateData.rowCount == rowCount && stateData.columnCount == columnCount) { return; } createElements(rowCount, columnCount, false); stateData.rowCount = rowCount; stateData.columnCount = columnCount; stateData.imgIndex = 0; stateData.element = null; stateData.showMapping = new Map() }