changeset 1608:adc6a5704cdb

OrthancPluginConvertPixelFormat
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 02 Sep 2015 13:58:08 +0200
parents a1c92fd4d26d
children c74495267acf
files Core/ImageFormats/Image.h Core/ImageFormats/ImageBuffer.cpp Core/ImageFormats/ImageBuffer.h Core/ImageFormats/ImageProcessing.cpp Plugins/Engine/OrthancPlugins.cpp Plugins/Engine/OrthancPlugins.h Plugins/Include/orthanc/OrthancCPlugin.h UnitTestsSources/ImageTests.cpp
diffstat 8 files changed, 170 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/ImageFormats/Image.h	Wed Sep 02 13:58:08 2015 +0200
@@ -0,0 +1,55 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "ImageAccessor.h"
+#include "ImageBuffer.h"
+
+namespace Orthanc
+{
+  class Image : public ImageAccessor
+  {
+  private:
+    ImageBuffer  buffer_;
+
+  public:
+    Image(PixelFormat format,
+          unsigned int width,
+          unsigned int height) :
+      buffer_(format, width, height)
+    {
+      ImageAccessor accessor = buffer_.GetAccessor();
+      AssignWritable(format, width, height, accessor.GetPitch(), accessor.GetBuffer());
+    }
+  };
+}
--- a/Core/ImageFormats/ImageBuffer.cpp	Tue Sep 01 17:40:45 2015 +0200
+++ b/Core/ImageFormats/ImageBuffer.cpp	Wed Sep 02 13:58:08 2015 +0200
@@ -85,9 +85,9 @@
   }
 
 
-  ImageBuffer::ImageBuffer(unsigned int width,
-                           unsigned int height,
-                           PixelFormat format)
+  ImageBuffer::ImageBuffer(PixelFormat format,
+                           unsigned int width,
+                           unsigned int height)
   {
     Initialize();
     SetWidth(width);
--- a/Core/ImageFormats/ImageBuffer.h	Tue Sep 01 17:40:45 2015 +0200
+++ b/Core/ImageFormats/ImageBuffer.h	Wed Sep 02 13:58:08 2015 +0200
@@ -59,9 +59,9 @@
     void Deallocate();
 
   public:
-    ImageBuffer(unsigned int width,
-                unsigned int height,
-                PixelFormat format);
+    ImageBuffer(PixelFormat format,
+                unsigned int width,
+                unsigned int height);
 
     ImageBuffer()
     {
--- a/Core/ImageFormats/ImageProcessing.cpp	Tue Sep 01 17:40:45 2015 +0200
+++ b/Core/ImageFormats/ImageProcessing.cpp	Wed Sep 02 13:58:08 2015 +0200
@@ -378,6 +378,47 @@
       return;
     }
 
+    if (target.GetFormat() == PixelFormat_RGB24 &&
+        source.GetFormat() == PixelFormat_RGBA32)
+    {
+      for (unsigned int y = 0; y < source.GetHeight(); y++)
+      {
+        const uint8_t* p = reinterpret_cast<const uint8_t*>(source.GetConstRow(y));
+        uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y));
+        for (unsigned int x = 0; x < source.GetWidth(); x++)
+        {
+          q[0] = p[0];
+          q[1] = p[1];
+          q[2] = p[2];
+          p += 4;
+          q += 3;
+        }
+      }
+
+      return;
+    }
+
+    if (target.GetFormat() == PixelFormat_RGBA32 &&
+        source.GetFormat() == PixelFormat_RGB24)
+    {
+      for (unsigned int y = 0; y < source.GetHeight(); y++)
+      {
+        const uint8_t* p = reinterpret_cast<const uint8_t*>(source.GetConstRow(y));
+        uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y));
+        for (unsigned int x = 0; x < source.GetWidth(); x++)
+        {
+          q[0] = p[0];
+          q[1] = p[1];
+          q[2] = p[2];
+          q[3] = 255;   // Set the alpha channel to full opacity
+          p += 3;
+          q += 4;
+        }
+      }
+
+      return;
+    }
+
     throw OrthancException(ErrorCode_NotImplemented);
   }
 
--- a/Plugins/Engine/OrthancPlugins.cpp	Tue Sep 01 17:40:45 2015 +0200
+++ b/Plugins/Engine/OrthancPlugins.cpp	Wed Sep 02 13:58:08 2015 +0200
@@ -42,10 +42,12 @@
 #include "../../OrthancServer/ServerToolbox.h"
 #include "../../Core/Compression/ZlibCompressor.h"
 #include "../../Core/Compression/GzipCompressor.h"
+#include "../../Core/ImageFormats/Image.h"
 #include "../../Core/ImageFormats/PngReader.h"
 #include "../../Core/ImageFormats/PngWriter.h"
 #include "../../Core/ImageFormats/JpegReader.h"
 #include "../../Core/ImageFormats/JpegWriter.h"
+#include "../../Core/ImageFormats/ImageProcessing.h"
 
 #include <boost/regex.hpp> 
 
@@ -1168,6 +1170,18 @@
   }
 
 
+  void OrthancPlugins::ConvertPixelFormat(const void* parameters)
+  {
+    const _OrthancPluginConvertPixelFormat& p = *reinterpret_cast<const _OrthancPluginConvertPixelFormat*>(parameters);
+    const ImageAccessor& source = *reinterpret_cast<const ImageAccessor*>(p.source);
+
+    std::auto_ptr<ImageAccessor> target(new Image(Convert(p.targetFormat), source.GetWidth(), source.GetHeight()));
+    ImageProcessing::Convert(*target, source);
+
+    *(p.target) = reinterpret_cast<OrthancPluginImage*>(target.release());
+  }
+
+
   bool OrthancPlugins::InvokeService(_OrthancPluginService service,
                                      const void* parameters)
   {
@@ -1530,6 +1544,10 @@
         CallHttpClient(parameters);
         return true;
 
+      case _OrthancPluginService_ConvertPixelFormat:
+        ConvertPixelFormat(parameters);
+        return true;
+
       default:
       {
         // This service is unknown to the Orthanc plugin engine
--- a/Plugins/Engine/OrthancPlugins.h	Tue Sep 01 17:40:45 2015 +0200
+++ b/Plugins/Engine/OrthancPlugins.h	Wed Sep 02 13:58:08 2015 +0200
@@ -104,6 +104,8 @@
 
     void CompressImage(const void* parameters);
 
+    void ConvertPixelFormat(const void* parameters);
+
     void CallHttpClient(const void* parameters);
 
   public:
--- a/Plugins/Include/orthanc/OrthancCPlugin.h	Tue Sep 01 17:40:45 2015 +0200
+++ b/Plugins/Include/orthanc/OrthancCPlugin.h	Wed Sep 02 13:58:08 2015 +0200
@@ -437,6 +437,7 @@
     _OrthancPluginService_UncompressImage = 6005,
     _OrthancPluginService_FreeImage = 6006,
     _OrthancPluginService_CompressImage = 6007,
+    _OrthancPluginService_ConvertPixelFormat = 6008,
 
     _OrthancPluginService_INTERNAL = 0x7fffffff
   } _OrthancPluginService;
@@ -3272,6 +3273,48 @@
 
 
 
+  typedef struct
+  {
+    OrthancPluginImage**       target;
+    const OrthancPluginImage*  source;
+    OrthancPluginPixelFormat   targetFormat;
+  } _OrthancPluginConvertPixelFormat;
+
+
+  /**
+   * @brief Change the pixel format of an image.
+   *
+   * This function creates a new image, changing the memory layout of the pixels.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param source The source image.
+   * @param targetFormat The target pixel format.
+   * @return The resulting image. It must be freed with OrthancPluginFreeImage().
+   * @ingroup Compression
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginImage *OrthancPluginConvertPixelFormat(
+    OrthancPluginContext*      context,
+    const OrthancPluginImage*  source,
+    OrthancPluginPixelFormat   targetFormat)
+  {
+    OrthancPluginImage* target = NULL;
+
+    _OrthancPluginConvertPixelFormat params;
+    params.target = &target;
+    params.source = source;
+    params.targetFormat = targetFormat;
+
+    if (context->InvokeService(context, _OrthancPluginService_ConvertPixelFormat, &params) != OrthancPluginErrorCode_Success)
+    {
+      return NULL;
+    }
+    else
+    {
+      return target;
+    }
+  }
+
+
 #ifdef  __cplusplus
 }
 #endif
--- a/UnitTestsSources/ImageTests.cpp	Tue Sep 01 17:40:45 2015 +0200
+++ b/UnitTestsSources/ImageTests.cpp	Wed Sep 02 13:58:08 2015 +0200
@@ -34,7 +34,7 @@
 #include "gtest/gtest.h"
 
 #include <stdint.h>
-#include "../Core/ImageFormats/ImageBuffer.h"
+#include "../Core/ImageFormats/Image.h"
 #include "../Core/ImageFormats/PngReader.h"
 #include "../Core/ImageFormats/PngWriter.h"
 #include "../Core/ImageFormats/JpegReader.h"
@@ -196,11 +196,10 @@
   std::string s;
 
   {
-    Orthanc::ImageBuffer img(16, 16, Orthanc::PixelFormat_Grayscale8);
-    Orthanc::ImageAccessor accessor = img.GetAccessor();
+    Orthanc::Image img(Orthanc::PixelFormat_Grayscale8, 16, 16);
     for (unsigned int y = 0, value = 0; y < img.GetHeight(); y++)
     {
-      uint8_t* p = reinterpret_cast<uint8_t*>(accessor.GetRow(y));
+      uint8_t* p = reinterpret_cast<uint8_t*>(img.GetRow(y));
       for (unsigned int x = 0; x < img.GetWidth(); x++, p++)
       {
         *p = value++;
@@ -208,9 +207,9 @@
     }
 
     Orthanc::JpegWriter w;
-    w.WriteToFile("UnitTestsResults/hello.jpg", accessor);
+    w.WriteToFile("UnitTestsResults/hello.jpg", img);
 
-    w.WriteToMemory(s, accessor);
+    w.WriteToMemory(s, img);
     Orthanc::Toolbox::WriteFile(s, "UnitTestsResults/hello2.jpg");
 
     std::string t;