diff --git a/Modules/CppRestSdk/files.cmake b/Modules/CppRestSdk/files.cmake index 712619726b..5087f362a0 100644 --- a/Modules/CppRestSdk/files.cmake +++ b/Modules/CppRestSdk/files.cmake @@ -1,6 +1,7 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkRESTServer.cpp mitkRESTClient.cpp + mitkRESTUtil.cpp ) diff --git a/Modules/CppRestSdk/include/mitkRESTClient.h b/Modules/CppRestSdk/include/mitkRESTClient.h index 480cf94025..f6fa93ea41 100644 --- a/Modules/CppRestSdk/include/mitkRESTClient.h +++ b/Modules/CppRestSdk/include/mitkRESTClient.h @@ -1,63 +1,65 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKRESTCLIENT_H #define MITKRESTCLIENT_H #include "cpprest/asyncrt_utils.h" #include "cpprest/containerstream.h" #include "cpprest/filestream.h" #include "cpprest/http_client.h" #include "cpprest/json.h" #include "cpprest/producerconsumerstream.h" #include "cpprest/uri.h" // hm.. maybe go after that warning at some time? seems like a nasty hack, but works so far :) #pragma warning(disable : 4251) #include "MitkCppRestSdkExports.h" typedef web::http::client::http_client MitkClient; typedef web::http::http_request MitkRequest; typedef web::http::http_response MitkResponse; typedef web::http::methods MitkRESTMethods; typedef web::http::uri_builder MitkUriBuilder; typedef web::http::status_codes MitkRestStatusCodes; typedef web::json::json_exception MitkJsonException; namespace mitk { class MITKCPPRESTSDK_EXPORT RESTClient { public:; RESTClient(utility::string_t url); virtual ~RESTClient(); pplx::task Post(utility::string_t uri, utility::string_t contentType, concurrency::streams::basic_istream fileStream); + + pplx::task Post(utility::string_t uri, utility::string_t contentType, utility::string_t filePath); pplx::task Get(const utility::string_t filePath, utility::string_t uri); pplx::task WadoRS(const utility::string_t filePath, std::string studyUID, std::string seriesUID, std::string instanceUID); pplx::task WadoRS(const utility::string_t filePath, std::string studyUID, std::string seriesUID); pplx::task StowRS(utility::string_t filePath, std::string studyUID); private: MitkClient m_Client; }; }; #endif // MITKRESTCLIENT_H diff --git a/Modules/CppRestSdk/include/mitkRESTUtil.h b/Modules/CppRestSdk/include/mitkRESTUtil.h new file mode 100644 index 0000000000..731a9b60f3 --- /dev/null +++ b/Modules/CppRestSdk/include/mitkRESTUtil.h @@ -0,0 +1,74 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITKRESTUTIL_H +#define MITKRESTUTIL_H + +#include +#include +#include "MitkCppRestSdkExports.h" + +// hm.. maybe go after that warning at some time? seems like a nasty hack, but works so far :) +#pragma warning(disable : 4251) + +namespace mitk +{ + class MITKCPPRESTSDK_EXPORT RESTUtil + { + + public: + RESTUtil(); + virtual ~RESTUtil(); + + std::string body_content() + { + return m_BodyContent; + } + + std::string boundary() + { + return m_Boundary; + } + + void ContentType(const std::string &contentType) + { + m_ContentType = contentType; + } + + void AddParameter(const std::string &name, const std::string &value) + { + m_Params.push_back(std::move(std::pair(name, value))); + } + + void AddFile(const std::string &name, const std::string &value) + { + m_Files.push_back(std::move(std::pair(name, value))); + } + + std::string& GenBodyContent(); + + private: + std::string m_BoundaryPrefix; + std::string m_RandChars; + std::string m_Boundary = "boundary"; + std::string m_BodyContent; + std::string m_ContentType; + std::vector> m_Params; + std::vector> m_Files; + }; +}; + +#endif // MITKRESTUTIL_H diff --git a/Modules/CppRestSdk/src/mitkRESTClient.cpp b/Modules/CppRestSdk/src/mitkRESTClient.cpp index 4ba224d3a6..8d5f219694 100644 --- a/Modules/CppRestSdk/src/mitkRESTClient.cpp +++ b/Modules/CppRestSdk/src/mitkRESTClient.cpp @@ -1,162 +1,197 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkRESTClient.h" +#include "mitkRESTUtil.h" +#include #include mitk::RESTClient::RESTClient(utility::string_t url) : m_Client(url) { } mitk::RESTClient::~RESTClient() {} pplx::task mitk::RESTClient::Get(utility::string_t filePath, utility::string_t uri) { MITK_DEBUG << "Calling GET with " << utility::conversions::to_utf8string(uri) << " on client " << utility::conversions::to_utf8string(m_Client.base_uri().to_string()) << " save into " << utility::conversions::to_utf8string(filePath); auto fileBuffer = std::make_shared>(); return concurrency::streams::file_buffer::open(filePath, std::ios::out).then([=](concurrency::streams::streambuf outFile) -> pplx::task { *fileBuffer = outFile; return m_Client.request(MitkRESTMethods::GET, uri); }) // Write the response body into the file buffer. .then([=](MitkResponse response) -> pplx::task { MITK_DEBUG << "Status code: " << response.status_code(); return response.body().read_to_end(*fileBuffer); }) // Close the file buffer. .then([=](size_t) { return fileBuffer->close(); }); } pplx::task mitk::RESTClient::Post(utility::string_t uri, utility::string_t contentType, concurrency::streams::basic_istream fileStream) { MITK_INFO << "Calling POST with " << utility::conversions::to_utf8string(uri) << " on client " << utility::conversions::to_utf8string(m_Client.base_uri().to_string()); + + concurrency::streams::container_buffer inStringBuffer; + return fileStream.read(inStringBuffer, fileStream.streambuf().size()).then([=](size_t bytesRead) -> pplx::task + { + const std::string &text = inStringBuffer.collection(); + + std::string body = ""; + body += "\r\n--boundary"; + body += "\r\nContentType: " + utility::conversions::to_utf8string("application/dicom") + "\r\n\r\n"; + body += text; + body += "\r\n--boundary--"; + + auto utf8String = utility::conversions::to_utf8string(body); + + auto binaryVector = std::vector(utf8String.begin(), utf8String.end()); + + MitkRequest postRequest(MitkRESTMethods::POST); + postRequest.set_request_uri(uri); + postRequest.headers().add(U("Content-Type"), contentType); + postRequest.set_body(binaryVector); + + MITK_INFO << "Request: " << utility::conversions::to_utf8string(postRequest.to_string()); + + return m_Client.request(postRequest).then([fileStream](MitkResponse response) + { + fileStream.close(); + MITK_INFO << "Response: " << utility::conversions::to_utf8string(response.to_string()); + }); + }); +} + +pplx::task mitk::RESTClient::Post(utility::string_t uri, utility::string_t contentType, utility::string_t filePath) +{ + mitk::RESTUtil util; + util.AddParameter("dicomObject", std::experimental::filesystem::path(utility::conversions::to_utf8string(filePath)).filename().string()); + util.AddFile("file", utility::conversions::to_utf8string(filePath)); + std::string boundary = util.boundary(); + std::string body = util.GenBodyContent(); + MitkRequest postRequest(MitkRESTMethods::POST); postRequest.set_request_uri(uri); - postRequest.headers().add(U("Content-Type"), contentType); - postRequest.set_body(fileStream); - - MITK_INFO << fileStream.is_open(); - MITK_INFO << fileStream.is_valid(); - MITK_INFO << fileStream.streambuf().size(); - MITK_INFO << fileStream.streambuf().can_read(); + postRequest.set_body(body, utility::conversions::to_utf8string(contentType)); MITK_INFO << "Request: " << utility::conversions::to_utf8string(postRequest.to_string()); - - return m_Client.request(postRequest).then([fileStream](MitkResponse response) + + return m_Client.request(postRequest).then([](MitkResponse response) { - fileStream.close(); MITK_INFO << "Response: " << utility::conversions::to_utf8string(response.to_string()); }); + } pplx::task mitk::RESTClient::WadoRS(utility::string_t filePath, std::string studyUID, std::string seriesUID, std::string instanceUID) { MitkUriBuilder builder(U("wado")); builder.append_query(U("requestType"), U("WADO")); builder.append_query(U("studyUID"), utility::conversions::to_string_t(studyUID)); builder.append_query(U("seriesUID"), utility::conversions::to_string_t(seriesUID)); builder.append_query(U("objectUID"), utility::conversions::to_string_t(instanceUID)); builder.append_query(U("contentType"), U("application/dicom")); return Get(filePath, builder.to_string()); } pplx::task mitk::RESTClient::WadoRS(const utility::string_t folderPath, std::string studyUID, std::string seriesUID) { // this is actually a quido-rs request, should be packed into a seperate method.. at some time.. //but there are many possible requests to support: http://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_6.7.html MitkUriBuilder builder(U("rs/instances")); builder.append_query(U("StudyInstanceUID"), utility::conversions::to_string_t(studyUID)); builder.append_query(U("SeriesInstanceUID"), utility::conversions::to_string_t(seriesUID)); MITK_INFO << utility::conversions::to_utf8string(builder.to_string()); MitkRequest getSeries(MitkRESTMethods::GET); getSeries.set_request_uri(builder.to_string()); getSeries.headers().add(U("Accept"), U("application/json")); return m_Client.request(getSeries).then([=](MitkResponse response) -> pplx::task { MITK_INFO << "search for instances in series with uid " << seriesUID << " status: " << response.status_code(); auto jsonListResult = response.extract_json().get(); auto resultArray = jsonListResult.as_array(); auto firstFileName = std::string(); std::vector> tasks; for (unsigned short i = 0; i < resultArray.size(); i++) { try { auto firstResult = resultArray[i]; auto sopInstanceUIDKey = firstResult.at(U("00080018")); auto sopInstanceObject = sopInstanceUIDKey.as_object(); auto valueKey = sopInstanceObject.at(U("Value")); auto valueArray = valueKey.as_array(); auto sopInstanceUID = valueArray[0].as_string(); auto fileName = utility::string_t(sopInstanceUID).append(U(".dcm")); // save first file name as result to load series if (i == 0) { firstFileName = utility::conversions::to_utf8string(fileName); } auto filePath = utility::string_t(folderPath).append(fileName); auto task = WadoRS(filePath, studyUID, seriesUID, utility::conversions::to_utf8string(sopInstanceUID)); tasks.push_back(task); } catch (const web::json::json_exception& e) { MITK_ERROR << e.what(); } } auto joinTask = pplx::when_all(begin(tasks), end(tasks)); return joinTask.then([=](void) { return utility::conversions::to_utf8string(folderPath).append(firstFileName); }); }); } pplx::task mitk::RESTClient::StowRS(utility::string_t filePath, std::string studyUID) { // TODO: add data MitkUriBuilder builder(U("rs/studies")); builder.append_path(utility::conversions::to_string_t(studyUID)); return concurrency::streams::file_stream::open_istream(filePath).then([=](concurrency::streams::basic_istream fileStream) { - return Post(builder.to_string(), U("multipart/related; type='application/dicom';"), fileStream); + return Post(builder.to_string(), U("multipart/related; type='application/dicom'; boundary='boundary'"), fileStream); }); } \ No newline at end of file diff --git a/Modules/CppRestSdk/src/mitkRESTUtil.cpp b/Modules/CppRestSdk/src/mitkRESTUtil.cpp new file mode 100644 index 0000000000..438fbba5e1 --- /dev/null +++ b/Modules/CppRestSdk/src/mitkRESTUtil.cpp @@ -0,0 +1,86 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkRESTUtil.h" + +#include +#include +#include +#include +#include + +#include + +#include + +mitk::RESTUtil::RESTUtil() {} + +mitk::RESTUtil::~RESTUtil() {} + +std::string& mitk::RESTUtil::GenBodyContent() +{ + std::vector > futures; + m_BodyContent.clear(); + + for (auto &file : m_Files) + { + std::future content_futures = std::async(std::launch::async, [&file]() + { + std::ifstream ifile(file.second, std::ios::binary | std::ios::ate); + std::streamsize size = ifile.tellg(); + ifile.seekg(0, std::ios::beg); + char *buff = new char[size]; + ifile.read(buff, size); + ifile.close(); + std::string ret(buff, size); + delete[] buff; + return ret; + }); + futures.push_back(std::move(content_futures)); + } + + for (auto ¶m : m_Params) + { + m_BodyContent += "\r\n--"; + m_BodyContent += m_Boundary; + m_BodyContent += "\r\nContent-Disposition: form-data; name=\""; + m_BodyContent += param.first; + m_BodyContent += "\"\r\n\r\n"; + m_BodyContent += param.second; + } + + for (size_t i = 0; i < m_Files.size(); ++i) + { + std::string fileContent = futures[i].get(); + + auto filename = std::experimental::filesystem::path(m_Files[i].second).filename(); + + m_BodyContent += "\r\n--"; + m_BodyContent += m_Boundary; + m_BodyContent += "\r\nContent-Disposition: form-data; name=\""; + m_BodyContent += m_Files[i].first; + m_BodyContent += "\"; filename=\""; + m_BodyContent += filename.string(); + m_BodyContent += "\"\r\nContent-Type: "; + m_BodyContent += m_ContentType; + m_BodyContent += "\r\n\r\n"; + m_BodyContent += fileContent; + } + m_BodyContent += "\r\n--"; + m_BodyContent += m_Boundary; + m_BodyContent += "--\r\n"; + return m_BodyContent; +} diff --git a/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/SegmentationReworkViewControls.ui b/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/SegmentationReworkViewControls.ui index 55f1d26631..e058f1edb6 100644 --- a/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/SegmentationReworkViewControls.ui +++ b/Plugins/org.mitk.gui.qt.segmentation.rework/src/internal/SegmentationReworkViewControls.ui @@ -1,126 +1,126 @@ SegmentationReworkViewControls 0 0 465 673 0 0 QmitkTemplate true QLabel { color: rgb(255, 0, 0) } Please select an image! Segmentation A: Segmentation B: ground truth: Qt::Horizontal 0 - 300 + 400 16777215 - 300 + 400 Qt::Horizontal Do image processing Upload new Segmentation C Qt::Vertical QSizePolicy::Expanding 20 220 QmitkChartWidget QWidget
QmitkChartWidget.h
1