# HG changeset patch # User Sebastien Jodogne # Date 1460749443 -7200 # Node ID e8cfda4c8a2f9e92da3f4c7515fefdece8fc3403 # Parent 5754d39b011d4feaff7fbb745efa439bfc3f50bb Sync + support of JPEG2000 lossless images with YBR_RCT photometric interpretation diff -r 5754d39b011d -r e8cfda4c8a2f NEWS --- a/NEWS Fri Mar 25 17:38:34 2016 +0100 +++ b/NEWS Fri Apr 15 21:44:03 2016 +0200 @@ -3,6 +3,7 @@ * Option "EnableGdcm" to replace the built-in decoder of Orthanc with GDCM * Fixed rendering of 16bpp images if values are < 0 or >= 32768 +* Decoding of JPEG2000 lossless images with YBR_RCT photometric interpretation Version 2.0 (2015-12-10) diff -r 5754d39b011d -r e8cfda4c8a2f Orthanc/Core/ChunkedBuffer.cpp --- a/Orthanc/Core/ChunkedBuffer.cpp Fri Mar 25 17:38:34 2016 +0100 +++ b/Orthanc/Core/ChunkedBuffer.cpp Fri Apr 15 21:44:03 2016 +0200 @@ -95,5 +95,6 @@ } chunks_.clear(); + numBytes_ = 0; } } diff -r 5754d39b011d -r e8cfda4c8a2f Orthanc/Core/Enumerations.cpp --- a/Orthanc/Core/Enumerations.cpp Fri Mar 25 17:38:34 2016 +0100 +++ b/Orthanc/Core/Enumerations.cpp Fri Apr 15 21:44:03 2016 +0200 @@ -212,10 +212,10 @@ return "The specified path does not point to a directory"; case ErrorCode_HttpPortInUse: - return "The TCP port of the HTTP server is already in use"; + return "The TCP port of the HTTP server is privileged or already in use"; case ErrorCode_DicomPortInUse: - return "The TCP port of the DICOM server is already in use"; + return "The TCP port of the DICOM server is privileged or already in use"; case ErrorCode_BadHttpStatusInRest: return "This HTTP status is not allowed in a REST API"; @@ -718,6 +718,31 @@ } + const char* EnumerationToString(PixelFormat format) + { + switch (format) + { + case PixelFormat_RGB24: + return "RGB24"; + + case PixelFormat_RGBA32: + return "RGBA32"; + + case PixelFormat_Grayscale8: + return "Grayscale (unsigned 8bpp)"; + + case PixelFormat_Grayscale16: + return "Grayscale (unsigned 16bpp)"; + + case PixelFormat_SignedGrayscale16: + return "Grayscale (signed 16bpp)"; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + Encoding StringToEncoding(const char* encoding) { std::string s(encoding); diff -r 5754d39b011d -r e8cfda4c8a2f Orthanc/Core/Enumerations.h --- a/Orthanc/Core/Enumerations.h Fri Mar 25 17:38:34 2016 +0100 +++ b/Orthanc/Core/Enumerations.h Fri Apr 15 21:44:03 2016 +0200 @@ -100,8 +100,8 @@ ErrorCode_DirectoryOverFile = 2000 /*!< The directory to be created is already occupied by a regular file */, ErrorCode_FileStorageCannotWrite = 2001 /*!< Unable to create a subdirectory or a file in the file storage */, ErrorCode_DirectoryExpected = 2002 /*!< The specified path does not point to a directory */, - ErrorCode_HttpPortInUse = 2003 /*!< The TCP port of the HTTP server is already in use */, - ErrorCode_DicomPortInUse = 2004 /*!< The TCP port of the DICOM server is already in use */, + ErrorCode_HttpPortInUse = 2003 /*!< The TCP port of the HTTP server is privileged or already in use */, + ErrorCode_DicomPortInUse = 2004 /*!< The TCP port of the DICOM server is privileged or already in use */, ErrorCode_BadHttpStatusInRest = 2005 /*!< This HTTP status is not allowed in a REST API */, ErrorCode_RegularFileExpected = 2006 /*!< The specified path does not point to a regular file */, ErrorCode_PathToExecutable = 2007 /*!< Unable to get the path to the executable */, @@ -444,6 +444,8 @@ const char* EnumerationToString(RequestOrigin origin); + const char* EnumerationToString(PixelFormat format); + Encoding StringToEncoding(const char* encoding); ResourceType StringToResourceType(const char* type); diff -r 5754d39b011d -r e8cfda4c8a2f Orthanc/Core/Images/ImageAccessor.cpp --- a/Orthanc/Core/Images/ImageAccessor.cpp Fri Mar 25 17:38:34 2016 +0100 +++ b/Orthanc/Core/Images/ImageAccessor.cpp Fri Apr 15 21:44:03 2016 +0200 @@ -121,7 +121,7 @@ { if (buffer_ != NULL) { - return reinterpret_cast(buffer_) + y * pitch_; + return buffer_ + y * pitch_; } else { @@ -143,7 +143,7 @@ if (buffer_ != NULL) { - return reinterpret_cast(buffer_) + y * pitch_; + return buffer_ + y * pitch_; } else { @@ -174,9 +174,12 @@ width_ = width; height_ = height; pitch_ = pitch; - buffer_ = const_cast(buffer); + buffer_ = reinterpret_cast(const_cast(buffer)); - assert(GetBytesPerPixel() * width_ <= pitch_); + if (GetBytesPerPixel() * width_ > pitch_) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } } @@ -191,9 +194,12 @@ width_ = width; height_ = height; pitch_ = pitch; - buffer_ = buffer; + buffer_ = reinterpret_cast(buffer); - assert(GetBytesPerPixel() * width_ <= pitch_); + if (GetBytesPerPixel() * width_ > pitch_) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } } @@ -226,4 +232,43 @@ buffer.Flatten(target); } + + + ImageAccessor ImageAccessor::GetRegion(unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height) const + { + if (x + width > width_ || + y + height > height_) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + ImageAccessor result; + + if (width == 0 || + height == 0) + { + result.AssignWritable(format_, 0, 0, 0, NULL); + } + else + { + uint8_t* p = (buffer_ + + y * pitch_ + + x * GetBytesPerPixel()); + + if (readOnly_) + { + result.AssignReadOnly(format_, width, height, pitch_, p); + } + else + { + result.AssignWritable(format_, width, height, pitch_, p); + } + } + + return result; + } + } diff -r 5754d39b011d -r e8cfda4c8a2f Orthanc/Core/Images/ImageAccessor.h --- a/Orthanc/Core/Images/ImageAccessor.h Fri Mar 25 17:38:34 2016 +0100 +++ b/Orthanc/Core/Images/ImageAccessor.h Fri Apr 15 21:44:03 2016 +0200 @@ -35,6 +35,7 @@ #include "../Enumerations.h" #include +#include namespace Orthanc { @@ -46,7 +47,7 @@ unsigned int width_; unsigned int height_; unsigned int pitch_; - void *buffer_; + uint8_t *buffer_; public: ImageAccessor() @@ -119,5 +120,10 @@ void *buffer); void ToMatlabString(std::string& target) const; + + ImageAccessor GetRegion(unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height) const; }; } diff -r 5754d39b011d -r e8cfda4c8a2f Orthanc/Core/SQLite/Connection.cpp --- a/Orthanc/Core/SQLite/Connection.cpp Fri Mar 25 17:38:34 2016 +0100 +++ b/Orthanc/Core/SQLite/Connection.cpp Fri Apr 15 21:44:03 2016 +0200 @@ -163,7 +163,8 @@ if (error == SQLITE_ERROR) { #if ORTHANC_SQLITE_STANDALONE != 1 - LOG(ERROR) << "SQLite execute error: " << sqlite3_errmsg(db_); + LOG(ERROR) << "SQLite execute error: " << sqlite3_errmsg(db_) + << " (" << sqlite3_extended_errcode(db_) << ")"; #endif throw OrthancSQLiteException(ErrorCode_SQLiteExecute); diff -r 5754d39b011d -r e8cfda4c8a2f Orthanc/Core/SQLite/StatementReference.cpp --- a/Orthanc/Core/SQLite/StatementReference.cpp Fri Mar 25 17:38:34 2016 +0100 +++ b/Orthanc/Core/SQLite/StatementReference.cpp Fri Apr 15 21:44:03 2016 +0200 @@ -82,7 +82,8 @@ if (error != SQLITE_OK) { #if ORTHANC_SQLITE_STANDALONE != 1 - LOG(ERROR) << "SQLite: " << sqlite3_errmsg(database); + LOG(ERROR) << "SQLite: " << sqlite3_errmsg(database) + << " (" << sqlite3_extended_errcode(database) << ")"; #endif throw OrthancSQLiteException(ErrorCode_SQLitePrepareStatement); diff -r 5754d39b011d -r e8cfda4c8a2f Orthanc/Core/Toolbox.cpp --- a/Orthanc/Core/Toolbox.cpp Fri Mar 25 17:38:34 2016 +0100 +++ b/Orthanc/Core/Toolbox.cpp Fri Apr 15 21:44:03 2016 +0200 @@ -67,7 +67,7 @@ #include /* PATH_MAX */ #endif -#if defined(__linux) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) #include /* PATH_MAX */ #include #include @@ -132,7 +132,7 @@ { #if defined(_WIN32) ::Sleep(static_cast(microSeconds / static_cast(1000))); -#elif defined(__linux) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) +#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) usleep(microSeconds); #else #error Support your platform here @@ -206,6 +206,17 @@ } + static std::streamsize GetStreamSize(std::istream& f) + { + // http://www.cplusplus.com/reference/iostream/istream/tellg/ + f.seekg(0, std::ios::end); + std::streamsize size = f.tellg(); + f.seekg(0, std::ios::beg); + + return size; + } + + void Toolbox::ReadFile(std::string& content, const std::string& path) { @@ -222,11 +233,7 @@ throw OrthancException(ErrorCode_InexistentFile); } - // http://www.cplusplus.com/reference/iostream/istream/tellg/ - f.seekg(0, std::ios::end); - std::streamsize size = f.tellg(); - f.seekg(0, std::ios::beg); - + std::streamsize size = GetStreamSize(f); content.resize(size); if (size != 0) { @@ -237,6 +244,51 @@ } + bool Toolbox::ReadHeader(std::string& header, + const std::string& path, + size_t headerSize) + { + if (!IsRegularFile(path)) + { + LOG(ERROR) << std::string("The path does not point to a regular file: ") << path; + throw OrthancException(ErrorCode_RegularFileExpected); + } + + boost::filesystem::ifstream f; + f.open(path, std::ifstream::in | std::ifstream::binary); + if (!f.good()) + { + throw OrthancException(ErrorCode_InexistentFile); + } + + bool full = true; + + { + std::streamsize size = GetStreamSize(f); + if (size <= 0) + { + headerSize = 0; + full = false; + } + else if (static_cast(size) < headerSize) + { + headerSize = size; // Truncate to the size of the file + full = false; + } + } + + header.resize(headerSize); + if (headerSize != 0) + { + f.read(reinterpret_cast(&header[0]), headerSize); + } + + f.close(); + + return full; + } + + void Toolbox::WriteFile(const void* content, size_t size, const std::string& path) @@ -577,7 +629,7 @@ return std::string(&buffer[0]); } -#elif defined(__linux) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) +#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) static std::string GetPathToExecutableInternal() { std::vector buffer(PATH_MAX + 1); diff -r 5754d39b011d -r e8cfda4c8a2f Orthanc/Core/Toolbox.h --- a/Orthanc/Core/Toolbox.h Fri Mar 25 17:38:34 2016 +0100 +++ b/Orthanc/Core/Toolbox.h Fri Apr 15 21:44:03 2016 +0200 @@ -66,6 +66,10 @@ void ReadFile(std::string& content, const std::string& path); + bool ReadHeader(std::string& header, + const std::string& path, + size_t headerSize); + void WriteFile(const std::string& content, const std::string& path); diff -r 5754d39b011d -r e8cfda4c8a2f Orthanc/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp --- a/Orthanc/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp Fri Mar 25 17:38:34 2016 +0100 +++ b/Orthanc/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp Fri Apr 15 21:44:03 2016 +0200 @@ -112,7 +112,9 @@ else { if (image.GetPixelFormat().GetSamplesPerPixel() == 3 && - image.GetPhotometricInterpretation() != gdcm::PhotometricInterpretation::RGB) + image.GetPhotometricInterpretation() != gdcm::PhotometricInterpretation::RGB && + (image.GetTransferSyntax() != gdcm::TransferSyntax::JPEG2000Lossless || + image.GetPhotometricInterpretation() != gdcm::PhotometricInterpretation::YBR_RCT)) { photometric_.reset(new gdcm::ImageChangePhotometricInterpretation()); photometric_->SetInput(image); @@ -188,7 +190,8 @@ } } else if (image.GetPixelFormat().GetSamplesPerPixel() == 3 && - image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::RGB) + (image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::RGB || + image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::YBR_RCT)) { switch (image.GetPixelFormat()) { diff -r 5754d39b011d -r e8cfda4c8a2f Orthanc/Resources/CMake/BoostConfiguration.cmake --- a/Orthanc/Resources/CMake/BoostConfiguration.cmake Fri Mar 25 17:38:34 2016 +0100 +++ b/Orthanc/Resources/CMake/BoostConfiguration.cmake Fri Apr 15 21:44:03 2016 +0200 @@ -8,7 +8,7 @@ #set(Boost_USE_STATIC_LIBS ON) find_package(Boost - COMPONENTS filesystem thread system date_time regex locale) + COMPONENTS filesystem thread system date_time regex locale ${ORTHANC_BOOST_COMPONENTS}) if (NOT Boost_FOUND) message(FATAL_ERROR "Unable to locate Boost on this system") @@ -39,10 +39,10 @@ if (BOOST_STATIC) - # Parameters for Boost 1.59.0 - set(BOOST_NAME boost_1_59_0) - set(BOOST_BCP_SUFFIX bcpdigest-0.9.5) - set(BOOST_MD5 "08abb7cdbea0b380f9ab0d5cce476f12") + # Parameters for Boost 1.60.0 + set(BOOST_NAME boost_1_60_0) + set(BOOST_BCP_SUFFIX bcpdigest-1.0.1) + set(BOOST_MD5 "0646971514a1e012fbe382c5662a8605") set(BOOST_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz") set(BOOST_FILESYSTEM_SOURCES_DIR "${BOOST_NAME}/libs/filesystem/src") set(BOOST_SOURCES_DIR ${CMAKE_BINARY_DIR}/${BOOST_NAME}) diff -r 5754d39b011d -r e8cfda4c8a2f Orthanc/Resources/CMake/Compiler.cmake --- a/Orthanc/Resources/CMake/Compiler.cmake Fri Mar 25 17:38:34 2016 +0100 +++ b/Orthanc/Resources/CMake/Compiler.cmake Fri Apr 15 21:44:03 2016 +0200 @@ -10,7 +10,7 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-long-long -Wno-implicit-function-declaration") # --std=c99 makes libcurl not to compile # -pedantic gives a lot of warnings on OpenSSL - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Wno-long-long -Wno-variadic-macros") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -Wno-variadic-macros") if (CMAKE_CROSSCOMPILING) # http://stackoverflow.com/a/3543845/881731 @@ -73,6 +73,11 @@ link_libraries(dl) endif() + CHECK_INCLUDE_FILES(uuid/uuid.h HAVE_UUID_H) + if (NOT HAVE_UUID_H) + message(FATAL_ERROR "Please install the uuid-dev package") + endif() + elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") if (MSVC) message("MSVC compiler version = " ${MSVC_VERSION} "\n") @@ -97,6 +102,11 @@ link_libraries(rpcrt4 ws2_32) if (CMAKE_COMPILER_IS_GNUCXX) + # Some additional C/C++ compiler flags for MinGW + SET(MINGW_NO_WARNINGS "-Wno-unused-function -Wno-unused-variable") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MINGW_NO_WARNINGS} -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MINGW_NO_WARNINGS}") + # This is a patch for MinGW64 SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--allow-multiple-definition -static-libgcc -static-libstdc++") SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--allow-multiple-definition -static-libgcc -static-libstdc++") @@ -120,6 +130,11 @@ ) link_libraries(iconv) + CHECK_INCLUDE_FILES(uuid/uuid.h HAVE_UUID_H) + if (NOT HAVE_UUID_H) + message(FATAL_ERROR "Please install the uuid-dev package") + endif() + endif() @@ -139,17 +154,6 @@ endif() -if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - CHECK_INCLUDE_FILES(rpc.h HAVE_UUID_H) -else() - CHECK_INCLUDE_FILES(uuid/uuid.h HAVE_UUID_H) -endif() - -if (NOT HAVE_UUID_H) - message(FATAL_ERROR "Please install the uuid-dev package") -endif() - - if (STATIC_BUILD) add_definitions(-DORTHANC_STATIC=1) else() diff -r 5754d39b011d -r e8cfda4c8a2f Orthanc/Resources/CMake/JsonCppConfiguration.cmake --- a/Orthanc/Resources/CMake/JsonCppConfiguration.cmake Fri Mar 25 17:38:34 2016 +0100 +++ b/Orthanc/Resources/CMake/JsonCppConfiguration.cmake Fri Apr 15 21:44:03 2016 +0200 @@ -32,4 +32,29 @@ message(FATAL_ERROR "Please install the libjsoncpp-dev package") endif() + # Switch to the C++11 standard if the version of JsonCpp is 1.y.z + if (EXISTS ${JSONCPP_INCLUDE_DIR}/json/version.h) + file(STRINGS + "${JSONCPP_INCLUDE_DIR}/json/version.h" + JSONCPP_VERSION_MAJOR1 REGEX + ".*define JSONCPP_VERSION_MAJOR.*") + + if (NOT JSONCPP_VERSION_MAJOR1) + message(FATAL_ERROR "Unable to extract the major version of JsonCpp") + endif() + + string(REGEX REPLACE + ".*JSONCPP_VERSION_MAJOR.*([0-9]+)$" "\\1" + JSONCPP_VERSION_MAJOR ${JSONCPP_VERSION_MAJOR1}) + message("JsonCpp major version: ${JSONCPP_VERSION_MAJOR}") + + if (CMAKE_COMPILER_IS_GNUCXX AND + JSONCPP_VERSION_MAJOR GREATER 0) + message("Switching to C++11 standard, as version of JsonCpp is >= 1.0.0") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-deprecated-declarations") + endif() + else() + message("Unable to detect the major version of JsonCpp, assuming < 1.0.0") + endif() + endif()