Skip to content
Commits on Source (8)
repo: 02f7a0400a911dee22d2e761b21b6cab67ede076
node: daab267593577f078bc63d5b6ab62eb89286b6d2
branch: OrthancWebViewer-2.3
node: 21df474deeb16a56724c0bb3758e56f95e3eff9c
branch: OrthancWebViewer-2.4
latesttag: null
latesttagdistance: 161
changessincelatesttag: 165
latesttagdistance: 196
changessincelatesttag: 200
......@@ -14,7 +14,7 @@ Authors
4000 Liege
Belgium
* Osimis <info@osimis.io>
* Osimis S.A. <info@osimis.io>
Rue des Chasseurs Ardennais 3
4031 Liege
Belgium
# Orthanc - A Lightweight, RESTful DICOM Store
# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
# Department, University Hospital of Liege, Belgium
# Copyright (C) 2017 Osimis, Belgium
# Copyright (C) 2017-2018 Osimis S.A., Belgium
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU Affero General Public License
......@@ -21,39 +21,43 @@ cmake_minimum_required(VERSION 2.8)
project(OrthancWebViewer)
set(ORTHANC_WEBVIEWER_VERSION "2.3")
set(ORTHANC_WEBVIEWER_VERSION "2.4")
if (ORTHANC_WEBVIEWER_VERSION STREQUAL "mainline")
set(ORTHANC_FRAMEWORK_VERSION "mainline")
set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
else()
set(ORTHANC_FRAMEWORK_VERSION "1.3.2")
set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
endif()
# Parameters of the build
set(STATIC_BUILD OFF CACHE BOOL "Static build of the third-party libraries (necessary for Windows)")
SET(STANDALONE_BUILD ON CACHE BOOL "Standalone build (all the resources are embedded, necessary for releases)")
set(STANDALONE_BUILD ON CACHE BOOL "Standalone build (all the resources are embedded, necessary for releases)")
set(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages")
set(ORTHANC_FRAMEWORK_SOURCE "${ORTHANC_FRAMEWORK_DEFAULT_SOURCE}" CACHE STRING "Source of the Orthanc source code (can be \"hg\", \"archive\", \"web\" or \"path\")")
set(ORTHANC_FRAMEWORK_ARCHIVE "" CACHE STRING "Path to the Orthanc archive, if ORTHANC_FRAMEWORK_SOURCE is \"archive\"")
set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory, if ORTHANC_FRAMEWORK_SOURCE is \"path\"")
# Advanced parameters to fine-tune linking against system libraries
set(USE_SYSTEM_BOOST ON CACHE BOOL "Use the system version of Boost")
set(USE_SYSTEM_GDCM ON CACHE BOOL "Use the system version of Grassroot DICOM (GDCM)")
set(USE_SYSTEM_GOOGLE_TEST ON CACHE BOOL "Use the system version of Google Test")
set(USE_SYSTEM_JSONCPP ON CACHE BOOL "Use the system version of JsonCpp")
set(USE_SYSTEM_SQLITE ON CACHE BOOL "Use the system version of SQLite")
set(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK")
# Distribution-specific settings
set(USE_GTEST_DEBIAN_SOURCE_PACKAGE OFF CACHE BOOL "Use the sources of Google Test shipped with libgtest-dev (Debian only)")
mark_as_advanced(USE_GTEST_DEBIAN_SOURCE_PACKAGE)
set(ORTHANC_ROOT ${CMAKE_SOURCE_DIR}/Orthanc)
set(ORTHANC_DISABLE_PATCH ON) # No need for the "patch" command-line tool
include(CheckIncludeFiles)
include(CheckIncludeFileCXX)
include(CheckLibraryExists)
include(FindPythonInterp)
include(${CMAKE_SOURCE_DIR}/Orthanc/Resources/CMake/Compiler.cmake)
include(${CMAKE_SOURCE_DIR}/Orthanc/Resources/CMake/AutoGeneratedCode.cmake)
include(${CMAKE_SOURCE_DIR}/Orthanc/Resources/CMake/DownloadPackage.cmake)
include(${CMAKE_SOURCE_DIR}/Orthanc/Resources/CMake/BoostConfiguration.cmake)
include(${CMAKE_SOURCE_DIR}/Orthanc/Resources/CMake/GoogleTestConfiguration.cmake)
include(${CMAKE_SOURCE_DIR}/Orthanc/Resources/CMake/JsonCppConfiguration.cmake)
include(${CMAKE_SOURCE_DIR}/Orthanc/Resources/CMake/SQLiteConfiguration.cmake)
# Download and setup the Orthanc framework
include(${CMAKE_SOURCE_DIR}/Resources/Orthanc/DownloadOrthancFramework.cmake)
set(ORTHANC_FRAMEWORK_PLUGIN ON)
include(${ORTHANC_ROOT}/Resources/CMake/OrthancFrameworkParameters.cmake)
set(ENABLE_LOCALE OFF) # Disable support for locales (notably in Boost)
set(ENABLE_GOOGLE_TEST ON)
set(ENABLE_SQLITE ON)
include(${ORTHANC_ROOT}/Resources/CMake/OrthancFrameworkConfiguration.cmake)
include_directories(${ORTHANC_ROOT})
include(${CMAKE_SOURCE_DIR}/Resources/CMake/GdcmConfiguration.cmake)
include(${CMAKE_SOURCE_DIR}/Resources/CMake/JavaScriptLibraries.cmake)
......@@ -61,7 +65,7 @@ include(${CMAKE_SOURCE_DIR}/Resources/CMake/JavaScriptLibraries.cmake)
# Check that the Orthanc SDK headers are available
if (STATIC_BUILD OR NOT USE_SYSTEM_ORTHANC_SDK)
include_directories(${ORTHANC_ROOT}/Sdk-0.9.5)
include_directories(${CMAKE_SOURCE_DIR}/Resources/Orthanc/Sdk-0.9.5)
else ()
CHECK_INCLUDE_FILE_CXX(orthanc/OrthancCPlugin.h HAVE_ORTHANC_H)
if (NOT HAVE_ORTHANC_H)
......@@ -90,12 +94,6 @@ EmbedResources(
${EMBEDDED_RESOURCES}
)
add_definitions(
-DORTHANC_ENABLE_PUGIXML=0
-DORTHANC_SQLITE_STANDALONE=1
)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR
${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
......@@ -123,44 +121,15 @@ if (APPLE)
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -framework CoreFoundation")
endif()
add_definitions(
-DORTHANC_ENABLE_MD5=0
-DORTHANC_ENABLE_BASE64=0
-DORTHANC_ENABLE_LOGGING=0
-DORTHANC_SANDBOXED=0
)
set(CORE_SOURCES
${BOOST_SOURCES}
${SQLITE_SOURCES}
${JSONCPP_SOURCES}
# Sources inherited from Orthanc core
${CMAKE_SOURCE_DIR}/Orthanc/Core/ChunkedBuffer.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/Enumerations.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/FileStorage/FilesystemStorage.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/Images/ImageAccessor.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/Images/ImageBuffer.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/Images/ImageProcessing.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/MultiThreading/SharedMessageQueue.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/SQLite/Connection.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/SQLite/FunctionContext.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/SQLite/Statement.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/SQLite/StatementId.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/SQLite/StatementReference.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/SQLite/Transaction.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/SystemToolbox.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/Toolbox.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/DicomFormat/DicomMap.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/DicomFormat/DicomTag.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Core/DicomFormat/DicomValue.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Resources/ThirdParty/base64/base64.cpp
${CMAKE_SOURCE_DIR}/Plugin/Cache/CacheManager.cpp
${CMAKE_SOURCE_DIR}/Plugin/Cache/CacheScheduler.cpp
${CMAKE_SOURCE_DIR}/Plugin/ViewerToolbox.cpp
${CMAKE_SOURCE_DIR}/Plugin/ViewerPrefetchPolicy.cpp
${CMAKE_SOURCE_DIR}/Plugin/SeriesInformationAdapter.cpp
${ORTHANC_CORE_SOURCES}
)
add_library(OrthancWebViewer
......@@ -171,9 +140,9 @@ add_library(OrthancWebViewer
# The following files depend on GDCM
${CMAKE_SOURCE_DIR}/Plugin/DecodedImageAdapter.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Plugins/Samples/GdcmDecoder/GdcmDecoderCache.cpp
${CMAKE_SOURCE_DIR}/Orthanc/Plugins/Samples/GdcmDecoder/OrthancImageWrapper.cpp
${ORTHANC_ROOT}/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp
${ORTHANC_ROOT}/Plugins/Samples/GdcmDecoder/GdcmDecoderCache.cpp
${ORTHANC_ROOT}/Plugins/Samples/GdcmDecoder/OrthancImageWrapper.cpp
)
......@@ -199,7 +168,8 @@ install(
add_executable(UnitTests
${CORE_SOURCES}
${GTEST_SOURCES}
${JSONCPP_SOURCES}
${GOOGLE_TEST_SOURCES}
UnitTestsSources/UnitTestsMain.cpp
)
target_link_libraries(UnitTests ${GOOGLE_TEST_LIBRARIES})
......@@ -2,6 +2,19 @@ Pending changes in the mainline
===============================
Version 2.4 (2018-04-23)
========================
* Disable pinch zoom on mobile devices
* Fix download of DICOM instance from the toolbox
* Fix for Osimis issue WVB-319: Some images are not loading in US_MF
* Support of rendering RGB48 lookup tables (palette), if Orthanc SDK >= 1.3.1
* Support of OpenBSD
* Support of Linux Standard Base
* Resort to Orthanc framework
* Upgrade to GDCM 2.8.4 for static builds
Version 2.3 (2017-07-19)
========================
......
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017 Osimis, 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 "ChunkedBuffer.h"
#include <cassert>
#include <string.h>
namespace Orthanc
{
void ChunkedBuffer::Clear()
{
numBytes_ = 0;
for (Chunks::iterator it = chunks_.begin();
it != chunks_.end(); ++it)
{
delete *it;
}
}
void ChunkedBuffer::AddChunk(const void* chunkData,
size_t chunkSize)
{
if (chunkSize == 0)
{
return;
}
else
{
assert(chunkData != NULL);
chunks_.push_back(new std::string(reinterpret_cast<const char*>(chunkData), chunkSize));
numBytes_ += chunkSize;
}
}
void ChunkedBuffer::AddChunk(const std::string& chunk)
{
if (chunk.size() > 0)
{
AddChunk(&chunk[0], chunk.size());
}
}
void ChunkedBuffer::Flatten(std::string& result)
{
result.resize(numBytes_);
size_t pos = 0;
for (Chunks::iterator it = chunks_.begin();
it != chunks_.end(); ++it)
{
assert(*it != NULL);
size_t s = (*it)->size();
if (s != 0)
{
memcpy(&result[pos], (*it)->c_str(), s);
pos += s;
}
delete *it;
}
chunks_.clear();
numBytes_ = 0;
}
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017 Osimis, 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 <list>
#include <string>
namespace Orthanc
{
class ChunkedBuffer
{
private:
typedef std::list<std::string*> Chunks;
size_t numBytes_;
Chunks chunks_;
void Clear();
public:
ChunkedBuffer() : numBytes_(0)
{
}
~ChunkedBuffer()
{
Clear();
}
size_t GetNumBytes() const
{
return numBytes_;
}
void AddChunk(const void* chunkData,
size_t chunkSize);
void AddChunk(const std::string& chunk);
void Flatten(std::string& result);
};
}
This diff is collapsed.
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017 Osimis, 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 "DicomTag.h"
#include "DicomValue.h"
#include "../Enumerations.h"
#include <set>
#include <map>
#include <json/json.h>
namespace Orthanc
{
class DicomMap : public boost::noncopyable
{
private:
friend class DicomArray;
friend class FromDcmtkBridge;
friend class ParsedDicomFile;
typedef std::map<DicomTag, DicomValue*> Map;
Map map_;
// Warning: This takes the ownership of "value"
void SetValue(uint16_t group,
uint16_t element,
DicomValue* value);
void SetValue(DicomTag tag,
DicomValue* value);
void ExtractTags(DicomMap& source,
const DicomTag* tags,
size_t count) const;
static void GetMainDicomTagsInternal(std::set<DicomTag>& result, ResourceType level);
public:
DicomMap()
{
}
~DicomMap()
{
Clear();
}
size_t GetSize() const
{
return map_.size();
}
DicomMap* Clone() const;
void Assign(const DicomMap& other);
void Clear();
void SetValue(uint16_t group,
uint16_t element,
const DicomValue& value)
{
SetValue(group, element, value.Clone());
}
void SetValue(const DicomTag& tag,
const DicomValue& value)
{
SetValue(tag, value.Clone());
}
void SetValue(const DicomTag& tag,
const std::string& str,
bool isBinary)
{
SetValue(tag, new DicomValue(str, isBinary));
}
void SetValue(uint16_t group,
uint16_t element,
const std::string& str,
bool isBinary)
{
SetValue(group, element, new DicomValue(str, isBinary));
}
bool HasTag(uint16_t group, uint16_t element) const
{
return HasTag(DicomTag(group, element));
}
bool HasTag(const DicomTag& tag) const
{
return map_.find(tag) != map_.end();
}
const DicomValue& GetValue(uint16_t group, uint16_t element) const
{
return GetValue(DicomTag(group, element));
}
const DicomValue& GetValue(const DicomTag& tag) const;
// DO NOT delete the returned value!
const DicomValue* TestAndGetValue(uint16_t group, uint16_t element) const
{
return TestAndGetValue(DicomTag(group, element));
}
// DO NOT delete the returned value!
const DicomValue* TestAndGetValue(const DicomTag& tag) const;
void Remove(const DicomTag& tag);
void ExtractPatientInformation(DicomMap& result) const;
void ExtractStudyInformation(DicomMap& result) const;
void ExtractSeriesInformation(DicomMap& result) const;
void ExtractInstanceInformation(DicomMap& result) const;
static void SetupFindPatientTemplate(DicomMap& result);
static void SetupFindStudyTemplate(DicomMap& result);
static void SetupFindSeriesTemplate(DicomMap& result);
static void SetupFindInstanceTemplate(DicomMap& result);
void CopyTagIfExists(const DicomMap& source,
const DicomTag& tag);
static bool IsMainDicomTag(const DicomTag& tag, ResourceType level);
static bool IsMainDicomTag(const DicomTag& tag);
static void GetMainDicomTags(std::set<DicomTag>& result, ResourceType level);
static void GetMainDicomTags(std::set<DicomTag>& result);
void GetTags(std::set<DicomTag>& tags) const;
static void LoadMainDicomTags(const DicomTag*& tags,
size_t& size,
ResourceType level);
static bool ParseDicomMetaInformation(DicomMap& result,
const char* dicom,
size_t size);
};
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017 Osimis, 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 "DicomTag.h"
#include "../OrthancException.h"
#include <iostream>
#include <iomanip>
#include <stdio.h>
namespace Orthanc
{
bool DicomTag::operator< (const DicomTag& other) const
{
if (group_ < other.group_)
return true;
if (group_ > other.group_)
return false;
return element_ < other.element_;
}
std::ostream& operator<< (std::ostream& o, const DicomTag& tag)
{
using namespace std;
ios_base::fmtflags state = o.flags();
o.flags(ios::right | ios::hex);
o << "(" << setfill('0') << setw(4) << tag.GetGroup()
<< "," << setw(4) << tag.GetElement() << ")";
o.flags(state);
return o;
}
std::string DicomTag::Format() const
{
char b[16];
sprintf(b, "%04x,%04x", group_, element_);
return std::string(b);
}
const char* DicomTag::GetMainTagsName() const
{
if (*this == DICOM_TAG_ACCESSION_NUMBER)
return "AccessionNumber";
if (*this == DICOM_TAG_SOP_INSTANCE_UID)
return "SOPInstanceUID";
if (*this == DICOM_TAG_PATIENT_ID)
return "PatientID";
if (*this == DICOM_TAG_SERIES_INSTANCE_UID)
return "SeriesInstanceUID";
if (*this == DICOM_TAG_STUDY_INSTANCE_UID)
return "StudyInstanceUID";
if (*this == DICOM_TAG_PIXEL_DATA)
return "PixelData";
if (*this == DICOM_TAG_IMAGE_INDEX)
return "ImageIndex";
if (*this == DICOM_TAG_INSTANCE_NUMBER)
return "InstanceNumber";
if (*this == DICOM_TAG_NUMBER_OF_SLICES)
return "NumberOfSlices";
if (*this == DICOM_TAG_NUMBER_OF_FRAMES)
return "NumberOfFrames";
if (*this == DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES)
return "CardiacNumberOfImages";
if (*this == DICOM_TAG_IMAGES_IN_ACQUISITION)
return "ImagesInAcquisition";
if (*this == DICOM_TAG_PATIENT_NAME)
return "PatientName";
if (*this == DICOM_TAG_IMAGE_POSITION_PATIENT)
return "ImagePositionPatient";
if (*this == DICOM_TAG_IMAGE_ORIENTATION_PATIENT)
return "ImageOrientationPatient";
return "";
}
void DicomTag::AddTagsForModule(std::set<DicomTag>& target,
DicomModule module)
{
// REFERENCE: 11_03pu.pdf, DICOM PS 3.3 2011 - Information Object Definitions
switch (module)
{
case DicomModule_Patient:
// This is Table C.7-1 "Patient Module Attributes" (p. 373)
target.insert(DicomTag(0x0010, 0x0010)); // Patient's name
target.insert(DicomTag(0x0010, 0x0020)); // Patient ID
target.insert(DicomTag(0x0010, 0x0030)); // Patient's birth date
target.insert(DicomTag(0x0010, 0x0040)); // Patient's sex
target.insert(DicomTag(0x0008, 0x1120)); // Referenced patient sequence
target.insert(DicomTag(0x0010, 0x0032)); // Patient's birth time
target.insert(DicomTag(0x0010, 0x1000)); // Other patient IDs
target.insert(DicomTag(0x0010, 0x1002)); // Other patient IDs sequence
target.insert(DicomTag(0x0010, 0x1001)); // Other patient names
target.insert(DicomTag(0x0010, 0x2160)); // Ethnic group
target.insert(DicomTag(0x0010, 0x4000)); // Patient comments
target.insert(DicomTag(0x0010, 0x2201)); // Patient species description
target.insert(DicomTag(0x0010, 0x2202)); // Patient species code sequence
target.insert(DicomTag(0x0010, 0x2292)); // Patient breed description
target.insert(DicomTag(0x0010, 0x2293)); // Patient breed code sequence
target.insert(DicomTag(0x0010, 0x2294)); // Breed registration sequence
target.insert(DicomTag(0x0010, 0x2297)); // Responsible person
target.insert(DicomTag(0x0010, 0x2298)); // Responsible person role
target.insert(DicomTag(0x0010, 0x2299)); // Responsible organization
target.insert(DicomTag(0x0012, 0x0062)); // Patient identity removed
target.insert(DicomTag(0x0012, 0x0063)); // De-identification method
target.insert(DicomTag(0x0012, 0x0064)); // De-identification method code sequence
// Table 10-18 ISSUER OF PATIENT ID MACRO (p. 112)
target.insert(DicomTag(0x0010, 0x0021)); // Issuer of Patient ID
target.insert(DicomTag(0x0010, 0x0024)); // Issuer of Patient ID qualifiers sequence
break;
case DicomModule_Study:
// This is Table C.7-3 "General Study Module Attributes" (p. 378)
target.insert(DicomTag(0x0020, 0x000d)); // Study instance UID
target.insert(DicomTag(0x0008, 0x0020)); // Study date
target.insert(DicomTag(0x0008, 0x0030)); // Study time
target.insert(DicomTag(0x0008, 0x0090)); // Referring physician's name
target.insert(DicomTag(0x0008, 0x0096)); // Referring physician identification sequence
target.insert(DicomTag(0x0020, 0x0010)); // Study ID
target.insert(DicomTag(0x0008, 0x0050)); // Accession number
target.insert(DicomTag(0x0008, 0x0051)); // Issuer of accession number sequence
target.insert(DicomTag(0x0008, 0x1030)); // Study description
target.insert(DicomTag(0x0008, 0x1048)); // Physician(s) of record
target.insert(DicomTag(0x0008, 0x1049)); // Physician(s) of record identification sequence
target.insert(DicomTag(0x0008, 0x1060)); // Name of physician(s) reading study
target.insert(DicomTag(0x0008, 0x1062)); // Physician(s) reading study identification sequence
target.insert(DicomTag(0x0032, 0x1034)); // Requesting service code sequence
target.insert(DicomTag(0x0008, 0x1110)); // Referenced study sequence
target.insert(DicomTag(0x0008, 0x1032)); // Procedure code sequence
target.insert(DicomTag(0x0040, 0x1012)); // Reason for performed procedure code sequence
break;
case DicomModule_Series:
// This is Table C.7-5 "General Series Module Attributes" (p. 385)
target.insert(DicomTag(0x0008, 0x0060)); // Modality
target.insert(DicomTag(0x0020, 0x000e)); // Series Instance UID
target.insert(DicomTag(0x0020, 0x0011)); // Series Number
target.insert(DicomTag(0x0020, 0x0060)); // Laterality
target.insert(DicomTag(0x0008, 0x0021)); // Series Date
target.insert(DicomTag(0x0008, 0x0031)); // Series Time
target.insert(DicomTag(0x0008, 0x1050)); // Performing Physicians’ Name
target.insert(DicomTag(0x0008, 0x1052)); // Performing Physician Identification Sequence
target.insert(DicomTag(0x0018, 0x1030)); // Protocol Name
target.insert(DicomTag(0x0008, 0x103e)); // Series Description
target.insert(DicomTag(0x0008, 0x103f)); // Series Description Code Sequence
target.insert(DicomTag(0x0008, 0x1070)); // Operators' Name
target.insert(DicomTag(0x0008, 0x1072)); // Operator Identification Sequence
target.insert(DicomTag(0x0008, 0x1111)); // Referenced Performed Procedure Step Sequence
target.insert(DicomTag(0x0008, 0x1250)); // Related Series Sequence
target.insert(DicomTag(0x0018, 0x0015)); // Body Part Examined
target.insert(DicomTag(0x0018, 0x5100)); // Patient Position
target.insert(DicomTag(0x0028, 0x0108)); // Smallest Pixel Value in Series
target.insert(DicomTag(0x0029, 0x0109)); // Largest Pixel Value in Series
target.insert(DicomTag(0x0040, 0x0275)); // Request Attributes Sequence
target.insert(DicomTag(0x0010, 0x2210)); // Anatomical Orientation Type
// Table 10-16 PERFORMED PROCEDURE STEP SUMMARY MACRO ATTRIBUTES
target.insert(DicomTag(0x0040, 0x0253)); // Performed Procedure Step ID
target.insert(DicomTag(0x0040, 0x0244)); // Performed Procedure Step Start Date
target.insert(DicomTag(0x0040, 0x0245)); // Performed Procedure Step Start Time
target.insert(DicomTag(0x0040, 0x0254)); // Performed Procedure Step Description
target.insert(DicomTag(0x0040, 0x0260)); // Performed Protocol Code Sequence
target.insert(DicomTag(0x0040, 0x0280)); // Comments on the Performed Procedure Step
break;
case DicomModule_Instance:
// This is Table C.12-1 "SOP Common Module Attributes" (p. 1207)
target.insert(DicomTag(0x0008, 0x0016)); // SOP Class UID
target.insert(DicomTag(0x0008, 0x0018)); // SOP Instance UID
target.insert(DicomTag(0x0008, 0x0005)); // Specific Character Set
target.insert(DicomTag(0x0008, 0x0012)); // Instance Creation Date
target.insert(DicomTag(0x0008, 0x0013)); // Instance Creation Time
target.insert(DicomTag(0x0008, 0x0014)); // Instance Creator UID
target.insert(DicomTag(0x0008, 0x001a)); // Related General SOP Class UID
target.insert(DicomTag(0x0008, 0x001b)); // Original Specialized SOP Class UID
target.insert(DicomTag(0x0008, 0x0110)); // Coding Scheme Identification Sequence
target.insert(DicomTag(0x0008, 0x0201)); // Timezone Offset From UTC
target.insert(DicomTag(0x0018, 0xa001)); // Contributing Equipment Sequence
target.insert(DicomTag(0x0020, 0x0013)); // Instance Number
target.insert(DicomTag(0x0100, 0x0410)); // SOP Instance Status
target.insert(DicomTag(0x0100, 0x0420)); // SOP Authorization DateTime
target.insert(DicomTag(0x0100, 0x0424)); // SOP Authorization Comment
target.insert(DicomTag(0x0100, 0x0426)); // Authorization Equipment Certification Number
target.insert(DicomTag(0x0400, 0x0500)); // Encrypted Attributes Sequence
target.insert(DicomTag(0x0400, 0x0561)); // Original Attributes Sequence
target.insert(DicomTag(0x0040, 0xa390)); // HL7 Structured Document Reference Sequence
target.insert(DicomTag(0x0028, 0x0303)); // Longitudinal Temporal Information Modified
// Table C.12-6 "DIGITAL SIGNATURES MACRO ATTRIBUTES" (p. 1216)
target.insert(DicomTag(0x4ffe, 0x0001)); // MAC Parameters sequence
target.insert(DicomTag(0xfffa, 0xfffa)); // Digital signatures sequence
break;
// TODO IMAGE MODULE?
default:
throw OrthancException(ErrorCode_ParameterOutOfRange);
}
}
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017 Osimis, 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>
#include <set>
#include <stdint.h>
#include "../Enumerations.h"
namespace Orthanc
{
class DicomTag
{
// This must stay a POD (plain old data structure)
private:
uint16_t group_;
uint16_t element_;
public:
DicomTag(uint16_t group,
uint16_t element) :
group_(group),
element_(element)
{
}
uint16_t GetGroup() const
{
return group_;
}
uint16_t GetElement() const
{
return element_;
}
bool IsPrivate() const
{
return group_ % 2 == 1;
}
const char* GetMainTagsName() const;
bool operator< (const DicomTag& other) const;
bool operator== (const DicomTag& other) const
{
return group_ == other.group_ && element_ == other.element_;
}
bool operator!= (const DicomTag& other) const
{
return !(*this == other);
}
std::string Format() const;
friend std::ostream& operator<< (std::ostream& o, const DicomTag& tag);
static void AddTagsForModule(std::set<DicomTag>& target,
DicomModule module);
};
// Aliases for the most useful tags
static const DicomTag DICOM_TAG_ACCESSION_NUMBER(0x0008, 0x0050);
static const DicomTag DICOM_TAG_SOP_INSTANCE_UID(0x0008, 0x0018);
static const DicomTag DICOM_TAG_PATIENT_ID(0x0010, 0x0020);
static const DicomTag DICOM_TAG_SERIES_INSTANCE_UID(0x0020, 0x000e);
static const DicomTag DICOM_TAG_STUDY_INSTANCE_UID(0x0020, 0x000d);
static const DicomTag DICOM_TAG_PIXEL_DATA(0x7fe0, 0x0010);
static const DicomTag DICOM_TAG_TRANSFER_SYNTAX_UID(0x0002, 0x0010);
static const DicomTag DICOM_TAG_IMAGE_INDEX(0x0054, 0x1330);
static const DicomTag DICOM_TAG_INSTANCE_NUMBER(0x0020, 0x0013);
static const DicomTag DICOM_TAG_NUMBER_OF_SLICES(0x0054, 0x0081);
static const DicomTag DICOM_TAG_NUMBER_OF_TIME_SLICES(0x0054, 0x0101);
static const DicomTag DICOM_TAG_NUMBER_OF_FRAMES(0x0028, 0x0008);
static const DicomTag DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES(0x0018, 0x1090);
static const DicomTag DICOM_TAG_IMAGES_IN_ACQUISITION(0x0020, 0x1002);
static const DicomTag DICOM_TAG_PATIENT_NAME(0x0010, 0x0010);
static const DicomTag DICOM_TAG_ENCAPSULATED_DOCUMENT(0x0042, 0x0011);
static const DicomTag DICOM_TAG_STUDY_DESCRIPTION(0x0008, 0x1030);
static const DicomTag DICOM_TAG_SERIES_DESCRIPTION(0x0008, 0x103e);
static const DicomTag DICOM_TAG_MODALITY(0x0008, 0x0060);
// The following is used for "modify/anonymize" operations
static const DicomTag DICOM_TAG_SOP_CLASS_UID(0x0008, 0x0016);
static const DicomTag DICOM_TAG_MEDIA_STORAGE_SOP_CLASS_UID(0x0002, 0x0002);
static const DicomTag DICOM_TAG_MEDIA_STORAGE_SOP_INSTANCE_UID(0x0002, 0x0003);
static const DicomTag DICOM_TAG_DEIDENTIFICATION_METHOD(0x0012, 0x0063);
// DICOM tags used for fMRI (thanks to Will Ryder)
static const DicomTag DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS(0x0020, 0x0105);
static const DicomTag DICOM_TAG_TEMPORAL_POSITION_IDENTIFIER(0x0020, 0x0100);
// Tags for C-FIND and C-MOVE
static const DicomTag DICOM_TAG_MESSAGE_ID(0x0000, 0x0110);
static const DicomTag DICOM_TAG_SPECIFIC_CHARACTER_SET(0x0008, 0x0005);
static const DicomTag DICOM_TAG_QUERY_RETRIEVE_LEVEL(0x0008, 0x0052);
static const DicomTag DICOM_TAG_MODALITIES_IN_STUDY(0x0008, 0x0061);
// Tags for images
static const DicomTag DICOM_TAG_COLUMNS(0x0028, 0x0011);
static const DicomTag DICOM_TAG_ROWS(0x0028, 0x0010);
static const DicomTag DICOM_TAG_SAMPLES_PER_PIXEL(0x0028, 0x0002);
static const DicomTag DICOM_TAG_BITS_ALLOCATED(0x0028, 0x0100);
static const DicomTag DICOM_TAG_BITS_STORED(0x0028, 0x0101);
static const DicomTag DICOM_TAG_HIGH_BIT(0x0028, 0x0102);
static const DicomTag DICOM_TAG_PIXEL_REPRESENTATION(0x0028, 0x0103);
static const DicomTag DICOM_TAG_PLANAR_CONFIGURATION(0x0028, 0x0006);
static const DicomTag DICOM_TAG_PHOTOMETRIC_INTERPRETATION(0x0028, 0x0004);
static const DicomTag DICOM_TAG_IMAGE_ORIENTATION_PATIENT(0x0020, 0x0037);
static const DicomTag DICOM_TAG_IMAGE_POSITION_PATIENT(0x0020, 0x0032);
// Tags related to date and time
static const DicomTag DICOM_TAG_ACQUISITION_DATE(0x0008, 0x0022);
static const DicomTag DICOM_TAG_ACQUISITION_TIME(0x0008, 0x0032);
static const DicomTag DICOM_TAG_CONTENT_DATE(0x0008, 0x0023);
static const DicomTag DICOM_TAG_CONTENT_TIME(0x0008, 0x0033);
static const DicomTag DICOM_TAG_INSTANCE_CREATION_DATE(0x0008, 0x0012);
static const DicomTag DICOM_TAG_INSTANCE_CREATION_TIME(0x0008, 0x0013);
static const DicomTag DICOM_TAG_PATIENT_BIRTH_DATE(0x0010, 0x0030);
static const DicomTag DICOM_TAG_PATIENT_BIRTH_TIME(0x0010, 0x0032);
static const DicomTag DICOM_TAG_SERIES_DATE(0x0008, 0x0021);
static const DicomTag DICOM_TAG_SERIES_TIME(0x0008, 0x0031);
static const DicomTag DICOM_TAG_STUDY_DATE(0x0008, 0x0020);
static const DicomTag DICOM_TAG_STUDY_TIME(0x0008, 0x0030);
// Various tags
static const DicomTag DICOM_TAG_SERIES_TYPE(0x0054, 0x1000);
static const DicomTag DICOM_TAG_REQUESTED_PROCEDURE_DESCRIPTION(0x0032, 0x1060);
static const DicomTag DICOM_TAG_INSTITUTION_NAME(0x0008, 0x0080);
static const DicomTag DICOM_TAG_REQUESTING_PHYSICIAN(0x0032, 0x1032);
static const DicomTag DICOM_TAG_REFERRING_PHYSICIAN_NAME(0x0008, 0x0090);
static const DicomTag DICOM_TAG_OPERATOR_NAME(0x0008, 0x1070);
static const DicomTag DICOM_TAG_PERFORMED_PROCEDURE_STEP_DESCRIPTION(0x0040, 0x0254);
static const DicomTag DICOM_TAG_IMAGE_COMMENTS(0x0020, 0x4000);
static const DicomTag DICOM_TAG_ACQUISITION_DEVICE_PROCESSING_DESCRIPTION(0x0018, 0x1400);
static const DicomTag DICOM_TAG_CONTRAST_BOLUS_AGENT(0x0018, 0x0010);
// Counting patients, studies and series
// https://www.medicalconnections.co.uk/kb/Counting_Studies_Series_and_Instances
static const DicomTag DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES(0x0020, 0x1200);
static const DicomTag DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES(0x0020, 0x1202);
static const DicomTag DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES(0x0020, 0x1204);
static const DicomTag DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES(0x0020, 0x1206);
static const DicomTag DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES(0x0020, 0x1208);
static const DicomTag DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES(0x0020, 0x1209);
static const DicomTag DICOM_TAG_SOP_CLASSES_IN_STUDY(0x0008, 0x0062);
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017 Osimis, 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 "DicomValue.h"
#include "../OrthancException.h"
#include "../Toolbox.h"
namespace Orthanc
{
DicomValue::DicomValue(const DicomValue& other) :
type_(other.type_),
content_(other.content_)
{
}
DicomValue::DicomValue(const std::string& content,
bool isBinary) :
type_(isBinary ? Type_Binary : Type_String),
content_(content)
{
}
DicomValue::DicomValue(const char* data,
size_t size,
bool isBinary) :
type_(isBinary ? Type_Binary : Type_String)
{
content_.assign(data, size);
}
const std::string& DicomValue::GetContent() const
{
if (type_ == Type_Null)
{
throw OrthancException(ErrorCode_BadParameterType);
}
else
{
return content_;
}
}
DicomValue* DicomValue::Clone() const
{
return new DicomValue(*this);
}
#if ORTHANC_ENABLE_BASE64 == 1
void DicomValue::FormatDataUriScheme(std::string& target,
const std::string& mime) const
{
Toolbox::EncodeBase64(target, GetContent());
target.insert(0, "data:" + mime + ";base64,");
}
#endif
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017 Osimis, 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>
#include <boost/noncopyable.hpp>
#if !defined(ORTHANC_ENABLE_BASE64)
# error The macro ORTHANC_ENABLE_BASE64 must be defined
#endif
namespace Orthanc
{
class DicomValue : public boost::noncopyable
{
private:
enum Type
{
Type_Null,
Type_String,
Type_Binary
};
Type type_;
std::string content_;
DicomValue(const DicomValue& other);
public:
DicomValue() : type_(Type_Null)
{
}
DicomValue(const std::string& content,
bool isBinary);
DicomValue(const char* data,
size_t size,
bool isBinary);
const std::string& GetContent() const;
bool IsNull() const
{
return type_ == Type_Null;
}
bool IsBinary() const
{
return type_ == Type_Binary;
}
DicomValue* Clone() const;
#if ORTHANC_ENABLE_BASE64 == 1
void FormatDataUriScheme(std::string& target,
const std::string& mime) const;
void FormatDataUriScheme(std::string& target) const
{
FormatDataUriScheme(target, "application/octet-stream");
}
#endif
};
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017 Osimis, 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
/********************************************************************
** LINUX ARCHITECTURES
********************************************************************/
#if defined(__linux__)
# define ORTHANC_HAS_BUILTIN_BYTE_SWAP 1
# include <endian.h>
#endif
/********************************************************************
** WINDOWS ARCHITECTURES
**
** On Windows x86, "host" will always be little-endian ("le").
********************************************************************/
#if defined(_WIN32)
# if defined(_MSC_VER)
// Visual Studio - http://msdn.microsoft.com/en-us/library/a3140177.aspx
# define ORTHANC_HAS_BUILTIN_BYTE_SWAP 1
# define be16toh(x) _byteswap_ushort(x)
# define be32toh(x) _byteswap_ulong(x)
# define be64toh(x) _byteswap_uint64(x)
# elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
// MinGW >= 4.3 - Use builtin intrinsic for byte swapping
# define ORTHANC_HAS_BUILTIN_BYTE_SWAP 1
# define be16toh(x) __builtin_bswap16(x)
# define be32toh(x) __builtin_bswap32(x)
# define be64toh(x) __builtin_bswap64(x)
# else
// MinGW <= 4.2, we must manually implement the byte swapping
# define ORTHANC_HAS_BUILTIN_BYTE_SWAP 0
# define be16toh(x) __orthanc_bswap16(x)
# define be32toh(x) __orthanc_bswap32(x)
# define be64toh(x) __orthanc_bswap64(x)
# endif
# define htobe16(x) be16toh(x)
# define htobe32(x) be32toh(x)
# define htobe64(x) be64toh(x)
# define htole16(x) x
# define htole32(x) x
# define htole64(x) x
# define le16toh(x) x
# define le32toh(x) x
# define le64toh(x) x
#endif
/********************************************************************
** FREEBSD ARCHITECTURES
********************************************************************/
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
# define ORTHANC_HAS_BUILTIN_BYTE_SWAP 1
# include <arpa/inet.h>
#endif
/********************************************************************
** APPLE ARCHITECTURES (including OS X)
********************************************************************/
#if defined(__APPLE__)
# define ORTHANC_HAS_BUILTIN_BYTE_SWAP 1
# include <libkern/OSByteOrder.h>
# define be16toh(x) OSSwapBigToHostInt16(x)
# define be32toh(x) OSSwapBigToHostInt32(x)
# define be64toh(x) OSSwapBigToHostInt64(x)
# define htobe16(x) OSSwapHostToBigInt16(x)
# define htobe32(x) OSSwapHostToBigInt32(x)
# define htobe64(x) OSSwapHostToBigInt64(x)
# define htole16(x) OSSwapHostToLittleInt16(x)
# define htole32(x) OSSwapHostToLittleInt32(x)
# define htole64(x) OSSwapHostToLittleInt64(x)
# define le16toh(x) OSSwapLittleToHostInt16(x)
# define le32toh(x) OSSwapLittleToHostInt32(x)
# define le64toh(x) OSSwapLittleToHostInt64(x)
#endif
/********************************************************************
** PORTABLE (BUT SLOW) IMPLEMENTATION OF BYTE-SWAPPING
********************************************************************/
#if ORTHANC_HAS_BUILTIN_BYTE_SWAP != 1
#include <stdint.h>
static inline uint16_t __orthanc_bswap16(uint16_t a)
{
return (a << 8) | (a >> 8);
}
static inline uint32_t __orthanc_bswap32(uint32_t a)
{
const uint8_t* p = reinterpret_cast<const uint8_t*>(&a);
return (static_cast<uint32_t>(p[0]) << 24 |
static_cast<uint32_t>(p[1]) << 16 |
static_cast<uint32_t>(p[2]) << 8 |
static_cast<uint32_t>(p[3]));
}
static inline uint64_t __orthanc_bswap64(uint64_t a)
{
const uint8_t* p = reinterpret_cast<const uint8_t*>(&a);
return (static_cast<uint64_t>(p[0]) << 56 |
static_cast<uint64_t>(p[1]) << 48 |
static_cast<uint64_t>(p[2]) << 40 |
static_cast<uint64_t>(p[3]) << 32 |
static_cast<uint64_t>(p[4]) << 24 |
static_cast<uint64_t>(p[5]) << 16 |
static_cast<uint64_t>(p[6]) << 8 |
static_cast<uint64_t>(p[7]));
}
#endif
This diff is collapsed.
This diff is collapsed.
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017 Osimis, 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 "FilesystemStorage.h"
// http://stackoverflow.com/questions/1576272/storing-large-number-of-files-in-file-system
// http://stackoverflow.com/questions/446358/storing-a-large-number-of-images
#include "../Logging.h"
#include "../OrthancException.h"
#include "../Toolbox.h"
#include "../SystemToolbox.h"
#include <boost/filesystem/fstream.hpp>
static std::string ToString(const boost::filesystem::path& p)
{
#if BOOST_HAS_FILESYSTEM_V3 == 1
return p.filename().string();
#else
return p.filename();
#endif
}
namespace Orthanc
{
boost::filesystem::path FilesystemStorage::GetPath(const std::string& uuid) const
{
namespace fs = boost::filesystem;
if (!Toolbox::IsUuid(uuid))
{
throw OrthancException(ErrorCode_ParameterOutOfRange);
}
fs::path path = root_;
path /= std::string(&uuid[0], &uuid[2]);
path /= std::string(&uuid[2], &uuid[4]);
path /= uuid;
#if BOOST_HAS_FILESYSTEM_V3 == 1
path.make_preferred();
#endif
return path;
}
FilesystemStorage::FilesystemStorage(std::string root)
{
//root_ = boost::filesystem::absolute(root).string();
root_ = root;
SystemToolbox::MakeDirectory(root);
}
static const char* GetDescriptionInternal(FileContentType content)
{
// This function is for logging only (internal use), a more
// fully-featured version is available in ServerEnumerations.cpp
switch (content)
{
case FileContentType_Unknown:
return "Unknown";
case FileContentType_Dicom:
return "DICOM";
case FileContentType_DicomAsJson:
return "JSON summary of DICOM";
default:
return "User-defined";
}
}
void FilesystemStorage::Create(const std::string& uuid,
const void* content,
size_t size,
FileContentType type)
{
LOG(INFO) << "Creating attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type)
<< "\" type (size: " << (size / (1024 * 1024) + 1) << "MB)";
boost::filesystem::path path;
path = GetPath(uuid);
if (boost::filesystem::exists(path))
{
// Extremely unlikely case: This Uuid has already been created
// in the past.
throw OrthancException(ErrorCode_InternalError);
}
if (boost::filesystem::exists(path.parent_path()))
{
if (!boost::filesystem::is_directory(path.parent_path()))
{
throw OrthancException(ErrorCode_DirectoryOverFile);
}
}
else
{
if (!boost::filesystem::create_directories(path.parent_path()))
{
throw OrthancException(ErrorCode_FileStorageCannotWrite);
}
}
SystemToolbox::WriteFile(content, size, path.string());
}
void FilesystemStorage::Read(std::string& content,
const std::string& uuid,
FileContentType type)
{
LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type)
<< "\" content type";
content.clear();
SystemToolbox::ReadFile(content, GetPath(uuid).string());
}
uintmax_t FilesystemStorage::GetSize(const std::string& uuid) const
{
boost::filesystem::path path = GetPath(uuid);
return boost::filesystem::file_size(path);
}
void FilesystemStorage::ListAllFiles(std::set<std::string>& result) const
{
namespace fs = boost::filesystem;
result.clear();
if (fs::exists(root_) && fs::is_directory(root_))
{
for (fs::recursive_directory_iterator current(root_), end; current != end ; ++current)
{
if (SystemToolbox::IsRegularFile(current->path().string()))
{
try
{
fs::path d = current->path();
std::string uuid = ToString(d);
if (Toolbox::IsUuid(uuid))
{
fs::path p0 = d.parent_path().parent_path().parent_path();
std::string p1 = ToString(d.parent_path().parent_path());
std::string p2 = ToString(d.parent_path());
if (p1.length() == 2 &&
p2.length() == 2 &&
p1 == uuid.substr(0, 2) &&
p2 == uuid.substr(2, 2) &&
p0 == root_)
{
result.insert(uuid);
}
}
}
catch (fs::filesystem_error)
{
}
}
}
}
}
void FilesystemStorage::Clear()
{
namespace fs = boost::filesystem;
typedef std::set<std::string> List;
List result;
ListAllFiles(result);
for (List::const_iterator it = result.begin(); it != result.end(); ++it)
{
Remove(*it, FileContentType_Unknown /*ignored in this class*/);
}
}
void FilesystemStorage::Remove(const std::string& uuid,
FileContentType type)
{
LOG(INFO) << "Deleting attachment \"" << uuid << "\" of type " << static_cast<int>(type);
namespace fs = boost::filesystem;
fs::path p = GetPath(uuid);
try
{
fs::remove(p);
}
catch (...)
{
// Ignore the error
}
// Remove the two parent directories, ignoring the error code if
// these directories are not empty
try
{
#if BOOST_HAS_FILESYSTEM_V3 == 1
boost::system::error_code err;
fs::remove(p.parent_path(), err);
fs::remove(p.parent_path().parent_path(), err);
#else
fs::remove(p.parent_path());
fs::remove(p.parent_path().parent_path());
#endif
}
catch (...)
{
// Ignore the error
}
}
uintmax_t FilesystemStorage::GetCapacity() const
{
return boost::filesystem::space(root_).capacity;
}
uintmax_t FilesystemStorage::GetAvailableSpace() const
{
return boost::filesystem::space(root_).available;
}
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017 Osimis, 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 "IStorageArea.h"
#include <stdint.h>
#include <boost/filesystem.hpp>
#include <set>
namespace Orthanc
{
class FilesystemStorage : public IStorageArea
{
// TODO REMOVE THIS
friend class FilesystemHttpSender;
friend class FileStorageAccessor;
private:
boost::filesystem::path root_;
boost::filesystem::path GetPath(const std::string& uuid) const;
public:
explicit FilesystemStorage(std::string root);
virtual void Create(const std::string& uuid,
const void* content,
size_t size,
FileContentType type);
virtual void Read(std::string& content,
const std::string& uuid,
FileContentType type);
virtual void Remove(const std::string& uuid,
FileContentType type);
void ListAllFiles(std::set<std::string>& result) const;
uintmax_t GetSize(const std::string& uuid) const;
void Clear();
uintmax_t GetCapacity() const;
uintmax_t GetAvailableSpace() const;
};
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017 Osimis, 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>
#include <boost/noncopyable.hpp>
namespace Orthanc
{
class IStorageArea : public boost::noncopyable
{
public:
virtual ~IStorageArea()
{
}
virtual void Create(const std::string& uuid,
const void* content,
size_t size,
FileContentType type) = 0;
virtual void Read(std::string& content,
const std::string& uuid,
FileContentType type) = 0;
virtual void Remove(const std::string& uuid,
FileContentType type) = 0;
};
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017 Osimis, 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 <boost/noncopyable.hpp>
namespace Orthanc
{
/**
* This class should be the ancestor to any class whose type is
* determined at the runtime, and that can be dynamically allocated.
* Being a child of IDynamicObject only implies the existence of a
* virtual destructor.
**/
class IDynamicObject : public boost::noncopyable
{
public:
virtual ~IDynamicObject()
{
}
};
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017 Osimis, 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<double>(*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 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 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_ = reinterpret_cast<uint8_t*>(const_cast<void*>(buffer));
if (GetBytesPerPixel() * width_ > pitch_)
{
throw OrthancException(ErrorCode_ParameterOutOfRange);
}
}
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_ = reinterpret_cast<uint8_t*>(buffer);
if (GetBytesPerPixel() * width_ > pitch_)
{
throw OrthancException(ErrorCode_ParameterOutOfRange);
}
}
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_Float32:
ToMatlabStringInternal<float>(buffer, *this);
break;
case PixelFormat_RGB24:
RGB24ToMatlabString(buffer, *this);
break;
default:
throw OrthancException(ErrorCode_NotImplemented);
}
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;
}
void ImageAccessor::SetFormat(PixelFormat format)
{
if (readOnly_)
{
#if ORTHANC_ENABLE_LOGGING == 1
LOG(ERROR) << "Trying to modify the format of a read-only image";
#endif
throw OrthancException(ErrorCode_ReadOnly);
}
if (::Orthanc::GetBytesPerPixel(format) != ::Orthanc::GetBytesPerPixel(format_))
{
throw OrthancException(ErrorCode_IncompatibleImageFormat);
}
format_ = format;
}
}