Mercurial > hg > orthanc
diff OrthancServer/OrthancRestApi/OrthancRestArchive.cpp @ 1121:82567bac5e25
Creation of ZIP archives for media storage, with DICOMDIR
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 05 Sep 2014 14:28:43 +0200 |
parents | 6968356679c0 |
children | 6e7e5ed91c2d |
line wrap: on
line diff
--- a/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp Wed Sep 03 16:49:26 2014 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp Fri Sep 05 14:28:43 2014 +0200 @@ -33,6 +33,7 @@ #include "../PrecompiledHeadersServer.h" #include "OrthancRestApi.h" +#include "../DicomDirWriter.h" #include "../../Core/Compression/HierarchicalZipWriter.h" #include "../../Core/HttpServer/FilesystemHttpSender.h" #include "../../Core/Uuid.h" @@ -54,30 +55,38 @@ static std::string GetDirectoryNameInArchive(const Json::Value& resource, ResourceType resourceType) { + std::string s; + switch (resourceType) { case ResourceType_Patient: { std::string p = resource["MainDicomTags"]["PatientID"].asString(); std::string n = resource["MainDicomTags"]["PatientName"].asString(); - return p + " " + n; + s = p + " " + n; + break; } case ResourceType_Study: { - return resource["MainDicomTags"]["StudyDescription"].asString(); + s = resource["MainDicomTags"]["StudyDescription"].asString(); + break; } case ResourceType_Series: { std::string d = resource["MainDicomTags"]["SeriesDescription"].asString(); std::string m = resource["MainDicomTags"]["Modality"].asString(); - return m + " " + d; + s = m + " " + d; + break; } default: throw OrthancException(ErrorCode_InternalError); } + + // Get rid of special characters + return Toolbox::ConvertToAscii(s); } static bool CreateRootDirectoryInArchive(HierarchicalZipWriter& writer, @@ -126,13 +135,6 @@ const std::string& instancePublicId, const char* filename) { - Json::Value instance; - - if (!context.GetIndex().LookupResource(instance, instancePublicId, ResourceType_Instance)) - { - return false; - } - writer.OpenFile(filename); std::string dicom; @@ -233,13 +235,10 @@ return true; } - template <enum ResourceType resourceType> - static void GetArchive(RestApiGetCall& call) + + static bool IsZip64Required(ServerIndex& index, + const std::string& id) { - ServerContext& context = OrthancRestApi::GetContext(call); - - std::string id = call.GetUriComponent("id", ""); - /** * Determine whether ZIP64 is required. Original ZIP format can * store up to 2GB of data (some implementation supporting up to @@ -252,8 +251,8 @@ unsigned int countStudies; unsigned int countSeries; unsigned int countInstances; - context.GetIndex().GetStatistics(compressedSize, uncompressedSize, - countStudies, countSeries, countInstances, id); + index.GetStatistics(compressedSize, uncompressedSize, + countStudies, countSeries, countInstances, id); const bool isZip64 = (uncompressedSize >= 2 * GIGA_BYTES || countInstances >= 65535); @@ -261,6 +260,18 @@ << (uncompressedSize / MEGA_BYTES) << "MB using the " << (isZip64 ? "ZIP64" : "ZIP32") << " file format"; + return isZip64; + } + + + template <enum ResourceType resourceType> + static void GetArchive(RestApiGetCall& call) + { + ServerContext& context = OrthancRestApi::GetContext(call); + + std::string id = call.GetUriComponent("id", ""); + bool isZip64 = IsZip64Required(context.GetIndex(), id); + // Create a RAII for the temporary file to manage the ZIP file Toolbox::TemporaryFile tmp; @@ -288,10 +299,75 @@ } + static void GetMediaArchive(RestApiGetCall& call) + { + ServerContext& context = OrthancRestApi::GetContext(call); + + std::string id = call.GetUriComponent("id", ""); + bool isZip64 = IsZip64Required(context.GetIndex(), id); + + // Create a RAII for the temporary file to manage the ZIP file + Toolbox::TemporaryFile tmp; + + { + // Create a ZIP writer + HierarchicalZipWriter writer(tmp.GetPath().c_str()); + writer.SetZip64(isZip64); + writer.OpenDirectory("IMAGES"); + + // Create the DICOMDIR writer + DicomDirWriter dicomDir; + + // Retrieve the list of the instances + std::list<std::string> instances; + context.GetIndex().GetChildInstances(instances, id); + + size_t pos = 0; + for (std::list<std::string>::const_iterator + it = instances.begin(); it != instances.end(); it++, pos++) + { + // "DICOM restricts the filenames on DICOM media to 8 + // characters (some systems wrongly use 8.3, but this does not + // conform to the standard)." + std::string filename = "IM" + boost::lexical_cast<std::string>(pos); + writer.OpenFile(filename.c_str()); + + std::string dicom; + context.ReadFile(dicom, *it, FileContentType_Dicom); + writer.Write(dicom); + + ParsedDicomFile parsed(dicom); + dicomDir.Add("IMAGES", filename, parsed); + } + + // Add the DICOMDIR + writer.CloseDirectory(); + writer.OpenFile("DICOMDIR"); + std::string s; + dicomDir.Encode(s); + writer.Write(s); + } + + // 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 + } + + void OrthancRestApi::RegisterArchive() { Register("/patients/{id}/archive", GetArchive<ResourceType_Patient>); Register("/studies/{id}/archive", GetArchive<ResourceType_Study>); Register("/series/{id}/archive", GetArchive<ResourceType_Series>); + + Register("/patients/{id}/media", GetMediaArchive); + Register("/studies/{id}/media", GetMediaArchive); + Register("/series/{id}/media", GetMediaArchive); } }