22
33// special: for 'sparse' tiles, show a debug overlay on render.
44showDebugTiles = false ;
5+ // special: for z index multi-plane/focal images, pick only one z.
6+ whichZ = 1 ; // -1 means all no matter what.
57function DicomWebMods ( ) {
68 async function openSeries ( baseUrl , studyId , seriesId ) {
79 try {
@@ -66,6 +68,7 @@ function DicomWebMods() {
6668 // instanceWidth = tileSize*Math.ceil(instanceWidth/tileSize)
6769 instanceHeight = tileSize * Math . ceil ( instanceHeight / tileSize ) ;
6870 let tileMap = { } ;
71+ let uniquePhysZ = [ ] ;
6972 if ( x [ '52009230' ] ?. Value &&
7073 Array . isArray ( x [ '52009230' ] . Value ) &&
7174 x [ '52009230' ] . Value . length > 0 ) {
@@ -78,14 +81,16 @@ function DicomWebMods() {
7881 const row = item ?. [ '0048021F' ] ?. Value ?. [ 0 ] ;
7982 const physRow = item ?. [ '0040072A' ] ?. Value ?. [ 0 ] ;
8083 const physCol = item ?. [ '0040073A' ] ?. Value ?. [ 0 ] ;
84+ const physZ = item ?. [ '0040074A' ] ?. Value ?. [ 0 ] ;
8185 if ( col !== undefined && row !== undefined && tileSize ) {
8286 const tileX = Math . floor ( ( col - 1 ) / tileSize ) ;
8387 const tileY = Math . floor ( ( row - 1 ) / tileSize ) ;
84- tileMap [ `${ tileX } _${ tileY } ` ] = { 'idx' : i + 1 , 'col' : col - 1 , 'row' : row - 1 , 'physRow' : physRow , 'physCol' : physCol } ;
88+ tileMap [ `${ tileX } _${ tileY } ` ] = { 'idx' : i + 1 , 'col' : col - 1 , 'row' : row - 1 , 'physRow' : physRow , 'physCol' : physCol , 'physZ' : physZ } ;
8589 // console.log(row, col, tileX, tileY, i+1)
8690 }
8791 }
8892 console . log ( tileMap ) ;
93+ uniquePhysZ = [ ...new Set ( Object . values ( tileMap ) . map ( tile => tile . physZ ) ) ] . sort ( ( a , b ) => a - b ) ;
8994 }
9095
9196 return {
@@ -95,20 +100,21 @@ function DicomWebMods() {
95100 url : x [ 'url' ] ?. split ( '/metadata' ) [ 0 ] ?? '' ,
96101 type : x [ '00080008' ] ?. [ 'Value' ] ?? [ ] ,
97102 tileMap : tileMap ,
103+ uniquePhysZ : uniquePhysZ ,
98104 } ;
99105 } catch ( error ) {
100106 console . error ( 'Error processing instance metadata:' , error ) ;
101107 return null ;
102108 }
103109 } ) . filter ( ( x ) => {
104- if ( x == null || x . height == null || x . width == null || x . height < x . tileSize || x . width < x . tileSize ) {
110+ if ( x == null || x . height == null || x . width == null ) {
105111 return false ;
106112 }
107113 let types = x [ 'type' ] ;
108114 for ( let i = 0 ; i < types . length ; i ++ ) {
109115 let v = types [ i ] . toUpperCase ( ) ;
110116 if ( v . indexOf ( 'LABEL' ) !== - 1 ||
111- v . indexOf ( 'THUMBNAIL' ) !== - 1 ||
117+ v . indexOf ( 'THUMBNAIL' ) !== - 1 ||
112118 v . indexOf ( 'MACRO' ) !== - 1 ||
113119 v . indexOf ( 'OVERVIEW' ) !== - 1 ) {
114120 return false ;
@@ -129,6 +135,18 @@ function DicomWebMods() {
129135 instanceResults . forEach ( ( item , index ) => {
130136 item . order = index ;
131137 } ) ;
138+ // get a true list of possible z values
139+ const globalUniquePhysZ = [
140+ ...new Set ( instanceResults . flatMap ( inst => inst . uniquePhysZ ) )
141+ ] . sort ( ( a , b ) => a - b ) ;
142+
143+ // picking a z slice
144+ if ( whichZ == - 1 || globalUniquePhysZ . length == 0 ) {
145+ whichZ = false ; // sinal no slices to filter between
146+ } else {
147+ whichZ = Math . min ( Math . max ( whichZ , 0 ) , globalUniquePhysZ . length )
148+ instanceResults = instanceResults . filter ( inst => inst . uniquePhysZ . includes ( globalUniquePhysZ [ whichZ ] ) )
149+ }
132150
133151 if ( showDebugTiles ) {
134152 let newInstanceResults = [ ] ;
@@ -187,7 +205,9 @@ function DicomWebMods() {
187205 let tileCol = x [ 'tileMap' ] [ `${ xPos } _${ yPos } ` ] [ 'col' ] ;
188206 let physRow = x [ 'tileMap' ] [ `${ xPos } _${ yPos } ` ] [ 'physRow' ] ;
189207 let physCol = x [ 'tileMap' ] [ `${ xPos } _${ yPos } ` ] [ 'physCol' ] ;
190- if ( tileIdx !== undefined ) {
208+ let physZ = x [ 'tileMap' ] [ `${ xPos } _${ yPos } ` ] [ 'physZ' ] ;
209+
210+ if ( tileIdx !== undefined && ( whichZ === false || physZ == globalUniquePhysZ [ whichZ ] ) ) {
191211 let tileUrl = `${ x [ 'url' ] } /frames/${ tileIdx } /rendered` ;
192212 let lgFont = 50 * ( x [ 'tileSize' ] / 1024 ) ;
193213 let smFont = 30 * ( x [ 'tileSize' ] / 1024 ) ;
@@ -200,9 +220,10 @@ function DicomWebMods() {
200220 <text x="50%" y="35%" font-size="${ smFont } " text-anchor="middle" fill="#000">dcm C: ${ tileCol } </text>
201221 <text x="50%" y="40%" font-size="${ smFont } " text-anchor="middle" fill="#000">phys R: ${ physRow } </text>
202222 <text x="50%" y="45%" font-size="${ smFont } " text-anchor="middle" fill="#000">phys C: ${ physCol } </text>
203- <text x="50%" y="60%" font-size="${ smFont } " text-anchor="middle" fill="#000">L: ${ level } </text>
204- <text x="50%" y="65%" font-size="${ smFont } " text-anchor="middle" fill="#000">X: ${ xPos } </text>
205- <text x="50%" y="70%" font-size="${ smFont } " text-anchor="middle" fill="#000">Y: ${ yPos } </text>
223+ <text x="50%" y="55%" font-size="${ smFont } " text-anchor="middle" fill="#000">phys Z: ${ physZ } </text>
224+ <text x="50%" y="65%" font-size="${ smFont } " text-anchor="middle" fill="#000">L: ${ level } </text>
225+ <text x="50%" y="70%" font-size="${ smFont } " text-anchor="middle" fill="#000">X: ${ xPos } </text>
226+ <text x="50%" y="75%" font-size="${ smFont } " text-anchor="middle" fill="#000">Y: ${ yPos } </text>
206227 </svg>
207228 ` ;
208229 const encoded = encodeURIComponent ( svg )
0 commit comments