Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multichannel Imaging Support #654

Closed
wants to merge 18 commits into from
Closed
33 changes: 23 additions & 10 deletions apps/multi/multi.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<script type="text/javascript" src="../../core/openseadragon/openseadragon.js"></script>
<script src="../../core/Store.js"></script>
<script src="../../common/PathdbMods.js"></script>
<link rel="stylesheet" href="./style.css">
<title>Select an Image</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sample Images</title>
</head>
<body>
<h1> Images </h1>
<div id="pages"></div>
<div id="workspace" class="flex-grid"></div>
<h1>Sample HSI Images</h1>
<div id="imageList"></div>

<script>
document.addEventListener('DOMContentLoaded', function() {
fetch('/sample_images')
.then(response => response.json())
.then(data => {
const imageList = document.getElementById('imageList');
data.sample_files.forEach(file => {
const imgElement = document.createElement('img');
imgElement.src = `static/mat_files/${file}.jpg`; // Assuming you have JPEG versions for preview
imgElement.alt = `Sample Image ${file}`;
imageList.appendChild(imgElement);
});
})
.catch(error => console.error('Error:', error));
});
</script>
</body>
<script src="./multi.js"></script>
</html>
109 changes: 14 additions & 95 deletions apps/multi/multi.js
Original file line number Diff line number Diff line change
@@ -1,95 +1,14 @@
// initalize dependencies and params
let store = new Store('../../data/');
const urlParams = new URLSearchParams(window.location.search);
const page = parseInt(urlParams.get('p'), 10) || 0;
const mode = urlParams.get('mode');
const MAX_TILES = parseInt(urlParams.get('mt'), 10) || 16;
const prefixUrl = 'https://cdn.jsdelivr.net/npm/openseadragon@2.3/build/openseadragon/images/';
let query = JSON.parse(urlParams.get('q') || '{}');
let list = JSON.parse(urlParams.get('l') || '[]');

let viewers = [];

// run the pathdb mods as needed
if (mode == 'pathdb') {
PathDbMods();
}

const workspace = document.getElementById('workspace');

function addTile(url, i, name, dest) {
let d = document.createElement('div');
d.id = 'osd' + i;
d.className = 'osd col';
// tile size, and hidden to start
d.style = 'min-width: 400px; width:22%; height:400px';
// add link to slide
let b = document.createElement('a');
b.id = 'link' + i;
b.innerText = name;
b.href=dest;
d.appendChild(b);
d.appendChild(document.createElement('br'));
workspace.appendChild(d);
viewers[i] = OpenSeadragon({
id: d.id,
prefixUrl: prefixUrl,
tileSources: url,
});
}

function onInit() {
let promises = [];
if (list.length) {
for (j of list) {
promises.push(store.getSlide(j));
}
} else {
if (mode == 'pathdb') {
// use pathdb query instead
// promises.push(store.findSlide(null, null, null, null, query));
} else {
promises.push(store.findSlide(null, null, null, null, query));
}
}
Promise.all(promises).then((xx)=>{
let x = xx.flat();
// pagination
// previous?
if (page > 0) {
let p = document.createElement('a');
let prevParam = new URLSearchParams(window.location.search);
p.id = 'prevPage';
prevParam.set('p', page-1);
p.innerText = 'Prev';
p.href = './multi.html?' + prevParam.toString();
document.getElementById('pages').append(p);
}
// next?
if (page < Math.floor(x.length/MAX_TILES)-1) {
let p = document.createElement('a');
let nextParam = new URLSearchParams(window.location.search);
p.id = 'nextPage';
nextParam.set('p', page+1);
p.innerText = 'Next';
p.href = './multi.html?' + nextParam.toString();
document.getElementById('pages').append(p);
}
// tiles
let start = MAX_TILES * page;
let stop = Math.min(x.length, start+MAX_TILES);
for (let n = start; n < stop; n++) {
let item = x[n];
let loc = '../../img/IIP/raw/?DeepZoom=' + item.location + '.dzi';
let dest = '../viewer/viewer.html?slideId=' + item._id['$oid'];
if (mode == 'pathdb') {
dest += '&mode=pathdb';
}
addTile(loc, n, item.name, dest);
}
});
}

// TODO pagination

window.onload = onInit;
document.addEventListener('DOMContentLoaded', function() {
fetch('../../multichannel/')
.then(response => response.json())
.then(data => {
const imageList = document.getElementById('imageList');
data.sample_files.forEach(file => {
const imgElement = document.createElement('img');
imgElement.src = `static/mat_files/${file}.jpg`; // Assuming you have JPEG versions for preview
imgElement.alt = `Sample Image ${file}`;
imageList.appendChild(imgElement);
});
})
.catch(error => console.error('Error:', error));
});
38 changes: 38 additions & 0 deletions apps/multichannelimage/channel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const fileName = 'hsi1'; // This should be dynamically set based on the file chosen
document.getElementById('fileName').textContent = fileName;

fetch(`/bands/${fileName}`)
.then(response => response.json())
.then(data => {
const form = document.getElementById('bandSelectionForm');
for(let i = 0; i < data.num_bands; i++) {
const label = document.createElement('label');
label.textContent = `Band ${i}: `;
const select = document.createElement('select');
select.name = `band_${i}`;
['None', 'R', 'G', 'B'].forEach(color => {
const option = document.createElement('option');
option.value = color;
option.textContent = color;
select.appendChild(option);
});
label.appendChild(select);
form.appendChild(label);
form.appendChild(document.createElement('br'));
}
})
.catch(error => console.error('Error:', error));

document.getElementById('viewImageButton').addEventListener('click', function() {
const form = document.getElementById('bandSelectionForm');
const formData = new FormData(form);
fetch(`../../multichannel/select_bands/${fileName}`, {
method: 'POST',
body: formData
})
.then(response => {
if(response.ok) return response.json();
throw new Error('Network response was not ok.');
})
.catch(error => console.error('Error:', error));
});
18 changes: 18 additions & 0 deletions apps/multichannelimage/channels.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Select Bands</title>
</head>
<body>
<h1>Select Bands for <span id="fileName"></span></h1>
<form id="bandSelectionForm">
<!-- Band selection checkboxes will be inserted here -->
</form>

<button id="viewImageButton">View Image</button>
<script src="channel.js">
</script>
</body>
</html>
14 changes: 14 additions & 0 deletions apps/multichannelimage/multichannel.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="../../core/openseadragon/openseadragon.js"></script>
<link rel="stylesheet" href="./style.css">
<title>Multi channel image support</title>
</head>
<body>
<button id="chooseButton">Choose</button> <!-- Replace "Check" with a button -->
<div id="pages"></div>
<div id="workspace" class="flex-grid"></div>
</body>
<script src="./multichannel.js"></script>
</html>
14 changes: 14 additions & 0 deletions apps/multichannelimage/multichannel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
document.addEventListener('DOMContentLoaded', function() {
fetch('../../multichannel/')
.then(response => response.json())
.then(data => {
const imageList = document.getElementById('imageList');
data.sample_files.forEach(file => {
const imgElement = document.createElement('img');
imgElement.src = `static/mat_files/${file}.jpg`; // Assuming you have JPEG versions for preview
imgElement.alt = `Sample Image ${file}`;
imageList.appendChild(imgElement);
});
})
.catch(error => console.error('Error:', error));
});
46 changes: 46 additions & 0 deletions apps/multichannelimage/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#openseadragon-viewer {
width: 100%;
height: 750px;
}

body {
font-family: Arial, sans-serif;
background-color: #f2f2f2;
padding: 20px;
}

.container {
max-width: 800px;
margin: 0 auto;
background-color: #fff;
padding: 20px;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}

h2 {
text-align: center;
margin-bottom: 20px;
}

.form-container {
text-align: center;
margin-bottom: 20px;
}

.form-container input[type="file"] {
display: none;
}

.form-container label {
display: inline-block;
padding: 10px 20px;
background-color: #4CAF50;
color: #fff;
cursor: pointer;
border-radius: 5px;
}

.form-container label:hover {
background-color: #45a049;
}
24 changes: 24 additions & 0 deletions apps/multichannelimage/viewer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<title>Multi-channel Viewer</title>
<style>
body, html {
margin: 0;
padding: 0;
overflow: hidden;
width: 100%;
height: 100%;
}
#openseadragon-viewer {
width: 100%;
height: 750px;
}
</style>
<script src="../../core/openseadragon/openseadragon.min.js"></script>
<script src="viewer.js"></script>
</head>
<body>
<div id="openseadragon-viewer"></div>
</body>
</html>
34 changes: 34 additions & 0 deletions apps/multichannelimage/viewer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*function getParameterByName(name, url) {
console.log(name);
console.log(url);
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
*/
const dziPath = "44153.tif";
console.log(dziPath);
const channelOrder = [0,1,2];
console.log(channelOrder);

const viewer = OpenSeadragon({
id: "openseadragon-viewer",
prefixUrl: "../../core/openseadragon/images/",
tileSources: dziPath,// try to create an API and avoid saving it in local disk
// resource: https://openseadragon.github.io/examples/tilesource-dzi/
// resource: https://openseadragon.github.io/examples/tilesource-custom/
preserveViewport: true,
visibilityRatio: 1,
defaultZoomLevel: 0,
maxZoomPixelRatio: 1
});
function updateChannelOrder() {
const currentImage = viewer.world.getItemAt(0).getItems()[0];
currentImage.setChannelOrder(channelOrder);
currentImage.draw();
}
updateChannelOrder();