changeset 4406:4cb9f66a1c7c

documenting generation of images
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 24 Dec 2020 17:32:19 +0100
parents 5466f336b09f
children 2412601cd24b
files OrthancFramework/Sources/RestApi/RestApi.cpp OrthancFramework/Sources/RestApi/RestApiCall.h OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp
diffstat 3 files changed, 116 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Sources/RestApi/RestApi.cpp	Thu Dec 24 09:37:30 2020 +0100
+++ b/OrthancFramework/Sources/RestApi/RestApi.cpp	Thu Dec 24 17:32:19 2020 +0100
@@ -161,18 +161,21 @@
           throw OrthancException(ErrorCode_InternalError);
         }
 
-        std::set<std::string> uriArguments;
+        std::set<std::string> uriArgumentsNames;
+        HttpToolbox::Arguments uriArguments;
         
         for (HttpToolbox::Arguments::const_iterator
                it = components.begin(); it != components.end(); ++it)
         {
           assert(it->second.empty());
-          uriArguments.insert(it->first.c_str());
+          uriArgumentsNames.insert(it->first.c_str());
+          uriArguments[it->first] = "";
         }
 
         if (hasTrailing)
         {
-          uriArguments.insert("...");
+          uriArgumentsNames.insert("...");
+          uriArguments["..."] = "";
         }
 
         if (resource.HasHandler(HttpMethod_Get))
@@ -184,8 +187,7 @@
           RestApiOutput o3(o2, HttpMethod_Get);
           RestApiGetCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */,
                               "" /* username */, HttpToolbox::Arguments() /* HTTP headers */,
-                              HttpToolbox::Arguments() /* URI components */,
-                              UriComponents() /* trailing */,
+                              uriArguments, UriComponents() /* trailing */,
                               uri, HttpToolbox::Arguments() /* GET arguments */);
 
           bool ok = false;
@@ -194,7 +196,7 @@
           try
           {
             ok = (resource.Handle(call) &&
-                  call.GetDocumentation().FormatOpenApi(v, uriArguments));
+                  call.GetDocumentation().FormatOpenApi(v, uriArgumentsNames));
           }
           catch (OrthancException&)
           {
@@ -223,8 +225,8 @@
           RestApiOutput o3(o2, HttpMethod_Post);
           RestApiPostCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */,
                                "" /* username */, HttpToolbox::Arguments() /* HTTP headers */,
-                               HttpToolbox::Arguments() /* URI components */,
-                               UriComponents() /* trailing */, uri, NULL /* body */, 0 /* body size */);
+                               uriArguments, UriComponents() /* trailing */,
+                               uri, NULL /* body */, 0 /* body size */);
 
           bool ok = false;
           Json::Value v;
@@ -232,7 +234,7 @@
           try
           {
             ok = (resource.Handle(call) &&
-                  call.GetDocumentation().FormatOpenApi(v, uriArguments));
+                  call.GetDocumentation().FormatOpenApi(v, uriArgumentsNames));
           }
           catch (OrthancException&)
           {
@@ -261,8 +263,7 @@
           RestApiOutput o3(o2, HttpMethod_Delete);
           RestApiDeleteCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */,
                                  "" /* username */, HttpToolbox::Arguments() /* HTTP headers */,
-                                 HttpToolbox::Arguments() /* URI components */,
-                                 UriComponents() /* trailing */, uri);
+                                 uriArguments, UriComponents() /* trailing */, uri);
 
           bool ok = false;
           Json::Value v;
@@ -270,7 +271,7 @@
           try
           {
             ok = (resource.Handle(call) &&
-                  call.GetDocumentation().FormatOpenApi(v, uriArguments));
+                  call.GetDocumentation().FormatOpenApi(v, uriArgumentsNames));
           }
           catch (OrthancException&)
           {
@@ -299,8 +300,8 @@
           RestApiOutput o3(o2, HttpMethod_Put);
           RestApiPutCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */,
                               "" /* username */, HttpToolbox::Arguments() /* HTTP headers */,
-                              HttpToolbox::Arguments() /* URI components */,
-                              UriComponents() /* trailing */, uri, NULL /* body */, 0 /* body size */);
+                              uriArguments, UriComponents() /* trailing */, uri,
+                              NULL /* body */, 0 /* body size */);
 
           bool ok = false;
           Json::Value v;
@@ -308,7 +309,7 @@
           try
           {
             ok = (resource.Handle(call) &&
-                  call.GetDocumentation().FormatOpenApi(v, uriArguments));
+                  call.GetDocumentation().FormatOpenApi(v, uriArgumentsNames));
           }
           catch (OrthancException&)
           {
@@ -523,8 +524,8 @@
     OpenApiVisitor visitor(*this);
     
     UriComponents root;
-    std::set<std::string> uriArguments;
-    root_.ExploreAllResources(visitor, root, uriArguments);
+    std::set<std::string> uriArgumentsNames;
+    root_.ExploreAllResources(visitor, root, uriArgumentsNames);
 
     target = Json::objectValue;
 
--- a/OrthancFramework/Sources/RestApi/RestApiCall.h	Thu Dec 24 09:37:30 2020 +0100
+++ b/OrthancFramework/Sources/RestApi/RestApiCall.h	Thu Dec 24 17:32:19 2020 +0100
@@ -92,6 +92,11 @@
       return trailing_;
     }
 
+    bool HasUriComponent(const std::string& name) const
+    {
+      return (uriComponents_.find(name) != uriComponents_.end());
+    }
+
     std::string GetUriComponent(const std::string& name,
                                 const std::string& defaultValue) const
     {
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Thu Dec 24 09:37:30 2020 +0100
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Thu Dec 24 17:32:19 2020 +0100
@@ -664,8 +664,98 @@
       virtual bool RequiresDicomTags() const = 0;
 
       static void Apply(RestApiGetCall& call,
-                        IDecodedFrameHandler& handler)
+                        IDecodedFrameHandler& handler,
+                        ImageExtractionMode mode /* for generation of documentation */,
+                        bool isRendered /* for generation of documentation */)
       {
+        if (call.IsDocumentation())
+        {
+          std::string m;
+          if (!isRendered)
+          {
+            switch (mode)
+            {
+              case ImageExtractionMode_Preview:
+                m = "preview";
+                break;
+              case ImageExtractionMode_UInt8:
+                m = "uint8";
+                break;
+              case ImageExtractionMode_UInt16:
+                m = "uint16";
+                break;
+              case ImageExtractionMode_Int16:
+                m = "int16";
+                break;
+              default:
+                throw OrthancException(ErrorCode_ParameterOutOfRange);
+            }
+          }
+          
+          std::string description;
+          std::string verb = (isRendered ? "Render" : "Decode");
+          
+          if (call.HasUriComponent("frame"))
+          {
+            description = verb + " one frame of interest from the given DICOM instance.";
+            call.GetDocumentation()
+              .SetSummary(verb + " a frame" + (m.empty() ? "" : " (" + m + ")"))
+              .SetUriArgument("frame", RestApiCallDocumentation::Type_Number, "Index of the frame (starts at `0`)");
+          }
+          else
+          {
+            description = verb + " the first frame of the given DICOM instance.";
+            call.GetDocumentation()
+              .SetSummary(verb + " an image" + (m.empty() ? "" : " (" + m + ")"));
+          }
+
+          if (isRendered)
+          {
+            description += (" This function takes scaling into account (`RescaleSlope` and `RescaleIntercept` tags), "
+                            "as well as the default windowing stored in the DICOM file (`WindowCenter` and `WindowWidth`tags), "
+                            "and can be used to resize the resulting image. Color images are not affected by windowing.");
+            call.GetDocumentation()
+              .SetHttpGetArgument("window-center",RestApiCallDocumentation::Type_Number, "Windowing center", false)
+              .SetHttpGetArgument("window-width",RestApiCallDocumentation::Type_Number, "Windowing width", false)
+              .SetHttpGetArgument("width",RestApiCallDocumentation::Type_Number, "Width of the resized image", false)
+              .SetHttpGetArgument("height",RestApiCallDocumentation::Type_Number, "Height of the resized image", false)
+              .SetHttpGetArgument("smooth",RestApiCallDocumentation::Type_Boolean, "Whether to smooth image on resize", false);
+          }
+          else
+          {
+            switch (mode)
+            {
+              case ImageExtractionMode_Preview:
+                description += " The full dynamic range of grayscale images is rescaled to the [0,255] range.";
+                break;
+              case ImageExtractionMode_UInt8:
+                description += " Pixels of grayscale images are truncated to the [0,255] range.";
+                break;
+              case ImageExtractionMode_UInt16:
+                description += " Pixels of grayscale images are truncated to the [0,65535] range.";
+                break;
+              case ImageExtractionMode_Int16:
+                description += (" Pixels of grayscale images are truncated to the [-32768,32767] range. "
+                                "Negative values must be interpreted according to two's complement.");
+                break;
+              default:
+                throw OrthancException(ErrorCode_ParameterOutOfRange);
+            }
+          }
+          
+          call.GetDocumentation()
+            .SetTag("Instances")
+            .SetUriArgument("id", "Orthanc identifier of the DICOM instance of interest")
+            .SetHttpGetArgument("quality", RestApiCallDocumentation::Type_Number, "Quality for JPEG images (between 1 and 100, defaults to 90)", false)
+            .SetHttpHeader("Accept", "Format of the resulting image. Can be `image/png` (default), `image/jpeg` or `image/x-portable-arbitrarymap`")
+            .AddAnswerType(MimeType_Png, "PNG image")
+            .AddAnswerType(MimeType_Jpeg, "JPEG image")
+            .AddAnswerType(MimeType_Pam, "PAM image (Portable Arbitrary Map)")
+            .SetDescription(description);
+
+          return;
+        }
+        
         ServerContext& context = OrthancRestApi::GetContext(call);
 
         std::string frameId = call.GetUriComponent("frame", "0");
@@ -1060,7 +1150,7 @@
     Semaphore::Locker locker(throttlingSemaphore_);
         
     GetImageHandler handler(mode);
-    IDecodedFrameHandler::Apply(call, handler);
+    IDecodedFrameHandler::Apply(call, handler, mode, false /* not rendered */);
   }
 
 
@@ -1069,7 +1159,7 @@
     Semaphore::Locker locker(throttlingSemaphore_);
         
     RenderedFrameHandler handler;
-    IDecodedFrameHandler::Apply(call, handler);
+    IDecodedFrameHandler::Apply(call, handler, ImageExtractionMode_Preview /* arbitrary value */, true);
   }