changeset 6472:2dce738c496f pixel-anon

pixel anon: define interface + disable PixelMasker from core
author Alain Mazy <am@orthanc.team>
date Thu, 20 Nov 2025 17:49:15 +0100
parents d0920767534e
children 4d8248653a14
files OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake OrthancFramework/Sources/DicomParsing/DicomModification.cpp OrthancFramework/Sources/DicomParsing/DicomModification.h OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h OrthancServer/Sources/ServerContext.cpp
diffstat 5 files changed, 47 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake	Sat Nov 15 12:27:24 2025 +0100
+++ b/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake	Thu Nov 20 17:49:15 2025 +0100
@@ -549,7 +549,6 @@
   set(ORTHANC_DICOM_SOURCES_INTERNAL
     ${CMAKE_CURRENT_LIST_DIR}/../../Sources/DicomNetworking/DicomFindAnswers.cpp
     ${CMAKE_CURRENT_LIST_DIR}/../../Sources/DicomParsing/DicomModification.cpp
-    ${CMAKE_CURRENT_LIST_DIR}/../../Sources/DicomParsing/DicomPixelMasker.cpp
     ${CMAKE_CURRENT_LIST_DIR}/../../Sources/DicomParsing/DicomWebJsonVisitor.cpp
     ${CMAKE_CURRENT_LIST_DIR}/../../Sources/DicomParsing/FromDcmtkBridge.cpp
     ${CMAKE_CURRENT_LIST_DIR}/../../Sources/DicomParsing/ParsedDicomCache.cpp
--- a/OrthancFramework/Sources/DicomParsing/DicomModification.cpp	Sat Nov 15 12:27:24 2025 +0100
+++ b/OrthancFramework/Sources/DicomParsing/DicomModification.cpp	Thu Nov 20 17:49:15 2025 +0100
@@ -31,7 +31,6 @@
 #include "../SerializationToolbox.h"
 #include "FromDcmtkBridge.h"
 #include "ITagVisitor.h"
-#include "DicomPixelMasker.h"
 
 #include <memory>   // For std::unique_ptr
 
@@ -1016,15 +1015,14 @@
       }
     }
 
-    // (0.1) New in Orthanc 1.X.X: Apply pixel modifications
-    // This is done before modifying any tags because the pixelMasker has filters on the Orthanc ids ->
+    // (0.1) New in Orthanc 1.12.10: Apply custom modifications (e.g. pixels masking)
+    // This is done before modifying any tags because the dicomModifier_ might have filters on the Orthanc ids ->
     // the DICOM UID tags must not be modified before.
-    if (pixelMasker_ != NULL)
+    if (dicomModifier_ != NULL)
     {
-      pixelMasker_->Apply(toModify);
+      dicomModifier_->Apply(toModify);
     }
 
-
     // (0.2) Create a summary of the source file, if a custom generator
     // is provided
     if (identifierGenerator_ != NULL)
@@ -1334,12 +1332,13 @@
       privateCreator_ = SerializationToolbox::ReadString(request, "PrivateCreator");
     }
 
-    // New in Orthanc 1.X.X
-    if (request.isMember("MaskPixelData") && request["MaskPixelData"].isObject())
-    {
-      pixelMasker_.reset(new DicomPixelMasker());
-      pixelMasker_->ParseRequest(request);
-    }
+    // TODO-PIXEL-ANON: remove
+    // // New in Orthanc 1.X.X
+    // if (request.isMember("MaskPixelData") && request["MaskPixelData"].isObject())
+    // {
+    //   pixelMasker_.reset(new DicomPixelMasker());
+    //   pixelMasker_->ParseRequest(request);
+    // }
 
     if (!force)
     {
@@ -1461,12 +1460,13 @@
       privateCreator_ = SerializationToolbox::ReadString(request, "PrivateCreator");
     }
 
-    // New in Orthanc 1.X.X
-    if (request.isMember("MaskPixelData") && request["MaskPixelData"].isObject())
-    {
-      pixelMasker_.reset(new DicomPixelMasker());
-      pixelMasker_->ParseRequest(request);
-    }
+    // TODO-PIXEL-ANON: remove
+    // // New in Orthanc 1.X.X
+    // if (request.isMember("MaskPixelData") && request["MaskPixelData"].isObject())
+    // {
+    //   pixelMasker_.reset(new DicomPixelMasker());
+    //   pixelMasker_->ParseRequest(request);
+    // }
   }
 
   void DicomModification::SetDicomIdentifierGenerator(DicomModification::IDicomIdentifierGenerator &generator)
@@ -1931,6 +1931,6 @@
 
   bool DicomModification::RequiresUncompressedTransferSyntax() const
   {
-    return pixelMasker_ != NULL;
+    return dicomModifier_ != NULL;
   }
 }
--- a/OrthancFramework/Sources/DicomParsing/DicomModification.h	Sat Nov 15 12:27:24 2025 +0100
+++ b/OrthancFramework/Sources/DicomParsing/DicomModification.h	Thu Nov 20 17:49:15 2025 +0100
@@ -31,7 +31,6 @@
 
 namespace Orthanc
 {
-  class DicomPixelMasker;
 
   class ORTHANC_PUBLIC DicomModification : public boost::noncopyable
   {
@@ -56,6 +55,16 @@
                          const DicomMap& sourceDicom) = 0;                       
     };
 
+    class ORTHANC_PUBLIC IDicomModifier : public boost::noncopyable
+    {
+    public:
+      virtual ~IDicomModifier()
+      {
+      }
+
+      virtual bool Apply(ParsedDicomFile& dicom) = 0;                       
+    };
+
   private:
     class RelationshipsVisitor;
 
@@ -156,8 +165,8 @@
     ListOfPaths          removeSequences_;       // Must *never* be a path whose prefix is empty
     SequenceReplacements sequenceReplacements_;  // Must *never* be a path whose prefix is empty
 
-    // New in Orthanc 1.X.X
-    std::unique_ptr<DicomPixelMasker>     pixelMasker_;    // TODO-PIXEL-ANON: check ownership & serialization
+    // New in Orthanc 1.12.10
+    std::unique_ptr<IDicomModifier>     dicomModifier_;    // TODO-PIXEL-ANON: check ownership & serialization
 
     std::string MapDicomIdentifier(const std::string& original,
                                    ResourceType level);
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Sat Nov 15 12:27:24 2025 +0100
+++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Thu Nov 20 17:49:15 2025 +0100
@@ -10705,6 +10705,20 @@
     return context->InvokeService(context, _OrthancPluginService_RegisterAuditLogHandler, &params);
   }
 
+  // TODO-PIXEL-ANON: cleanup (or implement ;-) )
+  // ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterCustomModifier(
+  //   OrthancPluginContext*                  context,
+  //   OrthancPluginCustomModifierFactory     factory,    // signature like CreateCustomModifier(void* output, 
+  //                                                      //                                     const void* request, uint64_t requestSize // the full json request or only the "CustomModifier part" ?
+  //                                                      //                                     const char* resourceId, ResourceLevel ..  // that would allow the plugin e.g. to detect the areas to clear by e.g: detecting the patient face ...
+  //                                                      // )
+  //                                                      // Creates a CustomModifier from: 
+  //                                                      // - either a request payload 
+  //                                                      // - or, from a serialized modification job (the job would serialize its creation request.  This way, we don't need to implement serialize/unserialize in the CustomModifier)
+  //   OrthancPluginApplyCustomModifier       apply,      // signature like OrthancPluginDicomInstance* ApplyCustomModifier(void* modifier, OrthancPluginDicomInstance* source)
+  //   OrthancPluginFreeCustomModifier        free,       // signature like void FreeCustomModifier(void* modifier)
+  // )
+  
 
 #ifdef  __cplusplus
 }
--- a/OrthancServer/Sources/ServerContext.cpp	Sat Nov 15 12:27:24 2025 +0100
+++ b/OrthancServer/Sources/ServerContext.cpp	Thu Nov 20 17:49:15 2025 +0100
@@ -2096,7 +2096,7 @@
     const std::string originalSopInstanceUid = IDicomTranscoder::GetSopInstanceUid(dicomFile->GetDcmtkObject());  
     std::string forceModifiedSopInstanceUid;
 
-    // do we need to transcode before ?
+    // do we need to transcode before applying e.g custom pixels modifications ?
     DicomTransferSyntax currentTransferSyntax;
     if (modification.RequiresUncompressedTransferSyntax() && 
         dicomFile->LookupTransferSyntax(currentTransferSyntax) &&
@@ -2133,12 +2133,11 @@
         }
       }
 
-      if (!transcode) // if we had to change the TS for the modification, we need to restore the original TS afterwards
+      if (!transcode) // if we had to change the TS for the modification, we will need to restore the original TS afterwards
       {
         transcode = true;
         targetSyntax = currentTransferSyntax;
       }
-      
     }
 
     modification.Apply(*dicomFile);