Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkDICOMweb.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include "mitkDICOMweb.h"
14 
16 
17 mitk::DICOMweb::DICOMweb(utility::string_t baseURI) : m_BaseURI(baseURI)
18 {
19  MITK_INFO << "base uri: " << mitk::RESTUtil::convertToUtf8(m_BaseURI);
20  InitializeRESTManager();
21 }
22 
23 utility::string_t mitk::DICOMweb::CreateQIDOUri(mitk::RESTUtil::ParamMap map)
24 {
25  MitkUriBuilder queryBuilder(m_BaseURI + U("rs/instances"));
26 
27  for (auto const &element : map)
28  {
29  queryBuilder.append_query(element.first, element.second);
30  }
31 
32  return queryBuilder.to_string();
33 }
34 
35 utility::string_t mitk::DICOMweb::CreateWADOUri(utility::string_t studyUID,
36  utility::string_t seriesUID,
37  utility::string_t instanceUID)
38 {
39  MitkUriBuilder builder(m_BaseURI + U("wado"));
40  builder.append_query(U("requestType"), U("WADO"));
41  builder.append_query(U("studyUID"), studyUID);
42  builder.append_query(U("seriesUID"), seriesUID);
43  builder.append_query(U("objectUID"), instanceUID);
44  builder.append_query(U("contentType"), U("application/dicom"));
45 
46  return builder.to_string();
47 }
48 
49 utility::string_t mitk::DICOMweb::CreateSTOWUri(utility::string_t studyUID)
50 {
51  MitkUriBuilder builder(m_BaseURI + U("rs/studies"));
52  builder.append_path(studyUID);
53  return builder.to_string();
54 }
55 
56 pplx::task<void> mitk::DICOMweb::SendSTOW(utility::string_t filePath, utility::string_t studyUID)
57 {
58  auto uri = CreateSTOWUri(studyUID);
59 
60  // this is the working stow-rs request which supports just one dicom file packed into a multipart message
61  std::ifstream input(filePath, std::ios::binary);
62  if (!input)
63  {
64  MITK_WARN << "could not read file to POST";
65  return pplx::task<void>();
66  }
67 
68  std::vector<unsigned char> result;
69  std::vector<unsigned char> buffer;
70 
71  // Stop eating new lines in binary mode!!!
72  input.unsetf(std::ios::skipws);
73 
74  input.seekg(0, std::ios::end);
75  const std::streampos fileSize = input.tellg();
76  input.seekg(0, std::ios::beg);
77 
78  MITK_INFO << fileSize << " bytes will be sent.";
79  buffer.reserve(fileSize); // file size
80  std::copy(
81  std::istream_iterator<unsigned char>(input), std::istream_iterator<unsigned char>(), std::back_inserter(buffer));
82 
83  // in future more than one file should also be supported..
84  std::string head = "";
85  head += "\r\n--boundary";
86  head += "\r\nContent-Type: " + mitk::RESTUtil::convertToUtf8(U("application/dicom")) + "\r\n\r\n";
87 
88  std::vector<unsigned char> bodyVector(head.begin(), head.end());
89 
90  std::string tail = "";
91  tail += "\r\n--boundary--";
92 
93  result.insert(result.end(), bodyVector.begin(), bodyVector.end());
94  result.insert(result.end(), buffer.begin(), buffer.end());
95  result.insert(result.end(), tail.begin(), tail.end());
96 
98  headers.insert(mitk::RESTUtil::ParamMap::value_type(
99  U("Content-Type"), U("multipart/related; type=\"application/dicom\"; boundary=boundary")));
100 
101  try
102  {
103  return m_RESTManager->SendBinaryRequest(uri, mitk::IRESTManager::RequestType::Post, &result, headers)
104  .then([=](web::json::value result) {
105  MITK_INFO << "after send";
106  MITK_INFO << mitk::RESTUtil::convertToUtf8(result.serialize());
107  result.is_null();
108  });
109  }
110  catch (std::exception &e)
111  {
112  MITK_WARN << e.what();
113  }
114 
115  return pplx::task<void>();
116 }
117 
118 pplx::task<void> mitk::DICOMweb::SendWADO(utility::string_t filePath,
119  utility::string_t studyUID,
120  utility::string_t seriesUID,
121  utility::string_t instanceUID)
122 {
123  auto uri = CreateWADOUri(studyUID, seriesUID, instanceUID);
124 
125  // don't want return something
126  try
127  {
128  return m_RESTManager->SendJSONRequest(uri, mitk::IRESTManager::RequestType::Get, nullptr, {}, filePath)
129  .then([=](web::json::value result) { result.is_null(); });
130  }
131  catch (const mitk::Exception &e)
132  {
133  mitkThrow() << e.what();
134  }
135 }
136 
137 pplx::task<std::string> mitk::DICOMweb::SendWADO(utility::string_t folderPath,
138  utility::string_t studyUID,
139  utility::string_t seriesUID)
140 {
141  mitk::RESTUtil::ParamMap seriesInstances;
142  seriesInstances.insert(mitk::RESTUtil::ParamMap::value_type(U("StudyInstanceUID"), studyUID));
143  seriesInstances.insert(mitk::RESTUtil::ParamMap::value_type(U("SeriesInstanceUID"), seriesUID));
144 
145  return SendQIDO(seriesInstances).then([=](web::json::value jsonResult) -> pplx::task<std::string> {
146  auto jsonListResult = jsonResult;
147  auto resultArray = jsonListResult.as_array();
148 
149  auto firstFileName = std::string();
150 
151  std::vector<pplx::task<void>> tasks;
152 
153  for (unsigned short i = 0; i < resultArray.size(); i++)
154  {
155  try
156  {
157  auto firstResult = resultArray[i];
158  auto sopInstanceUIDKey = firstResult.at(U("00080018"));
159  auto sopInstanceObject = sopInstanceUIDKey.as_object();
160  auto valueKey = sopInstanceObject.at(U("Value"));
161  auto valueArray = valueKey.as_array();
162  auto sopInstanceUID = valueArray[0].as_string();
163 
164  auto fileName = utility::string_t(sopInstanceUID).append(U(".dcm"));
165 
166  // save first file name as result to load series
167  if (i == 0)
168  {
169  firstFileName = utility::conversions::to_utf8string(fileName);
170  }
171 
172  auto filePath = utility::string_t(folderPath).append(fileName);
173  auto task = SendWADO(filePath, studyUID, seriesUID, sopInstanceUID);
174  tasks.push_back(task);
175  }
176  catch (const web::json::json_exception &e)
177  {
178  MITK_ERROR << e.what();
179  mitkThrow() << e.what();
180  }
181  }
182 
183  auto joinTask = pplx::when_all(begin(tasks), end(tasks));
184 
185  auto returnTask = joinTask.then([=](void) -> std::string {
186  auto folderPathUtf8 = utility::conversions::to_utf8string(folderPath);
187  auto result = folderPathUtf8 + firstFileName;
188 
189  return result;
190  });
191 
192  return returnTask;
193  });
194 }
195 
197 {
198  auto uri = CreateQIDOUri(map);
199 
200  mitk::RESTUtil::ParamMap headers;
201  headers.insert(mitk::RESTUtil::ParamMap::value_type(U("Accept"), U("application/json")));
202  return m_RESTManager->SendJSONRequest(uri, mitk::IRESTManager::RequestType::Get, nullptr, headers);
203 }
204 
205 void mitk::DICOMweb::InitializeRESTManager()
206 {
207  auto *context = us::GetModuleContext();
208  auto managerRef = context->GetServiceReference<mitk::IRESTManager>();
209  if (managerRef)
210  {
211  auto managerService = context->GetService(managerRef);
212  if (managerService)
213  {
214  m_RESTManager = managerService;
215  }
216  }
217 }
virtual pplx::task< web::json::value > SendJSONRequest(const web::uri &uri, const RequestType &type=RequestType::Get, const web::json::value *body=nullptr, const std::map< utility::string_t, utility::string_t > headers={}, const utility::string_t &filePath={})=0
Executes a HTTP request in the mitkRESTClient class.
#define MITK_INFO
Definition: mitkLogMacros.h:18
#define MITK_ERROR
Definition: mitkLogMacros.h:20
This is a microservice interface for managing REST requests.
virtual pplx::task< web::json::value > SendBinaryRequest(const web::uri &uri, const RequestType &type=RequestType::Get, const std::vector< unsigned char > *body={}, const std::map< utility::string_t, utility::string_t > headers={})=0
Executes a HTTP request in the mitkRESTClient class.
#define MITK_WARN
Definition: mitkLogMacros.h:19
An object of this class represents an exception of MITK. Please don&#39;t instantiate exceptions manually...
Definition: mitkException.h:45
#define mitkThrow()
web::http::uri_builder MitkUriBuilder
Definition: mitkDICOMweb.h:42
pplx::task< web::json::value > SendQIDO(mitk::RESTUtil::ParamMap map)
Sends a QIDO request containing the given parameters to filter the query.
static std::string convertToUtf8(const utility::string_t &string)
Converts the given std::wstring into a std::string representation.
Definition: mitkRESTUtil.h:32
std::map< utility::string_t, utility::string_t > ParamMap
Definition: mitkRESTUtil.h:27
pplx::task< void > SendWADO(utility::string_t filePath, utility::string_t studyUID, utility::string_t seriesUID, utility::string_t instanceUID)
Sends a WADO request for an DICOM object instance matching the given uid parameters and stores it at ...
static ModuleContext * GetModuleContext()
Returns the module context of the calling module.
pplx::task< void > SendSTOW(utility::string_t filePath, utility::string_t studyUID)
Sends a STOW request with the file in the given path to the study given bei its UID.