changeset 1612:96582230ddcb

Core/ImageFormats folder renamed as Core/Images
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 04 Sep 2015 16:36:18 +0200
parents 5e9b2aac8b89
children 1ec254a7c645
files CMakeLists.txt Core/ImageFormats/Font.cpp Core/ImageFormats/Font.h Core/ImageFormats/FontRegistry.cpp Core/ImageFormats/FontRegistry.h Core/ImageFormats/Image.h Core/ImageFormats/ImageAccessor.cpp Core/ImageFormats/ImageAccessor.h Core/ImageFormats/ImageBuffer.cpp Core/ImageFormats/ImageBuffer.h Core/ImageFormats/ImageProcessing.cpp Core/ImageFormats/ImageProcessing.h Core/ImageFormats/JpegErrorManager.cpp Core/ImageFormats/JpegErrorManager.h Core/ImageFormats/JpegReader.cpp Core/ImageFormats/JpegReader.h Core/ImageFormats/JpegWriter.cpp Core/ImageFormats/JpegWriter.h Core/ImageFormats/PngReader.cpp Core/ImageFormats/PngReader.h Core/ImageFormats/PngWriter.cpp Core/ImageFormats/PngWriter.h Core/Images/Font.cpp Core/Images/Font.h Core/Images/FontRegistry.cpp Core/Images/FontRegistry.h Core/Images/Image.h Core/Images/ImageAccessor.cpp Core/Images/ImageAccessor.h Core/Images/ImageBuffer.cpp Core/Images/ImageBuffer.h Core/Images/ImageProcessing.cpp Core/Images/ImageProcessing.h Core/Images/JpegErrorManager.cpp Core/Images/JpegErrorManager.h Core/Images/JpegReader.cpp Core/Images/JpegReader.h Core/Images/JpegWriter.cpp Core/Images/JpegWriter.h Core/Images/PngReader.cpp Core/Images/PngReader.h Core/Images/PngWriter.cpp Core/Images/PngWriter.h OrthancServer/FromDcmtkBridge.cpp OrthancServer/Internals/DicomImageDecoder.cpp OrthancServer/Internals/DicomImageDecoder.h OrthancServer/OrthancInitialization.h OrthancServer/ParsedDicomFile.cpp OrthancServer/ParsedDicomFile.h Plugins/Engine/OrthancPlugins.cpp UnitTestsSources/FromDcmtkTests.cpp UnitTestsSources/ImageProcessingTests.cpp UnitTestsSources/ImageTests.cpp UnitTestsSources/JpegLosslessTests.cpp
diffstat 54 files changed, 3389 insertions(+), 3389 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Fri Sep 04 16:30:42 2015 +0200
+++ b/CMakeLists.txt	Fri Sep 04 16:36:18 2015 +0200
@@ -121,16 +121,16 @@
   Core/MultiThreading/ReaderWriterLock.cpp
   Core/MultiThreading/Semaphore.cpp
   Core/MultiThreading/SharedMessageQueue.cpp
-  Core/ImageFormats/Font.cpp
-  Core/ImageFormats/FontRegistry.cpp
-  Core/ImageFormats/ImageAccessor.cpp
-  Core/ImageFormats/ImageBuffer.cpp
-  Core/ImageFormats/ImageProcessing.cpp
-  Core/ImageFormats/JpegErrorManager.cpp
-  Core/ImageFormats/JpegReader.cpp
-  Core/ImageFormats/JpegWriter.cpp
-  Core/ImageFormats/PngReader.cpp
-  Core/ImageFormats/PngWriter.cpp
+  Core/Images/Font.cpp
+  Core/Images/FontRegistry.cpp
+  Core/Images/ImageAccessor.cpp
+  Core/Images/ImageBuffer.cpp
+  Core/Images/ImageProcessing.cpp
+  Core/Images/JpegErrorManager.cpp
+  Core/Images/JpegReader.cpp
+  Core/Images/JpegWriter.cpp
+  Core/Images/PngReader.cpp
+  Core/Images/PngWriter.cpp
   Core/SQLite/Connection.cpp
   Core/SQLite/FunctionContext.cpp
   Core/SQLite/Statement.cpp
--- a/Core/ImageFormats/Font.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,298 +0,0 @@
-/**
- * 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/>.
- **/
-
-
-#include "../PrecompiledHeaders.h"
-#include "Font.h"
-
-#include "../Toolbox.h"
-#include "../OrthancException.h"
-
-#include <stdio.h>
-#include <memory>
-#include <boost/lexical_cast.hpp>
-
-namespace Orthanc
-{
-  Font::~Font()
-  {
-    for (Characters::iterator it = characters_.begin();
-         it != characters_.end(); it++)
-    {
-      delete it->second;
-    }
-  }
-
-
-  void Font::LoadFromMemory(const std::string& font)
-  {
-    Json::Value v;
-    Json::Reader reader;
-    if (!reader.parse(font, v) ||
-        v.type() != Json::objectValue ||
-        !v.isMember("Name") ||
-        !v.isMember("Size") ||
-        !v.isMember("Characters") ||
-        v["Name"].type() != Json::stringValue ||
-        v["Size"].type() != Json::intValue ||
-        v["Characters"].type() != Json::objectValue)
-    {
-      throw OrthancException(ErrorCode_BadFont);
-    }
-
-    name_ = v["Name"].asString();
-    size_ = v["Size"].asUInt();
-    maxHeight_ = 0;
-
-    Json::Value::Members characters = v["Characters"].getMemberNames();
-
-    for (size_t i = 0; i < characters.size(); i++)
-    {
-      const Json::Value& info = v["Characters"][characters[i]];
-      if (info.type() != Json::objectValue ||
-          !info.isMember("Advance") ||
-          !info.isMember("Bitmap") ||
-          !info.isMember("Height") ||
-          !info.isMember("Top") ||
-          !info.isMember("Width") ||
-          info["Advance"].type() != Json::intValue ||
-          info["Bitmap"].type() != Json::arrayValue ||
-          info["Height"].type() != Json::intValue ||
-          info["Top"].type() != Json::intValue ||
-          info["Width"].type() != Json::intValue)
-      {
-        throw OrthancException(ErrorCode_BadFont);
-      }
-
-      std::auto_ptr<Character> c(new Character);
-      
-      c->advance_ = info["Advance"].asUInt();
-      c->height_ = info["Height"].asUInt();
-      c->top_ = info["Top"].asUInt();
-      c->width_ = info["Width"].asUInt();
-      c->bitmap_.resize(info["Bitmap"].size());
-
-      if (c->height_ > maxHeight_)
-      {
-        maxHeight_ = c->height_;
-      }
-      
-      for (Json::Value::ArrayIndex j = 0; j < info["Bitmap"].size(); j++)
-      {
-        if (info["Bitmap"][j].type() != Json::intValue)
-        {
-          throw OrthancException(ErrorCode_BadFont);
-        }
-
-        int value = info["Bitmap"][j].asInt();
-        if (value < 0 || value > 255)
-        {
-          throw OrthancException(ErrorCode_BadFont);
-        }
-
-        c->bitmap_[j] = value;
-      }
-
-      int index = boost::lexical_cast<int>(characters[i]);
-      if (index < 0 || index > 255)
-      {
-        throw OrthancException(ErrorCode_BadFont);
-      }
-
-      characters_[static_cast<char>(index)] = c.release();
-    }
-  }
-
-
-  void Font::LoadFromFile(const std::string& path)
-  {
-    std::string font;
-    Toolbox::ReadFile(font, path);
-    LoadFromMemory(font);
-  }
-
-
-  static unsigned int MyMin(unsigned int a, 
-                            unsigned int b)
-  {
-    return a < b ? a : b;
-  }
-
-
-  void Font::DrawCharacter(ImageAccessor& target,
-                           const Character& character,
-                           int x,
-                           int y,
-                           const uint8_t color[4]) const
-  {
-    // Compute the bounds of the character
-    if (x >= static_cast<int>(target.GetWidth()) ||
-        y >= static_cast<int>(target.GetHeight()))
-    {
-      // The character is out of the image
-      return;
-    }
-
-    unsigned int left = x < 0 ? -x : 0;
-    unsigned int top = y < 0 ? -y : 0;
-    unsigned int width = MyMin(character.width_, target.GetWidth() - x);
-    unsigned int height = MyMin(character.height_, target.GetHeight() - y);
-
-    uint8_t bpp = target.GetBytesPerPixel();
-
-    // Blit the font bitmap OVER the target image
-    // https://en.wikipedia.org/wiki/Alpha_compositing
-
-    for (unsigned int cy = top; cy < height; cy++)
-    {
-      uint8_t* p = reinterpret_cast<uint8_t*>(target.GetRow(y + cy)) + (x + left) * bpp;
-      unsigned int pos = cy * character.width_ + left;
-
-      switch (target.GetFormat())
-      {
-        case PixelFormat_Grayscale8:
-        {
-          assert(bpp == 1);
-          for (unsigned int cx = left; cx < width; cx++, pos++, p++)
-          {
-            uint16_t alpha = character.bitmap_[pos];
-            *p = (alpha * static_cast<uint16_t>(color[0]) + (255 - alpha) * static_cast<uint16_t>(*p)) >> 8;
-          }
-
-          break;
-        }
-
-        case PixelFormat_RGB24:
-        {
-          assert(bpp == 3);
-          for (unsigned int cx = left; cx < width; cx++, pos++, p += 3)
-          {
-            uint16_t alpha = character.bitmap_[pos];
-            p[0] = (alpha * static_cast<uint16_t>(color[0]) + (255 - alpha) * static_cast<uint16_t>(p[0])) >> 8;
-            p[1] = (alpha * static_cast<uint16_t>(color[1]) + (255 - alpha) * static_cast<uint16_t>(p[1])) >> 8;
-            p[2] = (alpha * static_cast<uint16_t>(color[2]) + (255 - alpha) * static_cast<uint16_t>(p[2])) >> 8;
-          }
-
-          break;
-        }
-
-        case PixelFormat_RGBA32:
-        {
-          assert(bpp == 4);
-
-          for (unsigned int cx = left; cx < width; cx++, pos++, p += 4)
-          {
-            float alpha = static_cast<float>(character.bitmap_[pos]) / 255.0f;
-            float beta = (1.0f - alpha) * static_cast<float>(p[3]) / 255.0f;
-            float denom = 1.0f / (alpha + beta);
-
-            for (uint8_t i = 0; i < 3; i++)
-            {
-              p[i] = static_cast<uint8_t>((alpha * static_cast<float>(color[i]) +
-                                           beta * static_cast<float>(p[i])) * denom);
-            }
-
-            p[3] = static_cast<uint8_t>(255.0f * (alpha + beta));
-          }
-
-          break;
-        }
-
-        default:
-          throw OrthancException(ErrorCode_NotImplemented);
-      }
-    }
-
-  }
-
-
-  void Font::DrawInternal(ImageAccessor& target,
-                          const std::string& utf8,
-                          int x,
-                          int y,
-                          const uint8_t color[4]) const
-  {
-    if (target.GetFormat() != PixelFormat_Grayscale8 &&
-        target.GetFormat() != PixelFormat_RGB24 &&
-        target.GetFormat() != PixelFormat_RGBA32)
-    {
-      throw OrthancException(ErrorCode_NotImplemented);
-    }
-
-    int a = x;
-
-    std::string s = Toolbox::ConvertFromUtf8(utf8, Encoding_Latin1);
-
-    for (size_t i = 0; i < s.size(); i++)
-    {
-      if (s[i] == '\n')
-      {
-        // Go to the next line
-        a = x;
-        y += maxHeight_ + 1;
-      }
-      else
-      {
-        Characters::const_iterator c = characters_.find(s[i]);
-        if (c != characters_.end())
-        {
-          DrawCharacter(target, *c->second, a, y + static_cast<int>(c->second->top_), color);
-          a += c->second->advance_;
-        }
-      }
-    }
-  }
-
-
-  void Font::Draw(ImageAccessor& target,
-                  const std::string& utf8,
-                  int x,
-                  int y,
-                  uint8_t grayscale) const
-  {
-    uint8_t color[4] = { grayscale, grayscale, grayscale, 255 };
-    DrawInternal(target, utf8, x, y, color);
-  }
-
-
-  void Font::Draw(ImageAccessor& target,
-                  const std::string& utf8,
-                  int x,
-                  int y,
-                  uint8_t r,
-                  uint8_t g,
-                  uint8_t b) const
-  {
-    uint8_t color[4] = { r, g, b, 255 };
-    DrawInternal(target, utf8, x, y, color);
-  }
-
-}
--- a/Core/ImageFormats/Font.h	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
-/**
- * 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 <stdint.h>
-#include <vector>
-#include <map>
-
-namespace Orthanc
-{
-  class Font
-  {
-  private:
-    struct Character
-    {
-      unsigned int  width_;
-      unsigned int  height_;
-      unsigned int  top_;
-      unsigned int  advance_;
-      std::vector<uint8_t>  bitmap_;
-    };
-
-    typedef std::map<char, Character*>  Characters;
-
-    std::string   name_;
-    unsigned int  size_;
-    Characters    characters_;
-    unsigned int  maxHeight_;
-
-    void DrawCharacter(ImageAccessor& target,
-                       const Character& character,
-                       int x,
-                       int y,
-                       const uint8_t color[4]) const;
-
-    void DrawInternal(ImageAccessor& target,
-                      const std::string& utf8,
-                      int x,
-                      int y,
-                      const uint8_t color[4]) const;
-
-  public:
-    ~Font();
-
-    void LoadFromMemory(const std::string& font);
-
-    void LoadFromFile(const std::string& path);
-
-    const std::string& GetName() const
-    {
-      return name_;
-    }
-
-    unsigned int GetSize() const
-    {
-      return size_;
-    }
-
-    void Draw(ImageAccessor& target,
-              const std::string& utf8,
-              int x,
-              int y,
-              uint8_t grayscale) const;
-
-    void Draw(ImageAccessor& target,
-              const std::string& utf8,
-              int x,
-              int y,
-              uint8_t r,
-              uint8_t g,
-              uint8_t b) const;
-  };
-}
--- a/Core/ImageFormats/FontRegistry.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/**
- * 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/>.
- **/
-
-
-#include "../PrecompiledHeaders.h"
-#include "FontRegistry.h"
-
-#include "../OrthancException.h"
-
-#include <memory>
-
-namespace Orthanc
-{
-  FontRegistry::~FontRegistry()
-  {
-    for (Fonts::iterator it = fonts_.begin(); it != fonts_.end(); ++it)
-    {
-      delete *it;
-    }
-  }
-
-
-  void FontRegistry::AddFromMemory(const std::string& font)
-  {
-    std::auto_ptr<Font> f(new Font);
-    f->LoadFromMemory(font);
-    fonts_.push_back(f.release());
-  }
-
-
-  void FontRegistry::AddFromFile(const std::string& path)
-  {
-    std::auto_ptr<Font> f(new Font);
-    f->LoadFromFile(path);
-    fonts_.push_back(f.release());
-  }
-
-
-  void FontRegistry::AddFromResource(EmbeddedResources::FileResourceId resource)
-  {
-    std::string content;
-    EmbeddedResources::GetFileResource(content, resource);
-    AddFromMemory(content);
-  }
-
-
-  const Font& FontRegistry::GetFont(size_t i) const
-  {
-    if (i >= fonts_.size())
-    {
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-    else
-    {
-      return *fonts_[i];
-    }
-  }
-}
--- a/Core/ImageFormats/FontRegistry.h	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/**
- * 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 "Font.h"
-
-#include <EmbeddedResources.h>   // Autogenerated file
-
-namespace Orthanc
-{
-  class FontRegistry
-  {
-  private:
-    typedef std::vector<Font*>  Fonts;
-
-    Fonts  fonts_;
-
-  public:
-    ~FontRegistry();
-
-    void AddFromMemory(const std::string& font);
-
-    void AddFromFile(const std::string& path);
-
-    void AddFromResource(EmbeddedResources::FileResourceId resource);
-
-    size_t GetSize() const
-    {
-      return fonts_.size();
-    }
-
-    const Font& GetFont(size_t i) const;
-  };
-}
--- a/Core/ImageFormats/Image.h	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/**
- * 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/ImageAccessor.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,229 +0,0 @@
-/**
- * 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/>.
- **/
-
-
-#include "../PrecompiledHeaders.h"
-#include "ImageAccessor.h"
-
-#include "../Logging.h"
-#include "../OrthancException.h"
-#include "../ChunkedBuffer.h"
-
-#include <stdint.h>
-#include <cassert>
-#include <boost/lexical_cast.hpp>
-
-
-
-namespace Orthanc
-{
-  template <typename PixelType>
-  static void ToMatlabStringInternal(ChunkedBuffer& target,
-                                     const ImageAccessor& source)
-  {
-    target.AddChunk("double([ ");
-
-    for (unsigned int y = 0; y < source.GetHeight(); y++)
-    {
-      const PixelType* p = reinterpret_cast<const PixelType*>(source.GetConstRow(y));
-
-      std::string s;
-      if (y > 0)
-      {
-        s = "; ";
-      }
-
-      s.reserve(source.GetWidth() * 8);
-
-      for (unsigned int x = 0; x < source.GetWidth(); x++, p++)
-      {
-        s += boost::lexical_cast<std::string>(static_cast<int>(*p)) + " ";
-      }
-
-      target.AddChunk(s);
-    }
-
-    target.AddChunk("])");
-  }
-
-
-  static void RGB24ToMatlabString(ChunkedBuffer& target,
-                                  const ImageAccessor& source)
-  {
-    assert(source.GetFormat() == PixelFormat_RGB24);
-
-    target.AddChunk("double(permute(reshape([ ");
-
-    for (unsigned int y = 0; y < source.GetHeight(); y++)
-    {
-      const uint8_t* p = reinterpret_cast<const uint8_t*>(source.GetConstRow(y));
-      
-      std::string s;
-      s.reserve(source.GetWidth() * 3 * 8);
-      
-      for (unsigned int x = 0; x < 3 * source.GetWidth(); x++, p++)
-      {
-        s += boost::lexical_cast<std::string>(static_cast<int>(*p)) + " ";
-      }
-      
-      target.AddChunk(s);
-    }
-
-    target.AddChunk("], [ 3 " + boost::lexical_cast<std::string>(source.GetHeight()) +
-                    " " + boost::lexical_cast<std::string>(source.GetWidth()) + " ]), [ 3 2 1 ]))");
-  }
-
-
-  void* ImageAccessor::GetBuffer() const
-  {
-    if (readOnly_)
-    {
-#if ORTHANC_ENABLE_LOGGING == 1
-      LOG(ERROR) << "Trying to write on a read-only image";
-#endif
-
-      throw OrthancException(ErrorCode_ReadOnly);
-    }
-
-    return buffer_;
-  }
-
-
-  const void* ImageAccessor::GetConstRow(unsigned int y) const
-  {
-    if (buffer_ != NULL)
-    {
-      return reinterpret_cast<const uint8_t*>(buffer_) + y * pitch_;
-    }
-    else
-    {
-      return NULL;
-    }
-  }
-
-
-  void* ImageAccessor::GetRow(unsigned int y) const
-  {
-    if (readOnly_)
-    {
-#if ORTHANC_ENABLE_LOGGING == 1
-      LOG(ERROR) << "Trying to write on a read-only image";
-#endif
-
-      throw OrthancException(ErrorCode_ReadOnly);
-    }
-
-    if (buffer_ != NULL)
-    {
-      return reinterpret_cast<uint8_t*>(buffer_) + y * pitch_;
-    }
-    else
-    {
-      return NULL;
-    }
-  }
-
-
-  void ImageAccessor::AssignEmpty(PixelFormat format)
-  {
-    readOnly_ = false;
-    format_ = format;
-    width_ = 0;
-    height_ = 0;
-    pitch_ = 0;
-    buffer_ = NULL;
-  }
-
-
-  void ImageAccessor::AssignReadOnly(PixelFormat format,
-                                     unsigned int width,
-                                     unsigned int height,
-                                     unsigned int pitch,
-                                     const void *buffer)
-  {
-    readOnly_ = true;
-    format_ = format;
-    width_ = width;
-    height_ = height;
-    pitch_ = pitch;
-    buffer_ = const_cast<void*>(buffer);
-
-    assert(GetBytesPerPixel() * width_ <= pitch_);
-  }
-
-
-  void ImageAccessor::AssignWritable(PixelFormat format,
-                                     unsigned int width,
-                                     unsigned int height,
-                                     unsigned int pitch,
-                                     void *buffer)
-  {
-    readOnly_ = false;
-    format_ = format;
-    width_ = width;
-    height_ = height;
-    pitch_ = pitch;
-    buffer_ = buffer;
-
-    assert(GetBytesPerPixel() * width_ <= pitch_);
-  }
-
-
-  void ImageAccessor::ToMatlabString(std::string& target) const
-  {
-    ChunkedBuffer buffer;
-
-    switch (GetFormat())
-    {
-      case PixelFormat_Grayscale8:
-        ToMatlabStringInternal<uint8_t>(buffer, *this);
-        break;
-
-      case PixelFormat_Grayscale16:
-        ToMatlabStringInternal<uint16_t>(buffer, *this);
-        break;
-
-      case PixelFormat_SignedGrayscale16:
-        ToMatlabStringInternal<int16_t>(buffer, *this);
-        break;
-
-      case PixelFormat_RGB24:
-        RGB24ToMatlabString(buffer, *this);
-        break;
-
-      default:
-        throw OrthancException(ErrorCode_NotImplemented);
-    }   
-
-    buffer.Flatten(target);
-  }
-
-}
--- a/Core/ImageFormats/ImageAccessor.h	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-/**
- * 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 "../Enumerations.h"
-
-#include <string>
-
-namespace Orthanc
-{
-  class ImageAccessor
-  {
-  private:
-    bool readOnly_;
-    PixelFormat format_;
-    unsigned int width_;
-    unsigned int height_;
-    unsigned int pitch_;
-    void *buffer_;
-
-  public:
-    ImageAccessor()
-    {
-      AssignEmpty(PixelFormat_Grayscale8);
-    }
-
-    virtual ~ImageAccessor()
-    {
-    }
-
-    bool IsReadOnly() const
-    {
-      return readOnly_;
-    }
-
-    PixelFormat GetFormat() const
-    {
-      return format_;
-    }
-
-    unsigned int GetBytesPerPixel() const
-    {
-      return ::Orthanc::GetBytesPerPixel(format_);
-    }
-
-    unsigned int GetWidth() const
-    {
-      return width_;
-    }
-
-    unsigned int GetHeight() const
-    {
-      return height_;
-    }
-
-    unsigned int GetPitch() const
-    {
-      return pitch_;
-    }
-
-    unsigned int GetSize() const
-    {
-      return GetHeight() * GetPitch();
-    }
-
-    const void* GetConstBuffer() const
-    {
-      return buffer_;
-    }
-
-    void* GetBuffer() const;
-
-    const void* GetConstRow(unsigned int y) const;
-
-    void* GetRow(unsigned int y) const;
-
-    void AssignEmpty(PixelFormat format);
-
-    void AssignReadOnly(PixelFormat format,
-                        unsigned int width,
-                        unsigned int height,
-                        unsigned int pitch,
-                        const void *buffer);
-
-    void AssignWritable(PixelFormat format,
-                        unsigned int width,
-                        unsigned int height,
-                        unsigned int pitch,
-                        void *buffer);
-
-    void ToMatlabString(std::string& target) const; 
-  };
-}
--- a/Core/ImageFormats/ImageBuffer.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,192 +0,0 @@
-/**
- * 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/>.
- **/
-
-
-#include "../PrecompiledHeaders.h"
-#include "ImageBuffer.h"
-
-#include "../OrthancException.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-namespace Orthanc
-{
-  void ImageBuffer::Allocate()
-  {
-    if (changed_)
-    {
-      Deallocate();
-
-      /*
-        if (forceMinimalPitch_)
-        {
-        TODO: Align pitch and memory buffer to optimal size for SIMD.
-        }
-      */
-
-      pitch_ = GetBytesPerPixel() * width_;
-      size_t size = pitch_ * height_;
-
-      if (size == 0)
-      {
-        buffer_ = NULL;
-      }
-      else
-      {
-        buffer_ = malloc(size);
-        if (buffer_ == NULL)
-        {
-          throw OrthancException(ErrorCode_NotEnoughMemory);
-        }
-      }
-
-      changed_ = false;
-    }
-  }
-
-
-  void ImageBuffer::Deallocate()
-  {
-    if (buffer_ != NULL)
-    {
-      free(buffer_);
-      buffer_ = NULL;
-      changed_ = true;
-    }
-  }
-
-
-  ImageBuffer::ImageBuffer(PixelFormat format,
-                           unsigned int width,
-                           unsigned int height)
-  {
-    Initialize();
-    SetWidth(width);
-    SetHeight(height);
-    SetFormat(format);
-  }
-
-
-  void ImageBuffer::Initialize()
-  {
-    changed_ = false;
-    forceMinimalPitch_ = true;
-    format_ = PixelFormat_Grayscale8;
-    width_ = 0;
-    height_ = 0;
-    pitch_ = 0;
-    buffer_ = NULL;
-  }
-
-
-  void ImageBuffer::SetFormat(PixelFormat format)
-  {
-    if (format != format_)
-    {
-      changed_ = true;
-      format_ = format;
-    }
-  }
-
-
-  void ImageBuffer::SetWidth(unsigned int width)
-  {
-    if (width != width_)
-    {
-      changed_ = true;
-      width_ = width;     
-    }
-  }
-
-
-  void ImageBuffer::SetHeight(unsigned int height)
-  {
-    if (height != height_)
-    {
-      changed_ = true;
-      height_ = height;     
-    }
-  }
-
-
-  ImageAccessor ImageBuffer::GetAccessor()
-  {
-    Allocate();
-
-    ImageAccessor accessor;
-    accessor.AssignWritable(format_, width_, height_, pitch_, buffer_);
-    return accessor;
-  }
-
-
-  ImageAccessor ImageBuffer::GetConstAccessor()
-  {
-    Allocate();
-
-    ImageAccessor accessor;
-    accessor.AssignReadOnly(format_, width_, height_, pitch_, buffer_);
-    return accessor;
-  }
-
-
-  void ImageBuffer::SetMinimalPitchForced(bool force)
-  {
-    if (force != forceMinimalPitch_)
-    {
-      changed_ = true;
-      forceMinimalPitch_ = force;
-    }
-  }
-
-
-  void ImageBuffer::AcquireOwnership(ImageBuffer& other)
-  {
-    // Remove the content of the current image
-    Deallocate();
-
-    // Force the allocation of the other image (if not already
-    // allocated)
-    other.Allocate();
-
-    // Transfer the content of the other image
-    changed_ = false;
-    forceMinimalPitch_ = other.forceMinimalPitch_;
-    format_ = other.format_;
-    width_ = other.width_;
-    height_ = other.height_;
-    pitch_ = other.pitch_;
-    buffer_ = other.buffer_;
-
-    // Force the reinitialization of the other image
-    other.Initialize();
-  }
-}
--- a/Core/ImageFormats/ImageBuffer.h	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-/**
- * 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 <vector>
-#include <stdint.h>
-#include <boost/noncopyable.hpp>
-
-namespace Orthanc
-{
-  class ImageBuffer : public boost::noncopyable
-  {
-  private:
-    bool changed_;
-
-    bool forceMinimalPitch_;  // Currently unused
-    PixelFormat format_;
-    unsigned int width_;
-    unsigned int height_;
-    unsigned int pitch_;
-    void *buffer_;
-
-    void Initialize();
-    
-    void Allocate();
-
-    void Deallocate();
-
-  public:
-    ImageBuffer(PixelFormat format,
-                unsigned int width,
-                unsigned int height);
-
-    ImageBuffer()
-    {
-      Initialize();
-    }
-
-    ~ImageBuffer()
-    {
-      Deallocate();
-    }
-
-    PixelFormat GetFormat() const
-    {
-      return format_;
-    }
-
-    void SetFormat(PixelFormat format);
-
-    unsigned int GetWidth() const
-    {
-      return width_;
-    }
-
-    void SetWidth(unsigned int width);
-
-    unsigned int GetHeight() const
-    {
-      return height_;
-    }
-
-    void SetHeight(unsigned int height);
-
-    unsigned int GetBytesPerPixel() const
-    {
-      return ::Orthanc::GetBytesPerPixel(format_);
-    }
-
-    ImageAccessor GetAccessor();
-
-    ImageAccessor GetConstAccessor();
-
-    bool IsMinimalPitchForced() const
-    {
-      return forceMinimalPitch_;
-    }
-
-    void SetMinimalPitchForced(bool force);
-
-    void AcquireOwnership(ImageBuffer& other);
-  };
-}
--- a/Core/ImageFormats/ImageProcessing.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,592 +0,0 @@
-/**
- * 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/>.
- **/
-
-
-#include "../PrecompiledHeaders.h"
-#include "ImageProcessing.h"
-
-#include "../OrthancException.h"
-
-#include <boost/math/special_functions/round.hpp>
-
-#include <cassert>
-#include <string.h>
-#include <limits>
-#include <stdint.h>
-
-namespace Orthanc
-{
-  template <typename TargetType, typename SourceType>
-  static void ConvertInternal(ImageAccessor& target,
-                              const ImageAccessor& source)
-  {
-    const TargetType minValue = std::numeric_limits<TargetType>::min();
-    const TargetType maxValue = std::numeric_limits<TargetType>::max();
-
-    for (unsigned int y = 0; y < source.GetHeight(); y++)
-    {
-      TargetType* t = reinterpret_cast<TargetType*>(target.GetRow(y));
-      const SourceType* s = reinterpret_cast<const SourceType*>(source.GetConstRow(y));
-
-      for (unsigned int x = 0; x < source.GetWidth(); x++, t++, s++)
-      {
-        if (static_cast<int32_t>(*s) < static_cast<int32_t>(minValue))
-        {
-          *t = minValue;
-        }
-        else if (static_cast<int32_t>(*s) > static_cast<int32_t>(maxValue))
-        {
-          *t = maxValue;
-        }
-        else
-        {
-          *t = static_cast<TargetType>(*s);
-        }
-      }
-    }
-  }
-
-
-  template <typename TargetType>
-  static void ConvertColorToGrayscale(ImageAccessor& target,
-                              const ImageAccessor& source)
-  {
-    assert(source.GetFormat() == PixelFormat_RGB24);
-
-    const TargetType minValue = std::numeric_limits<TargetType>::min();
-    const TargetType maxValue = std::numeric_limits<TargetType>::max();
-
-    for (unsigned int y = 0; y < source.GetHeight(); y++)
-    {
-      TargetType* t = reinterpret_cast<TargetType*>(target.GetRow(y));
-      const uint8_t* s = reinterpret_cast<const uint8_t*>(source.GetConstRow(y));
-
-      for (unsigned int x = 0; x < source.GetWidth(); x++, t++, s += 3)
-      {
-        // Y = 0.2126 R + 0.7152 G + 0.0722 B
-        int32_t v = (2126 * static_cast<int32_t>(s[0]) +
-                     7152 * static_cast<int32_t>(s[1]) +
-                     0722 * static_cast<int32_t>(s[2])) / 1000;
-        
-        if (static_cast<int32_t>(v) < static_cast<int32_t>(minValue))
-        {
-          *t = minValue;
-        }
-        else if (static_cast<int32_t>(v) > static_cast<int32_t>(maxValue))
-        {
-          *t = maxValue;
-        }
-        else
-        {
-          *t = static_cast<TargetType>(v);
-        }
-      }
-    }
-  }
-
-
-  template <typename PixelType>
-  static void SetInternal(ImageAccessor& image,
-                          int64_t constant)
-  {
-    for (unsigned int y = 0; y < image.GetHeight(); y++)
-    {
-      PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y));
-
-      for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
-      {
-        *p = static_cast<PixelType>(constant);
-      }
-    }
-  }
-
-
-  template <typename PixelType>
-  static void GetMinMaxValueInternal(PixelType& minValue,
-                                     PixelType& maxValue,
-                                     const ImageAccessor& source)
-  {
-    // Deal with the special case of empty image
-    if (source.GetWidth() == 0 ||
-        source.GetHeight() == 0)
-    {
-      minValue = 0;
-      maxValue = 0;
-      return;
-    }
-
-    minValue = std::numeric_limits<PixelType>::max();
-    maxValue = std::numeric_limits<PixelType>::min();
-
-    for (unsigned int y = 0; y < source.GetHeight(); y++)
-    {
-      const PixelType* p = reinterpret_cast<const PixelType*>(source.GetConstRow(y));
-
-      for (unsigned int x = 0; x < source.GetWidth(); x++, p++)
-      {
-        if (*p < minValue)
-        {
-          minValue = *p;
-        }
-
-        if (*p > maxValue)
-        {
-          maxValue = *p;
-        }
-      }
-    }
-  }
-
-
-
-  template <typename PixelType>
-  static void AddConstantInternal(ImageAccessor& image,
-                                  int64_t constant)
-  {
-    if (constant == 0)
-    {
-      return;
-    }
-
-    const int64_t minValue = std::numeric_limits<PixelType>::min();
-    const int64_t maxValue = std::numeric_limits<PixelType>::max();
-
-    for (unsigned int y = 0; y < image.GetHeight(); y++)
-    {
-      PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y));
-
-      for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
-      {
-        int64_t v = static_cast<int64_t>(*p) + constant;
-
-        if (v > maxValue)
-        {
-          *p = std::numeric_limits<PixelType>::max();
-        }
-        else if (v < minValue)
-        {
-          *p = std::numeric_limits<PixelType>::min();
-        }
-        else
-        {
-          *p = static_cast<PixelType>(v);
-        }
-      }
-    }
-  }
-
-
-
-  template <typename PixelType>
-  void MultiplyConstantInternal(ImageAccessor& image,
-                                float factor)
-  {
-    if (std::abs(factor - 1.0f) <= std::numeric_limits<float>::epsilon())
-    {
-      return;
-    }
-
-    const int64_t minValue = std::numeric_limits<PixelType>::min();
-    const int64_t maxValue = std::numeric_limits<PixelType>::max();
-
-    for (unsigned int y = 0; y < image.GetHeight(); y++)
-    {
-      PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y));
-
-      for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
-      {
-        int64_t v = boost::math::llround(static_cast<float>(*p) * factor);
-
-        if (v > maxValue)
-        {
-          *p = std::numeric_limits<PixelType>::max();
-        }
-        else if (v < minValue)
-        {
-          *p = std::numeric_limits<PixelType>::min();
-        }
-        else
-        {
-          *p = static_cast<PixelType>(v);
-        }
-      }
-    }
-  }
-
-
-  template <typename PixelType>
-  void ShiftScaleInternal(ImageAccessor& image,
-                          float offset,
-                          float scaling)
-  {
-    const float minValue = static_cast<float>(std::numeric_limits<PixelType>::min());
-    const float maxValue = static_cast<float>(std::numeric_limits<PixelType>::max());
-
-    for (unsigned int y = 0; y < image.GetHeight(); y++)
-    {
-      PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y));
-
-      for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
-      {
-        float v = (static_cast<float>(*p) + offset) * scaling;
-
-        if (v > maxValue)
-        {
-          *p = std::numeric_limits<PixelType>::max();
-        }
-        else if (v < minValue)
-        {
-          *p = std::numeric_limits<PixelType>::min();
-        }
-        else
-        {
-          *p = static_cast<PixelType>(boost::math::iround(v));
-        }
-      }
-    }
-  }
-
-
-  void ImageProcessing::Copy(ImageAccessor& target,
-                             const ImageAccessor& source)
-  {
-    if (target.GetWidth() != source.GetWidth() ||
-        target.GetHeight() != source.GetHeight())
-    {
-      throw OrthancException(ErrorCode_IncompatibleImageSize);
-    }
-
-    if (target.GetFormat() != source.GetFormat())
-    {
-      throw OrthancException(ErrorCode_IncompatibleImageFormat);
-    }
-
-    unsigned int lineSize = GetBytesPerPixel(source.GetFormat()) * source.GetWidth();
-
-    assert(source.GetPitch() >= lineSize && target.GetPitch() >= lineSize);
-
-    for (unsigned int y = 0; y < source.GetHeight(); y++)
-    {
-      memcpy(target.GetRow(y), source.GetConstRow(y), lineSize);
-    }
-  }
-
-
-  void ImageProcessing::Convert(ImageAccessor& target,
-                                const ImageAccessor& source)
-  {
-    if (target.GetWidth() != source.GetWidth() ||
-        target.GetHeight() != source.GetHeight())
-    {
-      throw OrthancException(ErrorCode_IncompatibleImageSize);
-    }
-
-    if (source.GetFormat() == target.GetFormat())
-    {
-      Copy(target, source);
-      return;
-    }
-
-    if (target.GetFormat() == PixelFormat_Grayscale16 &&
-        source.GetFormat() == PixelFormat_Grayscale8)
-    {
-      ConvertInternal<uint16_t, uint8_t>(target, source);
-      return;
-    }
-
-    if (target.GetFormat() == PixelFormat_SignedGrayscale16 &&
-        source.GetFormat() == PixelFormat_Grayscale8)
-    {
-      ConvertInternal<int16_t, uint8_t>(target, source);
-      return;
-    }
-
-    if (target.GetFormat() == PixelFormat_Grayscale8 &&
-        source.GetFormat() == PixelFormat_Grayscale16)
-    {
-      ConvertInternal<uint8_t, uint16_t>(target, source);
-      return;
-    }
-
-    if (target.GetFormat() == PixelFormat_SignedGrayscale16 &&
-        source.GetFormat() == PixelFormat_Grayscale16)
-    {
-      ConvertInternal<int16_t, uint16_t>(target, source);
-      return;
-    }
-
-    if (target.GetFormat() == PixelFormat_Grayscale8 &&
-        source.GetFormat() == PixelFormat_SignedGrayscale16)
-    {
-      ConvertInternal<uint8_t, int16_t>(target, source);
-      return;
-    }
-
-    if (target.GetFormat() == PixelFormat_Grayscale16 &&
-        source.GetFormat() == PixelFormat_SignedGrayscale16)
-    {
-      ConvertInternal<uint16_t, int16_t>(target, source);
-      return;
-    }
-
-    if (target.GetFormat() == PixelFormat_Grayscale8 &&
-        source.GetFormat() == PixelFormat_RGB24)
-    {
-      ConvertColorToGrayscale<uint8_t>(target, source);
-      return;
-    }
-
-    if (target.GetFormat() == PixelFormat_Grayscale16 &&
-        source.GetFormat() == PixelFormat_RGB24)
-    {
-      ConvertColorToGrayscale<uint16_t>(target, source);
-      return;
-    }
-
-    if (target.GetFormat() == PixelFormat_SignedGrayscale16 &&
-        source.GetFormat() == PixelFormat_RGB24)
-    {
-      ConvertColorToGrayscale<int16_t>(target, source);
-      return;
-    }
-
-    if (target.GetFormat() == PixelFormat_Grayscale8 &&
-        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++)
-        {
-          *q = static_cast<uint8_t>((2126 * static_cast<uint32_t>(p[0]) +
-                                     7152 * static_cast<uint32_t>(p[1]) +
-                                     0722 * static_cast<uint32_t>(p[2])) / 10000);
-          p += 4;
-        }
-      }
-
-      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);
-  }
-
-
-
-  void ImageProcessing::Set(ImageAccessor& image,
-                            int64_t value)
-  {
-    switch (image.GetFormat())
-    {
-      case PixelFormat_Grayscale8:
-        SetInternal<uint8_t>(image, value);
-        return;
-
-      case PixelFormat_Grayscale16:
-        SetInternal<uint16_t>(image, value);
-        return;
-
-      case PixelFormat_SignedGrayscale16:
-        SetInternal<int16_t>(image, value);
-        return;
-
-      default:
-        throw OrthancException(ErrorCode_NotImplemented);
-    }
-  }
-
-
-  void ImageProcessing::ShiftRight(ImageAccessor& image,
-                                   unsigned int shift)
-  {
-    if (image.GetWidth() == 0 ||
-        image.GetHeight() == 0 ||
-        shift == 0)
-    {
-      // Nothing to do
-      return;
-    }
-
-    throw OrthancException(ErrorCode_NotImplemented);
-  }
-
-
-  void ImageProcessing::GetMinMaxValue(int64_t& minValue,
-                                       int64_t& maxValue,
-                                       const ImageAccessor& image)
-  {
-    switch (image.GetFormat())
-    {
-      case PixelFormat_Grayscale8:
-      {
-        uint8_t a, b;
-        GetMinMaxValueInternal<uint8_t>(a, b, image);
-        minValue = a;
-        maxValue = b;
-        break;
-      }
-
-      case PixelFormat_Grayscale16:
-      {
-        uint16_t a, b;
-        GetMinMaxValueInternal<uint16_t>(a, b, image);
-        minValue = a;
-        maxValue = b;
-        break;
-      }
-
-      case PixelFormat_SignedGrayscale16:
-      {
-        int16_t a, b;
-        GetMinMaxValueInternal<int16_t>(a, b, image);
-        minValue = a;
-        maxValue = b;
-        break;
-      }
-
-      default:
-        throw OrthancException(ErrorCode_NotImplemented);
-    }
-  }
-
-
-
-  void ImageProcessing::AddConstant(ImageAccessor& image,
-                                    int64_t value)
-  {
-    switch (image.GetFormat())
-    {
-      case PixelFormat_Grayscale8:
-        AddConstantInternal<uint8_t>(image, value);
-        return;
-
-      case PixelFormat_Grayscale16:
-        AddConstantInternal<uint16_t>(image, value);
-        return;
-
-      case PixelFormat_SignedGrayscale16:
-        AddConstantInternal<int16_t>(image, value);
-        return;
-
-      default:
-        throw OrthancException(ErrorCode_NotImplemented);
-    }
-  }
-
-
-  void ImageProcessing::MultiplyConstant(ImageAccessor& image,
-                                         float factor)
-  {
-    switch (image.GetFormat())
-    {
-      case PixelFormat_Grayscale8:
-        MultiplyConstantInternal<uint8_t>(image, factor);
-        return;
-
-      case PixelFormat_Grayscale16:
-        MultiplyConstantInternal<uint16_t>(image, factor);
-        return;
-
-      case PixelFormat_SignedGrayscale16:
-        MultiplyConstantInternal<int16_t>(image, factor);
-        return;
-
-      default:
-        throw OrthancException(ErrorCode_NotImplemented);
-    }
-  }
-
-
-  void ImageProcessing::ShiftScale(ImageAccessor& image,
-                                   float offset,
-                                   float scaling)
-  {
-    switch (image.GetFormat())
-    {
-      case PixelFormat_Grayscale8:
-        ShiftScaleInternal<uint8_t>(image, offset, scaling);
-        return;
-
-      case PixelFormat_Grayscale16:
-        ShiftScaleInternal<uint16_t>(image, offset, scaling);
-        return;
-
-      case PixelFormat_SignedGrayscale16:
-        ShiftScaleInternal<int16_t>(image, offset, scaling);
-        return;
-
-      default:
-        throw OrthancException(ErrorCode_NotImplemented);
-    }
-  }
-}
--- a/Core/ImageFormats/ImageProcessing.h	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/**
- * 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 <stdint.h>
-
-namespace Orthanc
-{
-  class ImageProcessing
-  {
-  public:
-    static void Copy(ImageAccessor& target,
-                     const ImageAccessor& source);
-
-    static void Convert(ImageAccessor& target,
-                        const ImageAccessor& source);
-
-    static void Set(ImageAccessor& image,
-                    int64_t value);
-
-    static void ShiftRight(ImageAccessor& target,
-                           unsigned int shift);
-
-    static void GetMinMaxValue(int64_t& minValue,
-                               int64_t& maxValue,
-                               const ImageAccessor& image);
-
-    static void AddConstant(ImageAccessor& image,
-                            int64_t value);
-
-    static void MultiplyConstant(ImageAccessor& image,
-                                 float factor);
-
-    static void ShiftScale(ImageAccessor& image,
-                           float offset,
-                           float scaling);
-  };
-}
--- a/Core/ImageFormats/JpegErrorManager.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/**
- * 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/>.
- **/
-
-
-#include "../PrecompiledHeaders.h"
-#include "JpegErrorManager.h"
-
-namespace Orthanc
-{
-  namespace Internals
-  {
-    void JpegErrorManager::OutputMessage(j_common_ptr cinfo)
-    {
-      char message[JMSG_LENGTH_MAX];
-      (*cinfo->err->format_message) (cinfo, message);
-
-      JpegErrorManager* that = reinterpret_cast<JpegErrorManager*>(cinfo->err);
-      that->message = std::string(message);
-    }
-
-
-    void JpegErrorManager::ErrorExit(j_common_ptr cinfo)
-    {
-      (*cinfo->err->output_message) (cinfo);
-
-      JpegErrorManager* that = reinterpret_cast<JpegErrorManager*>(cinfo->err);
-      longjmp(that->setjmp_buffer, 1);
-    }
-      
-
-    JpegErrorManager::JpegErrorManager()
-    {
-      memset(&pub, 0, sizeof(struct jpeg_error_mgr));
-      memset(&setjmp_buffer, 0, sizeof(jmp_buf));
-
-      jpeg_std_error(&pub);
-      pub.error_exit = ErrorExit;
-      pub.output_message = OutputMessage;
-    }
-  }
-}
--- a/Core/ImageFormats/JpegErrorManager.h	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/**
- * 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 <string.h>
-#include <stdio.h>
-#include <jpeglib.h>
-#include <setjmp.h>
-#include <string>
-
-namespace Orthanc
-{
-  namespace Internals
-  {
-    class JpegErrorManager 
-    {
-    private:
-      struct jpeg_error_mgr pub;  /* "public" fields */
-      jmp_buf setjmp_buffer;      /* for return to caller */
-      std::string message;
-
-      static void OutputMessage(j_common_ptr cinfo);
-
-      static void ErrorExit(j_common_ptr cinfo);
-
-    public:
-      JpegErrorManager();
-
-      struct jpeg_error_mgr* GetPublic()
-      {
-        return &pub;
-      }
-
-      jmp_buf& GetJumpBuffer()
-      {
-        return setjmp_buffer;
-      }
-
-      const std::string& GetMessage() const
-      {
-        return message;
-      }
-    };
-  }
-}
--- a/Core/ImageFormats/JpegReader.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,184 +0,0 @@
-/**
- * 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/>.
- **/
-
-
-#include "../PrecompiledHeaders.h"
-#include "JpegReader.h"
-
-#include "JpegErrorManager.h"
-#include "../OrthancException.h"
-#include "../Logging.h"
-
-namespace Orthanc
-{
-  static void Uncompress(struct jpeg_decompress_struct& cinfo,
-                         std::string& content,
-                         ImageAccessor& accessor)
-  {
-    jpeg_read_header(&cinfo, TRUE);
-    jpeg_start_decompress(&cinfo);
-
-    PixelFormat format;
-    if (cinfo.output_components == 1 &&
-        cinfo.out_color_space == JCS_GRAYSCALE)
-    {
-      format = PixelFormat_Grayscale8;
-    }
-    else if (cinfo.output_components == 3 &&
-             cinfo.out_color_space == JCS_RGB)
-    {
-      format = PixelFormat_RGB24;
-    }
-    else
-    {
-      throw OrthancException(ErrorCode_NotImplemented);
-    }
-
-    unsigned int pitch = cinfo.output_width * cinfo.output_components;
-
-    /* Make a one-row-high sample array that will go away when done with image */
-    JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, pitch, 1);
-
-    try
-    {
-      content.resize(pitch * cinfo.output_height);
-    }
-    catch (...)
-    {
-      throw OrthancException(ErrorCode_NotEnoughMemory);
-    }
-
-    accessor.AssignWritable(format, cinfo.output_width, cinfo.output_height, pitch, 
-                            content.empty() ? NULL : &content[0]);
-
-    uint8_t* target = reinterpret_cast<uint8_t*>(&content[0]);
-    while (cinfo.output_scanline < cinfo.output_height) 
-    {
-      jpeg_read_scanlines(&cinfo, buffer, 1);
-      memcpy(target, buffer[0], pitch);
-      target += pitch;
-    }
-
-    // Everything went fine, "setjmp()" didn't get called
-
-    jpeg_finish_decompress(&cinfo);
-  }
-
-
-  void JpegReader::ReadFromFile(const char* filename)
-  {
-    FILE* fp = fopen(filename, "rb");
-    if (!fp)
-    {
-      throw OrthancException(ErrorCode_InexistentFile);
-    }
-
-    struct jpeg_decompress_struct cinfo;
-    memset(&cinfo, 0, sizeof(struct jpeg_decompress_struct));
-
-    Internals::JpegErrorManager jerr;
-    cinfo.err = jerr.GetPublic();
-    
-    if (setjmp(jerr.GetJumpBuffer())) 
-    {
-      jpeg_destroy_decompress(&cinfo);
-      fclose(fp);
-      LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage();
-      throw OrthancException(ErrorCode_InternalError);
-    }
-
-    // Below this line, we are under the scope of a "setjmp"
-
-    jpeg_create_decompress(&cinfo);
-    jpeg_stdio_src(&cinfo, fp);
-
-    try
-    {
-      Uncompress(cinfo, content_, *this);
-    }
-    catch (OrthancException&)
-    {
-      jpeg_destroy_decompress(&cinfo);
-      fclose(fp);
-      throw;
-    }
-
-    jpeg_destroy_decompress(&cinfo);
-    fclose(fp);
-  }
-
-
-  void JpegReader::ReadFromMemory(const void* buffer,
-                                  size_t size)
-  {
-    struct jpeg_decompress_struct cinfo;
-    memset(&cinfo, 0, sizeof(struct jpeg_decompress_struct));
-
-    Internals::JpegErrorManager jerr;
-    cinfo.err = jerr.GetPublic();
-    
-    if (setjmp(jerr.GetJumpBuffer())) 
-    {
-      jpeg_destroy_decompress(&cinfo);
-      LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage();
-      throw OrthancException(ErrorCode_InternalError);
-    }
-
-    // Below this line, we are under the scope of a "setjmp"
-    jpeg_create_decompress(&cinfo);
-    jpeg_mem_src(&cinfo, const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(buffer)), size);
-
-    try
-    {
-      Uncompress(cinfo, content_, *this);
-    }
-    catch (OrthancException&)
-    {
-      jpeg_destroy_decompress(&cinfo);
-      throw;
-    }
-
-    jpeg_destroy_decompress(&cinfo);
-  }
-
-
-  void JpegReader::ReadFromMemory(const std::string& buffer)
-  {
-    if (buffer.empty())
-    {
-      ReadFromMemory(NULL, 0);
-    }
-    else
-    {
-      ReadFromMemory(buffer.c_str(), buffer.size());
-    }
-  }
-}
--- a/Core/ImageFormats/JpegReader.h	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/**
- * 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 <string>
-
-namespace Orthanc
-{
-  class JpegReader : public ImageAccessor
-  {
-  private:
-    std::string  content_;
-
-  public:
-    void ReadFromFile(const char* filename);
-
-    void ReadFromFile(const std::string& filename)
-    {
-      ReadFromFile(filename.c_str());
-    }
-
-    void ReadFromMemory(const void* buffer,
-                        size_t size);
-
-    void ReadFromMemory(const std::string& buffer);
-  };
-}
--- a/Core/ImageFormats/JpegWriter.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,202 +0,0 @@
-/**
- * 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/>.
- **/
-
-
-#include "../PrecompiledHeaders.h"
-#include "JpegWriter.h"
-
-#include "../OrthancException.h"
-#include "../Logging.h"
-
-#include "JpegErrorManager.h"
-
-#include <vector>
-
-namespace Orthanc
-{
-  static void GetLines(std::vector<uint8_t*>& lines,
-                       unsigned int height,
-                       unsigned int pitch,
-                       PixelFormat format,
-                       const void* buffer)
-  {
-    if (format != PixelFormat_Grayscale8 &&
-        format != PixelFormat_RGB24)
-    {
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-
-    lines.resize(height);
-
-    uint8_t* base = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(buffer));
-    for (unsigned int y = 0; y < height; y++)
-    {
-      lines[y] = base + static_cast<intptr_t>(y) * static_cast<intptr_t>(pitch);
-    }
-  }
-
-
-  static void Compress(struct jpeg_compress_struct& cinfo,
-                       std::vector<uint8_t*>& lines,
-                       unsigned int width,
-                       unsigned int height,
-                       PixelFormat format,
-                       int quality)
-  {
-    cinfo.image_width = width;
-    cinfo.image_height = height;
-
-    switch (format)
-    {
-      case PixelFormat_Grayscale8:
-        cinfo.input_components = 1;
-        cinfo.in_color_space = JCS_GRAYSCALE;
-        break;
-
-      case PixelFormat_RGB24:
-        cinfo.input_components = 3;
-        cinfo.in_color_space = JCS_RGB;
-        break;
-
-      default:
-        throw OrthancException(ErrorCode_InternalError);
-    }
-
-    jpeg_set_defaults(&cinfo);
-    jpeg_set_quality(&cinfo, quality, TRUE);
-    jpeg_start_compress(&cinfo, TRUE);
-    jpeg_write_scanlines(&cinfo, &lines[0], height);
-    jpeg_finish_compress(&cinfo);
-    jpeg_destroy_compress(&cinfo);
-  }
-                       
-
-  void JpegWriter::SetQuality(uint8_t quality)
-  {
-    if (quality <= 0 || quality > 100)
-    {
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-
-    quality_ = quality;
-  }
-
-
-  void JpegWriter::WriteToFile(const char* filename,
-                               unsigned int width,
-                               unsigned int height,
-                               unsigned int pitch,
-                               PixelFormat format,
-                               const void* buffer)
-  {
-    FILE* fp = fopen(filename, "wb");
-    if (fp == NULL)
-    {
-      throw OrthancException(ErrorCode_FullStorage);
-    }
-
-    std::vector<uint8_t*> lines;
-    GetLines(lines, height, pitch, format, buffer);
-
-    struct jpeg_compress_struct cinfo;
-    memset(&cinfo, 0, sizeof(struct jpeg_compress_struct));
-
-    Internals::JpegErrorManager jerr;
-    cinfo.err = jerr.GetPublic();
-
-    if (setjmp(jerr.GetJumpBuffer())) 
-    {
-      /* If we get here, the JPEG code has signaled an error.
-       * We need to clean up the JPEG object, close the input file, and return.
-       */
-      jpeg_destroy_compress(&cinfo);
-      fclose(fp);
-      LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage();
-      throw OrthancException(ErrorCode_InternalError);
-    }
-
-    // Do not allocate data on the stack below this line!
-
-    jpeg_create_compress(&cinfo);
-    jpeg_stdio_dest(&cinfo, fp);
-    Compress(cinfo, lines, width, height, format, quality_);
-
-    // Everything went fine, "setjmp()" didn't get called
-
-    fclose(fp);
-  }
-
-
-  void JpegWriter::WriteToMemory(std::string& jpeg,
-                                 unsigned int width,
-                                 unsigned int height,
-                                 unsigned int pitch,
-                                 PixelFormat format,
-                                 const void* buffer)
-  {
-    std::vector<uint8_t*> lines;
-    GetLines(lines, height, pitch, format, buffer);
-
-    struct jpeg_compress_struct cinfo;
-    memset(&cinfo, 0, sizeof(struct jpeg_compress_struct));
-
-    Internals::JpegErrorManager jerr;
-
-    unsigned char* data = NULL;
-    unsigned long size;
-
-    if (setjmp(jerr.GetJumpBuffer())) 
-    {
-      jpeg_destroy_compress(&cinfo);
-
-      if (data != NULL)
-      {
-        free(data);
-      }
-
-      LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage();
-      throw OrthancException(ErrorCode_InternalError);
-    }
-
-    // Do not allocate data on the stack below this line!
-
-    jpeg_create_compress(&cinfo);
-    cinfo.err = jerr.GetPublic();
-    jpeg_mem_dest(&cinfo, &data, &size);
-
-    Compress(cinfo, lines, width, height, format, quality_);
-
-    // Everything went fine, "setjmp()" didn't get called
-
-    jpeg.assign(reinterpret_cast<const char*>(data), size);
-    free(data);
-  }
-}
--- a/Core/ImageFormats/JpegWriter.h	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/**
- * 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 <string>
-#include <stdint.h>
-
-namespace Orthanc
-{
-  class JpegWriter
-  {
-  private:
-    int  quality_;
-
-  public:
-    JpegWriter() : quality_(90)
-    {
-    }
-
-    void SetQuality(uint8_t quality);
-
-    uint8_t GetQuality() const
-    {
-      return quality_;
-    }
-
-    void WriteToFile(const char* filename,
-                     unsigned int width,
-                     unsigned int height,
-                     unsigned int pitch,
-                     PixelFormat format,
-                     const void* buffer);
-
-    void WriteToMemory(std::string& jpeg,
-                       unsigned int width,
-                       unsigned int height,
-                       unsigned int pitch,
-                       PixelFormat format,
-                       const void* buffer);
-
-    void WriteToFile(const char* filename,
-                     const ImageAccessor& accessor)
-    {
-      WriteToFile(filename, accessor.GetWidth(), accessor.GetHeight(),
-                  accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer());
-    }
-
-    void WriteToMemory(std::string& jpeg,
-                       const ImageAccessor& accessor)
-    {
-      WriteToMemory(jpeg, accessor.GetWidth(), accessor.GetHeight(),
-                    accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer());
-    }
-  };
-}
--- a/Core/ImageFormats/PngReader.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,313 +0,0 @@
-/**
- * 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/>.
- **/
-
-
-#include "../PrecompiledHeaders.h"
-#include "PngReader.h"
-
-#include "../OrthancException.h"
-#include "../Toolbox.h"
-
-#include <png.h>
-#include <string.h>  // For memcpy()
-
-namespace Orthanc
-{
-  namespace 
-  {
-    struct FileRabi
-    {
-      FILE* fp_;
-
-      FileRabi(const char* filename)
-      {
-        fp_ = fopen(filename, "rb");
-        if (!fp_)
-        {
-          throw OrthancException(ErrorCode_InexistentFile);
-        }
-      }
-
-      ~FileRabi()
-      {
-        if (fp_)
-          fclose(fp_);
-      }
-    };
-  }
-
-
-  struct PngReader::PngRabi
-  {
-    png_structp png_;
-    png_infop info_;
-    png_infop endInfo_;
-
-    void Destruct()
-    {
-      if (png_)
-      {
-        png_destroy_read_struct(&png_, &info_, &endInfo_);
-
-        png_ = NULL;
-        info_ = NULL;
-        endInfo_ = NULL;
-      }
-    }
-
-    PngRabi()
-    {
-      png_ = NULL;
-      info_ = NULL;
-      endInfo_ = NULL;
-
-      png_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-      if (!png_)
-      {
-        throw OrthancException(ErrorCode_NotEnoughMemory);
-      }
-
-      info_ = png_create_info_struct(png_);
-      if (!info_)
-      {
-        png_destroy_read_struct(&png_, NULL, NULL);
-        throw OrthancException(ErrorCode_NotEnoughMemory);
-      }
-
-      endInfo_ = png_create_info_struct(png_);
-      if (!info_)
-      {
-        png_destroy_read_struct(&png_, &info_, NULL);
-        throw OrthancException(ErrorCode_NotEnoughMemory);
-      }
-    }
-
-    ~PngRabi()
-    {
-      Destruct();
-    }
-
-    static void MemoryCallback(png_structp png_ptr, 
-                               png_bytep data, 
-                               png_size_t size);
-  };
-
-
-  void PngReader::CheckHeader(const void* header)
-  {
-    int is_png = !png_sig_cmp((png_bytep) header, 0, 8);
-    if (!is_png)
-    {
-      throw OrthancException(ErrorCode_BadFileFormat);
-    }
-  }
-
-  PngReader::PngReader()
-  {
-  }
-
-  void PngReader::Read(PngRabi& rabi)
-  {
-    png_set_sig_bytes(rabi.png_, 8);
-
-    png_read_info(rabi.png_, rabi.info_);
-
-    png_uint_32 width, height;
-    int bit_depth, color_type, interlace_type;
-    int compression_type, filter_method;
-    // get size and bit-depth of the PNG-image
-    png_get_IHDR(rabi.png_, rabi.info_,
-                 &width, &height,
-                 &bit_depth, &color_type, &interlace_type,
-                 &compression_type, &filter_method);
-
-    PixelFormat format;
-    unsigned int pitch;
-
-    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 8)
-    {
-      format = PixelFormat_Grayscale8;
-      pitch = width;
-    }
-    else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 16)
-    {
-      format = PixelFormat_Grayscale16;
-      pitch = 2 * width;
-
-      if (Toolbox::DetectEndianness() == Endianness_Little)
-      {
-        png_set_swap(rabi.png_);
-      }
-    }
-    else if (color_type == PNG_COLOR_TYPE_RGB && bit_depth == 8)
-    {
-      format = PixelFormat_RGB24;
-      pitch = 3 * width;
-    }
-    else if (color_type == PNG_COLOR_TYPE_RGBA && bit_depth == 8)
-    {
-      format = PixelFormat_RGBA32;
-      pitch = 4 * width;
-    }
-    else
-    {
-      throw OrthancException(ErrorCode_NotImplemented);
-    }
-
-    data_.resize(height * pitch);
-
-    if (height == 0 || width == 0)
-    {
-      // Empty image, we are done
-      AssignEmpty(format);
-      return;
-    }
-    
-    png_read_update_info(rabi.png_, rabi.info_);
-
-    std::vector<png_bytep> rows(height);
-    for (size_t i = 0; i < height; i++)
-    {
-      rows[i] = &data_[0] + i * pitch;
-    }
-
-    png_read_image(rabi.png_, &rows[0]);
-
-    AssignWritable(format, width, height, pitch, &data_[0]);
-  }
-
-  void PngReader::ReadFromFile(const char* filename)
-  {
-    FileRabi f(filename);
-
-    char header[8];
-    if (fread(header, 1, 8, f.fp_) != 8)
-    {
-      throw OrthancException(ErrorCode_BadFileFormat);
-    }
-
-    CheckHeader(header);
-
-    PngRabi rabi;
-
-    if (setjmp(png_jmpbuf(rabi.png_)))
-    {
-      rabi.Destruct();
-      throw OrthancException(ErrorCode_BadFileFormat);
-    }
-
-    png_init_io(rabi.png_, f.fp_);
-
-    Read(rabi);
-  }
-
-
-  namespace
-  {
-    struct MemoryBuffer
-    {
-      const uint8_t* buffer_;
-      size_t size_;
-      size_t pos_;
-      bool ok_;
-    };
-  }
-
-
-  void PngReader::PngRabi::MemoryCallback(png_structp png_ptr, 
-                                          png_bytep outBytes, 
-                                          png_size_t byteCountToRead)
-  {
-    MemoryBuffer* from = reinterpret_cast<MemoryBuffer*>(png_get_io_ptr(png_ptr));
-
-    if (!from->ok_)
-    {
-      return;
-    }
-
-    if (from->pos_ + byteCountToRead > from->size_)
-    {
-      from->ok_ = false;
-      return;
-    }
-
-    memcpy(outBytes, from->buffer_ + from->pos_, byteCountToRead);
-
-    from->pos_ += byteCountToRead;
-  }
-
-
-  void PngReader::ReadFromMemory(const void* buffer,
-                                 size_t size)
-  {
-    if (size < 8)
-    {
-      throw OrthancException(ErrorCode_BadFileFormat);
-    }
-
-    CheckHeader(buffer);
-
-    PngRabi rabi;
-
-    if (setjmp(png_jmpbuf(rabi.png_)))
-    {
-      rabi.Destruct();
-      throw OrthancException(ErrorCode_BadFileFormat);
-    }
-
-    MemoryBuffer tmp;
-    tmp.buffer_ = reinterpret_cast<const uint8_t*>(buffer) + 8;  // We skip the header
-    tmp.size_ = size - 8;
-    tmp.pos_ = 0;
-    tmp.ok_ = true;
-
-    png_set_read_fn(rabi.png_, &tmp, PngRabi::MemoryCallback);
-
-    Read(rabi);
-
-    if (!tmp.ok_)
-    {
-      throw OrthancException(ErrorCode_BadFileFormat);
-    }
-  }
-
-  void PngReader::ReadFromMemory(const std::string& buffer)
-  {
-    if (buffer.size() != 0)
-    {
-      ReadFromMemory(&buffer[0], buffer.size());
-    }
-    else
-    {
-      ReadFromMemory(NULL, 0);
-    }
-  }
-}
--- a/Core/ImageFormats/PngReader.h	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/**
- * 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 "../Enumerations.h"
-
-#include <vector>
-#include <stdint.h>
-#include <boost/shared_ptr.hpp>
-
-namespace Orthanc
-{
-  class PngReader : public ImageAccessor
-  {
-  private:
-    struct PngRabi;
-
-    std::vector<uint8_t> data_;
-
-    void CheckHeader(const void* header);
-
-    void Read(PngRabi& rabi);
-
-  public:
-    PngReader();
-
-    void ReadFromFile(const char* filename);
-
-    void ReadFromFile(const std::string& filename)
-    {
-      ReadFromFile(filename.c_str());
-    }
-
-    void ReadFromMemory(const void* buffer,
-                        size_t size);
-
-    void ReadFromMemory(const std::string& buffer);
-  };
-}
--- a/Core/ImageFormats/PngWriter.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,269 +0,0 @@
-/**
- * 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/>.
- **/
-
-
-#include "../PrecompiledHeaders.h"
-#include "PngWriter.h"
-
-#include <vector>
-#include <stdint.h>
-#include <png.h>
-#include "../OrthancException.h"
-#include "../ChunkedBuffer.h"
-#include "../Toolbox.h"
-
-
-// http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-4
-// http://zarb.org/~gc/html/libpng.html
-/*
-  void write_row_callback(png_ptr, png_uint_32 row, int pass)
-  {
-  }*/
-
-
-
-
-/*  bool isError_;
-
-// http://www.libpng.org/pub/png/book/chapter14.html#png.ch14.div.2
-
-static void ErrorHandler(png_structp png, png_const_charp message)
-{
-printf("** [%s]\n", message);
-
-PngWriter* that = (PngWriter*) png_get_error_ptr(png);
-that->isError_ = true;
-printf("** %d\n", (int)that);
-
-//((PngWriter*) payload)->isError_ = true;
-}
-
-static void WarningHandler(png_structp png, png_const_charp message)
-{
-  printf("++ %d\n", (int)message);
-}*/
-
-
-namespace Orthanc
-{
-  struct PngWriter::PImpl
-  {
-    png_structp png_;
-    png_infop info_;
-
-    // Filled by Prepare()
-    std::vector<uint8_t*> rows_;
-    int bitDepth_;
-    int colorType_;
-  };
-
-
-
-  PngWriter::PngWriter() : pimpl_(new PImpl)
-  {
-    pimpl_->png_ = NULL;
-    pimpl_->info_ = NULL;
-
-    pimpl_->png_ = png_create_write_struct
-      (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); //this, ErrorHandler, WarningHandler);
-    if (!pimpl_->png_)
-    {
-      throw OrthancException(ErrorCode_NotEnoughMemory);
-    }
-
-    pimpl_->info_ = png_create_info_struct(pimpl_->png_);
-    if (!pimpl_->info_)
-    {
-      png_destroy_write_struct(&pimpl_->png_, NULL);
-      throw OrthancException(ErrorCode_NotEnoughMemory);
-    }
-  }
-
-  PngWriter::~PngWriter()
-  {
-    if (pimpl_->info_)
-    {
-      png_destroy_info_struct(pimpl_->png_, &pimpl_->info_);
-    }
-
-    if (pimpl_->png_)
-    {
-      png_destroy_write_struct(&pimpl_->png_, NULL);
-    }
-  }
-
-
-
-  void PngWriter::Prepare(unsigned int width,
-                          unsigned int height,
-                          unsigned int pitch,
-                          PixelFormat format,
-                          const void* buffer)
-  {
-    pimpl_->rows_.resize(height);
-    for (unsigned int y = 0; y < height; y++)
-    {
-      pimpl_->rows_[y] = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(buffer)) + y * pitch;
-    }
-
-    switch (format)
-    {
-    case PixelFormat_RGB24:
-      pimpl_->bitDepth_ = 8;
-      pimpl_->colorType_ = PNG_COLOR_TYPE_RGB;
-      break;
-
-    case PixelFormat_RGBA32:
-      pimpl_->bitDepth_ = 8;
-      pimpl_->colorType_ = PNG_COLOR_TYPE_RGBA;
-      break;
-
-    case PixelFormat_Grayscale8:
-      pimpl_->bitDepth_ = 8;
-      pimpl_->colorType_ = PNG_COLOR_TYPE_GRAY;
-      break;
-
-    case PixelFormat_Grayscale16:
-    case PixelFormat_SignedGrayscale16:
-      pimpl_->bitDepth_ = 16;
-      pimpl_->colorType_ = PNG_COLOR_TYPE_GRAY;
-      break;
-
-    default:
-      throw OrthancException(ErrorCode_NotImplemented);
-    }
-  }
-
-
-  void PngWriter::Compress(unsigned int width,
-                           unsigned int height,
-                           unsigned int pitch,
-                           PixelFormat format)
-  {
-    png_set_IHDR(pimpl_->png_, pimpl_->info_, width, height,
-                 pimpl_->bitDepth_, pimpl_->colorType_, PNG_INTERLACE_NONE,
-                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
-
-    png_write_info(pimpl_->png_, pimpl_->info_);
-
-    if (height > 0)
-    {
-      switch (format)
-      {
-      case PixelFormat_Grayscale16:
-      case PixelFormat_SignedGrayscale16:
-      {
-        int transforms = 0;
-        if (Toolbox::DetectEndianness() == Endianness_Little)
-        {
-          transforms = PNG_TRANSFORM_SWAP_ENDIAN;
-        }
-
-        png_set_rows(pimpl_->png_, pimpl_->info_, &pimpl_->rows_[0]);
-        png_write_png(pimpl_->png_, pimpl_->info_, transforms, NULL);
-
-        break;
-      }
-
-      default:
-        png_write_image(pimpl_->png_, &pimpl_->rows_[0]);
-      }
-    }
-
-    png_write_end(pimpl_->png_, NULL);
-  }
-
-
-  void PngWriter::WriteToFile(const char* filename,
-                              unsigned int width,
-                              unsigned int height,
-                              unsigned int pitch,
-                              PixelFormat format,
-                              const void* buffer)
-  {
-    Prepare(width, height, pitch, format, buffer);
-
-    FILE* fp = fopen(filename, "wb");
-    if (!fp)
-    {
-      throw OrthancException(ErrorCode_CannotWriteFile);
-    }    
-
-    png_init_io(pimpl_->png_, fp);
-
-    if (setjmp(png_jmpbuf(pimpl_->png_)))
-    {
-      // Error during writing PNG
-      throw OrthancException(ErrorCode_CannotWriteFile);      
-    }
-
-    Compress(width, height, pitch, format);
-
-    fclose(fp);
-  }
-
-
-
-
-  static void MemoryCallback(png_structp png_ptr, 
-                             png_bytep data, 
-                             png_size_t size)
-  {
-    ChunkedBuffer* buffer = reinterpret_cast<ChunkedBuffer*>(png_get_io_ptr(png_ptr));
-    buffer->AddChunk(reinterpret_cast<const char*>(data), size);
-  }
-
-
-
-  void PngWriter::WriteToMemory(std::string& png,
-                                unsigned int width,
-                                unsigned int height,
-                                unsigned int pitch,
-                                PixelFormat format,
-                                const void* buffer)
-  {
-    ChunkedBuffer chunks;
-
-    Prepare(width, height, pitch, format, buffer);
-
-    if (setjmp(png_jmpbuf(pimpl_->png_)))
-    {
-      // Error during writing PNG
-      throw OrthancException(ErrorCode_InternalError);      
-    }
-
-    png_set_write_fn(pimpl_->png_, &chunks, MemoryCallback, NULL);
-
-    Compress(width, height, pitch, format);
-
-    chunks.Flatten(png);
-  }
-}
--- a/Core/ImageFormats/PngWriter.h	Fri Sep 04 16:30:42 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/**
- * 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 <boost/shared_ptr.hpp>
-#include <string>
-
-namespace Orthanc
-{
-  class PngWriter
-  {
-  private:
-    struct PImpl;
-    boost::shared_ptr<PImpl> pimpl_;
-
-    void Compress(unsigned int width,
-                  unsigned int height,
-                  unsigned int pitch,
-                  PixelFormat format);
-
-    void Prepare(unsigned int width,
-                 unsigned int height,
-                 unsigned int pitch,
-                 PixelFormat format,
-                 const void* buffer);
-
-  public:
-    PngWriter();
-
-    ~PngWriter();
-
-    void WriteToFile(const char* filename,
-                     unsigned int width,
-                     unsigned int height,
-                     unsigned int pitch,
-                     PixelFormat format,
-                     const void* buffer);
-
-    void WriteToMemory(std::string& png,
-                       unsigned int width,
-                       unsigned int height,
-                       unsigned int pitch,
-                       PixelFormat format,
-                       const void* buffer);
-
-    void WriteToFile(const char* filename,
-                     const ImageAccessor& accessor)
-    {
-      WriteToFile(filename, accessor.GetWidth(), accessor.GetHeight(),
-                  accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer());
-    }
-
-    void WriteToMemory(std::string& png,
-                       const ImageAccessor& accessor)
-    {
-      WriteToMemory(png, accessor.GetWidth(), accessor.GetHeight(),
-                    accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer());
-    }
-  };
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/Font.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,298 @@
+/**
+ * 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/>.
+ **/
+
+
+#include "../PrecompiledHeaders.h"
+#include "Font.h"
+
+#include "../Toolbox.h"
+#include "../OrthancException.h"
+
+#include <stdio.h>
+#include <memory>
+#include <boost/lexical_cast.hpp>
+
+namespace Orthanc
+{
+  Font::~Font()
+  {
+    for (Characters::iterator it = characters_.begin();
+         it != characters_.end(); it++)
+    {
+      delete it->second;
+    }
+  }
+
+
+  void Font::LoadFromMemory(const std::string& font)
+  {
+    Json::Value v;
+    Json::Reader reader;
+    if (!reader.parse(font, v) ||
+        v.type() != Json::objectValue ||
+        !v.isMember("Name") ||
+        !v.isMember("Size") ||
+        !v.isMember("Characters") ||
+        v["Name"].type() != Json::stringValue ||
+        v["Size"].type() != Json::intValue ||
+        v["Characters"].type() != Json::objectValue)
+    {
+      throw OrthancException(ErrorCode_BadFont);
+    }
+
+    name_ = v["Name"].asString();
+    size_ = v["Size"].asUInt();
+    maxHeight_ = 0;
+
+    Json::Value::Members characters = v["Characters"].getMemberNames();
+
+    for (size_t i = 0; i < characters.size(); i++)
+    {
+      const Json::Value& info = v["Characters"][characters[i]];
+      if (info.type() != Json::objectValue ||
+          !info.isMember("Advance") ||
+          !info.isMember("Bitmap") ||
+          !info.isMember("Height") ||
+          !info.isMember("Top") ||
+          !info.isMember("Width") ||
+          info["Advance"].type() != Json::intValue ||
+          info["Bitmap"].type() != Json::arrayValue ||
+          info["Height"].type() != Json::intValue ||
+          info["Top"].type() != Json::intValue ||
+          info["Width"].type() != Json::intValue)
+      {
+        throw OrthancException(ErrorCode_BadFont);
+      }
+
+      std::auto_ptr<Character> c(new Character);
+      
+      c->advance_ = info["Advance"].asUInt();
+      c->height_ = info["Height"].asUInt();
+      c->top_ = info["Top"].asUInt();
+      c->width_ = info["Width"].asUInt();
+      c->bitmap_.resize(info["Bitmap"].size());
+
+      if (c->height_ > maxHeight_)
+      {
+        maxHeight_ = c->height_;
+      }
+      
+      for (Json::Value::ArrayIndex j = 0; j < info["Bitmap"].size(); j++)
+      {
+        if (info["Bitmap"][j].type() != Json::intValue)
+        {
+          throw OrthancException(ErrorCode_BadFont);
+        }
+
+        int value = info["Bitmap"][j].asInt();
+        if (value < 0 || value > 255)
+        {
+          throw OrthancException(ErrorCode_BadFont);
+        }
+
+        c->bitmap_[j] = value;
+      }
+
+      int index = boost::lexical_cast<int>(characters[i]);
+      if (index < 0 || index > 255)
+      {
+        throw OrthancException(ErrorCode_BadFont);
+      }
+
+      characters_[static_cast<char>(index)] = c.release();
+    }
+  }
+
+
+  void Font::LoadFromFile(const std::string& path)
+  {
+    std::string font;
+    Toolbox::ReadFile(font, path);
+    LoadFromMemory(font);
+  }
+
+
+  static unsigned int MyMin(unsigned int a, 
+                            unsigned int b)
+  {
+    return a < b ? a : b;
+  }
+
+
+  void Font::DrawCharacter(ImageAccessor& target,
+                           const Character& character,
+                           int x,
+                           int y,
+                           const uint8_t color[4]) const
+  {
+    // Compute the bounds of the character
+    if (x >= static_cast<int>(target.GetWidth()) ||
+        y >= static_cast<int>(target.GetHeight()))
+    {
+      // The character is out of the image
+      return;
+    }
+
+    unsigned int left = x < 0 ? -x : 0;
+    unsigned int top = y < 0 ? -y : 0;
+    unsigned int width = MyMin(character.width_, target.GetWidth() - x);
+    unsigned int height = MyMin(character.height_, target.GetHeight() - y);
+
+    uint8_t bpp = target.GetBytesPerPixel();
+
+    // Blit the font bitmap OVER the target image
+    // https://en.wikipedia.org/wiki/Alpha_compositing
+
+    for (unsigned int cy = top; cy < height; cy++)
+    {
+      uint8_t* p = reinterpret_cast<uint8_t*>(target.GetRow(y + cy)) + (x + left) * bpp;
+      unsigned int pos = cy * character.width_ + left;
+
+      switch (target.GetFormat())
+      {
+        case PixelFormat_Grayscale8:
+        {
+          assert(bpp == 1);
+          for (unsigned int cx = left; cx < width; cx++, pos++, p++)
+          {
+            uint16_t alpha = character.bitmap_[pos];
+            *p = (alpha * static_cast<uint16_t>(color[0]) + (255 - alpha) * static_cast<uint16_t>(*p)) >> 8;
+          }
+
+          break;
+        }
+
+        case PixelFormat_RGB24:
+        {
+          assert(bpp == 3);
+          for (unsigned int cx = left; cx < width; cx++, pos++, p += 3)
+          {
+            uint16_t alpha = character.bitmap_[pos];
+            p[0] = (alpha * static_cast<uint16_t>(color[0]) + (255 - alpha) * static_cast<uint16_t>(p[0])) >> 8;
+            p[1] = (alpha * static_cast<uint16_t>(color[1]) + (255 - alpha) * static_cast<uint16_t>(p[1])) >> 8;
+            p[2] = (alpha * static_cast<uint16_t>(color[2]) + (255 - alpha) * static_cast<uint16_t>(p[2])) >> 8;
+          }
+
+          break;
+        }
+
+        case PixelFormat_RGBA32:
+        {
+          assert(bpp == 4);
+
+          for (unsigned int cx = left; cx < width; cx++, pos++, p += 4)
+          {
+            float alpha = static_cast<float>(character.bitmap_[pos]) / 255.0f;
+            float beta = (1.0f - alpha) * static_cast<float>(p[3]) / 255.0f;
+            float denom = 1.0f / (alpha + beta);
+
+            for (uint8_t i = 0; i < 3; i++)
+            {
+              p[i] = static_cast<uint8_t>((alpha * static_cast<float>(color[i]) +
+                                           beta * static_cast<float>(p[i])) * denom);
+            }
+
+            p[3] = static_cast<uint8_t>(255.0f * (alpha + beta));
+          }
+
+          break;
+        }
+
+        default:
+          throw OrthancException(ErrorCode_NotImplemented);
+      }
+    }
+
+  }
+
+
+  void Font::DrawInternal(ImageAccessor& target,
+                          const std::string& utf8,
+                          int x,
+                          int y,
+                          const uint8_t color[4]) const
+  {
+    if (target.GetFormat() != PixelFormat_Grayscale8 &&
+        target.GetFormat() != PixelFormat_RGB24 &&
+        target.GetFormat() != PixelFormat_RGBA32)
+    {
+      throw OrthancException(ErrorCode_NotImplemented);
+    }
+
+    int a = x;
+
+    std::string s = Toolbox::ConvertFromUtf8(utf8, Encoding_Latin1);
+
+    for (size_t i = 0; i < s.size(); i++)
+    {
+      if (s[i] == '\n')
+      {
+        // Go to the next line
+        a = x;
+        y += maxHeight_ + 1;
+      }
+      else
+      {
+        Characters::const_iterator c = characters_.find(s[i]);
+        if (c != characters_.end())
+        {
+          DrawCharacter(target, *c->second, a, y + static_cast<int>(c->second->top_), color);
+          a += c->second->advance_;
+        }
+      }
+    }
+  }
+
+
+  void Font::Draw(ImageAccessor& target,
+                  const std::string& utf8,
+                  int x,
+                  int y,
+                  uint8_t grayscale) const
+  {
+    uint8_t color[4] = { grayscale, grayscale, grayscale, 255 };
+    DrawInternal(target, utf8, x, y, color);
+  }
+
+
+  void Font::Draw(ImageAccessor& target,
+                  const std::string& utf8,
+                  int x,
+                  int y,
+                  uint8_t r,
+                  uint8_t g,
+                  uint8_t b) const
+  {
+    uint8_t color[4] = { r, g, b, 255 };
+    DrawInternal(target, utf8, x, y, color);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/Font.h	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,105 @@
+/**
+ * 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 <stdint.h>
+#include <vector>
+#include <map>
+
+namespace Orthanc
+{
+  class Font
+  {
+  private:
+    struct Character
+    {
+      unsigned int  width_;
+      unsigned int  height_;
+      unsigned int  top_;
+      unsigned int  advance_;
+      std::vector<uint8_t>  bitmap_;
+    };
+
+    typedef std::map<char, Character*>  Characters;
+
+    std::string   name_;
+    unsigned int  size_;
+    Characters    characters_;
+    unsigned int  maxHeight_;
+
+    void DrawCharacter(ImageAccessor& target,
+                       const Character& character,
+                       int x,
+                       int y,
+                       const uint8_t color[4]) const;
+
+    void DrawInternal(ImageAccessor& target,
+                      const std::string& utf8,
+                      int x,
+                      int y,
+                      const uint8_t color[4]) const;
+
+  public:
+    ~Font();
+
+    void LoadFromMemory(const std::string& font);
+
+    void LoadFromFile(const std::string& path);
+
+    const std::string& GetName() const
+    {
+      return name_;
+    }
+
+    unsigned int GetSize() const
+    {
+      return size_;
+    }
+
+    void Draw(ImageAccessor& target,
+              const std::string& utf8,
+              int x,
+              int y,
+              uint8_t grayscale) const;
+
+    void Draw(ImageAccessor& target,
+              const std::string& utf8,
+              int x,
+              int y,
+              uint8_t r,
+              uint8_t g,
+              uint8_t b) const;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/FontRegistry.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,86 @@
+/**
+ * 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/>.
+ **/
+
+
+#include "../PrecompiledHeaders.h"
+#include "FontRegistry.h"
+
+#include "../OrthancException.h"
+
+#include <memory>
+
+namespace Orthanc
+{
+  FontRegistry::~FontRegistry()
+  {
+    for (Fonts::iterator it = fonts_.begin(); it != fonts_.end(); ++it)
+    {
+      delete *it;
+    }
+  }
+
+
+  void FontRegistry::AddFromMemory(const std::string& font)
+  {
+    std::auto_ptr<Font> f(new Font);
+    f->LoadFromMemory(font);
+    fonts_.push_back(f.release());
+  }
+
+
+  void FontRegistry::AddFromFile(const std::string& path)
+  {
+    std::auto_ptr<Font> f(new Font);
+    f->LoadFromFile(path);
+    fonts_.push_back(f.release());
+  }
+
+
+  void FontRegistry::AddFromResource(EmbeddedResources::FileResourceId resource)
+  {
+    std::string content;
+    EmbeddedResources::GetFileResource(content, resource);
+    AddFromMemory(content);
+  }
+
+
+  const Font& FontRegistry::GetFont(size_t i) const
+  {
+    if (i >= fonts_.size())
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+    else
+    {
+      return *fonts_[i];
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/FontRegistry.h	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,64 @@
+/**
+ * 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 "Font.h"
+
+#include <EmbeddedResources.h>   // Autogenerated file
+
+namespace Orthanc
+{
+  class FontRegistry
+  {
+  private:
+    typedef std::vector<Font*>  Fonts;
+
+    Fonts  fonts_;
+
+  public:
+    ~FontRegistry();
+
+    void AddFromMemory(const std::string& font);
+
+    void AddFromFile(const std::string& path);
+
+    void AddFromResource(EmbeddedResources::FileResourceId resource);
+
+    size_t GetSize() const
+    {
+      return fonts_.size();
+    }
+
+    const Font& GetFont(size_t i) const;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/Image.h	Fri Sep 04 16:36:18 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());
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/ImageAccessor.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,229 @@
+/**
+ * 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/>.
+ **/
+
+
+#include "../PrecompiledHeaders.h"
+#include "ImageAccessor.h"
+
+#include "../Logging.h"
+#include "../OrthancException.h"
+#include "../ChunkedBuffer.h"
+
+#include <stdint.h>
+#include <cassert>
+#include <boost/lexical_cast.hpp>
+
+
+
+namespace Orthanc
+{
+  template <typename PixelType>
+  static void ToMatlabStringInternal(ChunkedBuffer& target,
+                                     const ImageAccessor& source)
+  {
+    target.AddChunk("double([ ");
+
+    for (unsigned int y = 0; y < source.GetHeight(); y++)
+    {
+      const PixelType* p = reinterpret_cast<const PixelType*>(source.GetConstRow(y));
+
+      std::string s;
+      if (y > 0)
+      {
+        s = "; ";
+      }
+
+      s.reserve(source.GetWidth() * 8);
+
+      for (unsigned int x = 0; x < source.GetWidth(); x++, p++)
+      {
+        s += boost::lexical_cast<std::string>(static_cast<int>(*p)) + " ";
+      }
+
+      target.AddChunk(s);
+    }
+
+    target.AddChunk("])");
+  }
+
+
+  static void RGB24ToMatlabString(ChunkedBuffer& target,
+                                  const ImageAccessor& source)
+  {
+    assert(source.GetFormat() == PixelFormat_RGB24);
+
+    target.AddChunk("double(permute(reshape([ ");
+
+    for (unsigned int y = 0; y < source.GetHeight(); y++)
+    {
+      const uint8_t* p = reinterpret_cast<const uint8_t*>(source.GetConstRow(y));
+      
+      std::string s;
+      s.reserve(source.GetWidth() * 3 * 8);
+      
+      for (unsigned int x = 0; x < 3 * source.GetWidth(); x++, p++)
+      {
+        s += boost::lexical_cast<std::string>(static_cast<int>(*p)) + " ";
+      }
+      
+      target.AddChunk(s);
+    }
+
+    target.AddChunk("], [ 3 " + boost::lexical_cast<std::string>(source.GetHeight()) +
+                    " " + boost::lexical_cast<std::string>(source.GetWidth()) + " ]), [ 3 2 1 ]))");
+  }
+
+
+  void* ImageAccessor::GetBuffer() const
+  {
+    if (readOnly_)
+    {
+#if ORTHANC_ENABLE_LOGGING == 1
+      LOG(ERROR) << "Trying to write on a read-only image";
+#endif
+
+      throw OrthancException(ErrorCode_ReadOnly);
+    }
+
+    return buffer_;
+  }
+
+
+  const void* ImageAccessor::GetConstRow(unsigned int y) const
+  {
+    if (buffer_ != NULL)
+    {
+      return reinterpret_cast<const uint8_t*>(buffer_) + y * pitch_;
+    }
+    else
+    {
+      return NULL;
+    }
+  }
+
+
+  void* ImageAccessor::GetRow(unsigned int y) const
+  {
+    if (readOnly_)
+    {
+#if ORTHANC_ENABLE_LOGGING == 1
+      LOG(ERROR) << "Trying to write on a read-only image";
+#endif
+
+      throw OrthancException(ErrorCode_ReadOnly);
+    }
+
+    if (buffer_ != NULL)
+    {
+      return reinterpret_cast<uint8_t*>(buffer_) + y * pitch_;
+    }
+    else
+    {
+      return NULL;
+    }
+  }
+
+
+  void ImageAccessor::AssignEmpty(PixelFormat format)
+  {
+    readOnly_ = false;
+    format_ = format;
+    width_ = 0;
+    height_ = 0;
+    pitch_ = 0;
+    buffer_ = NULL;
+  }
+
+
+  void ImageAccessor::AssignReadOnly(PixelFormat format,
+                                     unsigned int width,
+                                     unsigned int height,
+                                     unsigned int pitch,
+                                     const void *buffer)
+  {
+    readOnly_ = true;
+    format_ = format;
+    width_ = width;
+    height_ = height;
+    pitch_ = pitch;
+    buffer_ = const_cast<void*>(buffer);
+
+    assert(GetBytesPerPixel() * width_ <= pitch_);
+  }
+
+
+  void ImageAccessor::AssignWritable(PixelFormat format,
+                                     unsigned int width,
+                                     unsigned int height,
+                                     unsigned int pitch,
+                                     void *buffer)
+  {
+    readOnly_ = false;
+    format_ = format;
+    width_ = width;
+    height_ = height;
+    pitch_ = pitch;
+    buffer_ = buffer;
+
+    assert(GetBytesPerPixel() * width_ <= pitch_);
+  }
+
+
+  void ImageAccessor::ToMatlabString(std::string& target) const
+  {
+    ChunkedBuffer buffer;
+
+    switch (GetFormat())
+    {
+      case PixelFormat_Grayscale8:
+        ToMatlabStringInternal<uint8_t>(buffer, *this);
+        break;
+
+      case PixelFormat_Grayscale16:
+        ToMatlabStringInternal<uint16_t>(buffer, *this);
+        break;
+
+      case PixelFormat_SignedGrayscale16:
+        ToMatlabStringInternal<int16_t>(buffer, *this);
+        break;
+
+      case PixelFormat_RGB24:
+        RGB24ToMatlabString(buffer, *this);
+        break;
+
+      default:
+        throw OrthancException(ErrorCode_NotImplemented);
+    }   
+
+    buffer.Flatten(target);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/ImageAccessor.h	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,123 @@
+/**
+ * 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 "../Enumerations.h"
+
+#include <string>
+
+namespace Orthanc
+{
+  class ImageAccessor
+  {
+  private:
+    bool readOnly_;
+    PixelFormat format_;
+    unsigned int width_;
+    unsigned int height_;
+    unsigned int pitch_;
+    void *buffer_;
+
+  public:
+    ImageAccessor()
+    {
+      AssignEmpty(PixelFormat_Grayscale8);
+    }
+
+    virtual ~ImageAccessor()
+    {
+    }
+
+    bool IsReadOnly() const
+    {
+      return readOnly_;
+    }
+
+    PixelFormat GetFormat() const
+    {
+      return format_;
+    }
+
+    unsigned int GetBytesPerPixel() const
+    {
+      return ::Orthanc::GetBytesPerPixel(format_);
+    }
+
+    unsigned int GetWidth() const
+    {
+      return width_;
+    }
+
+    unsigned int GetHeight() const
+    {
+      return height_;
+    }
+
+    unsigned int GetPitch() const
+    {
+      return pitch_;
+    }
+
+    unsigned int GetSize() const
+    {
+      return GetHeight() * GetPitch();
+    }
+
+    const void* GetConstBuffer() const
+    {
+      return buffer_;
+    }
+
+    void* GetBuffer() const;
+
+    const void* GetConstRow(unsigned int y) const;
+
+    void* GetRow(unsigned int y) const;
+
+    void AssignEmpty(PixelFormat format);
+
+    void AssignReadOnly(PixelFormat format,
+                        unsigned int width,
+                        unsigned int height,
+                        unsigned int pitch,
+                        const void *buffer);
+
+    void AssignWritable(PixelFormat format,
+                        unsigned int width,
+                        unsigned int height,
+                        unsigned int pitch,
+                        void *buffer);
+
+    void ToMatlabString(std::string& target) const; 
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/ImageBuffer.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,192 @@
+/**
+ * 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/>.
+ **/
+
+
+#include "../PrecompiledHeaders.h"
+#include "ImageBuffer.h"
+
+#include "../OrthancException.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+namespace Orthanc
+{
+  void ImageBuffer::Allocate()
+  {
+    if (changed_)
+    {
+      Deallocate();
+
+      /*
+        if (forceMinimalPitch_)
+        {
+        TODO: Align pitch and memory buffer to optimal size for SIMD.
+        }
+      */
+
+      pitch_ = GetBytesPerPixel() * width_;
+      size_t size = pitch_ * height_;
+
+      if (size == 0)
+      {
+        buffer_ = NULL;
+      }
+      else
+      {
+        buffer_ = malloc(size);
+        if (buffer_ == NULL)
+        {
+          throw OrthancException(ErrorCode_NotEnoughMemory);
+        }
+      }
+
+      changed_ = false;
+    }
+  }
+
+
+  void ImageBuffer::Deallocate()
+  {
+    if (buffer_ != NULL)
+    {
+      free(buffer_);
+      buffer_ = NULL;
+      changed_ = true;
+    }
+  }
+
+
+  ImageBuffer::ImageBuffer(PixelFormat format,
+                           unsigned int width,
+                           unsigned int height)
+  {
+    Initialize();
+    SetWidth(width);
+    SetHeight(height);
+    SetFormat(format);
+  }
+
+
+  void ImageBuffer::Initialize()
+  {
+    changed_ = false;
+    forceMinimalPitch_ = true;
+    format_ = PixelFormat_Grayscale8;
+    width_ = 0;
+    height_ = 0;
+    pitch_ = 0;
+    buffer_ = NULL;
+  }
+
+
+  void ImageBuffer::SetFormat(PixelFormat format)
+  {
+    if (format != format_)
+    {
+      changed_ = true;
+      format_ = format;
+    }
+  }
+
+
+  void ImageBuffer::SetWidth(unsigned int width)
+  {
+    if (width != width_)
+    {
+      changed_ = true;
+      width_ = width;     
+    }
+  }
+
+
+  void ImageBuffer::SetHeight(unsigned int height)
+  {
+    if (height != height_)
+    {
+      changed_ = true;
+      height_ = height;     
+    }
+  }
+
+
+  ImageAccessor ImageBuffer::GetAccessor()
+  {
+    Allocate();
+
+    ImageAccessor accessor;
+    accessor.AssignWritable(format_, width_, height_, pitch_, buffer_);
+    return accessor;
+  }
+
+
+  ImageAccessor ImageBuffer::GetConstAccessor()
+  {
+    Allocate();
+
+    ImageAccessor accessor;
+    accessor.AssignReadOnly(format_, width_, height_, pitch_, buffer_);
+    return accessor;
+  }
+
+
+  void ImageBuffer::SetMinimalPitchForced(bool force)
+  {
+    if (force != forceMinimalPitch_)
+    {
+      changed_ = true;
+      forceMinimalPitch_ = force;
+    }
+  }
+
+
+  void ImageBuffer::AcquireOwnership(ImageBuffer& other)
+  {
+    // Remove the content of the current image
+    Deallocate();
+
+    // Force the allocation of the other image (if not already
+    // allocated)
+    other.Allocate();
+
+    // Transfer the content of the other image
+    changed_ = false;
+    forceMinimalPitch_ = other.forceMinimalPitch_;
+    format_ = other.format_;
+    width_ = other.width_;
+    height_ = other.height_;
+    pitch_ = other.pitch_;
+    buffer_ = other.buffer_;
+
+    // Force the reinitialization of the other image
+    other.Initialize();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/ImageBuffer.h	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,115 @@
+/**
+ * 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 <vector>
+#include <stdint.h>
+#include <boost/noncopyable.hpp>
+
+namespace Orthanc
+{
+  class ImageBuffer : public boost::noncopyable
+  {
+  private:
+    bool changed_;
+
+    bool forceMinimalPitch_;  // Currently unused
+    PixelFormat format_;
+    unsigned int width_;
+    unsigned int height_;
+    unsigned int pitch_;
+    void *buffer_;
+
+    void Initialize();
+    
+    void Allocate();
+
+    void Deallocate();
+
+  public:
+    ImageBuffer(PixelFormat format,
+                unsigned int width,
+                unsigned int height);
+
+    ImageBuffer()
+    {
+      Initialize();
+    }
+
+    ~ImageBuffer()
+    {
+      Deallocate();
+    }
+
+    PixelFormat GetFormat() const
+    {
+      return format_;
+    }
+
+    void SetFormat(PixelFormat format);
+
+    unsigned int GetWidth() const
+    {
+      return width_;
+    }
+
+    void SetWidth(unsigned int width);
+
+    unsigned int GetHeight() const
+    {
+      return height_;
+    }
+
+    void SetHeight(unsigned int height);
+
+    unsigned int GetBytesPerPixel() const
+    {
+      return ::Orthanc::GetBytesPerPixel(format_);
+    }
+
+    ImageAccessor GetAccessor();
+
+    ImageAccessor GetConstAccessor();
+
+    bool IsMinimalPitchForced() const
+    {
+      return forceMinimalPitch_;
+    }
+
+    void SetMinimalPitchForced(bool force);
+
+    void AcquireOwnership(ImageBuffer& other);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/ImageProcessing.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,592 @@
+/**
+ * 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/>.
+ **/
+
+
+#include "../PrecompiledHeaders.h"
+#include "ImageProcessing.h"
+
+#include "../OrthancException.h"
+
+#include <boost/math/special_functions/round.hpp>
+
+#include <cassert>
+#include <string.h>
+#include <limits>
+#include <stdint.h>
+
+namespace Orthanc
+{
+  template <typename TargetType, typename SourceType>
+  static void ConvertInternal(ImageAccessor& target,
+                              const ImageAccessor& source)
+  {
+    const TargetType minValue = std::numeric_limits<TargetType>::min();
+    const TargetType maxValue = std::numeric_limits<TargetType>::max();
+
+    for (unsigned int y = 0; y < source.GetHeight(); y++)
+    {
+      TargetType* t = reinterpret_cast<TargetType*>(target.GetRow(y));
+      const SourceType* s = reinterpret_cast<const SourceType*>(source.GetConstRow(y));
+
+      for (unsigned int x = 0; x < source.GetWidth(); x++, t++, s++)
+      {
+        if (static_cast<int32_t>(*s) < static_cast<int32_t>(minValue))
+        {
+          *t = minValue;
+        }
+        else if (static_cast<int32_t>(*s) > static_cast<int32_t>(maxValue))
+        {
+          *t = maxValue;
+        }
+        else
+        {
+          *t = static_cast<TargetType>(*s);
+        }
+      }
+    }
+  }
+
+
+  template <typename TargetType>
+  static void ConvertColorToGrayscale(ImageAccessor& target,
+                              const ImageAccessor& source)
+  {
+    assert(source.GetFormat() == PixelFormat_RGB24);
+
+    const TargetType minValue = std::numeric_limits<TargetType>::min();
+    const TargetType maxValue = std::numeric_limits<TargetType>::max();
+
+    for (unsigned int y = 0; y < source.GetHeight(); y++)
+    {
+      TargetType* t = reinterpret_cast<TargetType*>(target.GetRow(y));
+      const uint8_t* s = reinterpret_cast<const uint8_t*>(source.GetConstRow(y));
+
+      for (unsigned int x = 0; x < source.GetWidth(); x++, t++, s += 3)
+      {
+        // Y = 0.2126 R + 0.7152 G + 0.0722 B
+        int32_t v = (2126 * static_cast<int32_t>(s[0]) +
+                     7152 * static_cast<int32_t>(s[1]) +
+                     0722 * static_cast<int32_t>(s[2])) / 1000;
+        
+        if (static_cast<int32_t>(v) < static_cast<int32_t>(minValue))
+        {
+          *t = minValue;
+        }
+        else if (static_cast<int32_t>(v) > static_cast<int32_t>(maxValue))
+        {
+          *t = maxValue;
+        }
+        else
+        {
+          *t = static_cast<TargetType>(v);
+        }
+      }
+    }
+  }
+
+
+  template <typename PixelType>
+  static void SetInternal(ImageAccessor& image,
+                          int64_t constant)
+  {
+    for (unsigned int y = 0; y < image.GetHeight(); y++)
+    {
+      PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y));
+
+      for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
+      {
+        *p = static_cast<PixelType>(constant);
+      }
+    }
+  }
+
+
+  template <typename PixelType>
+  static void GetMinMaxValueInternal(PixelType& minValue,
+                                     PixelType& maxValue,
+                                     const ImageAccessor& source)
+  {
+    // Deal with the special case of empty image
+    if (source.GetWidth() == 0 ||
+        source.GetHeight() == 0)
+    {
+      minValue = 0;
+      maxValue = 0;
+      return;
+    }
+
+    minValue = std::numeric_limits<PixelType>::max();
+    maxValue = std::numeric_limits<PixelType>::min();
+
+    for (unsigned int y = 0; y < source.GetHeight(); y++)
+    {
+      const PixelType* p = reinterpret_cast<const PixelType*>(source.GetConstRow(y));
+
+      for (unsigned int x = 0; x < source.GetWidth(); x++, p++)
+      {
+        if (*p < minValue)
+        {
+          minValue = *p;
+        }
+
+        if (*p > maxValue)
+        {
+          maxValue = *p;
+        }
+      }
+    }
+  }
+
+
+
+  template <typename PixelType>
+  static void AddConstantInternal(ImageAccessor& image,
+                                  int64_t constant)
+  {
+    if (constant == 0)
+    {
+      return;
+    }
+
+    const int64_t minValue = std::numeric_limits<PixelType>::min();
+    const int64_t maxValue = std::numeric_limits<PixelType>::max();
+
+    for (unsigned int y = 0; y < image.GetHeight(); y++)
+    {
+      PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y));
+
+      for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
+      {
+        int64_t v = static_cast<int64_t>(*p) + constant;
+
+        if (v > maxValue)
+        {
+          *p = std::numeric_limits<PixelType>::max();
+        }
+        else if (v < minValue)
+        {
+          *p = std::numeric_limits<PixelType>::min();
+        }
+        else
+        {
+          *p = static_cast<PixelType>(v);
+        }
+      }
+    }
+  }
+
+
+
+  template <typename PixelType>
+  void MultiplyConstantInternal(ImageAccessor& image,
+                                float factor)
+  {
+    if (std::abs(factor - 1.0f) <= std::numeric_limits<float>::epsilon())
+    {
+      return;
+    }
+
+    const int64_t minValue = std::numeric_limits<PixelType>::min();
+    const int64_t maxValue = std::numeric_limits<PixelType>::max();
+
+    for (unsigned int y = 0; y < image.GetHeight(); y++)
+    {
+      PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y));
+
+      for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
+      {
+        int64_t v = boost::math::llround(static_cast<float>(*p) * factor);
+
+        if (v > maxValue)
+        {
+          *p = std::numeric_limits<PixelType>::max();
+        }
+        else if (v < minValue)
+        {
+          *p = std::numeric_limits<PixelType>::min();
+        }
+        else
+        {
+          *p = static_cast<PixelType>(v);
+        }
+      }
+    }
+  }
+
+
+  template <typename PixelType>
+  void ShiftScaleInternal(ImageAccessor& image,
+                          float offset,
+                          float scaling)
+  {
+    const float minValue = static_cast<float>(std::numeric_limits<PixelType>::min());
+    const float maxValue = static_cast<float>(std::numeric_limits<PixelType>::max());
+
+    for (unsigned int y = 0; y < image.GetHeight(); y++)
+    {
+      PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y));
+
+      for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
+      {
+        float v = (static_cast<float>(*p) + offset) * scaling;
+
+        if (v > maxValue)
+        {
+          *p = std::numeric_limits<PixelType>::max();
+        }
+        else if (v < minValue)
+        {
+          *p = std::numeric_limits<PixelType>::min();
+        }
+        else
+        {
+          *p = static_cast<PixelType>(boost::math::iround(v));
+        }
+      }
+    }
+  }
+
+
+  void ImageProcessing::Copy(ImageAccessor& target,
+                             const ImageAccessor& source)
+  {
+    if (target.GetWidth() != source.GetWidth() ||
+        target.GetHeight() != source.GetHeight())
+    {
+      throw OrthancException(ErrorCode_IncompatibleImageSize);
+    }
+
+    if (target.GetFormat() != source.GetFormat())
+    {
+      throw OrthancException(ErrorCode_IncompatibleImageFormat);
+    }
+
+    unsigned int lineSize = GetBytesPerPixel(source.GetFormat()) * source.GetWidth();
+
+    assert(source.GetPitch() >= lineSize && target.GetPitch() >= lineSize);
+
+    for (unsigned int y = 0; y < source.GetHeight(); y++)
+    {
+      memcpy(target.GetRow(y), source.GetConstRow(y), lineSize);
+    }
+  }
+
+
+  void ImageProcessing::Convert(ImageAccessor& target,
+                                const ImageAccessor& source)
+  {
+    if (target.GetWidth() != source.GetWidth() ||
+        target.GetHeight() != source.GetHeight())
+    {
+      throw OrthancException(ErrorCode_IncompatibleImageSize);
+    }
+
+    if (source.GetFormat() == target.GetFormat())
+    {
+      Copy(target, source);
+      return;
+    }
+
+    if (target.GetFormat() == PixelFormat_Grayscale16 &&
+        source.GetFormat() == PixelFormat_Grayscale8)
+    {
+      ConvertInternal<uint16_t, uint8_t>(target, source);
+      return;
+    }
+
+    if (target.GetFormat() == PixelFormat_SignedGrayscale16 &&
+        source.GetFormat() == PixelFormat_Grayscale8)
+    {
+      ConvertInternal<int16_t, uint8_t>(target, source);
+      return;
+    }
+
+    if (target.GetFormat() == PixelFormat_Grayscale8 &&
+        source.GetFormat() == PixelFormat_Grayscale16)
+    {
+      ConvertInternal<uint8_t, uint16_t>(target, source);
+      return;
+    }
+
+    if (target.GetFormat() == PixelFormat_SignedGrayscale16 &&
+        source.GetFormat() == PixelFormat_Grayscale16)
+    {
+      ConvertInternal<int16_t, uint16_t>(target, source);
+      return;
+    }
+
+    if (target.GetFormat() == PixelFormat_Grayscale8 &&
+        source.GetFormat() == PixelFormat_SignedGrayscale16)
+    {
+      ConvertInternal<uint8_t, int16_t>(target, source);
+      return;
+    }
+
+    if (target.GetFormat() == PixelFormat_Grayscale16 &&
+        source.GetFormat() == PixelFormat_SignedGrayscale16)
+    {
+      ConvertInternal<uint16_t, int16_t>(target, source);
+      return;
+    }
+
+    if (target.GetFormat() == PixelFormat_Grayscale8 &&
+        source.GetFormat() == PixelFormat_RGB24)
+    {
+      ConvertColorToGrayscale<uint8_t>(target, source);
+      return;
+    }
+
+    if (target.GetFormat() == PixelFormat_Grayscale16 &&
+        source.GetFormat() == PixelFormat_RGB24)
+    {
+      ConvertColorToGrayscale<uint16_t>(target, source);
+      return;
+    }
+
+    if (target.GetFormat() == PixelFormat_SignedGrayscale16 &&
+        source.GetFormat() == PixelFormat_RGB24)
+    {
+      ConvertColorToGrayscale<int16_t>(target, source);
+      return;
+    }
+
+    if (target.GetFormat() == PixelFormat_Grayscale8 &&
+        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++)
+        {
+          *q = static_cast<uint8_t>((2126 * static_cast<uint32_t>(p[0]) +
+                                     7152 * static_cast<uint32_t>(p[1]) +
+                                     0722 * static_cast<uint32_t>(p[2])) / 10000);
+          p += 4;
+        }
+      }
+
+      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);
+  }
+
+
+
+  void ImageProcessing::Set(ImageAccessor& image,
+                            int64_t value)
+  {
+    switch (image.GetFormat())
+    {
+      case PixelFormat_Grayscale8:
+        SetInternal<uint8_t>(image, value);
+        return;
+
+      case PixelFormat_Grayscale16:
+        SetInternal<uint16_t>(image, value);
+        return;
+
+      case PixelFormat_SignedGrayscale16:
+        SetInternal<int16_t>(image, value);
+        return;
+
+      default:
+        throw OrthancException(ErrorCode_NotImplemented);
+    }
+  }
+
+
+  void ImageProcessing::ShiftRight(ImageAccessor& image,
+                                   unsigned int shift)
+  {
+    if (image.GetWidth() == 0 ||
+        image.GetHeight() == 0 ||
+        shift == 0)
+    {
+      // Nothing to do
+      return;
+    }
+
+    throw OrthancException(ErrorCode_NotImplemented);
+  }
+
+
+  void ImageProcessing::GetMinMaxValue(int64_t& minValue,
+                                       int64_t& maxValue,
+                                       const ImageAccessor& image)
+  {
+    switch (image.GetFormat())
+    {
+      case PixelFormat_Grayscale8:
+      {
+        uint8_t a, b;
+        GetMinMaxValueInternal<uint8_t>(a, b, image);
+        minValue = a;
+        maxValue = b;
+        break;
+      }
+
+      case PixelFormat_Grayscale16:
+      {
+        uint16_t a, b;
+        GetMinMaxValueInternal<uint16_t>(a, b, image);
+        minValue = a;
+        maxValue = b;
+        break;
+      }
+
+      case PixelFormat_SignedGrayscale16:
+      {
+        int16_t a, b;
+        GetMinMaxValueInternal<int16_t>(a, b, image);
+        minValue = a;
+        maxValue = b;
+        break;
+      }
+
+      default:
+        throw OrthancException(ErrorCode_NotImplemented);
+    }
+  }
+
+
+
+  void ImageProcessing::AddConstant(ImageAccessor& image,
+                                    int64_t value)
+  {
+    switch (image.GetFormat())
+    {
+      case PixelFormat_Grayscale8:
+        AddConstantInternal<uint8_t>(image, value);
+        return;
+
+      case PixelFormat_Grayscale16:
+        AddConstantInternal<uint16_t>(image, value);
+        return;
+
+      case PixelFormat_SignedGrayscale16:
+        AddConstantInternal<int16_t>(image, value);
+        return;
+
+      default:
+        throw OrthancException(ErrorCode_NotImplemented);
+    }
+  }
+
+
+  void ImageProcessing::MultiplyConstant(ImageAccessor& image,
+                                         float factor)
+  {
+    switch (image.GetFormat())
+    {
+      case PixelFormat_Grayscale8:
+        MultiplyConstantInternal<uint8_t>(image, factor);
+        return;
+
+      case PixelFormat_Grayscale16:
+        MultiplyConstantInternal<uint16_t>(image, factor);
+        return;
+
+      case PixelFormat_SignedGrayscale16:
+        MultiplyConstantInternal<int16_t>(image, factor);
+        return;
+
+      default:
+        throw OrthancException(ErrorCode_NotImplemented);
+    }
+  }
+
+
+  void ImageProcessing::ShiftScale(ImageAccessor& image,
+                                   float offset,
+                                   float scaling)
+  {
+    switch (image.GetFormat())
+    {
+      case PixelFormat_Grayscale8:
+        ShiftScaleInternal<uint8_t>(image, offset, scaling);
+        return;
+
+      case PixelFormat_Grayscale16:
+        ShiftScaleInternal<uint16_t>(image, offset, scaling);
+        return;
+
+      case PixelFormat_SignedGrayscale16:
+        ShiftScaleInternal<int16_t>(image, offset, scaling);
+        return;
+
+      default:
+        throw OrthancException(ErrorCode_NotImplemented);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/ImageProcessing.h	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,70 @@
+/**
+ * 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 <stdint.h>
+
+namespace Orthanc
+{
+  class ImageProcessing
+  {
+  public:
+    static void Copy(ImageAccessor& target,
+                     const ImageAccessor& source);
+
+    static void Convert(ImageAccessor& target,
+                        const ImageAccessor& source);
+
+    static void Set(ImageAccessor& image,
+                    int64_t value);
+
+    static void ShiftRight(ImageAccessor& target,
+                           unsigned int shift);
+
+    static void GetMinMaxValue(int64_t& minValue,
+                               int64_t& maxValue,
+                               const ImageAccessor& image);
+
+    static void AddConstant(ImageAccessor& image,
+                            int64_t value);
+
+    static void MultiplyConstant(ImageAccessor& image,
+                                 float factor);
+
+    static void ShiftScale(ImageAccessor& image,
+                           float offset,
+                           float scaling);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/JpegErrorManager.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,69 @@
+/**
+ * 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/>.
+ **/
+
+
+#include "../PrecompiledHeaders.h"
+#include "JpegErrorManager.h"
+
+namespace Orthanc
+{
+  namespace Internals
+  {
+    void JpegErrorManager::OutputMessage(j_common_ptr cinfo)
+    {
+      char message[JMSG_LENGTH_MAX];
+      (*cinfo->err->format_message) (cinfo, message);
+
+      JpegErrorManager* that = reinterpret_cast<JpegErrorManager*>(cinfo->err);
+      that->message = std::string(message);
+    }
+
+
+    void JpegErrorManager::ErrorExit(j_common_ptr cinfo)
+    {
+      (*cinfo->err->output_message) (cinfo);
+
+      JpegErrorManager* that = reinterpret_cast<JpegErrorManager*>(cinfo->err);
+      longjmp(that->setjmp_buffer, 1);
+    }
+      
+
+    JpegErrorManager::JpegErrorManager()
+    {
+      memset(&pub, 0, sizeof(struct jpeg_error_mgr));
+      memset(&setjmp_buffer, 0, sizeof(jmp_buf));
+
+      jpeg_std_error(&pub);
+      pub.error_exit = ErrorExit;
+      pub.output_message = OutputMessage;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/JpegErrorManager.h	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,74 @@
+/**
+ * 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 <string.h>
+#include <stdio.h>
+#include <jpeglib.h>
+#include <setjmp.h>
+#include <string>
+
+namespace Orthanc
+{
+  namespace Internals
+  {
+    class JpegErrorManager 
+    {
+    private:
+      struct jpeg_error_mgr pub;  /* "public" fields */
+      jmp_buf setjmp_buffer;      /* for return to caller */
+      std::string message;
+
+      static void OutputMessage(j_common_ptr cinfo);
+
+      static void ErrorExit(j_common_ptr cinfo);
+
+    public:
+      JpegErrorManager();
+
+      struct jpeg_error_mgr* GetPublic()
+      {
+        return &pub;
+      }
+
+      jmp_buf& GetJumpBuffer()
+      {
+        return setjmp_buffer;
+      }
+
+      const std::string& GetMessage() const
+      {
+        return message;
+      }
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/JpegReader.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,184 @@
+/**
+ * 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/>.
+ **/
+
+
+#include "../PrecompiledHeaders.h"
+#include "JpegReader.h"
+
+#include "JpegErrorManager.h"
+#include "../OrthancException.h"
+#include "../Logging.h"
+
+namespace Orthanc
+{
+  static void Uncompress(struct jpeg_decompress_struct& cinfo,
+                         std::string& content,
+                         ImageAccessor& accessor)
+  {
+    jpeg_read_header(&cinfo, TRUE);
+    jpeg_start_decompress(&cinfo);
+
+    PixelFormat format;
+    if (cinfo.output_components == 1 &&
+        cinfo.out_color_space == JCS_GRAYSCALE)
+    {
+      format = PixelFormat_Grayscale8;
+    }
+    else if (cinfo.output_components == 3 &&
+             cinfo.out_color_space == JCS_RGB)
+    {
+      format = PixelFormat_RGB24;
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_NotImplemented);
+    }
+
+    unsigned int pitch = cinfo.output_width * cinfo.output_components;
+
+    /* Make a one-row-high sample array that will go away when done with image */
+    JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, pitch, 1);
+
+    try
+    {
+      content.resize(pitch * cinfo.output_height);
+    }
+    catch (...)
+    {
+      throw OrthancException(ErrorCode_NotEnoughMemory);
+    }
+
+    accessor.AssignWritable(format, cinfo.output_width, cinfo.output_height, pitch, 
+                            content.empty() ? NULL : &content[0]);
+
+    uint8_t* target = reinterpret_cast<uint8_t*>(&content[0]);
+    while (cinfo.output_scanline < cinfo.output_height) 
+    {
+      jpeg_read_scanlines(&cinfo, buffer, 1);
+      memcpy(target, buffer[0], pitch);
+      target += pitch;
+    }
+
+    // Everything went fine, "setjmp()" didn't get called
+
+    jpeg_finish_decompress(&cinfo);
+  }
+
+
+  void JpegReader::ReadFromFile(const char* filename)
+  {
+    FILE* fp = fopen(filename, "rb");
+    if (!fp)
+    {
+      throw OrthancException(ErrorCode_InexistentFile);
+    }
+
+    struct jpeg_decompress_struct cinfo;
+    memset(&cinfo, 0, sizeof(struct jpeg_decompress_struct));
+
+    Internals::JpegErrorManager jerr;
+    cinfo.err = jerr.GetPublic();
+    
+    if (setjmp(jerr.GetJumpBuffer())) 
+    {
+      jpeg_destroy_decompress(&cinfo);
+      fclose(fp);
+      LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage();
+      throw OrthancException(ErrorCode_InternalError);
+    }
+
+    // Below this line, we are under the scope of a "setjmp"
+
+    jpeg_create_decompress(&cinfo);
+    jpeg_stdio_src(&cinfo, fp);
+
+    try
+    {
+      Uncompress(cinfo, content_, *this);
+    }
+    catch (OrthancException&)
+    {
+      jpeg_destroy_decompress(&cinfo);
+      fclose(fp);
+      throw;
+    }
+
+    jpeg_destroy_decompress(&cinfo);
+    fclose(fp);
+  }
+
+
+  void JpegReader::ReadFromMemory(const void* buffer,
+                                  size_t size)
+  {
+    struct jpeg_decompress_struct cinfo;
+    memset(&cinfo, 0, sizeof(struct jpeg_decompress_struct));
+
+    Internals::JpegErrorManager jerr;
+    cinfo.err = jerr.GetPublic();
+    
+    if (setjmp(jerr.GetJumpBuffer())) 
+    {
+      jpeg_destroy_decompress(&cinfo);
+      LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage();
+      throw OrthancException(ErrorCode_InternalError);
+    }
+
+    // Below this line, we are under the scope of a "setjmp"
+    jpeg_create_decompress(&cinfo);
+    jpeg_mem_src(&cinfo, const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(buffer)), size);
+
+    try
+    {
+      Uncompress(cinfo, content_, *this);
+    }
+    catch (OrthancException&)
+    {
+      jpeg_destroy_decompress(&cinfo);
+      throw;
+    }
+
+    jpeg_destroy_decompress(&cinfo);
+  }
+
+
+  void JpegReader::ReadFromMemory(const std::string& buffer)
+  {
+    if (buffer.empty())
+    {
+      ReadFromMemory(NULL, 0);
+    }
+    else
+    {
+      ReadFromMemory(buffer.c_str(), buffer.size());
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/JpegReader.h	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,59 @@
+/**
+ * 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 <string>
+
+namespace Orthanc
+{
+  class JpegReader : public ImageAccessor
+  {
+  private:
+    std::string  content_;
+
+  public:
+    void ReadFromFile(const char* filename);
+
+    void ReadFromFile(const std::string& filename)
+    {
+      ReadFromFile(filename.c_str());
+    }
+
+    void ReadFromMemory(const void* buffer,
+                        size_t size);
+
+    void ReadFromMemory(const std::string& buffer);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/JpegWriter.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,202 @@
+/**
+ * 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/>.
+ **/
+
+
+#include "../PrecompiledHeaders.h"
+#include "JpegWriter.h"
+
+#include "../OrthancException.h"
+#include "../Logging.h"
+
+#include "JpegErrorManager.h"
+
+#include <vector>
+
+namespace Orthanc
+{
+  static void GetLines(std::vector<uint8_t*>& lines,
+                       unsigned int height,
+                       unsigned int pitch,
+                       PixelFormat format,
+                       const void* buffer)
+  {
+    if (format != PixelFormat_Grayscale8 &&
+        format != PixelFormat_RGB24)
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+
+    lines.resize(height);
+
+    uint8_t* base = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(buffer));
+    for (unsigned int y = 0; y < height; y++)
+    {
+      lines[y] = base + static_cast<intptr_t>(y) * static_cast<intptr_t>(pitch);
+    }
+  }
+
+
+  static void Compress(struct jpeg_compress_struct& cinfo,
+                       std::vector<uint8_t*>& lines,
+                       unsigned int width,
+                       unsigned int height,
+                       PixelFormat format,
+                       int quality)
+  {
+    cinfo.image_width = width;
+    cinfo.image_height = height;
+
+    switch (format)
+    {
+      case PixelFormat_Grayscale8:
+        cinfo.input_components = 1;
+        cinfo.in_color_space = JCS_GRAYSCALE;
+        break;
+
+      case PixelFormat_RGB24:
+        cinfo.input_components = 3;
+        cinfo.in_color_space = JCS_RGB;
+        break;
+
+      default:
+        throw OrthancException(ErrorCode_InternalError);
+    }
+
+    jpeg_set_defaults(&cinfo);
+    jpeg_set_quality(&cinfo, quality, TRUE);
+    jpeg_start_compress(&cinfo, TRUE);
+    jpeg_write_scanlines(&cinfo, &lines[0], height);
+    jpeg_finish_compress(&cinfo);
+    jpeg_destroy_compress(&cinfo);
+  }
+                       
+
+  void JpegWriter::SetQuality(uint8_t quality)
+  {
+    if (quality <= 0 || quality > 100)
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+
+    quality_ = quality;
+  }
+
+
+  void JpegWriter::WriteToFile(const char* filename,
+                               unsigned int width,
+                               unsigned int height,
+                               unsigned int pitch,
+                               PixelFormat format,
+                               const void* buffer)
+  {
+    FILE* fp = fopen(filename, "wb");
+    if (fp == NULL)
+    {
+      throw OrthancException(ErrorCode_FullStorage);
+    }
+
+    std::vector<uint8_t*> lines;
+    GetLines(lines, height, pitch, format, buffer);
+
+    struct jpeg_compress_struct cinfo;
+    memset(&cinfo, 0, sizeof(struct jpeg_compress_struct));
+
+    Internals::JpegErrorManager jerr;
+    cinfo.err = jerr.GetPublic();
+
+    if (setjmp(jerr.GetJumpBuffer())) 
+    {
+      /* If we get here, the JPEG code has signaled an error.
+       * We need to clean up the JPEG object, close the input file, and return.
+       */
+      jpeg_destroy_compress(&cinfo);
+      fclose(fp);
+      LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage();
+      throw OrthancException(ErrorCode_InternalError);
+    }
+
+    // Do not allocate data on the stack below this line!
+
+    jpeg_create_compress(&cinfo);
+    jpeg_stdio_dest(&cinfo, fp);
+    Compress(cinfo, lines, width, height, format, quality_);
+
+    // Everything went fine, "setjmp()" didn't get called
+
+    fclose(fp);
+  }
+
+
+  void JpegWriter::WriteToMemory(std::string& jpeg,
+                                 unsigned int width,
+                                 unsigned int height,
+                                 unsigned int pitch,
+                                 PixelFormat format,
+                                 const void* buffer)
+  {
+    std::vector<uint8_t*> lines;
+    GetLines(lines, height, pitch, format, buffer);
+
+    struct jpeg_compress_struct cinfo;
+    memset(&cinfo, 0, sizeof(struct jpeg_compress_struct));
+
+    Internals::JpegErrorManager jerr;
+
+    unsigned char* data = NULL;
+    unsigned long size;
+
+    if (setjmp(jerr.GetJumpBuffer())) 
+    {
+      jpeg_destroy_compress(&cinfo);
+
+      if (data != NULL)
+      {
+        free(data);
+      }
+
+      LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage();
+      throw OrthancException(ErrorCode_InternalError);
+    }
+
+    // Do not allocate data on the stack below this line!
+
+    jpeg_create_compress(&cinfo);
+    cinfo.err = jerr.GetPublic();
+    jpeg_mem_dest(&cinfo, &data, &size);
+
+    Compress(cinfo, lines, width, height, format, quality_);
+
+    // Everything went fine, "setjmp()" didn't get called
+
+    jpeg.assign(reinterpret_cast<const char*>(data), size);
+    free(data);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/JpegWriter.h	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,87 @@
+/**
+ * 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 <string>
+#include <stdint.h>
+
+namespace Orthanc
+{
+  class JpegWriter
+  {
+  private:
+    int  quality_;
+
+  public:
+    JpegWriter() : quality_(90)
+    {
+    }
+
+    void SetQuality(uint8_t quality);
+
+    uint8_t GetQuality() const
+    {
+      return quality_;
+    }
+
+    void WriteToFile(const char* filename,
+                     unsigned int width,
+                     unsigned int height,
+                     unsigned int pitch,
+                     PixelFormat format,
+                     const void* buffer);
+
+    void WriteToMemory(std::string& jpeg,
+                       unsigned int width,
+                       unsigned int height,
+                       unsigned int pitch,
+                       PixelFormat format,
+                       const void* buffer);
+
+    void WriteToFile(const char* filename,
+                     const ImageAccessor& accessor)
+    {
+      WriteToFile(filename, accessor.GetWidth(), accessor.GetHeight(),
+                  accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer());
+    }
+
+    void WriteToMemory(std::string& jpeg,
+                       const ImageAccessor& accessor)
+    {
+      WriteToMemory(jpeg, accessor.GetWidth(), accessor.GetHeight(),
+                    accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer());
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/PngReader.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,313 @@
+/**
+ * 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/>.
+ **/
+
+
+#include "../PrecompiledHeaders.h"
+#include "PngReader.h"
+
+#include "../OrthancException.h"
+#include "../Toolbox.h"
+
+#include <png.h>
+#include <string.h>  // For memcpy()
+
+namespace Orthanc
+{
+  namespace 
+  {
+    struct FileRabi
+    {
+      FILE* fp_;
+
+      FileRabi(const char* filename)
+      {
+        fp_ = fopen(filename, "rb");
+        if (!fp_)
+        {
+          throw OrthancException(ErrorCode_InexistentFile);
+        }
+      }
+
+      ~FileRabi()
+      {
+        if (fp_)
+          fclose(fp_);
+      }
+    };
+  }
+
+
+  struct PngReader::PngRabi
+  {
+    png_structp png_;
+    png_infop info_;
+    png_infop endInfo_;
+
+    void Destruct()
+    {
+      if (png_)
+      {
+        png_destroy_read_struct(&png_, &info_, &endInfo_);
+
+        png_ = NULL;
+        info_ = NULL;
+        endInfo_ = NULL;
+      }
+    }
+
+    PngRabi()
+    {
+      png_ = NULL;
+      info_ = NULL;
+      endInfo_ = NULL;
+
+      png_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+      if (!png_)
+      {
+        throw OrthancException(ErrorCode_NotEnoughMemory);
+      }
+
+      info_ = png_create_info_struct(png_);
+      if (!info_)
+      {
+        png_destroy_read_struct(&png_, NULL, NULL);
+        throw OrthancException(ErrorCode_NotEnoughMemory);
+      }
+
+      endInfo_ = png_create_info_struct(png_);
+      if (!info_)
+      {
+        png_destroy_read_struct(&png_, &info_, NULL);
+        throw OrthancException(ErrorCode_NotEnoughMemory);
+      }
+    }
+
+    ~PngRabi()
+    {
+      Destruct();
+    }
+
+    static void MemoryCallback(png_structp png_ptr, 
+                               png_bytep data, 
+                               png_size_t size);
+  };
+
+
+  void PngReader::CheckHeader(const void* header)
+  {
+    int is_png = !png_sig_cmp((png_bytep) header, 0, 8);
+    if (!is_png)
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+  }
+
+  PngReader::PngReader()
+  {
+  }
+
+  void PngReader::Read(PngRabi& rabi)
+  {
+    png_set_sig_bytes(rabi.png_, 8);
+
+    png_read_info(rabi.png_, rabi.info_);
+
+    png_uint_32 width, height;
+    int bit_depth, color_type, interlace_type;
+    int compression_type, filter_method;
+    // get size and bit-depth of the PNG-image
+    png_get_IHDR(rabi.png_, rabi.info_,
+                 &width, &height,
+                 &bit_depth, &color_type, &interlace_type,
+                 &compression_type, &filter_method);
+
+    PixelFormat format;
+    unsigned int pitch;
+
+    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 8)
+    {
+      format = PixelFormat_Grayscale8;
+      pitch = width;
+    }
+    else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 16)
+    {
+      format = PixelFormat_Grayscale16;
+      pitch = 2 * width;
+
+      if (Toolbox::DetectEndianness() == Endianness_Little)
+      {
+        png_set_swap(rabi.png_);
+      }
+    }
+    else if (color_type == PNG_COLOR_TYPE_RGB && bit_depth == 8)
+    {
+      format = PixelFormat_RGB24;
+      pitch = 3 * width;
+    }
+    else if (color_type == PNG_COLOR_TYPE_RGBA && bit_depth == 8)
+    {
+      format = PixelFormat_RGBA32;
+      pitch = 4 * width;
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_NotImplemented);
+    }
+
+    data_.resize(height * pitch);
+
+    if (height == 0 || width == 0)
+    {
+      // Empty image, we are done
+      AssignEmpty(format);
+      return;
+    }
+    
+    png_read_update_info(rabi.png_, rabi.info_);
+
+    std::vector<png_bytep> rows(height);
+    for (size_t i = 0; i < height; i++)
+    {
+      rows[i] = &data_[0] + i * pitch;
+    }
+
+    png_read_image(rabi.png_, &rows[0]);
+
+    AssignWritable(format, width, height, pitch, &data_[0]);
+  }
+
+  void PngReader::ReadFromFile(const char* filename)
+  {
+    FileRabi f(filename);
+
+    char header[8];
+    if (fread(header, 1, 8, f.fp_) != 8)
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+
+    CheckHeader(header);
+
+    PngRabi rabi;
+
+    if (setjmp(png_jmpbuf(rabi.png_)))
+    {
+      rabi.Destruct();
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+
+    png_init_io(rabi.png_, f.fp_);
+
+    Read(rabi);
+  }
+
+
+  namespace
+  {
+    struct MemoryBuffer
+    {
+      const uint8_t* buffer_;
+      size_t size_;
+      size_t pos_;
+      bool ok_;
+    };
+  }
+
+
+  void PngReader::PngRabi::MemoryCallback(png_structp png_ptr, 
+                                          png_bytep outBytes, 
+                                          png_size_t byteCountToRead)
+  {
+    MemoryBuffer* from = reinterpret_cast<MemoryBuffer*>(png_get_io_ptr(png_ptr));
+
+    if (!from->ok_)
+    {
+      return;
+    }
+
+    if (from->pos_ + byteCountToRead > from->size_)
+    {
+      from->ok_ = false;
+      return;
+    }
+
+    memcpy(outBytes, from->buffer_ + from->pos_, byteCountToRead);
+
+    from->pos_ += byteCountToRead;
+  }
+
+
+  void PngReader::ReadFromMemory(const void* buffer,
+                                 size_t size)
+  {
+    if (size < 8)
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+
+    CheckHeader(buffer);
+
+    PngRabi rabi;
+
+    if (setjmp(png_jmpbuf(rabi.png_)))
+    {
+      rabi.Destruct();
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+
+    MemoryBuffer tmp;
+    tmp.buffer_ = reinterpret_cast<const uint8_t*>(buffer) + 8;  // We skip the header
+    tmp.size_ = size - 8;
+    tmp.pos_ = 0;
+    tmp.ok_ = true;
+
+    png_set_read_fn(rabi.png_, &tmp, PngRabi::MemoryCallback);
+
+    Read(rabi);
+
+    if (!tmp.ok_)
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+  }
+
+  void PngReader::ReadFromMemory(const std::string& buffer)
+  {
+    if (buffer.size() != 0)
+    {
+      ReadFromMemory(&buffer[0], buffer.size());
+    }
+    else
+    {
+      ReadFromMemory(NULL, 0);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/PngReader.h	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,71 @@
+/**
+ * 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 "../Enumerations.h"
+
+#include <vector>
+#include <stdint.h>
+#include <boost/shared_ptr.hpp>
+
+namespace Orthanc
+{
+  class PngReader : public ImageAccessor
+  {
+  private:
+    struct PngRabi;
+
+    std::vector<uint8_t> data_;
+
+    void CheckHeader(const void* header);
+
+    void Read(PngRabi& rabi);
+
+  public:
+    PngReader();
+
+    void ReadFromFile(const char* filename);
+
+    void ReadFromFile(const std::string& filename)
+    {
+      ReadFromFile(filename.c_str());
+    }
+
+    void ReadFromMemory(const void* buffer,
+                        size_t size);
+
+    void ReadFromMemory(const std::string& buffer);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/PngWriter.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,269 @@
+/**
+ * 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/>.
+ **/
+
+
+#include "../PrecompiledHeaders.h"
+#include "PngWriter.h"
+
+#include <vector>
+#include <stdint.h>
+#include <png.h>
+#include "../OrthancException.h"
+#include "../ChunkedBuffer.h"
+#include "../Toolbox.h"
+
+
+// http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-4
+// http://zarb.org/~gc/html/libpng.html
+/*
+  void write_row_callback(png_ptr, png_uint_32 row, int pass)
+  {
+  }*/
+
+
+
+
+/*  bool isError_;
+
+// http://www.libpng.org/pub/png/book/chapter14.html#png.ch14.div.2
+
+static void ErrorHandler(png_structp png, png_const_charp message)
+{
+printf("** [%s]\n", message);
+
+PngWriter* that = (PngWriter*) png_get_error_ptr(png);
+that->isError_ = true;
+printf("** %d\n", (int)that);
+
+//((PngWriter*) payload)->isError_ = true;
+}
+
+static void WarningHandler(png_structp png, png_const_charp message)
+{
+  printf("++ %d\n", (int)message);
+}*/
+
+
+namespace Orthanc
+{
+  struct PngWriter::PImpl
+  {
+    png_structp png_;
+    png_infop info_;
+
+    // Filled by Prepare()
+    std::vector<uint8_t*> rows_;
+    int bitDepth_;
+    int colorType_;
+  };
+
+
+
+  PngWriter::PngWriter() : pimpl_(new PImpl)
+  {
+    pimpl_->png_ = NULL;
+    pimpl_->info_ = NULL;
+
+    pimpl_->png_ = png_create_write_struct
+      (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); //this, ErrorHandler, WarningHandler);
+    if (!pimpl_->png_)
+    {
+      throw OrthancException(ErrorCode_NotEnoughMemory);
+    }
+
+    pimpl_->info_ = png_create_info_struct(pimpl_->png_);
+    if (!pimpl_->info_)
+    {
+      png_destroy_write_struct(&pimpl_->png_, NULL);
+      throw OrthancException(ErrorCode_NotEnoughMemory);
+    }
+  }
+
+  PngWriter::~PngWriter()
+  {
+    if (pimpl_->info_)
+    {
+      png_destroy_info_struct(pimpl_->png_, &pimpl_->info_);
+    }
+
+    if (pimpl_->png_)
+    {
+      png_destroy_write_struct(&pimpl_->png_, NULL);
+    }
+  }
+
+
+
+  void PngWriter::Prepare(unsigned int width,
+                          unsigned int height,
+                          unsigned int pitch,
+                          PixelFormat format,
+                          const void* buffer)
+  {
+    pimpl_->rows_.resize(height);
+    for (unsigned int y = 0; y < height; y++)
+    {
+      pimpl_->rows_[y] = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(buffer)) + y * pitch;
+    }
+
+    switch (format)
+    {
+    case PixelFormat_RGB24:
+      pimpl_->bitDepth_ = 8;
+      pimpl_->colorType_ = PNG_COLOR_TYPE_RGB;
+      break;
+
+    case PixelFormat_RGBA32:
+      pimpl_->bitDepth_ = 8;
+      pimpl_->colorType_ = PNG_COLOR_TYPE_RGBA;
+      break;
+
+    case PixelFormat_Grayscale8:
+      pimpl_->bitDepth_ = 8;
+      pimpl_->colorType_ = PNG_COLOR_TYPE_GRAY;
+      break;
+
+    case PixelFormat_Grayscale16:
+    case PixelFormat_SignedGrayscale16:
+      pimpl_->bitDepth_ = 16;
+      pimpl_->colorType_ = PNG_COLOR_TYPE_GRAY;
+      break;
+
+    default:
+      throw OrthancException(ErrorCode_NotImplemented);
+    }
+  }
+
+
+  void PngWriter::Compress(unsigned int width,
+                           unsigned int height,
+                           unsigned int pitch,
+                           PixelFormat format)
+  {
+    png_set_IHDR(pimpl_->png_, pimpl_->info_, width, height,
+                 pimpl_->bitDepth_, pimpl_->colorType_, PNG_INTERLACE_NONE,
+                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+    png_write_info(pimpl_->png_, pimpl_->info_);
+
+    if (height > 0)
+    {
+      switch (format)
+      {
+      case PixelFormat_Grayscale16:
+      case PixelFormat_SignedGrayscale16:
+      {
+        int transforms = 0;
+        if (Toolbox::DetectEndianness() == Endianness_Little)
+        {
+          transforms = PNG_TRANSFORM_SWAP_ENDIAN;
+        }
+
+        png_set_rows(pimpl_->png_, pimpl_->info_, &pimpl_->rows_[0]);
+        png_write_png(pimpl_->png_, pimpl_->info_, transforms, NULL);
+
+        break;
+      }
+
+      default:
+        png_write_image(pimpl_->png_, &pimpl_->rows_[0]);
+      }
+    }
+
+    png_write_end(pimpl_->png_, NULL);
+  }
+
+
+  void PngWriter::WriteToFile(const char* filename,
+                              unsigned int width,
+                              unsigned int height,
+                              unsigned int pitch,
+                              PixelFormat format,
+                              const void* buffer)
+  {
+    Prepare(width, height, pitch, format, buffer);
+
+    FILE* fp = fopen(filename, "wb");
+    if (!fp)
+    {
+      throw OrthancException(ErrorCode_CannotWriteFile);
+    }    
+
+    png_init_io(pimpl_->png_, fp);
+
+    if (setjmp(png_jmpbuf(pimpl_->png_)))
+    {
+      // Error during writing PNG
+      throw OrthancException(ErrorCode_CannotWriteFile);      
+    }
+
+    Compress(width, height, pitch, format);
+
+    fclose(fp);
+  }
+
+
+
+
+  static void MemoryCallback(png_structp png_ptr, 
+                             png_bytep data, 
+                             png_size_t size)
+  {
+    ChunkedBuffer* buffer = reinterpret_cast<ChunkedBuffer*>(png_get_io_ptr(png_ptr));
+    buffer->AddChunk(reinterpret_cast<const char*>(data), size);
+  }
+
+
+
+  void PngWriter::WriteToMemory(std::string& png,
+                                unsigned int width,
+                                unsigned int height,
+                                unsigned int pitch,
+                                PixelFormat format,
+                                const void* buffer)
+  {
+    ChunkedBuffer chunks;
+
+    Prepare(width, height, pitch, format, buffer);
+
+    if (setjmp(png_jmpbuf(pimpl_->png_)))
+    {
+      // Error during writing PNG
+      throw OrthancException(ErrorCode_InternalError);      
+    }
+
+    png_set_write_fn(pimpl_->png_, &chunks, MemoryCallback, NULL);
+
+    Compress(width, height, pitch, format);
+
+    chunks.Flatten(png);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Images/PngWriter.h	Fri Sep 04 16:36:18 2015 +0200
@@ -0,0 +1,92 @@
+/**
+ * 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 <boost/shared_ptr.hpp>
+#include <string>
+
+namespace Orthanc
+{
+  class PngWriter
+  {
+  private:
+    struct PImpl;
+    boost::shared_ptr<PImpl> pimpl_;
+
+    void Compress(unsigned int width,
+                  unsigned int height,
+                  unsigned int pitch,
+                  PixelFormat format);
+
+    void Prepare(unsigned int width,
+                 unsigned int height,
+                 unsigned int pitch,
+                 PixelFormat format,
+                 const void* buffer);
+
+  public:
+    PngWriter();
+
+    ~PngWriter();
+
+    void WriteToFile(const char* filename,
+                     unsigned int width,
+                     unsigned int height,
+                     unsigned int pitch,
+                     PixelFormat format,
+                     const void* buffer);
+
+    void WriteToMemory(std::string& png,
+                       unsigned int width,
+                       unsigned int height,
+                       unsigned int pitch,
+                       PixelFormat format,
+                       const void* buffer);
+
+    void WriteToFile(const char* filename,
+                     const ImageAccessor& accessor)
+    {
+      WriteToFile(filename, accessor.GetWidth(), accessor.GetHeight(),
+                  accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer());
+    }
+
+    void WriteToMemory(std::string& png,
+                       const ImageAccessor& accessor)
+    {
+      WriteToMemory(png, accessor.GetWidth(), accessor.GetHeight(),
+                    accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer());
+    }
+  };
+}
--- a/OrthancServer/FromDcmtkBridge.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ b/OrthancServer/FromDcmtkBridge.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -45,7 +45,7 @@
 #include "../Core/Logging.h"
 #include "../Core/Toolbox.h"
 #include "../Core/OrthancException.h"
-#include "../Core/ImageFormats/PngWriter.h"
+#include "../Core/Images/PngWriter.h"
 #include "../Core/Uuid.h"
 #include "../Core/DicomFormat/DicomString.h"
 #include "../Core/DicomFormat/DicomNullValue.h"
--- a/OrthancServer/Internals/DicomImageDecoder.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ b/OrthancServer/Internals/DicomImageDecoder.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -82,8 +82,8 @@
 
 #include "../../Core/Logging.h"
 #include "../../Core/OrthancException.h"
-#include "../../Core/ImageFormats/ImageProcessing.h"
-#include "../../Core/ImageFormats/PngWriter.h"  // TODO REMOVE THIS
+#include "../../Core/Images/ImageProcessing.h"
+#include "../../Core/Images/PngWriter.h"  // TODO REMOVE THIS
 #include "../../Core/DicomFormat/DicomIntegerPixelAccessor.h"
 #include "../ToDcmtkBridge.h"
 #include "../FromDcmtkBridge.h"
--- a/OrthancServer/Internals/DicomImageDecoder.h	Fri Sep 04 16:30:42 2015 +0200
+++ b/OrthancServer/Internals/DicomImageDecoder.h	Fri Sep 04 16:36:18 2015 +0200
@@ -34,7 +34,7 @@
 
 #include <dcmtk/dcmdata/dcfilefo.h>
 
-#include "../../Core/ImageFormats/ImageBuffer.h"
+#include "../../Core/Images/ImageBuffer.h"
 
 namespace Orthanc
 {
--- a/OrthancServer/OrthancInitialization.h	Fri Sep 04 16:30:42 2015 +0200
+++ b/OrthancServer/OrthancInitialization.h	Fri Sep 04 16:36:18 2015 +0200
@@ -42,7 +42,7 @@
 #include "OrthancPeerParameters.h"
 #include "IDatabaseWrapper.h"
 #include "../Core/FileStorage/IStorageArea.h"
-#include "../Core/ImageFormats/FontRegistry.h"
+#include "../Core/Images/FontRegistry.h"
 
 namespace Orthanc
 {
--- a/OrthancServer/ParsedDicomFile.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ b/OrthancServer/ParsedDicomFile.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -87,13 +87,13 @@
 #include "../Core/Logging.h"
 #include "../Core/Toolbox.h"
 #include "../Core/OrthancException.h"
-#include "../Core/ImageFormats/ImageBuffer.h"
-#include "../Core/ImageFormats/PngWriter.h"
+#include "../Core/Images/ImageBuffer.h"
+#include "../Core/Images/PngWriter.h"
 #include "../Core/Uuid.h"
 #include "../Core/DicomFormat/DicomString.h"
 #include "../Core/DicomFormat/DicomNullValue.h"
 #include "../Core/DicomFormat/DicomIntegerPixelAccessor.h"
-#include "../Core/ImageFormats/PngReader.h"
+#include "../Core/Images/PngReader.h"
 
 #include <list>
 #include <limits>
--- a/OrthancServer/ParsedDicomFile.h	Fri Sep 04 16:30:42 2015 +0200
+++ b/OrthancServer/ParsedDicomFile.h	Fri Sep 04 16:36:18 2015 +0200
@@ -35,8 +35,8 @@
 #include "../Core/DicomFormat/DicomInstanceHasher.h"
 #include "../Core/RestApi/RestApiOutput.h"
 #include "ServerEnumerations.h"
-#include "../Core/ImageFormats/ImageAccessor.h"
-#include "../Core/ImageFormats/ImageBuffer.h"
+#include "../Core/Images/ImageAccessor.h"
+#include "../Core/Images/ImageBuffer.h"
 
 namespace Orthanc
 {
--- a/Plugins/Engine/OrthancPlugins.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ b/Plugins/Engine/OrthancPlugins.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -42,12 +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 "../../Core/Images/Image.h"
+#include "../../Core/Images/PngReader.h"
+#include "../../Core/Images/PngWriter.h"
+#include "../../Core/Images/JpegReader.h"
+#include "../../Core/Images/JpegWriter.h"
+#include "../../Core/Images/ImageProcessing.h"
 
 #include <boost/regex.hpp> 
 
--- a/UnitTestsSources/FromDcmtkTests.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ b/UnitTestsSources/FromDcmtkTests.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -37,9 +37,9 @@
 #include "../OrthancServer/OrthancInitialization.h"
 #include "../OrthancServer/DicomModification.h"
 #include "../Core/OrthancException.h"
-#include "../Core/ImageFormats/ImageBuffer.h"
-#include "../Core/ImageFormats/PngReader.h"
-#include "../Core/ImageFormats/PngWriter.h"
+#include "../Core/Images/ImageBuffer.h"
+#include "../Core/Images/PngReader.h"
+#include "../Core/Images/PngWriter.h"
 #include "../Core/Uuid.h"
 #include "../Resources/EncodingTests.h"
 
--- a/UnitTestsSources/ImageProcessingTests.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ b/UnitTestsSources/ImageProcessingTests.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -34,8 +34,8 @@
 #include "gtest/gtest.h"
 
 #include "../Core/DicomFormat/DicomImageInformation.h"
-#include "../Core/ImageFormats/ImageBuffer.h"
-#include "../Core/ImageFormats/ImageProcessing.h"
+#include "../Core/Images/ImageBuffer.h"
+#include "../Core/Images/ImageProcessing.h"
 
 using namespace Orthanc;
 
--- a/UnitTestsSources/ImageTests.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ b/UnitTestsSources/ImageTests.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -33,13 +33,13 @@
 #include "PrecompiledHeadersUnitTests.h"
 #include "gtest/gtest.h"
 
-#include "../Core/ImageFormats/Font.h"
-#include "../Core/ImageFormats/Image.h"
-#include "../Core/ImageFormats/ImageProcessing.h"
-#include "../Core/ImageFormats/JpegReader.h"
-#include "../Core/ImageFormats/JpegWriter.h"
-#include "../Core/ImageFormats/PngReader.h"
-#include "../Core/ImageFormats/PngWriter.h"
+#include "../Core/Images/Font.h"
+#include "../Core/Images/Image.h"
+#include "../Core/Images/ImageProcessing.h"
+#include "../Core/Images/JpegReader.h"
+#include "../Core/Images/JpegWriter.h"
+#include "../Core/Images/PngReader.h"
+#include "../Core/Images/PngWriter.h"
 #include "../Core/Toolbox.h"
 #include "../Core/Uuid.h"
 #include "../OrthancServer/OrthancInitialization.h"
--- a/UnitTestsSources/JpegLosslessTests.cpp	Fri Sep 04 16:30:42 2015 +0200
+++ b/UnitTestsSources/JpegLosslessTests.cpp	Fri Sep 04 16:36:18 2015 +0200
@@ -41,8 +41,8 @@
 
 #include "../OrthancServer/ParsedDicomFile.h"
 #include "../Core/OrthancException.h"
-#include "../Core/ImageFormats/ImageBuffer.h"
-#include "../Core/ImageFormats/PngWriter.h"
+#include "../Core/Images/ImageBuffer.h"
+#include "../Core/Images/PngWriter.h"
 
 using namespace Orthanc;