.
This commit is contained in:
@@ -579,4 +579,5 @@ function delete_multiple(url, csrf_token) {
|
||||
}
|
||||
|
||||
}
|
||||
window.delete_multiple = delete_multiple
|
||||
window.delete_multiple = delete_multiple
|
||||
|
||||
|
||||
@@ -0,0 +1,373 @@
|
||||
let active_file_inputs = new Set();
|
||||
|
||||
function add_input_form() {
|
||||
var form_idx = $('#id_images-TOTAL_FORMS').val();
|
||||
$('#image_form_set').append($($('#empty_form').html().replace(/__prefix__/g, form_idx)).on("change",
|
||||
input_change));
|
||||
$('#id_images-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
||||
}
|
||||
|
||||
async function blobToBase64(blob) {
|
||||
return new Promise((resolve, _) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => resolve(reader.result);
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
|
||||
function extendInputs(form_id, n) {
|
||||
// Makes sure we have n inputs available
|
||||
// returns available inputs
|
||||
inputs = getUnusedInputs($(`#${form_id} input[type=file][id^=id_images-]`));
|
||||
//fileInput = document.getElementById("id_images-0-image");
|
||||
|
||||
|
||||
// Make sure we have enough input targets
|
||||
input_diff = (n - inputs.length)
|
||||
|
||||
if (input_diff > 0) {
|
||||
for (let j = 0; j < input_diff; j++) {
|
||||
add_input_form()
|
||||
}
|
||||
|
||||
// Need to make sure we include the new ones...
|
||||
inputs = getUnusedInputs($(`#${form_id} input[type=file][id^=id_images-]`));
|
||||
}
|
||||
return inputs;
|
||||
}
|
||||
|
||||
function getCurrentFormFiles(form_id) {
|
||||
inputs = $(`#${form_id} input[type=file]`);
|
||||
|
||||
let files = new Set();
|
||||
for (let j = 0; j < inputs.length; j++) {
|
||||
i = inputs.get(j);
|
||||
if (i.files.length > 0) {
|
||||
files.add(i.files[0]);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
function getUnusedInputs(inputs) {
|
||||
new_inputs = [];
|
||||
for (let i = 0; i < inputs.length; i++) {
|
||||
input = inputs.get(i);
|
||||
|
||||
if (!input.value) {
|
||||
new_inputs.push(input);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $(new_inputs);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function addFile(f, feedback) {
|
||||
let dT = new DataTransfer();
|
||||
dT.clearData();
|
||||
dT.items.add(f);
|
||||
for (let i = 0; i < inputs.length; i++) {
|
||||
el = inputs.get(i);
|
||||
|
||||
if (el.files.length == 0) {
|
||||
el.files = dT.files;
|
||||
//ocr(el)
|
||||
|
||||
if (feedback) {
|
||||
arr = el.name.split("-");
|
||||
arr.splice(2, 1, "feedback_image");
|
||||
feedback_el_name = arr.join("-");
|
||||
|
||||
$(`[name=${feedback_el_name}]`).prop("checked", true);
|
||||
}
|
||||
|
||||
$(el).change();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function ocr2(url, input) {
|
||||
console.log("OCR", input)
|
||||
Tesseract.recognize(
|
||||
url,
|
||||
'eng',
|
||||
//{ logger: m => console.log(m) }
|
||||
).then(({
|
||||
data: {
|
||||
text
|
||||
}
|
||||
}) => {
|
||||
l = text.toLowerCase();
|
||||
uploading_el = $(`img[data-input-id='${input.id}'], div[data-input-id='${input.id}']`)
|
||||
uploading_el.removeClass("image-ident-loading");
|
||||
console.log("found text", l);
|
||||
if (l.includes("accesion") || l.includes("number") || l.search(
|
||||
/(ref|rk9|rh8|ra9|rbz)\d+/g) > -1) {
|
||||
console.log("Match found ", input);
|
||||
$(input).addClass("image-ident-warning");
|
||||
uploading_el.addClass("image-ident-warning");
|
||||
} else {
|
||||
$(input).addClass("image-ident-ok");
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function input_change(evt) {
|
||||
file = evt.target.files[0];
|
||||
$(evt.target).removeClass("image-ident-warning");
|
||||
$(evt.target).removeClass("image-ident-ok");
|
||||
|
||||
el = evt.target;
|
||||
|
||||
readFileAndProcess2(el);
|
||||
|
||||
}
|
||||
|
||||
function showEditPopup(url) {
|
||||
var win = window.open(url, "Edit",
|
||||
'height=500,width=800,resizable=yes,scrollbars=yes');
|
||||
return false;
|
||||
}
|
||||
|
||||
function showAddPopup(triggeringLink) {
|
||||
var name = triggeringLink.id.replace(/^add_/, '');
|
||||
href = triggeringLink.href;
|
||||
var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
|
||||
win.focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
function closePopup(win, newID, newRepr, id) {
|
||||
$(id + "_to").append('<option value=' + newID + ' title=' + newRepr + ' >' + newRepr + '</option>')
|
||||
win.close();
|
||||
}
|
||||
|
||||
|
||||
async function readFileAndProcess2(el) {
|
||||
|
||||
//file_set = $("#image_form_set input[type=file]");
|
||||
|
||||
//file_set.each(async (n, el) => {
|
||||
|
||||
if (el.files.length > 0) {
|
||||
filename = el.files[0].name;
|
||||
// Probably no need to await here anymore
|
||||
//await readFile(el.files[0], el);
|
||||
|
||||
|
||||
|
||||
|
||||
$(el).parent().parent().find(".temp-thumb").remove();
|
||||
|
||||
let url = URL.createObjectURL(el.files[0])
|
||||
|
||||
n = el.id.split("-")[1];
|
||||
$(`#drop-filenames span[data-input-id='${el.id}']`).remove();
|
||||
|
||||
let extra_class = " image-ident-loading";
|
||||
if ($(el).hasClass("image-ident-warning")) {
|
||||
extra_class = " image-ident-warning";
|
||||
} else if ($(el).hasClass("image-ident-ok")) {
|
||||
extra_class = " image-ident-ok";
|
||||
}
|
||||
|
||||
//let extra_class = "";
|
||||
let imageId;
|
||||
if (el.files[0].type.startsWith("image")) {
|
||||
|
||||
let hash = CryptoJS.MD5(el.files[0]).toString();
|
||||
|
||||
base = await blobToBase64(el.files[0]);
|
||||
imageId = "base64://" + base.split(",")[1];
|
||||
imageId2 = base;
|
||||
const element = $(`<img class='temp-thumb' src=${imageId}></div>`).get(0)
|
||||
$(el).parent().parent().prepend(element);
|
||||
|
||||
|
||||
ocr2(url, el);
|
||||
checkHash(hash, el);
|
||||
|
||||
if ($("#drop-filenames").length > 0) {
|
||||
$("#drop-filenames").append(
|
||||
`<span data-input-id='${el.id}'><span>${n}: ${el.files[0].name}</span><img class='uploading${extra_class}' data-input-id='${el.id}' src=${url}></span>`
|
||||
)
|
||||
}
|
||||
} else {
|
||||
imageId = `wadouri:${url}`;
|
||||
imageId2 = imageId
|
||||
|
||||
const element = $(`<div class='temp-thumb' src=${imageId2}></div>`).get(0)
|
||||
$(el).parent().parent().prepend(element);
|
||||
cornerstone.enable(element);
|
||||
cornerstone.loadAndCacheImage(imageId).then(function (image) {
|
||||
cornerstone.displayImage(element, image);
|
||||
cornerstone.resize(element)
|
||||
|
||||
|
||||
if (hash_url) {
|
||||
let pixel_data = image.getPixelData().toString()
|
||||
|
||||
let hash = CryptoJS.MD5(pixel_data).toString();
|
||||
checkHash(hash, el);
|
||||
}
|
||||
|
||||
|
||||
console.log("image", image)
|
||||
|
||||
extractDicomDetails(image.data.byteArray)
|
||||
|
||||
});
|
||||
|
||||
if ($("#drop-filenames").length > 0) {
|
||||
$("#drop-filenames").append(
|
||||
`<span data-input-id='${el.id}'><span>${n}: ${el.files[0].name}</span><div class='uploading${extra_class}' data-input-id='${el.id}' src=${url}></div></span>`
|
||||
)
|
||||
|
||||
const element2 = $(`#drop-filenames div[data-input-id='${el.id}']`).get(0);
|
||||
cornerstone.enable(element2);
|
||||
cornerstone.loadAndCacheImage(imageId).then(function (image) {
|
||||
cornerstone.displayImage(element2, image);
|
||||
|
||||
$(element2).addClass("temp-thumb-large");
|
||||
cornerstone.resize(element2)
|
||||
setTimeout(function () {
|
||||
ocr2($(element2).find("canvas").get(0).toDataURL(), el);
|
||||
$(element2).removeClass("temp-thumb-large");
|
||||
cornerstone.resize(element2)
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
active_file_inputs.delete(el)
|
||||
console.log("active", active_file_inputs)
|
||||
// Only load once all queued files have been processed
|
||||
if (active_file_inputs.size < 1) {
|
||||
//load_viewer = true;
|
||||
loadViewer();
|
||||
}
|
||||
}
|
||||
//})
|
||||
}
|
||||
|
||||
function checkHash(hash, input, url) {
|
||||
$.ajax({
|
||||
url: hash_url,
|
||||
data: {
|
||||
csrfmiddlewaretoken: csrf_token,
|
||||
hash: hash
|
||||
},
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
})
|
||||
// $.ajax().done(), $.ajax().fail(), $ajax().always() are upto you. Add/change accordingly
|
||||
.done(function (data) {
|
||||
console.log(data);
|
||||
|
||||
if (data.status == "success") {
|
||||
console.log("success");
|
||||
console.log(data.id)
|
||||
if (data.id) {
|
||||
//toastr.info(`id ${data.id}`)
|
||||
uploading_el = $(`img[data-input-id='${input.id}'], div[data-input-id='${input.id}']`)
|
||||
$(input).addClass("image-duplicate");
|
||||
uploading_el.addClass("image-duplicate");
|
||||
|
||||
toastr.warning(`Image (${input.files[0].name}) already exists.<br /><a href='${data.url}'>Click to view</a><br /><button type="button" class="btn clear">Dismiss</button>`, "Duplicate image", {
|
||||
"closeButton": false,
|
||||
"debug": false,
|
||||
"newestOnTop": false,
|
||||
"progressBar": false,
|
||||
"positionClass": "toast-top-full-width",
|
||||
"preventDuplicates": false,
|
||||
"onclick": null,
|
||||
"showDuration": "0",
|
||||
"hideDuration": "0",
|
||||
"timeOut": 0,
|
||||
"extendedTimeOut": 0,
|
||||
"showEasing": "swing",
|
||||
"hideEasing": "linear",
|
||||
"showMethod": "fadeIn",
|
||||
"hideMethod": "fadeOut",
|
||||
"tapToDismiss": false
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
.always(function () {
|
||||
console.log('[Done]');
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function updateImagePositions() {
|
||||
console.log("UP pos");
|
||||
|
||||
file_set = $("#image_form_set ul");
|
||||
|
||||
n = 0;
|
||||
for (let i = 0; i < file_set.length; i++) {
|
||||
ul = file_set.get(i);
|
||||
console.log(ul)
|
||||
|
||||
file_element = $(ul).find("input[type=file]").get(0);
|
||||
|
||||
// If a (new) file is being uploaded we save it's name prior to it being hashed
|
||||
if (file_element.files.length > 0) {
|
||||
file_name = file_element.files[0].name
|
||||
//$(ul).find("input[type=text]").val(file_name);
|
||||
$(ul).find("input[name*='filename']").val(file_name);
|
||||
}
|
||||
|
||||
if (file_element.files.length > 0 || $(ul).find(":contains('Currently:')")) {
|
||||
n++;
|
||||
$(ul).find("input[type=number]").val(n);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function loadViewer() {
|
||||
console.log("LOAD VIEWER")
|
||||
// temp fix before starting viewer collapsed
|
||||
$("#single-dicom-viewer").show()
|
||||
//file_set = $("#image_form_set input[type=file]");
|
||||
|
||||
//n = 0;
|
||||
//for (let i = 0; i < file_set.length; i++) {
|
||||
// el = file_set.get(i)
|
||||
// if (el.files.length > 0) {
|
||||
// n++;
|
||||
// }
|
||||
//}
|
||||
|
||||
image_set = $("#image_form_set .temp-thumb").get() //.map(function() { return $(this).attr("src")}).get();
|
||||
console.log(image_set);
|
||||
//console.log()
|
||||
//if (n == image_set.length) {
|
||||
const event = new CustomEvent('loadDicomViewer', {
|
||||
"detail": image_set
|
||||
});
|
||||
|
||||
window.dispatchEvent(event);
|
||||
sortable('.sortable');
|
||||
//sortable('.sortable')[0].addEventListener('sortstop', function(e) {
|
||||
updateImagePositions();
|
||||
//}
|
||||
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
@@ -0,0 +1,61 @@
|
||||
import json
|
||||
from re import A
|
||||
import pytest
|
||||
|
||||
# from django.contrib.auth.models import User
|
||||
from django.urls import reverse
|
||||
|
||||
from rich.pretty import pprint
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
from anatomy.views import GenericExamViews as AnatomyExamViews
|
||||
|
||||
from anatomy.models import Exam
|
||||
|
||||
from generic.models import CidUser, CidUserGroup
|
||||
|
||||
APP_NAME = "anatomy"
|
||||
|
||||
def create_cid_user_and_groups(db):
|
||||
group1 = CidUserGroup.objects.create(name="Group1")
|
||||
group2= CidUserGroup.objects.create(name="Group2")
|
||||
|
||||
cid_user_1000 = CidUser.objects.create(cid=1000, passcode="ABCD", group=group1)
|
||||
cid_user_1001 = CidUser.objects.create(cid=1001, passcode="EFGH", group=group1)
|
||||
cid_user_2001 = CidUser.objects.create(cid=2001, passcode="EFGH", group=group2)
|
||||
|
||||
assert cid_user_1000.cid == 1000
|
||||
assert cid_user_1001.cid == 1001
|
||||
|
||||
|
||||
|
||||
|
||||
def create_exam(db):
|
||||
exam: Exam = AnatomyExamViews.Exam.objects.create(name="Cid Exam", exam_mode=True, active=True)
|
||||
|
||||
group1: CidUserGroup = CidUserGroup.objects.get(name="Group1")
|
||||
|
||||
exam.cid_user_groups.add(group1)
|
||||
|
||||
exam.valid_cid_users.add(*group1.ciduser_set.all())
|
||||
|
||||
assert exam in group1.anatomy_cid_user_groups.all()
|
||||
|
||||
assert exam
|
||||
|
||||
def test_exams(db, client):
|
||||
create_cid_user_and_groups(db)
|
||||
create_exam(db)
|
||||
|
||||
active_exams = client.get(reverse(f"{APP_NAME}:active_exams"))
|
||||
assert active_exams.status_code == 200
|
||||
assert len(json.load(active_exams.content)) == 0
|
||||
|
||||
cid_user_1001 = CidUser.objects.get(cid=1001)
|
||||
|
||||
for cid_user in [cid_user_1001]
|
||||
active_exams_cid = client.get(reverse(f"{APP_NAME}:active_exams_cid", ))
|
||||
|
||||
print(active_exams_cid.status_code)
|
||||
print(active_exams_cid.content)
|
||||
+5
-2
@@ -149,7 +149,7 @@ class SeriesForm(ModelForm):
|
||||
"all": ["css/widgets.css"],
|
||||
}
|
||||
# Adding this javascript is crucial
|
||||
js = ["jsi18n.js", "tesseract.min.js"]
|
||||
js = ["jsi18n.js", "tesseract.min.js", "js/upload_form_helpers.js"]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.user = kwargs.pop(
|
||||
@@ -239,7 +239,7 @@ class CaseForm(ModelForm):
|
||||
"all": ["css/widgets.css"],
|
||||
}
|
||||
# Adding this javascript is crucial
|
||||
js = ["jsi18n.js", "tesseract.min.js"]
|
||||
js = ["jsi18n.js", "tesseract.min.js", "js/upload_form_helpers.js"]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
logging.info("LOG")
|
||||
@@ -371,6 +371,7 @@ CaseDifferentialFormSet = inlineformset_factory(
|
||||
|
||||
|
||||
class CaseSeriesForm(ModelForm):
|
||||
|
||||
def __init__(self, *args, user, **kwargs):
|
||||
super(CaseSeriesForm, self).__init__(*args, **kwargs)
|
||||
|
||||
@@ -386,6 +387,8 @@ class CaseSeriesForm(ModelForm):
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
class CaseCollectionCaseForm(ModelForm):
|
||||
def __init__(self, *args, user, **kwargs):
|
||||
super(CaseCollectionCaseForm, self).__init__(*args, **kwargs)
|
||||
|
||||
@@ -6,15 +6,10 @@
|
||||
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
||||
|
||||
<script type="text/javascript">
|
||||
let crsf_token = "{{csrf_token}}";
|
||||
let hash_url = false;
|
||||
document.addEventListener('drop', function (e) { e.preventDefault(); }, false);
|
||||
|
||||
function add_input_form() {
|
||||
var form_idx = $('#id_images-TOTAL_FORMS').val();
|
||||
$('#image_form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
|
||||
$('#id_images-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
$("#add_examination").appendTo($("label[for='id_examination']"));
|
||||
|
||||
@@ -44,71 +39,93 @@
|
||||
dropContainer.ondrop = function (evt) {
|
||||
$(evt.target).removeClass("drop-target-active");
|
||||
|
||||
file_drop_number = evt.dataTransfer.files.length;
|
||||
|
||||
if (evt.dataTransfer.files.length < 1) {
|
||||
toastr.warning(`Drop failed :( try again?`);
|
||||
if (file_drop_number < 1) {
|
||||
toastr.warning(`Drop failed (no files), try again.`);
|
||||
} else {
|
||||
toastr.info(`Adding ${evt.dataTransfer.files.length} files.`);
|
||||
toastr.info(`Loading ${file_drop_number} dropped image(s).`);
|
||||
}
|
||||
|
||||
// Get all input elements
|
||||
inputs = $("#atlas-form input[type=file][id^=id_images-]");
|
||||
//fileInput = document.getElementById("id_images-0-image");
|
||||
inputs = extendInputs("atlas-form", file_drop_number);
|
||||
|
||||
// Make sure we have enough input targets
|
||||
input_diff = (evt.dataTransfer.files.length - inputs.length)
|
||||
console.log("drop inputs", inputs, evt);
|
||||
|
||||
if (input_diff > 0) {
|
||||
for (let j = 0; j < input_diff; j++) {
|
||||
add_input_form()
|
||||
}
|
||||
|
||||
// Need to make sure we include the new ones...
|
||||
inputs = $("#atlas-form input[type=file][id^=id_images-]");
|
||||
}
|
||||
|
||||
// Loop through each dropped file and try to assign to an
|
||||
// input element
|
||||
[...evt.dataTransfer.files].forEach((f) => {
|
||||
let dT = new DataTransfer();
|
||||
dT.clearData();
|
||||
dT.items.add(f);
|
||||
for (let i = 0; i < inputs.length; i++) {
|
||||
el = inputs.get(i)
|
||||
|
||||
if (el.files.length == 0) {
|
||||
el.files = dT.files;
|
||||
//ocr(el)
|
||||
|
||||
return false
|
||||
}
|
||||
feedback = false;
|
||||
if (evt.target.id == "feedback-drop-target") {
|
||||
feedback = true;
|
||||
}
|
||||
addFile(f, feedback)
|
||||
})
|
||||
|
||||
// // If you want to use some of the dropped files
|
||||
// const dT = new DataTransfer();
|
||||
// dT.items.add(evt.dataTransfer.files[0]);
|
||||
// dT.items.add(evt.dataTransfer.files[3]);
|
||||
// fileInput.files = dT.files;
|
||||
|
||||
loadDicomViewerAndFileImages();
|
||||
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
};
|
||||
//dropContainer.ondrop = function (evt) {
|
||||
// $(evt.target).removeClass("drop-target-active");
|
||||
|
||||
|
||||
// if (evt.dataTransfer.files.length < 1) {
|
||||
// toastr.warning(`Drop failed :( try again?`);
|
||||
// } else {
|
||||
// toastr.info(`Adding ${evt.dataTransfer.files.length} files.`);
|
||||
// }
|
||||
|
||||
// // Get all input elements
|
||||
// inputs = $("#atlas-form input[type=file][id^=id_images-]");
|
||||
// //fileInput = document.getElementById("id_images-0-image");
|
||||
|
||||
// // Make sure we have enough input targets
|
||||
// input_diff = (evt.dataTransfer.files.length - inputs.length)
|
||||
|
||||
// if (input_diff > 0) {
|
||||
// for (let j = 0; j < input_diff; j++) {
|
||||
// add_input_form()
|
||||
// }
|
||||
|
||||
// // Need to make sure we include the new ones...
|
||||
// inputs = $("#atlas-form input[type=file][id^=id_images-]");
|
||||
// }
|
||||
|
||||
// // Loop through each dropped file and try to assign to an
|
||||
// // input element
|
||||
// [...evt.dataTransfer.files].forEach((f) => {
|
||||
// let dT = new DataTransfer();
|
||||
// dT.clearData();
|
||||
// dT.items.add(f);
|
||||
// for (let i = 0; i < inputs.length; i++) {
|
||||
// el = inputs.get(i)
|
||||
|
||||
// if (el.files.length == 0) {
|
||||
// el.files = dT.files;
|
||||
// //ocr(el)
|
||||
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
|
||||
// // // If you want to use some of the dropped files
|
||||
// // const dT = new DataTransfer();
|
||||
// // dT.items.add(evt.dataTransfer.files[0]);
|
||||
// // dT.items.add(evt.dataTransfer.files[3]);
|
||||
// // fileInput.files = dT.files;
|
||||
|
||||
// loadDicomViewerAndFileImages();
|
||||
|
||||
// evt.preventDefault();
|
||||
// evt.stopPropagation();
|
||||
//};
|
||||
|
||||
|
||||
$('#add_more_images').click(() => { add_input_form() });
|
||||
|
||||
$("input[type=file]").on('change', function () {
|
||||
$(this).removeClass("image-ident-warning");
|
||||
$(this).removeClass("image-ident-ok");
|
||||
console.log("input change1");
|
||||
console.log("input change", this);
|
||||
//ocr(this);
|
||||
//LoadDicomViewer();
|
||||
|
||||
});
|
||||
$("input[type=file]").on('change', input_change);
|
||||
|
||||
|
||||
|
||||
@@ -134,63 +151,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
function ocr(input) {
|
||||
// Tesseract.recognize(f, "eng",{ logger: m => console.log(m) }
|
||||
// ).then(({ data: { text } }) => {
|
||||
// console.log(text);
|
||||
// l = text.toLowerCase();
|
||||
// if (l.includes("accesion") || l.includes("number") || l.search(/(REF|RK9|RH8|RA9)\d+/g)) {
|
||||
// console.log("SHIT", this);
|
||||
// }
|
||||
// })
|
||||
|
||||
console.log('{% static "worker.min.js" %}');
|
||||
console.log('{{ STATIC_URL }}/tesseract-core.wasm.js %}');
|
||||
|
||||
const worker = Tesseract.createWorker({
|
||||
workerPath: '{% static "worker.min.js" %}',
|
||||
langPath: '{% static "" %}',
|
||||
//langPath: '{{ STATIC_URL }}',
|
||||
corePath: '{% static "tesseract-core.wasm.js" %}',
|
||||
});
|
||||
|
||||
const url = URL.createObjectURL(input.files[0]);
|
||||
let img = new Image;
|
||||
img.src = url;
|
||||
|
||||
img.onload = function () {
|
||||
|
||||
|
||||
width = img.width;
|
||||
|
||||
// const rectangle = { left: 0, top: 0, width: width, height: 10 }
|
||||
|
||||
|
||||
(async () => {
|
||||
await worker.load();
|
||||
await worker.loadLanguage('eng');
|
||||
await worker.initialize('eng');
|
||||
// const { data: { text } } = await worker.recognize(input.files[0], { rectangle });
|
||||
const { data: { text } } = await worker.recognize(input.files[0]);
|
||||
//console.log(text);
|
||||
l = text.toLowerCase();
|
||||
$(`img[data-input-id='${input.id}'`).removeClass("image-ident-loading");
|
||||
console.log(l);
|
||||
if (l.includes("accesion") || l.includes("number") || l.search(/(ref|rk9|rh8|ra9|rbz)\d+/g) > -1) {
|
||||
$(input).addClass("image-ident-warning");
|
||||
$(`img[data-input-id='${input.id}'`).addClass("image-ident-warning");
|
||||
} else {
|
||||
$(input).addClass("image-ident-ok");
|
||||
|
||||
}
|
||||
|
||||
await worker.terminate();
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function loadDicomViewerAndFileImages(callback) {
|
||||
$("#single-dicom-viewer").empty()
|
||||
//images = []
|
||||
@@ -263,55 +223,29 @@
|
||||
|
||||
}
|
||||
|
||||
function loadViewer(images) {
|
||||
//dicomViewer.loadCornerstone($("#single-dicom-viewer"), null, images, annotations);
|
||||
file_set = $("#image_form_set input[type=file]");
|
||||
|
||||
n = 0;
|
||||
for (let i = 0; i < file_set.length; i++) {
|
||||
el = file_set.get(i)
|
||||
if (el.files.length > 0) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
image_set = $("#image_form_set img");
|
||||
if (n == image_set.length) {
|
||||
const event = new CustomEvent('loadDicomViewer', { "detail": image_set });
|
||||
|
||||
window.dispatchEvent(event);
|
||||
sortable('.sortable');
|
||||
//sortable('.sortable')[0].addEventListener('sortstop', function(e) {
|
||||
updateImagePositions();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function updateImagePositions() {
|
||||
console.log("UP pos");
|
||||
|
||||
file_set = $("#image_form_set ul");
|
||||
|
||||
n = 0;
|
||||
for (let i = 0; i < file_set.length; i++) {
|
||||
ul = file_set.get(i);
|
||||
console.log(ul)
|
||||
|
||||
file_element = $(ul).find("input[type=file]").get(0);
|
||||
|
||||
// If a (new) file is being uploaded we save it's name prior to it being hashed
|
||||
if (file_element.files.length > 0) {
|
||||
file_name = file_element.files[0].name
|
||||
$(ul).find("input[type=text]").val(file_name);
|
||||
}
|
||||
|
||||
if (file_element.files.length > 0 || $(ul).find(":contains('Currently:')")) {
|
||||
n++;
|
||||
$(ul).find("input[type=number]").val(n);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// function loadViewer(images) {
|
||||
// //dicomViewer.loadCornerstone($("#single-dicom-viewer"), null, images, annotations);
|
||||
// file_set = $("#image_form_set input[type=file]");
|
||||
//
|
||||
// n = 0;
|
||||
// for (let i = 0; i < file_set.length; i++) {
|
||||
// el = file_set.get(i)
|
||||
// if (el.files.length > 0) {
|
||||
// n++;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// image_set = $("#image_form_set img");
|
||||
// if (n == image_set.length) {
|
||||
// const event = new CustomEvent('loadDicomViewer', { "detail": image_set });
|
||||
//
|
||||
// window.dispatchEvent(event);
|
||||
// sortable('.sortable');
|
||||
// //sortable('.sortable')[0].addEventListener('sortstop', function(e) {
|
||||
// updateImagePositions();
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
function extractDicomDetails(byteArray) {
|
||||
// We need to setup a try/catch block because parseDicom will throw an exception
|
||||
@@ -486,13 +420,12 @@
|
||||
</table>
|
||||
|
||||
<h3>Images:</h3>
|
||||
<input type="button" value="Add More Images (manually)" id="add_more_images">
|
||||
<div id="drop-container" class="series-drop">Drop images here (or use the buttons below). Dropping images here will overwrite
|
||||
existing images in the series. When drag and dropping make sure to drag the first image or the order will not be
|
||||
maintained. Note: dicom images are often not exported in order (although their order can be automatically
|
||||
detected once uploaded)
|
||||
<div id="single-dicom-viewer" class="dicom-viewer" data-images="" data-annotations=''></div>
|
||||
<div id="drop-filenames"></div>
|
||||
{% comment %} <div id="drop-filenames"></div> {% endcomment %}
|
||||
</div>
|
||||
<div id="image_form_set" class="sortable">
|
||||
{% for form in image_formset %}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
DEBUG=1
|
||||
SECRET_KEY=w(s0&(_eb058wvmg@44_repv8)r9@5p8fx*g_@c)1dm&d*ew^u
|
||||
DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1]
|
||||
|
||||
DB_NAME=rad
|
||||
DB_HOST=db
|
||||
DB_USER=django
|
||||
DB_PASSWORD=postgres
|
||||
DB_PORT=5432
|
||||
@@ -0,0 +1,27 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
web:
|
||||
build: ./rad
|
||||
command: python manage.py runserver 0.0.0.0:8000
|
||||
volumes:
|
||||
- ./rad/:/usr/src/rad/
|
||||
- ../rts/:/usr/src/rad/rts
|
||||
- ./backups:/usr/src/backups
|
||||
- ./media:/usr/src/media
|
||||
- ./static:/usr/src/static
|
||||
ports:
|
||||
- 8000:8000
|
||||
env_file:
|
||||
- ./.env.dev
|
||||
db:
|
||||
image: postgres:14.2-alpine
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data/
|
||||
environment:
|
||||
- POSTGRES_USER=django
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
- POSTGRES_DB=rad
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
+1
-1
@@ -1587,7 +1587,7 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
answer_score = 0
|
||||
ans = "Not answered"
|
||||
else:
|
||||
if user_answer.normal:
|
||||
if exam.app_name == "rapids" and user_answer.normal:
|
||||
ans = "Normal"
|
||||
else:
|
||||
ans = user_answer.answer
|
||||
|
||||
+56
-41
@@ -5,47 +5,62 @@ from . import views
|
||||
|
||||
app_name = "physics"
|
||||
|
||||
urlpatterns = [
|
||||
# path("question/", views.QuestionView.as_view(), name="question_view"),
|
||||
path("question/", views.QuestionView.as_view(), name="question_view"),
|
||||
path("question/<int:pk>/", views.question_detail, name="question_detail"),
|
||||
# path("question/create/", views.QuestionCreate.as_view(), name="anatomy_question_create"),
|
||||
# path("question/<int:pk>/update", views.QuestionUpdate.as_view(), name="anatomy_question_update"),
|
||||
# path("exam/<int:pk>/<int:sk>/mark", views.mark, name="mark"),
|
||||
# path("exam/<int:pk>/mark", views.mark_overview, name="mark_overview"),
|
||||
path("exam/<int:pk>/take_old", views.exam_take_old, name="exam_take_old"),
|
||||
path(
|
||||
"exam/<int:pk>/<int:sk>/<str:cid>/<str:passcode>/take",
|
||||
views.exam_take,
|
||||
name="exam_take",
|
||||
),
|
||||
path("exam/<int:pk>/start", views.exam_start, name="exam_start"),
|
||||
path(
|
||||
"exam/<int:pk>/<str:cid>/<str:passcode>/finish",
|
||||
views.exam_take_overview,
|
||||
name="exam_take_overview",
|
||||
),
|
||||
path("exam/<int:pk>/authors", views.ExamAuthorUpdate.as_view(), name="exam_authors"),
|
||||
path("exam/<int:exam_id>/clone", views.ExamClone.as_view(), name="exam_clone"),
|
||||
path("exam/<int:pk>/update", views.ExamUpdate.as_view(), name="exam_update"),
|
||||
path("exam/<int:pk>/delete", views.ExamDelete.as_view(), name="exam_delete"),
|
||||
path("exam/available", views.active_exams, name="active_exams"),
|
||||
# path("exam/json/<int:pk>", views.exam_json, name="exam_json"),
|
||||
# path("exam/json/<int:pk>/recreate", views.exam_json_recreate, name="exam_json_recreate"),
|
||||
path(
|
||||
"user_answers/",
|
||||
views.UserAnswerTableView.as_view(),
|
||||
name="user_answer_table_view",
|
||||
),
|
||||
path(
|
||||
"user_answers/<int:pk>", views.UserAnswerView.as_view(), name="user_answer_view"
|
||||
),
|
||||
path(
|
||||
"user_answers/<int:pk>/delete",
|
||||
views.UserAnswerDelete.as_view(),
|
||||
name="user_answer_delete",
|
||||
),
|
||||
]
|
||||
urlpatterns = []
|
||||
|
||||
urlpatterns.extend(
|
||||
[
|
||||
# path("question/", views.QuestionView.as_view(), name="question_view"),
|
||||
path("question/", views.QuestionView.as_view(), name="question_view"),
|
||||
path("question/<int:pk>/", views.question_detail, name="question_detail"),
|
||||
# path("question/create/", views.QuestionCreate.as_view(), name="anatomy_question_create"),
|
||||
# path("question/<int:pk>/update", views.QuestionUpdate.as_view(), name="anatomy_question_update"),
|
||||
# path("exam/<int:pk>/<int:sk>/mark", views.mark, name="mark"),
|
||||
# path("exam/<int:pk>/mark", views.mark_overview, name="mark_overview"),
|
||||
path("exam/<int:pk>/take_old", views.exam_take_old, name="exam_take_old"),
|
||||
path(
|
||||
"exam/<int:pk>/<int:sk>/<str:cid>/<str:passcode>/take",
|
||||
views.exam_take,
|
||||
name="exam_take",
|
||||
),
|
||||
path("exam/<int:pk>/start", views.exam_start, name="exam_start"),
|
||||
path(
|
||||
"exam/<int:pk>/<str:cid>/<str:passcode>/finish",
|
||||
views.exam_take_overview,
|
||||
name="exam_take_overview",
|
||||
),
|
||||
path(
|
||||
"exam/<int:pk>/authors",
|
||||
views.ExamAuthorUpdate.as_view(),
|
||||
name="exam_authors",
|
||||
),
|
||||
path("exam/<int:exam_id>/clone", views.ExamClone.as_view(), name="exam_clone"),
|
||||
path("exam/<int:pk>/update", views.ExamUpdate.as_view(), name="exam_update"),
|
||||
path("exam/<int:pk>/delete", views.ExamDelete.as_view(), name="exam_delete"),
|
||||
path("exam/available", views.active_exams, name="active_exams"),
|
||||
# path("exam/json/<int:pk>", views.exam_json, name="exam_json"),
|
||||
# path("exam/json/<int:pk>/recreate", views.exam_json_recreate, name="exam_json_recreate"),
|
||||
path(
|
||||
"user_answers/",
|
||||
views.UserAnswerTableView.as_view(),
|
||||
name="user_answer_table_view",
|
||||
),
|
||||
path(
|
||||
"user_answers/<int:pk>",
|
||||
views.UserAnswerView.as_view(),
|
||||
name="user_answer_view",
|
||||
),
|
||||
path(
|
||||
"user_answers/<int:pk>/delete",
|
||||
views.UserAnswerDelete.as_view(),
|
||||
name="user_answer_delete",
|
||||
),
|
||||
path(
|
||||
"exam/<int:pk>/scores/<int:cid>/<str:passcode>/",
|
||||
views.exam_scores_cid_user,
|
||||
name="exam_scores_cid_user",
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
urlpatterns.extend(generic_view_urls(views.GenericViews))
|
||||
urlpatterns.extend(generic_exam_urls(views.GenericExamViews))
|
||||
+1
-1
@@ -76,7 +76,7 @@ class RapidForm(ModelForm):
|
||||
"all": ["css/widgets.css"],
|
||||
}
|
||||
# Adding this javascript is crucial
|
||||
js = ["jsi18n.js", "tesseract.min.js"]
|
||||
js = ["jsi18n.js", "tesseract.min.js", "js/upload_form_helpers.js"]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.user = kwargs.pop(
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
|
||||
<script type="text/javascript">
|
||||
let normal = false;
|
||||
let csrf_token = "{{csrf_token}}";
|
||||
let hash_url = "{% url 'rapids:rapid_question_by_hash' %}";
|
||||
//let monitor_directory_handler = false;
|
||||
//let monitor_interval_id = false;
|
||||
|
||||
// set to hold the files that are still being processed
|
||||
let active_file_inputs = new Set();
|
||||
let load_viewer = false;
|
||||
|
||||
// async function listAllFilesAndDirs(dirHandle, files_only) {
|
||||
@@ -39,84 +40,13 @@
|
||||
// return files;
|
||||
// }
|
||||
|
||||
function showEditPopup(url) {
|
||||
var win = window.open(url, "Edit",
|
||||
'height=500,width=800,resizable=yes,scrollbars=yes');
|
||||
return false;
|
||||
}
|
||||
|
||||
function showAddPopup(triggeringLink) {
|
||||
var name = triggeringLink.id.replace(/^add_/, '');
|
||||
href = triggeringLink.href;
|
||||
var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
|
||||
win.focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
function closePopup(win, newID, newRepr, id) {
|
||||
$(id + "_to").append('<option value=' + newID + ' title=' + newRepr + ' >' + newRepr + '</option>')
|
||||
win.close();
|
||||
}
|
||||
|
||||
document.addEventListener('drop', function (e) {
|
||||
e.preventDefault();
|
||||
}, false);
|
||||
|
||||
function getUnusedInputs(inputs) {
|
||||
new_inputs = [];
|
||||
for (let i = 0; i < inputs.length; i++) {
|
||||
input = inputs.get(i);
|
||||
|
||||
if (!input.value) {
|
||||
new_inputs.push(input);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $(new_inputs);
|
||||
|
||||
}
|
||||
|
||||
function getCurrentFiles() {
|
||||
inputs = $("#rapid-form input[type=file]");
|
||||
|
||||
let files = new Set();
|
||||
for (let j = 0; j < inputs.length; j++) {
|
||||
i = inputs.get(j);
|
||||
if (i.files.length > 0) {
|
||||
files.add(i.files[0]);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
function extendInputs(n) {
|
||||
// Makes sure we have n inputs available
|
||||
// returns available inputs
|
||||
inputs = getUnusedInputs($("#rapid-form input[type=file][id^=id_images-]"));
|
||||
//fileInput = document.getElementById("id_images-0-image");
|
||||
|
||||
|
||||
// Make sure we have enough input targets
|
||||
input_diff = (n - inputs.length)
|
||||
|
||||
if (input_diff > 0) {
|
||||
for (let j = 0; j < input_diff; j++) {
|
||||
add_input_form()
|
||||
}
|
||||
|
||||
// Need to make sure we include the new ones...
|
||||
inputs = getUnusedInputs($("#rapid-form input[type=file][id^=id_images-]"));
|
||||
}
|
||||
return inputs;
|
||||
}
|
||||
|
||||
function add_input_form() {
|
||||
var form_idx = $('#id_images-TOTAL_FORMS').val();
|
||||
$('#image_form_set').append($($('#empty_form').html().replace(/__prefix__/g, form_idx)).on("change",
|
||||
input_change));
|
||||
$('#id_images-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
||||
}
|
||||
|
||||
function add_answers_input_form() {
|
||||
var form_idx = $('#id_answers-TOTAL_FORMS').val();
|
||||
@@ -125,62 +55,6 @@
|
||||
$('#id_answers-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
||||
}
|
||||
|
||||
function input_change(evt) {
|
||||
file = evt.target.files[0];
|
||||
$(evt.target).removeClass("image-ident-warning");
|
||||
$(evt.target).removeClass("image-ident-ok");
|
||||
|
||||
|
||||
|
||||
el = evt.target;
|
||||
|
||||
|
||||
//readFileAndProcess();
|
||||
readFileAndProcess2(el);
|
||||
|
||||
// Check if we have selected a examination type
|
||||
if (!$("#id_examination_to option").length) {
|
||||
|
||||
// Yes we do read the file twice (here and where loading it in the viewer)
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (file) {
|
||||
var arrayBuffer = reader.result;
|
||||
// Here we have the file data as an ArrayBuffer. dicomParser requires as input a
|
||||
// Uint8Array so we create that here
|
||||
var byteArray = new Uint8Array(arrayBuffer);
|
||||
extractDicomStudyDescription(byteArray)
|
||||
}
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function addFile(f, feedback) {
|
||||
let dT = new DataTransfer();
|
||||
dT.clearData();
|
||||
dT.items.add(f);
|
||||
for (let i = 0; i < inputs.length; i++) {
|
||||
el = inputs.get(i);
|
||||
|
||||
if (el.files.length == 0) {
|
||||
el.files = dT.files;
|
||||
//ocr(el)
|
||||
|
||||
if (feedback) {
|
||||
arr = el.name.split("-");
|
||||
arr.splice(2, 1, "feedback_image");
|
||||
feedback_el_name = arr.join("-");
|
||||
|
||||
$(`[name=${feedback_el_name}]`).prop("checked", true);
|
||||
}
|
||||
|
||||
$(el).change();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
@@ -223,7 +97,7 @@
|
||||
}
|
||||
|
||||
// Get all input elements
|
||||
inputs = extendInputs(file_drop_number);
|
||||
inputs = extendInputs("rapid-form", file_drop_number);
|
||||
|
||||
console.log("drop inputs", inputs, evt);
|
||||
|
||||
@@ -250,7 +124,7 @@
|
||||
// listAllFilesAndDirs(monitor_directory_handler).then(async function (
|
||||
// items) {
|
||||
// files_to_add = new Set();
|
||||
// current_files = getCurrentFiles();
|
||||
// current_files = getCurrentFormFiles();
|
||||
// current_files_tuple = new Set()
|
||||
// for (let elem of current_files) {
|
||||
// current_files_tuple.add(
|
||||
@@ -368,321 +242,83 @@
|
||||
|
||||
});
|
||||
|
||||
function ocr2(url, input) {
|
||||
console.log("OCR", url, input)
|
||||
Tesseract.recognize(
|
||||
url,
|
||||
'eng',
|
||||
{ logger: m => console.log(m) }
|
||||
).then(({ data: { text } }) => {
|
||||
l = text.toLowerCase();
|
||||
uploading_el = $(`img[data-input-id='${input.id}'], div[data-input-id='${input.id}']`)
|
||||
uploading_el.removeClass("image-ident-loading");
|
||||
console.log("found text", l);
|
||||
if (l.includes("accesion") || l.includes("number") || l.search(
|
||||
/(ref|rk9|rh8|ra9|rbz)\d+/g) > -1) {
|
||||
console.log("Match found ", input);
|
||||
$(input).addClass("image-ident-warning");
|
||||
uploading_el.addClass("image-ident-warning");
|
||||
} else {
|
||||
$(input).addClass("image-ident-ok");
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
async function blobToBase64(blob) {
|
||||
return new Promise((resolve, _) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => resolve(reader.result);
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
// async function readFileAndProcess(callback) {
|
||||
// //$("#single-dicom-viewer").empty()
|
||||
// //images = []
|
||||
// //Function that returns a promise to read the file
|
||||
// const reader = (file) => {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// const fileReader = new FileReader();
|
||||
// fileReader.onload = () => resolve(fileReader);
|
||||
// fileReader.readAsDataURL(file);
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// // Add file to the process list
|
||||
// active_file_inputs.add(el)
|
||||
// const readFile = (file, el) => {
|
||||
// reader(file).then(reader => {
|
||||
// console.log("12345", reader)
|
||||
// $(el).parent().parent().find(".temp-thumb").remove();
|
||||
//
|
||||
// if (reader.result.startsWith("data:application/octet-stream;base64")) {
|
||||
// const element = $(`<div class='temp-thumb' src=${reader.result}></div>`).get(0)
|
||||
// $(el).parent().parent().prepend(element);
|
||||
// const imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add(
|
||||
// file
|
||||
// );
|
||||
// cornerstone.enable(element);
|
||||
// cornerstone.loadAndCacheImage(imageId).then(function (image) {
|
||||
// cornerstone.displayImage(element, image);
|
||||
// cornerstone.resize(element)
|
||||
//
|
||||
// });
|
||||
//
|
||||
// } else {
|
||||
// var image = new Image();
|
||||
// image.title = file.name;
|
||||
// image.src = reader.result;
|
||||
// image.className = "temp-thumb";
|
||||
// $(el).parent().parent().prepend(image);
|
||||
// //images.push(reader.result);
|
||||
// }
|
||||
//
|
||||
// active_file_inputs.delete(el)
|
||||
// console.log("active", active_file_inputs)
|
||||
// // Only load once all queued files have been processed
|
||||
// if (active_file_inputs.size < 1) {
|
||||
// loadViewer();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// file_set = $("#image_form_set input[type=file]");
|
||||
//
|
||||
// file_set.each(async (n, el) => {
|
||||
// if (el.files.length > 0) {
|
||||
// filename = el.files[0].name;
|
||||
// // Probably no need to await here anymore
|
||||
// await readFile(el.files[0], el);
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
async function readFileAndProcess2(el) {
|
||||
|
||||
//file_set = $("#image_form_set input[type=file]");
|
||||
|
||||
//file_set.each(async (n, el) => {
|
||||
|
||||
if (el.files.length > 0) {
|
||||
filename = el.files[0].name;
|
||||
// Probably no need to await here anymore
|
||||
//await readFile(el.files[0], el);
|
||||
// const viewLoadChecker = setInterval(function () {
|
||||
// if (load_viewer) {
|
||||
// load_viewer = false;
|
||||
// loadViewer();
|
||||
// }
|
||||
// }, 2000);
|
||||
|
||||
|
||||
|
||||
|
||||
console.log(el.files[0])
|
||||
function extractDicomDetails(byteArray) {
|
||||
if (!$("#id_examination_to option").length) {
|
||||
|
||||
$(el).parent().parent().find(".temp-thumb").remove();
|
||||
|
||||
let url = URL.createObjectURL(el.files[0])
|
||||
|
||||
n = el.id.split("-")[1];
|
||||
$(`#drop-filenames span[data-input-id='${el.id}']`).remove();
|
||||
|
||||
let extra_class = " image-ident-loading";
|
||||
if ($(el).hasClass("image-ident-warning")) {
|
||||
extra_class = " image-ident-warning";
|
||||
} else if ($(el).hasClass("image-ident-ok")) {
|
||||
extra_class = " image-ident-ok";
|
||||
}
|
||||
|
||||
//let extra_class = "";
|
||||
let imageId;
|
||||
if (el.files[0].type.startsWith("image")) {
|
||||
|
||||
let hash = CryptoJS.MD5(el.files[0]).toString();
|
||||
console.log("HASH", hash)
|
||||
|
||||
base = await blobToBase64(el.files[0]);
|
||||
imageId = "base64://" + base.split(",")[1];
|
||||
imageId2 = base;
|
||||
const element = $(`<img class='temp-thumb' src=${imageId}></div>`).get(0)
|
||||
$(el).parent().parent().prepend(element);
|
||||
|
||||
|
||||
ocr2(url, el);
|
||||
checkHash(hash, el);
|
||||
|
||||
$("#drop-filenames").append(
|
||||
`<span data-input-id='${el.id}'><span>${n}: ${el.files[0].name}</span><img class='uploading${extra_class}' data-input-id='${el.id}' src=${url}></span>`
|
||||
)
|
||||
} else {
|
||||
imageId = `wadouri:${url}`;
|
||||
imageId2 = imageId
|
||||
|
||||
console.log(imageId)
|
||||
const element = $(`<div class='temp-thumb' src=${imageId2}></div>`).get(0)
|
||||
$(el).parent().parent().prepend(element);
|
||||
cornerstone.enable(element);
|
||||
cornerstone.loadAndCacheImage(imageId).then(function (image) {
|
||||
cornerstone.displayImage(element, image);
|
||||
cornerstone.resize(element)
|
||||
|
||||
|
||||
let pixel_data = image.getPixelData().toString()
|
||||
console.log(element, "pixel data", pixel_data)
|
||||
|
||||
let hash = CryptoJS.MD5(pixel_data).toString();
|
||||
console.log(element, "HASH", hash)
|
||||
checkHash(hash, el);
|
||||
|
||||
});
|
||||
|
||||
$("#drop-filenames").append(
|
||||
`<span data-input-id='${el.id}'><span>${n}: ${el.files[0].name}</span><div class='uploading${extra_class}' data-input-id='${el.id}' src=${url}></div></span>`
|
||||
)
|
||||
|
||||
const element2 = $(`#drop-filenames div[data-input-id='${el.id}']`).get(0);
|
||||
cornerstone.enable(element2);
|
||||
cornerstone.loadAndCacheImage(imageId).then(function (image) {
|
||||
cornerstone.displayImage(element2, image);
|
||||
|
||||
$(element2).addClass("temp-thumb-large");
|
||||
cornerstone.resize(element2)
|
||||
setTimeout(function () {
|
||||
ocr2($(element2).find("canvas").get(0).toDataURL(), el);
|
||||
$(element2).removeClass("temp-thumb-large");
|
||||
cornerstone.resize(element2)
|
||||
}, 500);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
active_file_inputs.delete(el)
|
||||
console.log("active", active_file_inputs)
|
||||
// Only load once all queued files have been processed
|
||||
if (active_file_inputs.size < 1) {
|
||||
load_viewer = true;
|
||||
//loadViewer();
|
||||
}
|
||||
}
|
||||
//})
|
||||
}
|
||||
|
||||
async function readFileAndProcess(callback) {
|
||||
//$("#single-dicom-viewer").empty()
|
||||
//images = []
|
||||
//Function that returns a promise to read the file
|
||||
const reader = (file) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = () => resolve(fileReader);
|
||||
fileReader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
// Add file to the process list
|
||||
active_file_inputs.add(el)
|
||||
const readFile = (file, el) => {
|
||||
reader(file).then(reader => {
|
||||
console.log("12345", reader)
|
||||
$(el).parent().parent().find(".temp-thumb").remove();
|
||||
|
||||
if (reader.result.startsWith("data:application/octet-stream;base64")) {
|
||||
const element = $(`<div class='temp-thumb' src=${reader.result}></div>`).get(0)
|
||||
$(el).parent().parent().prepend(element);
|
||||
const imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add(
|
||||
file
|
||||
);
|
||||
cornerstone.enable(element);
|
||||
cornerstone.loadAndCacheImage(imageId).then(function (image) {
|
||||
cornerstone.displayImage(element, image);
|
||||
cornerstone.resize(element)
|
||||
|
||||
});
|
||||
|
||||
} else {
|
||||
var image = new Image();
|
||||
image.title = file.name;
|
||||
image.src = reader.result;
|
||||
image.className = "temp-thumb";
|
||||
$(el).parent().parent().prepend(image);
|
||||
//images.push(reader.result);
|
||||
}
|
||||
|
||||
active_file_inputs.delete(el)
|
||||
console.log("active", active_file_inputs)
|
||||
// Only load once all queued files have been processed
|
||||
if (active_file_inputs.size < 1) {
|
||||
loadViewer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
file_set = $("#image_form_set input[type=file]");
|
||||
|
||||
file_set.each(async (n, el) => {
|
||||
if (el.files.length > 0) {
|
||||
filename = el.files[0].name;
|
||||
// Probably no need to await here anymore
|
||||
await readFile(el.files[0], el);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const viewLoadChecker = setInterval(function () {
|
||||
if (load_viewer) {
|
||||
load_viewer = false;
|
||||
loadViewer();
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
function loadViewer() {
|
||||
console.log("LOAD VIEWER")
|
||||
// temp fix before starting viewer collapsed
|
||||
$("#single-dicom-viewer").show()
|
||||
//file_set = $("#image_form_set input[type=file]");
|
||||
|
||||
//n = 0;
|
||||
//for (let i = 0; i < file_set.length; i++) {
|
||||
// el = file_set.get(i)
|
||||
// if (el.files.length > 0) {
|
||||
// n++;
|
||||
// }
|
||||
//}
|
||||
|
||||
image_set = $("#image_form_set .temp-thumb").get()//.map(function() { return $(this).attr("src")}).get();
|
||||
console.log(image_set);
|
||||
//console.log()
|
||||
//if (n == image_set.length) {
|
||||
const event = new CustomEvent('loadDicomViewer', {
|
||||
"detail": image_set
|
||||
});
|
||||
|
||||
window.dispatchEvent(event);
|
||||
sortable('.sortable');
|
||||
//sortable('.sortable')[0].addEventListener('sortstop', function(e) {
|
||||
updateImagePositions();
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
function updateImagePositions() {
|
||||
console.log("UP pos");
|
||||
|
||||
file_set = $("#image_form_set ul");
|
||||
|
||||
n = 0;
|
||||
for (let i = 0; i < file_set.length; i++) {
|
||||
ul = file_set.get(i);
|
||||
console.log(ul)
|
||||
|
||||
file_element = $(ul).find("input[type=file]").get(0);
|
||||
|
||||
// If a (new) file is being uploaded we save it's name prior to it being hashed
|
||||
if (file_element.files.length > 0) {
|
||||
file_name = file_element.files[0].name
|
||||
//$(ul).find("input[type=text]").val(file_name);
|
||||
$(ul).find("input[name*='filename']").val(file_name);
|
||||
}
|
||||
|
||||
if (file_element.files.length > 0 || $(ul).find(":contains('Currently:')")) {
|
||||
n++;
|
||||
$(ul).find("input[type=number]").val(n);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function checkHash(hash, input) {
|
||||
$.ajax({
|
||||
url: "{% url 'rapids:rapid_question_by_hash' %}",
|
||||
data: {
|
||||
csrfmiddlewaretoken: '{{ csrf_token }}',
|
||||
hash: hash
|
||||
},
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
})
|
||||
// $.ajax().done(), $.ajax().fail(), $ajax().always() are upto you. Add/change accordingly
|
||||
.done(function (data) {
|
||||
console.log(data);
|
||||
|
||||
if (data.status == "success") {
|
||||
console.log("success");
|
||||
console.log(data.id)
|
||||
if (data.id) {
|
||||
//toastr.info(`id ${data.id}`)
|
||||
uploading_el = $(`img[data-input-id='${input.id}'], div[data-input-id='${input.id}']`)
|
||||
$(input).addClass("image-duplicate");
|
||||
uploading_el.addClass("image-duplicate");
|
||||
|
||||
toastr.warning(`Image (${input.files[0].name}) already exists.<br /><a href='${data.url}'>Click to view</a><br /><button type="button" class="btn clear">Dismiss</button>`, "Duplicate image", {
|
||||
"closeButton": false,
|
||||
"debug": false,
|
||||
"newestOnTop": false,
|
||||
"progressBar": false,
|
||||
"positionClass": "toast-top-full-width",
|
||||
"preventDuplicates": false,
|
||||
"onclick": null,
|
||||
"showDuration": "0",
|
||||
"hideDuration": "0",
|
||||
"timeOut": 0,
|
||||
"extendedTimeOut": 0,
|
||||
"showEasing": "swing",
|
||||
"hideEasing": "linear",
|
||||
"showMethod": "fadeIn",
|
||||
"hideMethod": "fadeOut",
|
||||
"tapToDismiss": false
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
.always(function () {
|
||||
console.log('[Done]');
|
||||
})
|
||||
}
|
||||
|
||||
function extractDicomStudyDescription(byteArray) {
|
||||
// We need to setup a try/catch block because parseDicom will throw an exception
|
||||
// if you attempt to parse a non dicom part 10 file (or one that is corrupted)
|
||||
try {
|
||||
@@ -717,6 +353,7 @@
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -179,4 +179,4 @@ def test_index(client, create_superuser, exam_views, django_user_model):
|
||||
|
||||
print(json_response)
|
||||
|
||||
assert len(json_response) == 2
|
||||
assert len(json_response) == 2
|
||||
Reference in New Issue
Block a user