!97 新增 dcm 等医疗数位影像预览

Merge pull request !97 from 高雄/dcm
pull/98/MERGE
kailing 2023-04-20 08:21:46 +00:00 committed by Gitee
commit f520001863
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
19 changed files with 86959 additions and 1 deletions

View File

@ -21,6 +21,7 @@
19. svg
20. mp3,wav,mp4,flv
21. avi,mov,rm,webm,ts,rm,mkv,mpeg,ogg,mpg,rmvb,wmv,3gp,ts,swf
22. dcm
>
###

View File

@ -25,6 +25,7 @@ Document online preview project solution, built using the popular Spring Boot fr
19. Supports vector image format files such as `svg`.
20. Supports `mp3`,`wav`,`mp4`,`flv` .
21. Supports many audio and video format files such as `avi`, `mov`, `wmv`, `mkv`, `3gp`, and `rm`.
22. Supports for `dcm` .
### Features
- Build with the popular frame spring boot

View File

@ -30,7 +30,8 @@ public enum FileType {
XMIND("xmindFilePreviewImpl"),
SVG("svgFilePreviewImpl"),
Epub("epubFilePreviewImpl"),
BPMN("bpmnFilePreviewImpl");
BPMN("bpmnFilePreviewImpl"),
DCM("dcmFilePreviewImpl");
private static final String[] OFFICE_TYPES = {"docx", "wps", "doc", "docm", "xls", "xlsx", "csv" ,"xlsm", "ppt", "pptx", "vsd", "rtf", "odt", "wmf", "emf", "dps", "et", "ods", "ots", "tsv", "odp", "otp", "sxi", "ott", "vsdx", "fodt", "fods", "xltx","tga","psd","dotm","ett","xlt","xltm","wpt","dot","xlam","dotx","xla"};
private static final String[] PICTURE_TYPES = {"jpg", "jpeg", "png", "gif", "bmp", "ico", "jfif", "webp"};
@ -39,6 +40,7 @@ public enum FileType {
private static final String[] EML_TYPES = {"eml"};
private static final String[] XMIND_TYPES = {"xmind"};
private static final String[] Epub_TYPES = {"epub"};
private static final String[] DCM_TYPES = {"dcm"};
private static final String[] TIFF_TYPES = {"tif", "tiff"};
private static final String[] OFD_TYPES = {"ofd"};
private static final String[] SVG_TYPES = {"svg"};
@ -95,6 +97,9 @@ public enum FileType {
for (String online3D : Online3D_TYPES) {
FILE_TYPE_MAPPER.put(online3D, FileType.Online3D);
}
for (String dcm : DCM_TYPES) {
FILE_TYPE_MAPPER.put(dcm, FileType.DCM);
}
FILE_TYPE_MAPPER.put("md", FileType.MARKDOWN);
FILE_TYPE_MAPPER.put("xml", FileType.XML);
FILE_TYPE_MAPPER.put("pdf", FileType.PDF);

View File

@ -29,6 +29,7 @@ public interface FilePreview {
String XML_FILE_PREVIEW_PAGE = "xml";
String MARKDOWN_FILE_PREVIEW_PAGE = "markdown";
String BPMN_FILE_PREVIEW_PAGE = "bpmn";
String DCM_FILE_PREVIEW_PAGE = "dcm";
String NOT_SUPPORTED_FILE_PAGE = "fileNotSupported";
String filePreviewHandle(String url, Model model, FileAttribute fileAttribute);

View File

@ -0,0 +1,25 @@
package cn.keking.service.impl;
import cn.keking.model.FileAttribute;
import cn.keking.service.FilePreview;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
/**
* Dcm
*/
@Service
public class DcmFilePreviewImpl implements FilePreview {
private final CommonPreviewImpl commonPreview;
public DcmFilePreviewImpl(CommonPreviewImpl commonPreview) {
this.commonPreview = commonPreview;
}
@Override
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
commonPreview.filePreviewHandle(url,model,fileAttribute);
return DCM_FILE_PREVIEW_PAGE;
}
}

View File

@ -0,0 +1,159 @@
class DICOMZero {
constructor(options={}) {
this.status = options.status || function() {};
this.reset();
}
reset() {
this.mappingLog = [];
this.dataTransfer = undefined;
this.datasets = [];
this.readers = [];
this.arrayBuffers = [];
this.files = [];
this.fileIndex = 0;
this.context = {patients: []};
}
static datasetFromArrayBuffer(arrayBuffer) {
let dicomData = dcmjs.data.DicomMessage.readFile(arrayBuffer);
let dataset = dcmjs.data.DicomMetaDictionary.naturalizeDataset(dicomData.dict);
dataset._meta = dcmjs.data.DicomMetaDictionary.namifyDataset(dicomData.meta);
return(dataset);
}
// return a function to use as the 'onload' callback for the file reader.
// The function takes a progress event argument and it knows (from this class instance)
// when all files have been read so it can invoke the doneCallback when all
// have been read.
getReadDICOMFunction(doneCallback, statusCallback) {
statusCallback = statusCallback || console.log;
return progressEvent => {
let reader = progressEvent.target;
let arrayBuffer = reader.result;
this.arrayBuffers.push(arrayBuffer);
let dicomData;
try {
dicomData = dcmjs.data.DicomMessage.readFile(arrayBuffer);
let dataset = dcmjs.data.DicomMetaDictionary.naturalizeDataset(dicomData.dict);
dataset._meta = dcmjs.data.DicomMetaDictionary.namifyDataset(dicomData.meta);
this.datasets.push(dataset);
} catch (error) {
console.error(error);
statusCallback("skipping non-dicom file");
}
let readerIndex = this.readers.indexOf(reader);
if (readerIndex < 0) {
reject("Logic error: Unexpected reader!");
} else {
this.readers.splice(readerIndex, 1); // remove the reader
}
if (this.fileIndex === this.dataTransfer.files.length) {
statusCallback(`Normalizing...`);
try {
this.multiframe = dcmjs.normalizers.Normalizer.normalizeToDataset(this.datasets);
} catch (e) {
console.error('Could not convert to multiframe');
console.error(e);
}
if (this.multiframe.SOPClassUID == dcmjs.data.DicomMetaDictionary.sopClassUIDsByName['Segmentation']){
statusCallback(`Creating segmentation...`);
try {
this.seg = new dcmjs.derivations.Segmentation([this.multiframe]);
statusCallback(`Created ${this.multiframe.NumberOfFrames} frame multiframe object and segmentation.`);
} catch (e) {
console.error('Could not create segmentation');
console.error(e);
}
} else if (this.multiframe.SOPClassUID == dcmjs.data.DicomMetaDictionary.sopClassUIDsByName['ParametricMapStorage']){
statusCallback(`Creating parametric map...`);
try {
this.pm = new dcmjs.derivations.ParametricMap([this.multiframe]);
statusCallback(`Created ${this.multiframe.NumberOfFrames} frame multiframe object and parametric map.`);
} catch (e) {
console.error('Could not create parametric map');
console.error(e);
}
}
doneCallback();
} else {
statusCallback(`Reading... (${this.fileIndex+1}).`);
this.readOneFile(doneCallback, statusCallback);
}
};
}
// Used for file selection button or drop of file list
readOneFile(doneCallback, statusCallback) {
let file = this.dataTransfer.files[this.fileIndex];
this.fileIndex++;
let reader = new FileReader();
reader.onload = this.getReadDICOMFunction(doneCallback, statusCallback);
reader.readAsArrayBuffer(file);
this.files.push(file);
this.readers.push(reader);
}
handleDataTransferFileAsDataset(file, options={}) {
options.doneCallback = options.doneCallback || function(){};
let reader = new FileReader();
reader.onload = (progressEvent) => {
let dataset = DICOMZero.datasetFromArrayBuffer(reader.result);
options.doneCallback(dataset);
}
reader.readAsArrayBuffer(file);
}
extractDatasetFromZipArrayBuffer(arrayBuffer) {
this.status(`Extracting ${this.datasets.length} of ${this.expectedDICOMFileCount}...`);
this.datasets.push(DICOMZero.datasetFromArrayBuffer(arrayBuffer));
if (this.datasets.length == this.expectedDICOMFileCount) {
this.status(`Finished extracting`);
this.zipFinishCallback();
}
};
handleZip(zip) {
this.zip = zip;
this.expectedDICOMFileCount = 0;
Object.keys(zip.files).forEach(fileKey => {
this.status(`Considering ${fileKey}...`);
if (fileKey.endsWith('.dcm')) {
this.expectedDICOMFileCount += 1;
zip.files[fileKey].async('arraybuffer').then(this.extractDatasetFromZipArrayBuffer.bind(this));
}
});
}
extractFromZipArrayBuffer(arrayBuffer, finishCallback=function(){}) {
this.zipFinishCallback = finishCallback;
this.status("Extracting from zip...");
JSZip.loadAsync(arrayBuffer)
.then(this.handleZip.bind(this));
}
organizeDatasets() {
this.datasets.forEach(dataset => {
let patientName = dataset.PatientName;
let studyTag = dataset.StudyDate + ": " + dataset.StudyDescription;
let seriesTag = dataset.SeriesNumber + ": " + dataset.SeriesDescription;
let patientNames = this.context.patients.map(patient => patient.name);
let patientIndex = patientNames.indexOf(dataset.PatientName);
if (patientIndex == -1) {
this.context.patients.push({
name: dataset.PatientName,
id: this.context.patients.length,
studies: {}
});
}
let studyNames; // TODO - finish organizing
});
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
cornerstoneTools.external.cornerstone = cornerstone;
cornerstoneTools.external.Hammer = Hammer;
cornerstoneTools.external.cornerstoneMath = cornerstoneMath;
cornerstoneTools.init();
cornerstoneTools.addTool(cornerstoneTools.BidirectionalTool);
cornerstoneTools.addTool(cornerstoneTools.ArrowAnnotateTool);
cornerstoneTools.addTool(cornerstoneTools.EllipticalRoiTool);
function getBlobUrl(url) {
const baseUrl = window.URL || window.webkitURL;
const blob = new Blob([`importScripts('${url}')`], {
type: "application/javascript"
});
return baseUrl.createObjectURL(blob);
}
const config = {
maxWebWorkers: navigator.hardwareConcurrency || 1,
startWebWorkersOnDemand: true,
webWorkerPath: getBlobUrl(
"https://unpkg.com/cornerstone-wado-image-loader/dist/cornerstoneWADOImageLoaderWebWorker.min.js"
),
webWorkerTaskPaths: [],
taskConfiguration: {
decodeTask: {
loadCodecsOnStartup: true,
initializeCodecsOnStartup: false,
codecsPath: getBlobUrl(
"https://unpkg.com/cornerstone-wado-image-loader/dist/cornerstoneWADOImageLoaderCodecs.min.js"
),
usePDFJS: false,
strict: false
}
}
};
cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
cornerstoneWADOImageLoader.external.dicomParser = dicomParser;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,103 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0">
<title>DCM</title>
<#include "*/commonHeader.ftl">
</head>
<style>
.container{
width: 100%;
height: 600px;
max-width: 900px;
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: green;
}
</style>
<body>
<#if currentUrl?contains("http://") || currentUrl?contains("https://")>
<#assign finalUrl="${currentUrl}">
<#else>
<#assign finalUrl="${baseUrl}${currentUrl}">
</#if>
<div class="container" id="cornerstoneViewport">
</div>
<script src="dcm/cornerstone.js"></script>
<script src="dcm/cornerstoneMath.js"></script>
<script src="dcm/cornerstoneTools.js"></script>
<script src="dcm/dicomParser.js"></script>
<script src="dcm/cornerstoneWADOImageLoader.bundle.min.js"></script>
<script src="dcm/hammer.min.js"></script>
<script src="dcm/initCornerstone.js"></script>
<script src="dcm/react.development.js" ></script>
<script src="dcm/react-dom.development.js"></script>
<script>
"use strict";
var process = {
env: {
NODE_ENV: "production"
}
};
window.process = process;
</script>
<script src="dcm/index.umd.js"></script>
<script>
var url = '${finalUrl}';
var baseUrl = '${baseUrl}'.endsWith('/') ? '${baseUrl}' : '${baseUrl}' + '/';
if (!url.startsWith(baseUrl)) {
url = baseUrl + 'getCorsFile?urlPath=' + encodeURIComponent(Base64.encode(url));
}
"use strict";
var imageNames = [];
for (var i = 1; i < 546; i++) {
imageNames.push(url);
}
// console.log(url);
var imageIds = imageNames.map(name => {
return 'dicomweb:'+url+'';
});
var imagePromises = imageIds.map(imageId => {
return cornerstone.loadAndCacheImage(imageId);
});
var exampleData = {
stack: {
currentImageIdIndex: 0,
imageIds: imageIds
}
};
var CornerstoneViewport = window["react-cornerstone-viewport"];
var props = {
viewportData: exampleData,
cornerstone,
cornerstoneTools,
activeTool: "Brush"
};
var app = React.createElement(CornerstoneViewport, props, null);
ReactDOM.render(
app,
document.getElementById("cornerstoneViewport")
);
/*初始化水印*/
window.onload = function () {
initWaterMark();
}
</script>
</body>
</html>

View File

@ -79,6 +79,7 @@
<li> svg </li>
<li> mp3,wav,mp4,flv </li>
<li> avi,mov,rm,webm,ts,rm,mkv,mpeg,ogg,mpg,rmvb,wmv,3gp,ts,swf </li>
<li> dcm </li>
</ol>
</div>
<#-- -->

View File

@ -46,6 +46,16 @@
<div class="page-header">
<h1></h1>
</div>
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title">20230420v4.3.0-SNAPSHOT</h3>
</div>
<div class="panel-body">
<div>
1. dcm <br>
</div>
</div>
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title">20230418v4.2.1 </h3>