# HG changeset patch # User Sebastien Jodogne # Date 1448457272 -3600 # Node ID b530c3dfe2a6b97828b4b4e13f212f7f40fe4123 # Parent 0ef4e6e66b560880360e6e0eefe506602ce39a82 refactoring image decoding diff -r 0ef4e6e66b56 -r b530c3dfe2a6 NEWS --- a/NEWS Wed Nov 25 10:32:54 2015 +0100 +++ b/NEWS Wed Nov 25 14:14:32 2015 +0100 @@ -60,7 +60,7 @@ ----------- * Full indexation of the patient/study tags to speed up searches and C-Find -* Full refactoring of the searching features +* Many refactorings, notably of the searching features and of the image decoding * C-Move SCP for studies using AccessionNumber tag * Fix issue 4 (C-Store Association not renegotiated on Specific-to-specific transfer syntax change) * "--logdir" flag creates a single log file instead of 3 separate files for errors/warnings/infos diff -r 0ef4e6e66b56 -r b530c3dfe2a6 OrthancServer/IDicomImageDecoder.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/IDicomImageDecoder.h Wed Nov 25 14:14:32 2015 +0100 @@ -0,0 +1,54 @@ +/** + * 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 . + **/ + + +#pragma once + +#include "../Core/Images/ImageBuffer.h" + +#include + +namespace Orthanc +{ + class ParsedDicomFile; + + class IDicomImageDecoder : public boost::noncopyable + { + public: + virtual ~IDicomImageDecoder() + { + } + + virtual bool Decode(ImageBuffer& target, + ParsedDicomFile& dicom, + unsigned int frame) = 0; + }; +} diff -r 0ef4e6e66b56 -r b530c3dfe2a6 OrthancServer/Internals/DicomImageDecoder.cpp --- a/OrthancServer/Internals/DicomImageDecoder.cpp Wed Nov 25 10:32:54 2015 +0100 +++ b/OrthancServer/Internals/DicomImageDecoder.cpp Wed Nov 25 14:14:32 2015 +0100 @@ -87,6 +87,7 @@ #include "../../Core/DicomFormat/DicomIntegerPixelAccessor.h" #include "../ToDcmtkBridge.h" #include "../FromDcmtkBridge.h" +#include "../ParsedDicomFile.h" #include @@ -531,9 +532,11 @@ bool DicomImageDecoder::Decode(ImageBuffer& target, - DcmDataset& dataset, + ParsedDicomFile& dicom, unsigned int frame) { + DcmDataset& dataset = *dicom.GetDcmtkObject().getDataset(); + if (IsUncompressedImage(dataset)) { DecodeUncompressedImage(target, dataset, frame); @@ -588,20 +591,11 @@ } - bool DicomImageDecoder::DecodeAndTruncate(ImageBuffer& target, - DcmDataset& dataset, - unsigned int frame, - PixelFormat format, - bool allowColorConversion) + bool DicomImageDecoder::TruncateDecodedImage(ImageBuffer& target, + ImageBuffer& source, + PixelFormat format, + bool allowColorConversion) { - // TODO Special case for uncompressed images - - ImageBuffer source; - if (!Decode(source, dataset, frame)) - { - return false; - } - // If specified, prevent the conversion between color and // grayscale images bool isSourceColor = IsColorImage(source.GetFormat()); @@ -634,18 +628,9 @@ } - bool DicomImageDecoder::DecodePreview(ImageBuffer& target, - DcmDataset& dataset, - unsigned int frame) + bool DicomImageDecoder::PreviewDecodedImage(ImageBuffer& target, + ImageBuffer& source) { - // TODO Special case for uncompressed images - - ImageBuffer source; - if (!Decode(source, dataset, frame)) - { - return false; - } - switch (source.GetFormat()) { case PixelFormat_RGB24: diff -r 0ef4e6e66b56 -r b530c3dfe2a6 OrthancServer/Internals/DicomImageDecoder.h --- a/OrthancServer/Internals/DicomImageDecoder.h Wed Nov 25 10:32:54 2015 +0100 +++ b/OrthancServer/Internals/DicomImageDecoder.h Wed Nov 25 14:14:32 2015 +0100 @@ -34,11 +34,11 @@ #include -#include "../../Core/Images/ImageBuffer.h" +#include "../IDicomImageDecoder.h" namespace Orthanc { - class DicomImageDecoder + class DicomImageDecoder : public IDicomImageDecoder { private: class ImageSource; @@ -65,18 +65,16 @@ #endif public: - static bool Decode(ImageBuffer& target, - DcmDataset& dataset, - unsigned int frame); + virtual bool Decode(ImageBuffer& target, + ParsedDicomFile& dicom, + unsigned int frame); - static bool DecodeAndTruncate(ImageBuffer& target, - DcmDataset& dataset, - unsigned int frame, - PixelFormat format, - bool allowColorConversion); + static bool TruncateDecodedImage(ImageBuffer& target, + ImageBuffer& source, + PixelFormat format, + bool allowColorConversion); - static bool DecodePreview(ImageBuffer& target, - DcmDataset& dataset, - unsigned int frame); + static bool PreviewDecodedImage(ImageBuffer& target, + ImageBuffer& source); }; } diff -r 0ef4e6e66b56 -r b530c3dfe2a6 OrthancServer/OrthancRestApi/OrthancRestResources.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Wed Nov 25 10:32:54 2015 +0100 +++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Wed Nov 25 14:14:32 2015 +0100 @@ -39,6 +39,7 @@ #include "../FromDcmtkBridge.h" #include "../ServerContext.h" #include "../SliceOrdering.h" +#include "../Internals/DicomImageDecoder.h" namespace Orthanc @@ -265,6 +266,7 @@ class ImageToEncode { private: + IDicomImageDecoder& decoder_; std::string format_; std::string encoded_; ParsedDicomFile& dicom_; @@ -272,9 +274,11 @@ ImageExtractionMode mode_; public: - ImageToEncode(ParsedDicomFile& dicom, + ImageToEncode(IDicomImageDecoder& decoder, + ParsedDicomFile& dicom, unsigned int frame, ImageExtractionMode mode) : + decoder_(decoder), dicom_(dicom), frame_(frame), mode_(mode) @@ -310,6 +314,11 @@ { output.AnswerBuffer(encoded_, format_); } + + IDicomImageDecoder& GetDecoder() const + { + return decoder_; + } }; class EncodePng : public HttpContentNegociation::IHandler @@ -327,7 +336,8 @@ { assert(type == "image"); assert(subtype == "png"); - image_.GetDicom().ExtractPngImage(image_.GetTarget(), image_.GetFrame(), image_.GetMode()); + image_.GetDicom().ExtractPngImage(image_.GetTarget(), image_.GetDecoder(), + image_.GetFrame(), image_.GetMode()); image_.SetFormat("image/png"); } }; @@ -367,7 +377,8 @@ { assert(type == "image"); assert(subtype == "jpeg"); - image_.GetDicom().ExtractJpegImage(image_.GetTarget(), image_.GetFrame(), image_.GetMode(), quality_); + image_.GetDicom().ExtractJpegImage(image_.GetTarget(), image_.GetDecoder(), + image_.GetFrame(), image_.GetMode(), quality_); image_.SetFormat("image/jpeg"); } }; @@ -399,7 +410,8 @@ try { - ImageToEncode image(dicom, frame, mode); + DicomImageDecoder decoder; // TODO plugins + ImageToEncode image(decoder, dicom, frame, mode); HttpContentNegociation negociation; EncodePng png(image); negociation.Register("image/png", png); @@ -453,7 +465,8 @@ ParsedDicomFile dicom(dicomContent); ImageBuffer buffer; - dicom.ExtractImage(buffer, frame); + DicomImageDecoder decoder; // TODO plugin + dicom.ExtractImage(buffer, decoder, frame); ImageAccessor accessor(buffer.GetConstAccessor()); diff -r 0ef4e6e66b56 -r b530c3dfe2a6 OrthancServer/ParsedDicomFile.cpp --- a/OrthancServer/ParsedDicomFile.cpp Wed Nov 25 10:32:54 2015 +0100 +++ b/OrthancServer/ParsedDicomFile.cpp Wed Nov 25 14:14:32 2015 +0100 @@ -888,7 +888,7 @@ } - DcmFileFormat& ParsedDicomFile::GetDcmtkObject() + DcmFileFormat& ParsedDicomFile::GetDcmtkObject() const { return *pimpl_->file_.get(); } @@ -1049,11 +1049,10 @@ void ParsedDicomFile::ExtractImage(ImageBuffer& result, + IDicomImageDecoder& decoder, unsigned int frame) { - DcmDataset& dataset = *pimpl_->file_->getDataset(); - - if (!DicomImageDecoder::Decode(result, dataset, frame)) + if (!decoder.Decode(result, *this, frame)) { throw OrthancException(ErrorCode_BadFileFormat); } @@ -1061,29 +1060,34 @@ void ParsedDicomFile::ExtractImage(ImageBuffer& result, + IDicomImageDecoder& decoder, unsigned int frame, ImageExtractionMode mode) { - DcmDataset& dataset = *pimpl_->file_->getDataset(); + ImageBuffer source; + if (!decoder.Decode(source, *this, frame)) + { + throw OrthancException(ErrorCode_BadFileFormat); + } bool ok = false; switch (mode) { case ImageExtractionMode_UInt8: - ok = DicomImageDecoder::DecodeAndTruncate(result, dataset, frame, PixelFormat_Grayscale8, false); + ok = DicomImageDecoder::TruncateDecodedImage(result, source, PixelFormat_Grayscale8, false); break; case ImageExtractionMode_UInt16: - ok = DicomImageDecoder::DecodeAndTruncate(result, dataset, frame, PixelFormat_Grayscale16, false); + ok = DicomImageDecoder::TruncateDecodedImage(result, source, PixelFormat_Grayscale16, false); break; case ImageExtractionMode_Int16: - ok = DicomImageDecoder::DecodeAndTruncate(result, dataset, frame, PixelFormat_SignedGrayscale16, false); + ok = DicomImageDecoder::TruncateDecodedImage(result, source, PixelFormat_SignedGrayscale16, false); break; case ImageExtractionMode_Preview: - ok = DicomImageDecoder::DecodePreview(result, dataset, frame); + ok = DicomImageDecoder::PreviewDecodedImage(result, source); break; default: @@ -1092,17 +1096,18 @@ if (!ok) { - throw OrthancException(ErrorCode_BadFileFormat); + throw OrthancException(ErrorCode_NotImplemented); } } void ParsedDicomFile::ExtractPngImage(std::string& result, + IDicomImageDecoder& decoder, unsigned int frame, ImageExtractionMode mode) { ImageBuffer buffer; - ExtractImage(buffer, frame, mode); + ExtractImage(buffer, decoder, frame, mode); ImageAccessor accessor(buffer.GetConstAccessor()); PngWriter writer; @@ -1111,6 +1116,7 @@ void ParsedDicomFile::ExtractJpegImage(std::string& result, + IDicomImageDecoder& decoder, unsigned int frame, ImageExtractionMode mode, uint8_t quality) @@ -1122,7 +1128,7 @@ } ImageBuffer buffer; - ExtractImage(buffer, frame, mode); + ExtractImage(buffer, decoder, frame, mode); ImageAccessor accessor(buffer.GetConstAccessor()); JpegWriter writer; diff -r 0ef4e6e66b56 -r b530c3dfe2a6 OrthancServer/ParsedDicomFile.h --- a/OrthancServer/ParsedDicomFile.h Wed Nov 25 10:32:54 2015 +0100 +++ b/OrthancServer/ParsedDicomFile.h Wed Nov 25 14:14:32 2015 +0100 @@ -33,11 +33,10 @@ #pragma once #include "../Core/DicomFormat/DicomInstanceHasher.h" +#include "../Core/IDynamicObject.h" #include "../Core/RestApi/RestApiOutput.h" +#include "IDicomImageDecoder.h" #include "ServerEnumerations.h" -#include "../Core/Images/ImageAccessor.h" -#include "../Core/Images/ImageBuffer.h" -#include "../Core/IDynamicObject.h" class DcmDataset; class DcmFileFormat; @@ -77,7 +76,7 @@ ~ParsedDicomFile(); - DcmFileFormat& GetDcmtkObject(); + DcmFileFormat& GetDcmtkObject() const; ParsedDicomFile* Clone(); @@ -128,17 +127,21 @@ const std::string& content); void ExtractImage(ImageBuffer& result, + IDicomImageDecoder& decoder, unsigned int frame); void ExtractImage(ImageBuffer& result, + IDicomImageDecoder& decoder, unsigned int frame, ImageExtractionMode mode); void ExtractPngImage(std::string& result, + IDicomImageDecoder& decoder, unsigned int frame, ImageExtractionMode mode); void ExtractJpegImage(std::string& result, + IDicomImageDecoder& decoder, unsigned int frame, ImageExtractionMode mode, uint8_t quality);