Skip to content
Commits on Source (3)
#!/bin/sh
set -ev
export Python=${Python:?}
export WORKSPACE=${WORKSPACE:?}
mkdir build
mkdir install
cd build
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/opt/icu4c/lib/pkgconfig
cmake \
-D CMAKE_INSTALL_PREFIX="${WORKSPACE}/install" \
-D PYTHON_LIBRARY=/usr/local/Frameworks/Python.framework/Versions/2.7/lib/libpython2.7.dylib \
${CMAKE_OPTIONS} \
..
make ${MAKE_OPTIONS} install
#!/usr/bin/env python
from __future__ import print_function
import json
import os
import subprocess
import sys
brew_conflicting = ["json-c"]
brew_required = [
"boost", "boost-python", "cmake", "cppcheck", "dcmtk", "icu4c", "jsoncpp",
"lcov", "log4cpp", "pkg-config", "python"+os.environ["Python"]
]
pip_required = ["cpp-coveralls", "nose"]
for formula in brew_conflicting:
info = json.loads(
subprocess.check_output(["brew", "info", "--json=v1", formula]))
if len(info) > 1:
print("Too many formulas matching {}".format(formula))
sys.exit(1)
elif len(info) == 0:
continue
installed = (len(info[0]["installed"]) != 0)
if installed:
print("Removing conflicting formula: {}".format(formula))
subprocess.check_call(["brew", "unlink", formula])
for formula in brew_required:
info = json.loads(
subprocess.check_output(["brew", "info", "--json=v1", formula]))
if len(info) > 1:
print("Too many formulas matching {}".format(formula))
sys.exit(1)
elif len(info) == 0:
print("No formula matching {}".format(formula))
sys.exit(1)
action = None
if len(info[0]["installed"]) == 0:
action = "install"
elif info[0]["installed"][-1]["version"] != info[0]["versions"]["stable"]:
action = "upgrade"
if action is not None:
subprocess.check_call(["brew", action, formula])
subprocess.check_call(
["pip"+os.environ["Python"], "install", "--user", "-U"]+pip_required)
#!/bin/sh
set -ev
export Python=${Python:?}
export WORKSPACE=${WORKSPACE:?}
cd build
export PYTHONPATH=${WORKSPACE}/install/$(python${Python} -c "from distutils.sysconfig import *; print(get_python_lib(True, prefix=''))")
../tests/run --no-network --nose ~/Library/Python/${Python}*/bin/nosetests
#!/bin/sh
set -ev
export Architecture=${Architecture:?}
export Distribution=${Distribution:?}
export Python=${Python:?}
export WORKSPACE=${WORKSPACE:?}
if [ "${Python}" = "2" ]
then
PYTHON_VERSION="$(pyversions -dv)"
elif [ "${Python}" = "3" ]
then
PYTHON_VERSION="$(py3versions -dv)"
else
PYTHON_VERSION="UNKOWN"
fi
PYTHON_VERSION_NO_DOT=$(echo $PYTHON_VERSION | sed 's|\.||')
if [ "${Distribution}" != "ubuntu/precise" -a "${Distribution}" != "debian/wheezy" ]; then
TRIPLET="$(dpkg-architecture -qDEB_HOST_MULTIARCH)"
else
TRIPLET=""
fi
BOOST_PYTHON_LIBRARY=/usr/lib/${TRIPLET}/libboost_python-py${PYTHON_VERSION_NO_DOT}.so
cd ${WORKSPACE}
mkdir -p build
mkdir -p install
cd build
cmake \
-D CMAKE_INSTALL_PREFIX="${WORKSPACE}/install" \
-D Python_ADDITIONAL_VERSIONS=${PYTHON_VERSION} \
-D PYTHON_EXECUTABLE=/usr/bin/python${PYTHON_VERSION} \
-D Boost_PYTHON_LIBRARY_DEBUG=${BOOST_PYTHON_LIBRARY} \
-D Boost_PYTHON_LIBRARY_RELEASE=${BOOST_PYTHON_LIBRARY} \
${CMAKE_OPTIONS} \
..
make ${MAKE_OPTIONS} install
#!/bin/sh
set -ev
export Architecture=${Architecture:?}
export Distribution=${Distribution:?}
export Python=${Python:?}
export WORKSPACE=${WORKSPACE:?}
if [ "${Python}" = "2" ]
then
PYTHON_PREFIX="python"
elif [ "${Python}" = "3" ]
then
PYTHON_PREFIX="python3"
fi
# Compilation toolchain
PACKAGES="build-essential cmake pkg-config python-minimal"
# Dependencies of main lib
PACKAGES="${PACKAGES} libboost-dev libboost-date-time-dev libboost-filesystem-dev"
PACKAGES="${PACKAGES} libdcmtk2-dev libicu-dev libjsoncpp-dev liblog4cpp5-dev zlib1g-dev"
# Dependencies of Python wrappers
PACKAGES="${PACKAGES} libboost-python-dev ${PYTHON_PREFIX}-dev"
# Dependencies of unit tests
PACKAGES="${PACKAGES} dcmtk libboost-test-dev ${PYTHON_PREFIX}-nose"
# Coverage and static analysis
PACKAGES="${PACKAGES} cppcheck lcov wget"
if [ "${Distribution}" = "ubuntu/precise" ]
then
PACKAGES="${PACKAGES} libwrap0-dev"
fi
apt-get -y update
apt-get -y install ${PACKAGES}
#!/bin/sh
set -ev
export Architecture=${Architecture:?}
export Distribution=${Distribution:?}
export Python=${Python:?}
export WORKSPACE=${WORKSPACE:?}
cd ${WORKSPACE}
rm -rf generatedJUnitFiles/CTest/*
cd build
rm -rf Testing/*
if [ ! -d "${WORKSPACE}/generatedJUnitFiles" ]; then
mkdir "${WORKSPACE}/generatedJUnitFiles"
fi
wget -O lcov_cobertura https://raw.github.com/eriwen/lcov-to-cobertura-xml/master/lcov_cobertura/lcov_cobertura.py
chmod a+x lcov_cobertura
if [ "${Python}" = "2" ]
then
NOSE="nosetests-2.7"
elif [ "${Python}" = "3" ]
then
NOSE="nosetests3"
fi
if [ "${Python}" = "3" -a "${Distribution}" = "ubuntu/precise" -o "${Distribution}" = "debian/wheezy" ]
then
# Python 3.2 does not include PEP0414
2to3 -w ../tests/wrappers/test_vr.py
fi
if [ "${Python}" = "2" ]
then
PYTHON_VERSION="$(pyversions -dv)"
elif [ "${Python}" = "3" ]
then
PYTHON_VERSION="$(py3versions -dv)"
else
PYTHON_VERSION="UNKOWN"
fi
export LD_LIBRARY_PATH=${WORKSPACE}/install/lib
export PYTHONPATH=${WORKSPACE}/install/$(python${Python} -c "from distutils.sysconfig import *; print(get_python_lib(True, prefix=''))")
"${WORKSPACE}/tests/run" --no-network --nose ${NOSE}
DIRECTORY=`mktemp -d`
if [ "${Distribution}" != "ubuntu/precise" -a "${Distribution}" != "debian/wheezy" ]; then
lcov --quiet --capture --directory "${WORKSPACE}" --output-file ${DIRECTORY}/test.info
lcov --quiet --remove ${DIRECTORY}/test.info -o ${DIRECTORY}/filtered.info \
'/usr/*' '*/src/appli/*' '*/tests/*' '*/build/*'
else
touch ${DIRECTORY}/filtered.info
fi
cp ${DIRECTORY}/filtered.info "${WORKSPACE}/build/coverage.info"
./lcov_cobertura ${DIRECTORY}/filtered.info -b "${WORKSPACE}"
rm -rf ${DIRECTORY}
cppcheck -q --xml --xml-version=2 --enable=all \
-i "${WORKSPACE}/tests/tools" \
"${WORKSPACE}/src/" "${WORKSPACE}/tests/" "${WORKSPACE}/wrappers/" \
2> ${WORKSPACE}/build/cppcheck.xml
before_script:
- apt-get update -qq && apt-get install -y -qq build-essential pkg-config cmake ninja-build libdcmtk2-dev libwrap0-dev libjsoncpp-dev libicu-dev zlib1g-dev libboost-dev libboost-filesystem-dev libboost-python-dev libboost-regex-dev libboost-test-dev liblog4cpp5-dev dcmtk python-minimal python-nose
- mkdir build && cd build
- cmake -G Ninja -D CMAKE_CXX_FLAGS=-std=c++11 ../
trusty:
image: ubuntu:trusty
script: ninja && ../tests/run --no-network
xenial:
image: ubuntu:xenial
script: ninja && ../tests/run --no-network
......@@ -5,49 +5,19 @@ matrix:
sudo: required
dist: trusty
compiler: gcc
env: Architecture=amd64 Distribution=ubuntu/trusty Python=2 WORKSPACE=${TRAVIS_BUILD_DIR} CMAKE_OPTIONS="-D CMAKE_CXX_FLAGS=--coverage" MAKE_OPTIONS="-j$(nproc)"
- os: osx
compiler: clang
addons:
apt:
packages:
- libdcmtk2-dev
- libwrap0-dev
- libjsoncpp-dev
- libicu-dev
- zlib1g-dev
- libboost-dev
- libboost-date-time-dev
- libboost-filesystem-dev
- libboost-python-dev
- libboost-regex-dev
- libboost-test-dev
- liblog4cpp5-dev
- dcmtk
- cmake
- pkg-config
before_install:
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; fi
# JSONCpp conflicts with json-c
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew uninstall --ignore-dependencies json-c; fi
# Boost is already installed with another version
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew unlink boost; brew install boost boost-python; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install dcmtk icu4c jsoncpp log4cpp; fi
- pip install --user cpp-coveralls nose
- export PATH=$(python -c 'import site; print(site.getuserbase())')/bin:${PATH}
before_script:
- export SRC_DIR=$PWD
- mkdir build
- cd build
- export BIN_DIR=$PWD
- CMAKE_OPTIONS=""
- if [ "${CC}" = "gcc" ]; then CMAKE_OPTIONS='${CMAKE_OPTIONS} -DCMAKE_CXX_FLAGS="--coverage"'; fi
#- if [ "${CC}" = "gcc" ]; then CMAKE_OPTIONS='${CMAKE_OPTIONS} -DPYTHON_LIBRARY=/opt/python/2.7.12/lib/libpython2.7.so'; fi
#- if [ "$TRAVIS_OS_NAME" = "osx" ]; then CMAKE_OPTIONS='${CMAKE_OPTIONS} -DPYTHON_LIBRARY=/usr/local/Frameworks/Python.framework/Versions/2.7/lib/libpython2.7.dylib' ; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/opt/icu4c/lib/pkgconfig; fi
# Travis has a weird Python environment. Disable the wrappers
- cmake ${CMAKE_OPTIONS} -DBUILD_WRAPPERS=OFF ../
env: Python=2 WORKSPACE=${TRAVIS_BUILD_DIR} MAKE_OPTIONS="-j$(sysctl -n hw.ncpu)"
install:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo -E sh ./.ci/deb/install; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then ./.ci/brew/install; fi
- if [ "${CC}" = "gcc" ]; then pip${Python} install -U --user cpp-coveralls; fi
- if [ "${CC}" = "gcc" ]; then export PATH=$(python -c 'import site; print(site.getuserbase())')/bin:${PATH}; fi
script:
- make
- ../tests/run --no-network -e ".*"
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then ./.ci/deb/build; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then ./.ci/brew/build; fi
after_success:
- if [ "${CC}" = "gcc" ]; then coveralls --exclude examples --exclude tests --exclude-pattern '.*CMake[^/]+\.c(?:pp)?' --exclude-pattern "/usr/.*" --root=${SRC_DIR} --build-root ${BIN_DIR} > /dev/null; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then ./.ci/deb/post_build; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then ./.ci/brew/post_build; fi
- if [ "${CC}" = "gcc" ]; then coveralls -n -l build/coverage.info; fi
......@@ -2,14 +2,15 @@ cmake_minimum_required(VERSION 2.8)
project("odil")
set(odil_MAJOR_VERSION 0)
set(odil_MINOR_VERSION 8)
set(odil_PATCH_VERSION 0)
set(odil_MINOR_VERSION 9)
set(odil_PATCH_VERSION 1)
set(odil_VERSION
${odil_MAJOR_VERSION}.${odil_MINOR_VERSION}.${odil_PATCH_VERSION})
option(BUILD_SHARED_LIBS "Build Odil with shared libraries." ON)
option(BUILD_EXAMPLES "Build the examples directory." ON)
option(BUILD_WRAPPERS "Build the Python Wrappers." ON)
option(BUILD_PYTHON_WRAPPERS "Build the Python Wrappers." ON)
option(BUILD_JAVASCRIPT_WRAPPERS "Build the Javascript Wrappers." OFF)
option(WITH_DCMTK "Build the DCMTK converter" ON)
option(
......@@ -50,7 +51,6 @@ if(WIN32)
endif()
add_subdirectory("src")
add_subdirectory("applications")
if(BUILD_EXAMPLES)
add_subdirectory("examples")
......@@ -60,18 +60,25 @@ if(BUILD_TESTING)
add_subdirectory("tests")
endif()
if(BUILD_WRAPPERS)
add_subdirectory("wrappers")
if(BUILD_PYTHON_WRAPPERS)
add_subdirectory("wrappers/python")
add_subdirectory("applications")
endif()
if(BUILD_JAVASCRIPT_WRAPPERS)
add_subdirectory("wrappers/js")
endif()
file(GLOB_RECURSE ci_resources .ci/*)
add_custom_target(
CIIntegration ${CMAKE_COMMAND} -E echo "CI Integration"
SOURCES appveyor.yml .gitlab-ci.yml .travis.yml)
SOURCES appveyor.yml .travis.yml ${ci_resources})
set_target_properties(CIIntegration PROPERTIES FOLDER "Utils")
file(GLOB_RECURSE documentation documentation/*)
add_custom_target(
Documentation ${CMAKE_COMMAND} -E echo "Documentation"
SOURCES Doxyfile LICENSE.txt README.md)
SOURCES LICENSE.txt README.md ${documentation})
set_target_properties(Documentation PROPERTIES FOLDER "Utils")
add_custom_target(
......
This diff is collapsed.
......@@ -3,21 +3,20 @@
Odil is a C++11 library for the [DICOM](http://dicom.nema.org/) standard.
Odil leverages C++ constructs to provide a user-friendly API of the different
parts of the DICOM standard. Included in Odil are exception-based error
handling, generic access to datasets elements, standard JSON and XML
representation of datasets, and generic implementation of messages,
clients and servers for the various DICOM protocols.
Odil also provides conversion to and from
[DCMTK](http://dicom.offis.de/dcmtk.php.en) data structures.
parts of the DICOM standard. Included in Odil are:
- Reading and writing data sets with any transfer syntax
- Standard JSON and XML representation of datasets
- Clients and servers for the various DICOM protocols (C-FIND, C-GET, C-MOVE, C-STORE)
- Implementation of the DICOM web-services (WADO-RS, QIDO-RS, STOW-RS)
- Conversion to and from [DCMTK](http://dicom.offis.de/dcmtk.php.en) data structures.
Odil builds and run on:
* Linux (Debian 7 and 8, Ubuntu 12.04, 14.04, and 16.04, all 32 and 64 bits).
Official packages are available ([Debian](https://packages.debian.org/search?keywords=odil&searchon=sourcenames&suite=all&section=all), [Ubuntu](http://packages.ubuntu.com/search?keywords=odil&searchon=sourcenames&suite=all&section=all)),
as well as [unofficial backports](https://github.com/lamyj/packages).
* OS X
* Windows
- Linux (Debian 7, 8 and 9; Ubuntu 14.04, and 16.04). Official packages are available ([Debian](https://packages.debian.org/search?keywords=odil&searchon=sourcenames&suite=all&section=all), [Ubuntu](http://packages.ubuntu.com/search?keywords=odil&searchon=sourcenames&suite=all&section=all)), as well as [unofficial backports](https://github.com/lamyj/packages).
- macOS
- Windows
Installation and usage instructions are available on the [documentation website](http://odil.readthedocs.io/).
[![Build Status (Travis)](https://travis-ci.org/lamyj/odil.svg?branch=master)](https://travis-ci.org/lamyj/odil)
[![Build Status (Appveyor)](https://ci.appveyor.com/api/projects/status/github/lamyj/odil?svg=true)](https://ci.appveyor.com/project/lamyj/odil)
......
file(GLOB_RECURSE python_files *.py)
set(python_files ${python_files} odil)
file(GLOB_RECURSE module_files *.py)
set(python_files ${module_files} odil)
add_custom_target(
PythonFiles ${CMAKE_COMMAND} -E echo "Python files" SOURCES ${python_files})
set_target_properties(PythonFiles PROPERTIES FOLDER "Examples")
if(BUILD_PYTHON_WRAPPERS)
execute_process(
COMMAND ${PYTHON_EXECUTABLE}
-c "from distutils.sysconfig import *; print(get_python_lib(True, prefix=''))"
OUTPUT_VARIABLE PYTHON_SITE_PACKAGES
OUTPUT_STRIP_TRAILING_WHITESPACE)
install(DIRECTORY DESTINATION "${PYTHON_SITE_PACKAGES}")
install(FILES ${module_files} DESTINATION "${PYTHON_SITE_PACKAGES}/odil/cli")
configure_file("odil" "${CMAKE_CURRENT_BINARY_DIR}/odil")
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/odil" DESTINATION bin)
endif()
from . import dicomdir
from . import echo
from . import find
from . import get
from . import print_
from . import store
from . import transcode
......@@ -87,17 +87,20 @@ def get(
get_pc = odil.AssociationParameters.PresentationContext(
1, get_syntax, transfer_syntaxes, True, False)
abstract_syntaxes = find_abstract_syntaxes(
host, port, calling_ae_title, called_ae_title, level, keys)
if not abstract_syntaxes:
# Negotiate ALL storage syntaxes. Is there a better way to do this?
storage_uids = [
abstract_syntaxes = [
entry.key() for entry in odil.registry.uids_dictionary
if entry.data().name.endswith("Storage")
]
if len(storage_uids) > 126:
if len(abstract_syntaxes) > 126:
raise Exception("Too many storage syntaxes")
storage_pcs = [
odil.AssociationParameters.PresentationContext(
2*(i+1)+1, uid, transfer_syntaxes, False, True)
for i, uid in enumerate(storage_uids)
for i, uid in enumerate(abstract_syntaxes)
]
association = odil.Association()
......@@ -230,6 +233,63 @@ def get(
[os.path.join(directory, x) for x in callback.files],
directory, patient_key, study_key, series_key, image_key)
def find_abstract_syntaxes(
host, port, calling_ae_title, called_ae_title, level, keys):
""" Return the abstract syntaxes corresponding to the query, based on
SOP Classes in Study.
"""
query = odil.DataSet()
for key in keys:
key, value = key.split("=", 1)
value = value.split("\\")
if key in ["QueryRetrieveLevel", "SOPClassesInStudy"]:
continue
tag = getattr(odil.registry, key)
vr = odil.registry.public_dictionary[tag].vr
if vr in ["DS", "FL", "FD"]:
value = [float(x) for x in value]
elif vr in ["IS", "SL", "SS", "UL", "US"]:
value = [int(x) for x in value]
query.add(tag, value)
query.add("QueryRetrieveLevel", ["STUDY"])
query.add("SOPClassesInStudy")
find_syntax = getattr(
odil.registry,
"{}RootQueryRetrieveInformationModelFIND".format(level.capitalize()))
transfer_syntaxes = [
odil.registry.ImplicitVRLittleEndian,
odil.registry.ExplicitVRLittleEndian
]
find_pc = odil.AssociationParameters.PresentationContext(
1, find_syntax, transfer_syntaxes, True, False)
association = odil.Association()
association.set_peer_host(host)
association.set_peer_port(port)
association.update_parameters()\
.set_calling_ae_title(calling_ae_title)\
.set_called_ae_title(called_ae_title) \
.set_presentation_contexts([find_pc])
association.associate()
logging.info("Association established")
find = odil.FindSCU(association)
find.set_affected_sop_class(find_syntax)
data_sets = find.find(query)
sop_classes = set()
for data_set in data_sets:
if "SOPClassesInStudy" in data_set:
sop_classes.update(data_set.as_string("SOPClassesInStudy"))
return sop_classes
def to_iso_9660(value):
value = value[:8].upper()
value = re.sub(r"[^A-Z0-9_]", "_", value)
......
......@@ -21,7 +21,8 @@ def add_subparser(subparsers):
def print_(inputs, print_header, decode_uids):
for input in inputs:
logging.info("Printing {}".format(input))
header, data_set = odil.read(input)
with odil.open(input) as stream:
header, data_set = odil.Reader.read_file(stream)
max_length = find_max_name_length(data_set)
if print_header:
......
......@@ -28,11 +28,12 @@ def store(host, port, calling_ae_title, called_ae_title, filenames):
# read the whole data set for this
sop_classes = set()
for filename in filenames:
_, data_set = odil.read(
filename, halt_condition=lambda tag: tag>odil.registry.SOPClassUID)
with odil.open(filename) as stream:
_, data_set = odil.Reader.read_file(
stream,
halt_condition=lambda tag: tag>odil.registry.SOPClassUID)
sop_classes.update(data_set.as_string("SOPClassUID"))
print(sop_classes)
presentation_contexts = [
odil.AssociationParameters.PresentationContext(
2*i+1, sop_class, transfer_syntaxes, True, False)
......@@ -51,13 +52,12 @@ def store(host, port, calling_ae_title, called_ae_title, filenames):
negotiated_parameters = association.get_negotiated_parameters()
negotiated_pc = negotiated_parameters.get_presentation_contexts()
for pc in negotiated_pc:
print(pc.abstract_syntax, " ", pc.transfer_syntaxes[0])
store = odil.StoreSCU(association)
for filename in filenames:
_, data_set = odil.read(filename)
with odil.open(filename) as stream:
_, data_set = odil.Reader.read_file(stream)
try:
store.set_affected_sop_class(data_set)
......
......@@ -45,17 +45,20 @@ def transcode(input, output, format, transfer_syntax, pretty_print):
globals()["as_{}".format(format)](input, output, **kwargs)
def as_binary(input, output, transfer_syntax):
_, data_set = odil.read(input)
with odil.open(input) as stream:
_, data_set = odil.Reader.read_file(stream)
odil.write(data_set, output, transfer_syntax=transfer_syntax)
def as_json(input, output, pretty_print):
_, data_set = odil.read(input)
with odil.open(input) as stream:
_, data_set = odil.Reader.read_file(stream)
with open(output, "w") as fd:
json = odil.as_json(data_set, pretty_print)
fd.write(json)
def as_xml(input, output, pretty_print):
_, data_set = odil.read(input)
with odil.open(input) as stream:
_, data_set = odil.Reader.read_file(stream)
with open(output, "w") as fd:
xml = odil.as_xml(data_set, pretty_print)
fd.write(xml)