Skip to content
New issue

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

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

Already on GitHub? # to your account

feat(plugin): add asus web storage SSO plugin #48

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bluelight/data/configAsusSso.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"enabled": false,
"loginUrl": "<Your Raccoon SSO Login URL>",
"redirectUrl": "<BlueLight asusSsoCallback.html URL>",
"tokenInRequest": true
}
1 change: 1 addition & 0 deletions bluelight/data/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"plugin": [
{"path":"../scripts/plugin/oauth.js", "name": "oauth", "disableCatch": "true"},
{"path":"../scripts/plugin/asusSso/asusSso.js", "name": "asusSso", "disableCatch": "true"},
{"path":"../scripts/plugin/mpr2.js", "name": "MPR", "disableCatch": "true"},
{"path":"../scripts/plugin/mpr.js", "name": "MPR", "disableCatch": "true"},
{"path":"../scripts/plugin/vr.js", "name": "VR", "disableCatch": "true"},
Expand Down
55 changes: 55 additions & 0 deletions bluelight/html/asusSsoCallback.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<!DOCTYPE html>
<html>
<head></head>
<body>
Processing SSO login...
</body>
</html>

<script>
(async function () {
let config = await loadConfig("../data/configAsusSso.json");

if (config.enabled) {
let loginUrl = config.loginUrl;

window.addEventListener("message", (event) => {
const allowedOrigin = new URL(
loginUrl
).origin;
if (event.origin !== allowedOrigin) return;

if (event.data.type === "SSO_TOKEN" && event.data.token) {
localStorage.setItem(
"asusWebStorageToken",
event.data.token
);
window.location.href =
localStorage.getItem("bluelightUrl") ||
"/bluelight/html/start.html";
}
});

const iframe = document.createElement("iframe");
iframe.style.display = "none";
iframe.src = loginUrl;
document.body.append(iframe);
}

async function loadConfig(url) {
return new Promise((resolve, reject) => {
let config = {};
let requestURL = url;
let request = new XMLHttpRequest();
request.open("GET", requestURL);
request.responseType = "json";
request.send();

request.onload = function () {
config = request.response;
return resolve(config);
};
});
}
})();
</script>
6 changes: 3 additions & 3 deletions bluelight/html/start.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
<script src="../scripts/external/cornerstone/dicomParser.js" async></script>
<script src="../scripts/external/cornerstone/dataDictionary.js"></script>

<script src="../scripts/external/cornerstone/decode/decodeImageFrame2.js"></script>
<!--<script type="module">
<!-- <script src="../scripts/external/cornerstone/decode/decodeImageFrame2.js"></script> -->
<script type="module">
import { decodeImageFrame } from "../scripts/external/cornerstone/decode/decodeImageFrame.js";
window.decodeImage = decodeImageFrame;
</script>-->
</script>

<script src="../scripts/onload.js"></script>
<script src="../scripts/patient.js"></script>
Expand Down
38 changes: 38 additions & 0 deletions bluelight/scripts/external/cornerstone/codecs/openjpegjs.js

Large diffs are not rendered by default.

Binary file not shown.
37 changes: 37 additions & 0 deletions bluelight/scripts/external/cornerstone/codecs/openjpegjs_decode.js

Large diffs are not rendered by default.

Binary file not shown.
21 changes: 21 additions & 0 deletions bluelight/scripts/external/cornerstone/codecs/openjpegwasm.js

Large diffs are not rendered by default.

Binary file not shown.

Large diffs are not rendered by default.

Binary file not shown.
256 changes: 89 additions & 167 deletions bluelight/scripts/external/cornerstone/decode/decoders/decodeJPEG2000.js
Original file line number Diff line number Diff line change
@@ -1,172 +1,94 @@
import OpenJPEG from '../../codecs/openJPEG-FixedMemory.js';
import JpxImage from '../../codecs/jpx.min.js';

function decodeJpx(imageFrame, pixelData) {
const jpxImage = new JpxImage();

jpxImage.parse(pixelData);

const tileCount = jpxImage.tiles.length;

if (tileCount !== 1) {
throw new Error(
`JPEG2000 decoder returned a tileCount of ${tileCount}, when 1 is expected`
);
}

imageFrame.columns = jpxImage.width;
imageFrame.rows = jpxImage.height;
imageFrame.pixelData = jpxImage.tiles[0].items;

return imageFrame;
}

let openJPEG;

function decodeOpenJPEG(data, bytesPerPixel, signed) {
const dataPtr = openJPEG._malloc(data.length);

openJPEG.writeArrayToMemory(data, dataPtr);

// create param outpout
const imagePtrPtr = openJPEG._malloc(4);
const imageSizePtr = openJPEG._malloc(4);
const imageSizeXPtr = openJPEG._malloc(4);
const imageSizeYPtr = openJPEG._malloc(4);
const imageSizeCompPtr = openJPEG._malloc(4);

const t0 = new Date().getTime();
const ret = openJPEG.ccall(
'jp2_decode',
'number',
['number', 'number', 'number', 'number', 'number', 'number', 'number'],
[
dataPtr,
data.length,
imagePtrPtr,
imageSizePtr,
imageSizeXPtr,
imageSizeYPtr,
imageSizeCompPtr,
]
);
// add num vomp..etc

if (ret !== 0) {
console.log('[opj_decode] decoding failed!');
openJPEG._free(dataPtr);
openJPEG._free(openJPEG.getValue(imagePtrPtr, '*'));
openJPEG._free(imageSizeXPtr);
openJPEG._free(imageSizeYPtr);
openJPEG._free(imageSizePtr);
openJPEG._free(imageSizeCompPtr);

return;
}

const imagePtr = openJPEG.getValue(imagePtrPtr, '*');

const image = {
length: openJPEG.getValue(imageSizePtr, 'i32'),
sx: openJPEG.getValue(imageSizeXPtr, 'i32'),
sy: openJPEG.getValue(imageSizeYPtr, 'i32'),
nbChannels: openJPEG.getValue(imageSizeCompPtr, 'i32'), // hard coded for now
perf_timetodecode: undefined,
pixelData: undefined,
};

// Copy the data from the EMSCRIPTEN heap into the correct type array
const length = image.sx * image.sy * image.nbChannels;
const src32 = new Int32Array(openJPEG.HEAP32.buffer, imagePtr, length);

if (bytesPerPixel === 1) {
if (Uint8Array.from) {
image.pixelData = Uint8Array.from(src32);
} else {
image.pixelData = new Uint8Array(length);
for (let i = 0; i < length; i++) {
image.pixelData[i] = src32[i];
}
import { OpenJPEGWASM } from '../../codecs/openjpegwasm_decode.js';
const openjpegWasm = new URL('../../codecs/openjpegwasm_decode.wasm', import.meta.url);
const local = {
codec: undefined,
decoder: undefined,
decodeConfig: {},
};

(function initialize(decodeConfig) {
local.decodeConfig = decodeConfig;
if (local.codec) {
return;
}
} else if (signed) {
if (Int16Array.from) {
image.pixelData = Int16Array.from(src32);
} else {
image.pixelData = new Int16Array(length);
for (let i = 0; i < length; i++) {
image.pixelData[i] = src32[i];
}
}
} else if (Uint16Array.from) {
image.pixelData = Uint16Array.from(src32);
} else {
image.pixelData = new Uint16Array(length);
for (let i = 0; i < length; i++) {
image.pixelData[i] = src32[i];
}
}

const t1 = new Date().getTime();

image.perf_timetodecode = t1 - t0;

// free
openJPEG._free(dataPtr);
openJPEG._free(imagePtrPtr);
openJPEG._free(imagePtr);
openJPEG._free(imageSizePtr);
openJPEG._free(imageSizeXPtr);
openJPEG._free(imageSizeYPtr);
openJPEG._free(imageSizeCompPtr);

return image;
}

function decodeOpenJpeg2000(imageFrame, pixelData) {
const bytesPerPixel = imageFrame.bitsAllocated <= 8 ? 1 : 2;
const signed = imageFrame.pixelRepresentation === 1;

const image = decodeOpenJPEG(pixelData, bytesPerPixel, signed);

imageFrame.columns = image.sx;
imageFrame.rows = image.sy;
imageFrame.pixelData = image.pixelData;
if (image.nbChannels > 1) {
imageFrame.photometricInterpretation = 'RGB';
}

return imageFrame;
OpenJPEGWASM({
locateFile: (f) => {
console.log("locateFile", f);
if (f.endsWith('.wasm')) {
return openjpegWasm.toString();
}
return f;
},
}).then(instance => {

local.decoder = new instance.J2KDecoder();
console.log("loaded jpeg2000 decoder", local.decoder);
}).catch(error => {
console.error("Failed to initialize JPEG2000 decoder:", error);
});
})(local.decodeConfig);

function decodeAsync(imageInfo, compressedImageFrame) {
const decoder = local.decoder;
const encodedBufferInWASM = decoder.getEncodedBuffer(compressedImageFrame.length);
encodedBufferInWASM.set(compressedImageFrame);
decoder.decode();
const frameInfo = decoder.getFrameInfo();
const decodedBufferInWASM = decoder.getDecodedBuffer();
const imageFrame = new Uint8Array(decodedBufferInWASM.length);
imageFrame.set(decodedBufferInWASM);
const imageOffset = `x: ${decoder.getImageOffset().x}, y: ${decoder.getImageOffset().y}`;
const numDecompositions = decoder.getNumDecompositions();
const numLayers = decoder.getNumLayers();
const progessionOrder = ['unknown', 'LRCP', 'RLCP', 'RPCL', 'PCRL', 'CPRL'][decoder.getProgressionOrder() + 1];
const reversible = decoder.getIsReversible();
const blockDimensions = `${decoder.getBlockDimensions().width} x ${decoder.getBlockDimensions().height}`;
const tileSize = `${decoder.getTileSize().width} x ${decoder.getTileSize().height}`;
const tileOffset = `${decoder.getTileOffset().x}, ${decoder.getTileOffset().y}`;
const colorTransform = decoder.getColorSpace();
const decodedSize = `${decodedBufferInWASM.length.toLocaleString()} bytes`;
const compressionRatio = `${(decodedBufferInWASM.length / encodedBufferInWASM.length).toFixed(2)}:1`;
const encodedImageInfo = {
columns: frameInfo.width,
rows: frameInfo.height,
bitsPerPixel: frameInfo.bitsPerSample,
signed: frameInfo.isSigned,
bytesPerPixel: imageInfo.bytesPerPixel,
componentsPerPixel: frameInfo.componentCount,
};
const pixelData = getPixelData(frameInfo, decodedBufferInWASM);
const encodeOptions = {
imageOffset,
numDecompositions,
numLayers,
progessionOrder,
reversible,
blockDimensions,
tileSize,
tileOffset,
colorTransform,
decodedSize,
compressionRatio,
};
return {
...imageInfo,
pixelData,
imageInfo: encodedImageInfo,
encodeOptions,
...encodeOptions,
...encodedImageInfo,
};
}

function initializeJPEG2000(decodeConfig) {
// check to make sure codec is loaded
if (!decodeConfig.usePDFJS) {
if (typeof OpenJPEG === 'undefined') {
throw new Error('OpenJPEG decoder not loaded');
function getPixelData(frameInfo, decodedBuffer) {
if (frameInfo.bitsPerSample > 8) {
if (frameInfo.isSigned) {
return new Int16Array(decodedBuffer.buffer, decodedBuffer.byteOffset, decodedBuffer.byteLength / 2);
}
return new Uint16Array(decodedBuffer.buffer, decodedBuffer.byteOffset, decodedBuffer.byteLength / 2);
}
}

if (!openJPEG) {
openJPEG = OpenJPEG();
if (!openJPEG || !openJPEG._jp2_decode) {
throw new Error('OpenJPEG failed to initialize');
if (frameInfo.isSigned) {
return new Int8Array(decodedBuffer.buffer, decodedBuffer.byteOffset, decodedBuffer.byteLength);
}
}
return new Uint8Array(decodedBuffer.buffer, decodedBuffer.byteOffset, decodedBuffer.byteLength);
}

function decodeJPEG2000(imageFrame, pixelData, decodeConfig, options = {}) {
initializeJPEG2000(decodeConfig);

if (options.usePDFJS || decodeConfig.usePDFJS) {
// OHIF image-JPEG2000 https://github.com/OHIF/image-JPEG2000
// console.log('PDFJS')
return decodeJpx(imageFrame, pixelData);
}

// OpenJPEG2000 https://github.com/jpambrun/openjpeg
// console.log('OpenJPEG')
return decodeOpenJpeg2000(imageFrame, pixelData);
}

export default decodeJPEG2000;
export { initializeJPEG2000 };
export default decodeAsync;
Loading
Loading