diff --git a/DicomAnnotUtils.py b/DicomAnnotUtils.py index 6cd337f..ee052a0 100644 --- a/DicomAnnotUtils.py +++ b/DicomAnnotUtils.py @@ -134,7 +134,7 @@ def create_annotation_dicom(annot_arrays, slide_file, geojson): # add the annotation data ds.AnnotationGroupSequence = [] - i = 0 + i = 1 idx = 1 point_indices = [] # make the array first? @@ -298,7 +298,7 @@ def dicomToCamic(annot_path, image_dimensions, output_file, source_url=None, sli newFeature = deepcopy(featureTemplate) newFeature['geometry']['type'] = "Ellipse" newFeature['geometry']['coordinates'] = [center_x, center_y] - newFeature['geometry']["radius"] = [major_axis_length,minor_axis_length], + newFeature['geometry']["radius"] = [major_axis_length,minor_axis_length] newFeature['geometry']["rotation"] = rotation newFeature['bound']['type'] = "Point" newFeature['bound']['coordinates'] = [center_x, center_y] @@ -378,11 +378,15 @@ def dicomToCamic(annot_path, image_dimensions, output_file, source_url=None, sli #print("prev", prevIndex, "idx", idx) # make a thing points = coordinates_array[prevIndex:end_idx, :] - points = np.concatenate((points, [points[0]])) + polygon = np.concatenate((points, [points[0]])) #print('len(points)', len(points)) if len(points) > 0: newFeature = deepcopy(featureTemplate) - newFeature['geometry']['coordinates'].append(points.tolist()) + if x.GraphicType == "POLYLINE": + newFeature['geometry']['type'] = "Polyline" + newFeature['geometry']['coordinates'].append(points.tolist()) + else: + newFeature['geometry']['coordinates'].append(polygon.tolist()) bounding_box = _makeBound(points) # [[min_x, min_y], [min_x, max_y], [max_x, max_y], [max_x, min_y],[min_x, min_y]] newFeature['bound']['coordinates'].append(bounding_box) @@ -401,10 +405,14 @@ def dicomToCamic(annot_path, image_dimensions, output_file, source_url=None, sli # and the bound # then add the last one points = coordinates_array[prevIndex:, :] - points = np.concatenate((points, [points[0]])) + polygon = np.concatenate((points, [points[0]])) if len(points) > 0: newFeature = deepcopy(featureTemplate) - newFeature['geometry']['coordinates'].append(points.tolist()) + if x.GraphicType == "POLYLINE": + newFeature['geometry']['type'] = "Polyline" + newFeature['geometry']['coordinates'].append(points.tolist()) + else: + newFeature['geometry']['coordinates'].append(polygon.tolist()) bounding_box = _makeBound(points) # [[min_x, min_y], [min_x, max_y], [max_x, max_y], [max_x, min_y],[min_x, min_y]] newFeature['bound']['coordinates'].append(bounding_box) @@ -422,9 +430,13 @@ def dicomToCamic(annot_path, image_dimensions, output_file, source_url=None, sli else: # whole thing at once. Only do area and circumference here. points = coordinates_array - points = np.concatenate((points, [points[0]])) + polygon = np.concatenate((points, [points[0]])) newFeature = deepcopy(featureTemplate) - newFeature['geometry']['coordinates'].append(points.tolist()) + if x.GraphicType == "POLYLINE": + newFeature['geometry']['type'] = "Polyline" + newFeature['geometry']['coordinates'].append(points.tolist()) + else: + newFeature['geometry']['coordinates'].append(polygon.tolist()) bounding_box = _makeBound(points) # [[min_x, min_y], [min_x, max_y], [max_x, max_y], [max_x, min_y],[min_x, min_y]] newFeature['bound']['coordinates'].append(bounding_box) diff --git a/SlideServer.py b/SlideServer.py index c321a5a..540396d 100644 --- a/SlideServer.py +++ b/SlideServer.py @@ -31,6 +31,8 @@ import hashlib from urllib.parse import urlparse from dicomweb_client.api import DICOMwebClient +import aiohttp +import asyncio from DicomAnnotUtils import dicomToCamic import pydicom @@ -59,6 +61,12 @@ app.config['SECRET_KEY'] = os.urandom(24) app.config['ROI_FOLDER'] = "/images/roiDownload" +download_folder = os.getenv('DOWNLOAD_FOLDER', app.config['UPLOAD_FOLDER']) +app.config['DOWNLOAD_FOLDER'] = download_folder + +if os.getenv("ALLOW_DOWNLOAD_ZIP") == "True": + ALLOWED_EXTENSIONS.add("zip") + #creating a uploading folder if it doesn't exist if not os.path.exists(app.config['TEMP_FOLDER']): os.mkdir(app.config['TEMP_FOLDER']) @@ -311,7 +319,7 @@ def getSlide(image_name): image_name = secure_relative_path(image_name) if not verify_extension(image_name): return flask.Response(json.dumps({"error": "Bad image type requested"}), status=400, mimetype='text/json') - folder = app.config['UPLOAD_FOLDER'] + folder = app.config['DOWNLOAD_FOLDER'] if os.sep in image_name: folder_and_file = image_name.rsplit(os.sep, 1) folder = os.path.join(folder, folder_and_file[0]) @@ -775,7 +783,7 @@ def find_referenced_image_by_files(source_url, study, ds): # If the instance is not found in the study return None, None -def downloadRawDicom(source_url, study_uid, series_uid, instance_uid, output_fn): +def OLDdownloadRawDicom(source_url, study_uid, series_uid, instance_uid, output_fn): instance_url = source_url + f"/studies/{study_uid}/series/{series_uid}/instances/{instance_uid}" response = requests.get(instance_url, stream=True) if response.status_code == 200: @@ -788,9 +796,9 @@ def downloadRawDicom(source_url, study_uid, series_uid, instance_uid, output_fn) if chunk: if not dicom_started: # Check if the chunk contains "\r\n\r\n"" - if b"\r\n\r\n" in chunk: + start_idx = chunk.find(b"\r\n\r\n") + if start_idx != -1: # Find the position of "\r\n\r\n"" in the chunk - start_idx = chunk.find(b"\r\n\r\n") file.write(chunk[start_idx + 4:]) # Set dicom_started to True dicom_started = True @@ -805,6 +813,34 @@ def downloadRawDicom(source_url, study_uid, series_uid, instance_uid, output_fn) else: print(f"Failed to retrieve DICOM instance. Status code: {response.status_code}") +def downloadRawDicom(source_url, study_uid, series_uid, instance_uid, output_fn): + asyncio.run(doDownloadRawDicom(source_url, study_uid, series_uid, instance_uid, output_fn)) + +async def doDownloadRawDicom(source_url, study_uid, series_uid, instance_uid, output_fn): + instance_url = source_url + f"/studies/{study_uid}/series/{series_uid}/instances/{instance_uid}" + async with aiohttp.ClientSession(trust_env=True) as session: + async with session.get(instance_url) as resp: + reader = aiohttp.MultipartReader.from_response(resp) + metadata = None + filedata = None + while True: + part = await reader.next() + if part is None: + break + else: + #print(dir(part)) + #filedata = await part.read(decode=False) + app.logger.info("Working on file: " + output_fn) + with open(output_fn, 'wb') as fd: + while True: + part_chunk = await part.read_chunk(1024*1024) + if part_chunk is None or len(part_chunk)==0: + break + else: + fd.write(part_chunk) + + + # dicom web based routes def doDicomSlideDownloads(source_url, study, series, instance_list, camic_slide_id): diff --git a/requirements.txt b/requirements.txt index f05d286..761666b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,4 +13,5 @@ google-auth-oauthlib pycurl pydicom dicomweb-client -pymongo \ No newline at end of file +pymongo +aiohttp \ No newline at end of file