Mercurial > hg > orthanc
comparison OrthancServer/OrthancRestApi.cpp @ 250:f23318b11b39
creation of zip files
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 05 Dec 2012 12:29:10 +0100 |
parents | 5694365ecb96 |
children | 15fcd925b05b |
comparison
equal
deleted
inserted
replaced
249:5694365ecb96 | 250:f23318b11b39 |
---|---|
294 call.GetOutput().Redirect("app/explorer.html"); | 294 call.GetOutput().Redirect("app/explorer.html"); |
295 } | 295 } |
296 | 296 |
297 static void GetSystemInformation(RestApi::GetCall& call) | 297 static void GetSystemInformation(RestApi::GetCall& call) |
298 { | 298 { |
299 RETRIEVE_CONTEXT(call); | |
300 Json::Value result = Json::objectValue; | 299 Json::Value result = Json::objectValue; |
301 | 300 |
302 result["Version"] = ORTHANC_VERSION; | 301 result["Version"] = ORTHANC_VERSION; |
303 result["Name"] = GetGlobalStringParameter("Name", ""); | 302 result["Name"] = GetGlobalStringParameter("Name", ""); |
304 | 303 |
351 } | 350 } |
352 | 351 |
353 | 352 |
354 // Download of ZIP files ---------------------------------------------------- | 353 // Download of ZIP files ---------------------------------------------------- |
355 | 354 |
356 static void GetPatientArchive(RestApi::GetCall& call) | 355 |
357 { | 356 static std::string GetDirectoryNameInArchive(const Json::Value& resource, |
358 RETRIEVE_CONTEXT(call); | 357 ResourceType resourceType) |
359 | 358 { |
360 Json::Value patient; | 359 switch (resourceType) |
361 if (!context.GetIndex().LookupResource(patient, call.GetUriComponent("id", ""), ResourceType_Patient)) | 360 { |
362 { | 361 case ResourceType_Patient: |
363 return; | 362 { |
364 } | 363 std::string p = resource["MainDicomTags"]["PatientID"].asString(); |
365 | 364 std::string n = resource["MainDicomTags"]["PatientName"].asString(); |
365 return p + " " + n; | |
366 } | |
367 | |
368 case ResourceType_Study: | |
369 return resource["MainDicomTags"]["StudyDescription"].asString(); | |
370 | |
371 case ResourceType_Series: | |
372 return resource["MainDicomTags"]["SeriesDescription"].asString(); | |
373 | |
374 default: | |
375 throw OrthancException(ErrorCode_InternalError); | |
376 } | |
377 } | |
378 | |
379 static bool CreateRootDirectoryInArchive(HierarchicalZipWriter& writer, | |
380 ServerContext& context, | |
381 const Json::Value& resource, | |
382 ResourceType resourceType) | |
383 { | |
384 if (resourceType == ResourceType_Patient) | |
385 { | |
386 return true; | |
387 } | |
388 | |
389 ResourceType parentType = GetParentResourceType(resourceType); | |
390 Json::Value parent; | |
391 | |
392 switch (resourceType) | |
393 { | |
394 case ResourceType_Study: | |
395 { | |
396 if (!context.GetIndex().LookupResource(parent, resource["ParentPatient"].asString(), parentType)) | |
397 { | |
398 return false; | |
399 } | |
400 | |
401 break; | |
402 } | |
403 | |
404 case ResourceType_Series: | |
405 if (!context.GetIndex().LookupResource(parent, resource["ParentStudy"].asString(), parentType) || | |
406 !CreateRootDirectoryInArchive(writer, context, parent, parentType)) | |
407 { | |
408 return false; | |
409 } | |
410 break; | |
411 | |
412 default: | |
413 throw OrthancException(ErrorCode_NotImplemented); | |
414 } | |
415 | |
416 writer.OpenDirectory(GetDirectoryNameInArchive(parent, parentType).c_str()); | |
417 return true; | |
418 } | |
419 | |
420 static bool ArchiveInstance(HierarchicalZipWriter& writer, | |
421 ServerContext& context, | |
422 const std::string& instancePublicId) | |
423 { | |
424 Json::Value instance; | |
425 if (!context.GetIndex().LookupResource(instance, instancePublicId, ResourceType_Instance)) | |
426 { | |
427 return false; | |
428 } | |
429 | |
430 std::string filename = instance["MainDicomTags"]["SOPInstanceUID"].asString() + ".dcm"; | |
431 writer.OpenFile(filename.c_str()); | |
432 | |
433 std::string dicom; | |
434 context.ReadFile(dicom, instancePublicId, FileContentType_Dicom); | |
435 writer.Write(dicom); | |
436 | |
437 return true; | |
438 } | |
439 | |
440 static bool ArchiveInternal(HierarchicalZipWriter& writer, | |
441 ServerContext& context, | |
442 const std::string& publicId, | |
443 ResourceType resourceType, | |
444 bool isFirstLevel) | |
445 { | |
446 Json::Value resource; | |
447 if (!context.GetIndex().LookupResource(resource, publicId, resourceType)) | |
448 { | |
449 return false; | |
450 } | |
451 | |
452 if (isFirstLevel && | |
453 !CreateRootDirectoryInArchive(writer, context, resource, resourceType)) | |
454 { | |
455 return false; | |
456 } | |
457 | |
458 writer.OpenDirectory(GetDirectoryNameInArchive(resource, resourceType).c_str()); | |
459 | |
460 switch (resourceType) | |
461 { | |
462 case ResourceType_Patient: | |
463 for (size_t i = 0; i < resource["Studies"].size(); i++) | |
464 { | |
465 std::string studyId = resource["Studies"][i].asString(); | |
466 if (!ArchiveInternal(writer, context, studyId, ResourceType_Study, false)) | |
467 { | |
468 return false; | |
469 } | |
470 } | |
471 break; | |
472 | |
473 case ResourceType_Study: | |
474 for (size_t i = 0; i < resource["Series"].size(); i++) | |
475 { | |
476 std::string seriesId = resource["Series"][i].asString(); | |
477 if (!ArchiveInternal(writer, context, seriesId, ResourceType_Series, false)) | |
478 { | |
479 return false; | |
480 } | |
481 } | |
482 break; | |
483 | |
484 case ResourceType_Series: | |
485 for (size_t i = 0; i < resource["Instances"].size(); i++) | |
486 { | |
487 if (!ArchiveInstance(writer, context, resource["Instances"][i].asString())) | |
488 { | |
489 return false; | |
490 } | |
491 } | |
492 break; | |
493 | |
494 default: | |
495 throw OrthancException(ErrorCode_InternalError); | |
496 } | |
497 | |
498 writer.CloseDirectory(); | |
499 return true; | |
500 } | |
501 | |
502 template <enum ResourceType resourceType> | |
503 static void GetArchive(RestApi::GetCall& call) | |
504 { | |
505 RETRIEVE_CONTEXT(call); | |
506 | |
507 // Create a RAII for the temporary file to manage the ZIP file | |
366 Toolbox::TemporaryFile tmp; | 508 Toolbox::TemporaryFile tmp; |
367 | 509 std::string id = call.GetUriComponent("id", ""); |
368 { | 510 |
511 { | |
512 // Create a ZIP writer | |
369 HierarchicalZipWriter writer(tmp.GetPath().c_str()); | 513 HierarchicalZipWriter writer(tmp.GetPath().c_str()); |
370 | 514 |
371 for (size_t i = 0; i < patient["Studies"].size(); i++) | 515 // Store the requested resource into the ZIP |
372 { | 516 if (!ArchiveInternal(writer, context, id, resourceType, true)) |
373 Json::Value study; | 517 { |
374 if (context.GetIndex().LookupResource(study, patient["Studies"][i].asString(), ResourceType_Study)) | 518 return; |
375 { | 519 } |
376 writer.OpenDirectory(study["MainDicomTags"]["StudyDescription"].asString().c_str()); | 520 } |
377 | 521 |
378 for (size_t i = 0; i < study["Series"].size(); i++) | 522 // Prepare the sending of the ZIP file |
379 { | |
380 Json::Value series; | |
381 if (context.GetIndex().LookupResource(series, study["Series"][i].asString(), ResourceType_Series)) | |
382 { | |
383 std::string m = series["MainDicomTags"]["Modality"].asString(); | |
384 std::string s = series["MainDicomTags"]["SeriesDescription"].asString(); | |
385 writer.OpenDirectory((m + " " + s).c_str()); | |
386 | |
387 for (size_t i = 0; i < series["Instances"].size(); i++) | |
388 { | |
389 Json::Value instance; | |
390 if (context.GetIndex().LookupResource(instance, series["Instances"][i].asString(), ResourceType_Instance)) | |
391 { | |
392 writer.OpenFile(instance["MainDicomTags"]["SOPInstanceUID"].asString().c_str()); | |
393 } | |
394 } | |
395 | |
396 writer.CloseDirectory(); | |
397 } | |
398 } | |
399 | |
400 writer.CloseDirectory(); | |
401 } | |
402 } | |
403 } | |
404 | |
405 FilesystemHttpSender sender(tmp.GetPath().c_str()); | 523 FilesystemHttpSender sender(tmp.GetPath().c_str()); |
524 sender.SetContentType("application/zip"); | |
525 sender.SetDownloadFilename(id + ".zip"); | |
526 | |
527 // Send the ZIP | |
406 call.GetOutput().AnswerFile(sender); | 528 call.GetOutput().AnswerFile(sender); |
529 | |
530 // The temporary file is automatically removed thanks to the RAII | |
407 } | 531 } |
408 | 532 |
409 | 533 |
410 // Changes API -------------------------------------------------------------- | 534 // Changes API -------------------------------------------------------------- |
411 | 535 |
708 Register("/patients/{id}", GetSingleResource<ResourceType_Patient>); | 832 Register("/patients/{id}", GetSingleResource<ResourceType_Patient>); |
709 Register("/series/{id}", DeleteSingleResource<ResourceType_Series>); | 833 Register("/series/{id}", DeleteSingleResource<ResourceType_Series>); |
710 Register("/series/{id}", GetSingleResource<ResourceType_Series>); | 834 Register("/series/{id}", GetSingleResource<ResourceType_Series>); |
711 Register("/studies/{id}", DeleteSingleResource<ResourceType_Study>); | 835 Register("/studies/{id}", DeleteSingleResource<ResourceType_Study>); |
712 Register("/studies/{id}", GetSingleResource<ResourceType_Study>); | 836 Register("/studies/{id}", GetSingleResource<ResourceType_Study>); |
713 Register("/patients/{id}/archive", GetPatientArchive); | 837 |
838 Register("/patients/{id}/archive", GetArchive<ResourceType_Patient>); | |
839 Register("/studies/{id}/archive", GetArchive<ResourceType_Study>); | |
840 Register("/series/{id}/archive", GetArchive<ResourceType_Series>); | |
714 | 841 |
715 Register("/instances/{id}/file", GetInstanceFile); | 842 Register("/instances/{id}/file", GetInstanceFile); |
716 Register("/instances/{id}/tags", GetInstanceTags<false>); | 843 Register("/instances/{id}/tags", GetInstanceTags<false>); |
717 Register("/instances/{id}/simplified-tags", GetInstanceTags<true>); | 844 Register("/instances/{id}/simplified-tags", GetInstanceTags<true>); |
718 Register("/instances/{id}/frames", ListFrames); | 845 Register("/instances/{id}/frames", ListFrames); |