# HG changeset patch
# User Sebastien Jodogne
# Date 1354706950 -3600
# Node ID f23318b11b39e5451e0876cc6eeaeab1dff9aae5
# Parent 5694365ecb969a562a410836c402403f15741f26
creation of zip files
diff -r 5694365ecb96 -r f23318b11b39 Core/Compression/HierarchicalZipWriter.cpp
--- a/Core/Compression/HierarchicalZipWriter.cpp Wed Dec 05 09:28:06 2012 +0100
+++ b/Core/Compression/HierarchicalZipWriter.cpp Wed Dec 05 12:29:10 2012 +0100
@@ -48,10 +48,14 @@
result.reserve(source.size());
for (size_t i = 0; i < source.size(); i++)
{
- if (source[i] < 128 &&
- source[i] >= 0)
+ char c = source[i];
+ if (c == '^')
+ c = ' ';
+
+ if (c < 128 &&
+ c >= 0)
{
- if (isspace(source[i]))
+ if (isspace(c))
{
if (!lastSpace)
{
@@ -59,11 +63,11 @@
result.push_back(' ');
}
}
- else if (isalnum(source[i]) ||
- source[i] == '.' ||
- source[i] == '_')
+ else if (isalnum(c) ||
+ c == '.' ||
+ c == '_')
{
- result.push_back(source[i]);
+ result.push_back(c);
lastSpace = false;
}
}
diff -r 5694365ecb96 -r f23318b11b39 NEWS
--- a/NEWS Wed Dec 05 09:28:06 2012 +0100
+++ b/NEWS Wed Dec 05 12:29:10 2012 +0100
@@ -1,6 +1,8 @@
Pending changes in the mainline
===============================
+* Download archives of patients, studies and serie as ZIP files
+
Version 0.3.0 (2012/11/30)
==========================
diff -r 5694365ecb96 -r f23318b11b39 OrthancExplorer/explorer.html
--- a/OrthancExplorer/explorer.html Wed Dec 05 09:28:06 2012 +0100
+++ b/OrthancExplorer/explorer.html Wed Dec 05 12:29:10 2012 +0100
@@ -84,6 +84,7 @@
Go to patient finder
Delete this patient
+ Download ZIP
@@ -115,6 +116,7 @@
Delete this study
+ Download ZIP
@@ -148,8 +150,9 @@
Delete this series
- Preview this series
- Store in another DICOM modality
+ Preview this series
+ Store in another DICOM modality
+ Download ZIP
@@ -185,8 +188,8 @@
Delete this instance
Download the DICOM file
Download the JSON file
- Preview the instance
- Store in another DICOM modality
+ Preview the instance
+ Store in another DICOM modality
diff -r 5694365ecb96 -r f23318b11b39 OrthancExplorer/explorer.js
--- a/OrthancExplorer/explorer.js Wed Dec 05 09:28:06 2012 +0100
+++ b/OrthancExplorer/explorer.js Wed Dec 05 12:29:10 2012 +0100
@@ -626,6 +626,7 @@
});
+
$('#instance-preview').live('click', function(e) {
if ($.mobile.pageData) {
GetSingleResource('instances', $.mobile.pageData.uuid + '/frames', function(frames) {
@@ -768,3 +769,20 @@
else
$('.tag-name').hide();
});
+
+
+$('#patient-archive').live('click', function(e) {
+ e.preventDefault(); //stop the browser from following
+ window.location.href = '../patients/' + $.mobile.pageData.uuid + '/archive';
+});
+
+$('#study-archive').live('click', function(e) {
+ e.preventDefault(); //stop the browser from following
+ window.location.href = '../studies/' + $.mobile.pageData.uuid + '/archive';
+});
+
+$('#series-archive').live('click', function(e) {
+ e.preventDefault(); //stop the browser from following
+ window.location.href = '../series/' + $.mobile.pageData.uuid + '/archive';
+});
+
diff -r 5694365ecb96 -r f23318b11b39 OrthancServer/OrthancRestApi.cpp
--- a/OrthancServer/OrthancRestApi.cpp Wed Dec 05 09:28:06 2012 +0100
+++ b/OrthancServer/OrthancRestApi.cpp Wed Dec 05 12:29:10 2012 +0100
@@ -296,7 +296,6 @@
static void GetSystemInformation(RestApi::GetCall& call)
{
- RETRIEVE_CONTEXT(call);
Json::Value result = Json::objectValue;
result["Version"] = ORTHANC_VERSION;
@@ -353,57 +352,182 @@
// Download of ZIP files ----------------------------------------------------
- static void GetPatientArchive(RestApi::GetCall& call)
+
+ static std::string GetDirectoryNameInArchive(const Json::Value& resource,
+ ResourceType resourceType)
+ {
+ switch (resourceType)
+ {
+ case ResourceType_Patient:
+ {
+ std::string p = resource["MainDicomTags"]["PatientID"].asString();
+ std::string n = resource["MainDicomTags"]["PatientName"].asString();
+ return p + " " + n;
+ }
+
+ case ResourceType_Study:
+ return resource["MainDicomTags"]["StudyDescription"].asString();
+
+ case ResourceType_Series:
+ return resource["MainDicomTags"]["SeriesDescription"].asString();
+
+ default:
+ throw OrthancException(ErrorCode_InternalError);
+ }
+ }
+
+ static bool CreateRootDirectoryInArchive(HierarchicalZipWriter& writer,
+ ServerContext& context,
+ const Json::Value& resource,
+ ResourceType resourceType)
+ {
+ if (resourceType == ResourceType_Patient)
+ {
+ return true;
+ }
+
+ ResourceType parentType = GetParentResourceType(resourceType);
+ Json::Value parent;
+
+ switch (resourceType)
+ {
+ case ResourceType_Study:
+ {
+ if (!context.GetIndex().LookupResource(parent, resource["ParentPatient"].asString(), parentType))
+ {
+ return false;
+ }
+
+ break;
+ }
+
+ case ResourceType_Series:
+ if (!context.GetIndex().LookupResource(parent, resource["ParentStudy"].asString(), parentType) ||
+ !CreateRootDirectoryInArchive(writer, context, parent, parentType))
+ {
+ return false;
+ }
+ break;
+
+ default:
+ throw OrthancException(ErrorCode_NotImplemented);
+ }
+
+ writer.OpenDirectory(GetDirectoryNameInArchive(parent, parentType).c_str());
+ return true;
+ }
+
+ static bool ArchiveInstance(HierarchicalZipWriter& writer,
+ ServerContext& context,
+ const std::string& instancePublicId)
+ {
+ Json::Value instance;
+ if (!context.GetIndex().LookupResource(instance, instancePublicId, ResourceType_Instance))
+ {
+ return false;
+ }
+
+ std::string filename = instance["MainDicomTags"]["SOPInstanceUID"].asString() + ".dcm";
+ writer.OpenFile(filename.c_str());
+
+ std::string dicom;
+ context.ReadFile(dicom, instancePublicId, FileContentType_Dicom);
+ writer.Write(dicom);
+
+ return true;
+ }
+
+ static bool ArchiveInternal(HierarchicalZipWriter& writer,
+ ServerContext& context,
+ const std::string& publicId,
+ ResourceType resourceType,
+ bool isFirstLevel)
+ {
+ Json::Value resource;
+ if (!context.GetIndex().LookupResource(resource, publicId, resourceType))
+ {
+ return false;
+ }
+
+ if (isFirstLevel &&
+ !CreateRootDirectoryInArchive(writer, context, resource, resourceType))
+ {
+ return false;
+ }
+
+ writer.OpenDirectory(GetDirectoryNameInArchive(resource, resourceType).c_str());
+
+ switch (resourceType)
+ {
+ case ResourceType_Patient:
+ for (size_t i = 0; i < resource["Studies"].size(); i++)
+ {
+ std::string studyId = resource["Studies"][i].asString();
+ if (!ArchiveInternal(writer, context, studyId, ResourceType_Study, false))
+ {
+ return false;
+ }
+ }
+ break;
+
+ case ResourceType_Study:
+ for (size_t i = 0; i < resource["Series"].size(); i++)
+ {
+ std::string seriesId = resource["Series"][i].asString();
+ if (!ArchiveInternal(writer, context, seriesId, ResourceType_Series, false))
+ {
+ return false;
+ }
+ }
+ break;
+
+ case ResourceType_Series:
+ for (size_t i = 0; i < resource["Instances"].size(); i++)
+ {
+ if (!ArchiveInstance(writer, context, resource["Instances"][i].asString()))
+ {
+ return false;
+ }
+ }
+ break;
+
+ default:
+ throw OrthancException(ErrorCode_InternalError);
+ }
+
+ writer.CloseDirectory();
+ return true;
+ }
+
+ template
+ static void GetArchive(RestApi::GetCall& call)
{
RETRIEVE_CONTEXT(call);
- Json::Value patient;
- if (!context.GetIndex().LookupResource(patient, call.GetUriComponent("id", ""), ResourceType_Patient))
- {
- return;
- }
-
+ // Create a RAII for the temporary file to manage the ZIP file
Toolbox::TemporaryFile tmp;
+ std::string id = call.GetUriComponent("id", "");
{
+ // Create a ZIP writer
HierarchicalZipWriter writer(tmp.GetPath().c_str());
-
- for (size_t i = 0; i < patient["Studies"].size(); i++)
- {
- Json::Value study;
- if (context.GetIndex().LookupResource(study, patient["Studies"][i].asString(), ResourceType_Study))
- {
- writer.OpenDirectory(study["MainDicomTags"]["StudyDescription"].asString().c_str());
- for (size_t i = 0; i < study["Series"].size(); i++)
- {
- Json::Value series;
- if (context.GetIndex().LookupResource(series, study["Series"][i].asString(), ResourceType_Series))
- {
- std::string m = series["MainDicomTags"]["Modality"].asString();
- std::string s = series["MainDicomTags"]["SeriesDescription"].asString();
- writer.OpenDirectory((m + " " + s).c_str());
-
- for (size_t i = 0; i < series["Instances"].size(); i++)
- {
- Json::Value instance;
- if (context.GetIndex().LookupResource(instance, series["Instances"][i].asString(), ResourceType_Instance))
- {
- writer.OpenFile(instance["MainDicomTags"]["SOPInstanceUID"].asString().c_str());
- }
- }
-
- writer.CloseDirectory();
- }
- }
-
- writer.CloseDirectory();
- }
+ // Store the requested resource into the ZIP
+ if (!ArchiveInternal(writer, context, id, resourceType, true))
+ {
+ return;
}
}
-
+
+ // Prepare the sending of the ZIP file
FilesystemHttpSender sender(tmp.GetPath().c_str());
+ sender.SetContentType("application/zip");
+ sender.SetDownloadFilename(id + ".zip");
+
+ // Send the ZIP
call.GetOutput().AnswerFile(sender);
+
+ // The temporary file is automatically removed thanks to the RAII
}
@@ -710,7 +834,10 @@
Register("/series/{id}", GetSingleResource);
Register("/studies/{id}", DeleteSingleResource);
Register("/studies/{id}", GetSingleResource);
- Register("/patients/{id}/archive", GetPatientArchive);
+
+ Register("/patients/{id}/archive", GetArchive);
+ Register("/studies/{id}/archive", GetArchive);
+ Register("/series/{id}/archive", GetArchive);
Register("/instances/{id}/file", GetInstanceFile);
Register("/instances/{id}/tags", GetInstanceTags);
diff -r 5694365ecb96 -r f23318b11b39 OrthancServer/ServerEnumerations.cpp
--- a/OrthancServer/ServerEnumerations.cpp Wed Dec 05 09:28:06 2012 +0100
+++ b/OrthancServer/ServerEnumerations.cpp Wed Dec 05 12:29:10 2012 +0100
@@ -39,20 +39,20 @@
{
switch (type)
{
- case ResourceType_Patient:
- return "Patient";
+ case ResourceType_Patient:
+ return "Patient";
- case ResourceType_Study:
- return "Study";
+ case ResourceType_Study:
+ return "Study";
- case ResourceType_Series:
- return "Series";
+ case ResourceType_Series:
+ return "Series";
- case ResourceType_Instance:
- return "Instance";
+ case ResourceType_Instance:
+ return "Instance";
- default:
- throw OrthancException(ErrorCode_ParameterOutOfRange);
+ default:
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
}
}
@@ -61,20 +61,20 @@
{
switch (type)
{
- case ResourceType_Patient:
- return "/patients/" + publicId;
+ case ResourceType_Patient:
+ return "/patients/" + publicId;
- case ResourceType_Study:
- return "/studies/" + publicId;
+ case ResourceType_Study:
+ return "/studies/" + publicId;
- case ResourceType_Series:
- return "/series/" + publicId;
+ case ResourceType_Series:
+ return "/series/" + publicId;
- case ResourceType_Instance:
- return "/instances/" + publicId;
+ case ResourceType_Instance:
+ return "/instances/" + publicId;
- default:
- throw OrthancException(ErrorCode_ParameterOutOfRange);
+ default:
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
}
}
@@ -82,20 +82,20 @@
{
switch (status)
{
- case SeriesStatus_Complete:
- return "Complete";
+ case SeriesStatus_Complete:
+ return "Complete";
- case SeriesStatus_Missing:
- return "Missing";
+ case SeriesStatus_Missing:
+ return "Missing";
- case SeriesStatus_Inconsistent:
- return "Inconsistent";
+ case SeriesStatus_Inconsistent:
+ return "Inconsistent";
- case SeriesStatus_Unknown:
- return "Unknown";
+ case SeriesStatus_Unknown:
+ return "Unknown";
- default:
- throw OrthancException(ErrorCode_ParameterOutOfRange);
+ default:
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
}
}
@@ -103,17 +103,17 @@
{
switch (status)
{
- case StoreStatus_Success:
- return "Success";
+ case StoreStatus_Success:
+ return "Success";
- case StoreStatus_AlreadyStored:
- return "AlreadyStored";
+ case StoreStatus_AlreadyStored:
+ return "AlreadyStored";
- case StoreStatus_Failure:
- return "Failure";
+ case StoreStatus_Failure:
+ return "Failure";
- default:
- throw OrthancException(ErrorCode_ParameterOutOfRange);
+ default:
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
}
}
@@ -122,23 +122,61 @@
{
switch (type)
{
- case ChangeType_CompletedSeries:
- return "CompletedSeries";
+ case ChangeType_CompletedSeries:
+ return "CompletedSeries";
+
+ case ChangeType_NewInstance:
+ return "NewInstance";
+
+ case ChangeType_NewPatient:
+ return "NewPatient";
+
+ case ChangeType_NewSeries:
+ return "NewSeries";
- case ChangeType_NewInstance:
- return "NewInstance";
+ case ChangeType_NewStudy:
+ return "NewStudy";
+
+ default:
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
+ }
+ }
- case ChangeType_NewPatient:
- return "NewPatient";
+
+ ResourceType GetParentResourceType(ResourceType type)
+ {
+ switch (type)
+ {
+ case ResourceType_Study:
+ return ResourceType_Patient;
- case ChangeType_NewSeries:
- return "NewSeries";
+ case ResourceType_Series:
+ return ResourceType_Study;
+
+ case ResourceType_Instance:
+ return ResourceType_Series;
+
+ default:
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
+ }
+ }
+
- case ChangeType_NewStudy:
- return "NewStudy";
+ ResourceType GetChildResourceType(ResourceType type)
+ {
+ switch (type)
+ {
+ case ResourceType_Patient:
+ return ResourceType_Study;
- default:
- throw OrthancException(ErrorCode_ParameterOutOfRange);
+ case ResourceType_Study:
+ return ResourceType_Series;
+
+ case ResourceType_Series:
+ return ResourceType_Instance;
+
+ default:
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
}
}
}
diff -r 5694365ecb96 -r f23318b11b39 OrthancServer/ServerEnumerations.h
--- a/OrthancServer/ServerEnumerations.h Wed Dec 05 09:28:06 2012 +0100
+++ b/OrthancServer/ServerEnumerations.h Wed Dec 05 12:29:10 2012 +0100
@@ -97,4 +97,8 @@
const char* ToString(StoreStatus status);
const char* ToString(ChangeType type);
+
+ ResourceType GetParentResourceType(ResourceType type);
+
+ ResourceType GetChildResourceType(ResourceType type);
}