Skip to content

Commit 58b71dd

Browse files
committed
cornerstone: display NIfTI and dicom image previews
1 parent 0a6885b commit 58b71dd

File tree

5 files changed

+68
-0
lines changed

5 files changed

+68
-0
lines changed

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
"node": ">= 14.0.0"
88
},
99
"dependencies": {
10+
"cornerstone-core": "^2.6.1",
11+
"cornerstone-tools": "^6.0.8",
12+
"@cornerstonejs/nifti-image-loader": "^1.0.7",
13+
"cornerstone-wado-image-loader": "^4.3.0",
14+
"dicom-parser": "^1.8.19",
1015
"@citation-js/core": "0.6.5",
1116
"@citation-js/plugin-bibtex": "0.6.5",
1217
"@citation-js/plugin-csl": "0.6.5",

routers/web/repo/view.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,10 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
597597
case fInfo.st.IsImage() && (setting.UI.SVG.Enabled || !fInfo.st.IsSvgImage()):
598598
ctx.Data["IsImageFile"] = true
599599
ctx.Data["CanCopyContent"] = true
600+
case strings.HasSuffix(strings.ToLower(blob.Name()), ".nii") || strings.HasSuffix(strings.ToLower(blob.Name()), ".nii.gz"):
601+
ctx.Data["IsNIfTI"] = true
602+
case strings.HasSuffix(strings.ToLower(blob.Name()), ".dcm") || strings.HasSuffix(strings.ToLower(blob.Name()), ".dicom"):
603+
ctx.Data["IsDICOM"] = true
600604
default:
601605
if fInfo.fileSize >= setting.UI.MaxDisplayFileSize {
602606
ctx.Data["IsFileTooLarge"] = true

templates/repo/view_file.tmpl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@
8080
</audio>
8181
{{else if .IsPDFFile}}
8282
<iframe width="100%" height="600px" src="{{AssetUrlPrefix}}/vendor/plugins/pdfjs/web/viewer.html?file={{$.RawFileLink}}"></iframe>
83+
{{else if .IsNIfTI}}
84+
<div class="cornerstone-viewport" style="width: 100%; height: 600px" data-src="nifti:{{$.RawFileLink}}"></div>
85+
{{else if .IsDICOM}}
86+
<div class="cornerstone-viewport" style="width: 100%; height: 600px" data-src="wadouri:{{$.RawFileLink}}"></div>
8387
{{else}}
8488
<a href="{{$.RawFileLink}}" rel="nofollow" class="btn btn-gray btn-radius">{{.locale.Tr "repo.file_view_raw"}}</a>
8589
{{end}}

web_src/js/features/cornerstone.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/* CornerstoneJS is a renderer and UI toolkit meant for
2+
* medical image formats: .nii, .dcm, and some others.
3+
*
4+
* To use: create an element like
5+
*
6+
* <div class='.cornerstone-viewport' data-src='nifti:/path/to/file.nii.gz' style='width: 100%; height 500px'></div>
7+
*
8+
* and file.nii.gz will load when the page loads.
9+
*
10+
* Swap out 'nifti' for 'wadouri:' if using a DICOM file.
11+
*
12+
*
13+
* **NOTE**: this is written using the _legacy_ cornerstone library,
14+
* cornerstone-core, and is *not* compatible with the rewrite
15+
* @cornerstonejs/core because @cornerstonejs/nifti-image-loader
16+
* isn't: https://github.com/cornerstonejs/cornerstone-nifti-image-loader/issues/48#issuecomment-1271794397
17+
* and rendering NIfTIs is the main reason this is here at all.
18+
*/
19+
20+
export async function initCornerstone() {
21+
if (!document.querySelector('.cornerstone-viewport')) return;
22+
23+
const cornerstone = await import( /* webpackChunkName: "cornerstone-core" */ 'cornerstone-core');
24+
const dicomParser = await import( /* webpackChunkName: "dicom-parser" */ 'dicom-parser');
25+
const cornerstoneWADOImageLoader = await import( /* webpackChunkName: "cornerstone-wado-image-loader" */ 'cornerstone-wado-image-loader');
26+
const cornerstoneNIFTIImageLoader = await import( /* webpackChunkName: "@cornerstonejs/nifti-image-loader" */ '@cornerstonejs/nifti-image-loader');
27+
28+
// why are these necessary? too much abstraction, that's why.
29+
cornerstoneWADOImageLoader.external.dicomParser = dicomParser
30+
cornerstoneWADOImageLoader.external.cornerstone = cornerstone
31+
cornerstoneNIFTIImageLoader.external.cornerstone = cornerstone
32+
33+
document.querySelectorAll('.cornerstone-viewport').forEach(function (canvas) {
34+
if (canvas.dataset.src === undefined) {
35+
return
36+
}
37+
cornerstone.enable(canvas)
38+
39+
console.info('Loading', canvas.dataset.src, 'into CornerstoneJS')
40+
cornerstone
41+
.loadAndCacheImage(canvas.dataset.src)
42+
.then((image) => {
43+
console.debug(image)
44+
45+
const viewport = cornerstone.getDefaultViewportForImage(canvas, image)
46+
cornerstone.displayImage(canvas, image, viewport)
47+
})
48+
.catch((err) => {
49+
console.error(err)
50+
})
51+
})
52+
53+
}

web_src/js/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ import {initCommonOrganization} from './features/common-organization.js';
8787
import {initRepoWikiForm} from './features/repo-wiki.js';
8888
import {initRepoCommentForm, initRepository} from './features/repo-legacy.js';
8989
import {initFormattingReplacements} from './features/formatting.js';
90+
import {initCornerstone} from './features/cornerstone.js';
9091
import {initCopyContent} from './features/copycontent.js';
9192
import {initCaptcha} from './features/captcha.js';
9293
import {initRepositoryActionView} from './components/RepoActionView.vue';
@@ -191,6 +192,7 @@ $(document).ready(() => {
191192

192193
initCommitStatuses();
193194
initCaptcha();
195+
initCornerstone();
194196

195197
initUserAuthLinkAccountView();
196198
initUserAuthOauth2();

0 commit comments

Comments
 (0)