Skip to content

Commit 29591ac

Browse files
committed
Add skeletons
1 parent dddb82e commit 29591ac

File tree

8 files changed

+333
-0
lines changed

8 files changed

+333
-0
lines changed

docs/release_notes/v1.0.0.rst

Whitespace-only changes.

rle/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Set package shortcuts."""
2+
3+
from ._version import __version__

rle/_rle.pyx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# cython: language_level=3
2+
# distutils: language=c++
3+
4+
5+
cdef extern from "decode.hpp":
6+
pass
7+
#cdef string Decode(
8+
# char *inArray,
9+
# char *outArray,
10+
# int inLength,
11+
# int outLength,
12+
#)

rle/_version.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""Version information based on PEP396 and 440."""
2+
3+
import re
4+
5+
6+
__version__ = '1.0.0.dev0'
7+
8+
9+
VERSION_PATTERN = r"""
10+
v?
11+
(?:
12+
(?:(?P<epoch>[0-9]+)!)? # epoch
13+
(?P<release>[0-9]+(?:\.[0-9]+)*) # release segment
14+
(?P<pre> # pre-release
15+
[-_\.]?
16+
(?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview))
17+
[-_\.]?
18+
(?P<pre_n>[0-9]+)?
19+
)?
20+
(?P<post> # post release
21+
(?:-(?P<post_n1>[0-9]+))
22+
|
23+
(?:
24+
[-_\.]?
25+
(?P<post_l>post|rev|r)
26+
[-_\.]?
27+
(?P<post_n2>[0-9]+)?
28+
)
29+
)?
30+
(?P<dev> # dev release
31+
[-_\.]?
32+
(?P<dev_l>dev)
33+
[-_\.]?
34+
(?P<dev_n>[0-9]+)?
35+
)?
36+
)
37+
(?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version
38+
"""
39+
40+
41+
def is_canonical(version):
42+
"""Return True if `version` is a PEP440 conformant version."""
43+
match = re.match(
44+
(
45+
r'^([1-9]\d*!)?(0|[1-9]\d*)'
46+
r'(\.(0|[1-9]\d*))'
47+
r'*((a|b|rc)(0|[1-9]\d*))'
48+
r'?(\.post(0|[1-9]\d*))'
49+
r'?(\.dev(0|[1-9]\d*))?$'
50+
),
51+
version
52+
)
53+
54+
return match is not None
55+
56+
57+
assert is_canonical(__version__)

rle/src/decode.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
2+
// Includes
3+
#include "std/stdio.hpp"
4+
#include "std/string.hpp"
5+
#include <sstream>
6+
7+
#include "decode.hpp"
8+
9+
10+
std::string Decode(char *inArray, char *outArray, int inLength, int outLength)
11+
{
12+
/*
13+
14+
Parameters
15+
----------
16+
char *inArray
17+
Pointer to the first element of a byte array containing the RLE
18+
data to be decompressed.
19+
char *outArray
20+
Pointer to the first element of a numpy.ndarray where the decompressed
21+
RLE data should be written.
22+
int inLength
23+
Length of the input array
24+
int outLength
25+
Expected length of the output array
26+
*/
27+
28+
//
29+
};
30+
31+
int decode_segment(const char *segment, unsigned int expected_length) {
32+
/*
33+
34+
Parameters
35+
----------
36+
char *segment
37+
The RLE encoded segment to be decoded
38+
int length
39+
Length of the segment
40+
*/
41+
42+
// Output
43+
std::stringstream out;
44+
// Current position
45+
unsigned int pos = 0;
46+
// Length of the output
47+
unsigned int output_length = 0;
48+
unsigned char header_byte;
49+
// Can only copy or extend by at most 128 bytes per loop
50+
// TODO:
51+
// Need proper output location
52+
// Need to fix up pointers, etc
53+
// Need to make sure we don't go past the end of the input
54+
while (output_length < expected_length) {
55+
header_byte = segment[pos] + 1;
56+
pos += 1;
57+
if (header_byte > 129) {
58+
// Extend by copying the next byte (-N + 1) times, however since
59+
// we are using uint8 this will be (256 - N + 1) times
60+
// memset(ptr out, int value, int nr of bytes to set to `value`)
61+
extend_len = 258 - header_byte;
62+
memset(out, segment[pos], extend_len);
63+
output_length += extend_len;
64+
pos += 1;
65+
} else if (header_byte < 129) {
66+
// Extend by literally copying the next (N + 1) bytes
67+
// memcopy(ptr out, ptr src, int nr of bytes to copy)
68+
memcopy(out, segment[pos], header_byte)
69+
//result.extend(segment[pos:pos + header_byte])
70+
output_length += header_byte;
71+
pos += header_byte;
72+
}
73+
}
74+
75+
if (output_length != expected_length) {
76+
return -1;
77+
}
78+
79+
return out;
80+
};

rle/src/decode.hpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
#include <iostream>
3+
#include <string>
4+
5+
#ifndef DECODE_HPP
6+
#define DECODE_HPP
7+
8+
// Prototypes
9+
// Decode an RLE encoded frame `inArray` to `outArray`
10+
//extern std::string decode_frame(
11+
// char *inArray,
12+
// char *outArray,
13+
// int inLength,
14+
// int outLength,
15+
//);
16+
// Decode an RLE encoded segment
17+
//extern decode_segment();
18+
// Parse the RLE header
19+
extern int decode_segment(const char *segment, int length);
20+
21+
#endif

rle/utils.py

Whitespace-only changes.

setup.py

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
2+
import os
3+
import sys
4+
from pathlib import Path
5+
import platform
6+
import setuptools
7+
from setuptools import setup, find_packages
8+
from setuptools.extension import Extension
9+
import subprocess
10+
from distutils.command.build import build as build_orig
11+
import distutils.sysconfig
12+
13+
14+
RLE_SRC = os.path.join('rle', 'src', 'rle')
15+
16+
17+
# Workaround for needing cython and numpy
18+
# Solution from: https://stackoverflow.com/a/54128391/12606901
19+
class build(build_orig):
20+
def finalize_options(self):
21+
super().finalize_options()
22+
__builtins__.__NUMPY_SETUP__ = False
23+
24+
import numpy
25+
for ext in self.distribution.ext_modules:
26+
if ext in extensions:
27+
ext.include_dirs.append(numpy.get_include())
28+
29+
30+
def get_mscv_args():
31+
"""Return a list of compiler args for MSVC++'s compiler."""
32+
flags = [
33+
'/GS', # Buffer security check
34+
'/W3', # Warning level
35+
'/wd"4335"', # Ignore warning 4335
36+
'/Zc:wchar_t', # Use windows char type
37+
'/Zc:inline', # Remove unreferenced function or data (...)
38+
'/Zc:forScope',
39+
'/Od', # Disable optimisation
40+
'/Oy-', # (x86 only) don't omit frame pointer
41+
'/openmp-', # Disable #pragma omp directive
42+
'/FC', # Display full path of source code files
43+
'/fp:precise', # Floating-point behaviour
44+
'/Gd', # (x86 only) use __cdecl calling convention
45+
'/GF-', # Disable string pooling
46+
'/GR', # Enable run-time type info
47+
'/RTC1', # Enable run-time error checking
48+
'/MT', # Create multithreading executable
49+
# /D defines constants and macros
50+
'/D_UNICODE',
51+
'/DUNICODE',
52+
]
53+
# Set the architecture based on system architecture and Python
54+
is_x64 = platform.architecture()[0] == '64bit'
55+
if is_x64 and sys.maxsize > 2**32:
56+
flags.append('/DWIN64=1')
57+
else:
58+
# Architecture is 32-bit, or Python is 32-bit
59+
flags.append('/DWIN32=1')
60+
61+
return flags
62+
63+
64+
def get_source_files():
65+
"""Return a list of paths to the source files to be compiled."""
66+
source_files = [
67+
'rle/_libjpeg.pyx',
68+
os.path.join(RLE_SRC, 'decode.cpp'),
69+
]
70+
#for fname in Path(RLE_SRC).glob('*/*'):
71+
# if '.cpp' in str(fname):
72+
# source_files.append(str(fname))
73+
74+
return source_files
75+
76+
77+
# Compiler and linker arguments
78+
extra_compile_args = []
79+
extra_link_args = []
80+
if platform.system() == 'Windows':
81+
os.environ['LIB'] = os.path.abspath(
82+
os.path.join(sys.executable, '../', 'libs')
83+
)
84+
extra_compile_args = get_mscv_args()
85+
86+
87+
extensions = [
88+
Extension(
89+
'_rle',
90+
get_source_files(),
91+
language='c++',
92+
include_dirs=[
93+
RLE_SRC,
94+
distutils.sysconfig.get_python_inc(),
95+
# Numpy includes get added by the `build` subclass
96+
],
97+
extra_compile_args=extra_compile_args,
98+
extra_link_args=extra_link_args,
99+
)
100+
]
101+
102+
VERSION_FILE = os.path.join('rle', '_version.py')
103+
with open(VERSION_FILE) as fp:
104+
exec(fp.read())
105+
106+
with open('README.md', 'r') as fp:
107+
long_description = fp.read()
108+
109+
setup(
110+
name = 'pylibjpeg-rle',
111+
description = (
112+
"A Python wrapper for libjpeg, with a focus on use as a plugin for "
113+
"for pylibjpeg"
114+
),
115+
long_description = long_description,
116+
long_description_content_type = 'text/markdown',
117+
version = __version__,
118+
author = "scaramallion",
119+
author_email = "[email protected]",
120+
url = "https://github.com/pydicom/pylibjpeg-rle",
121+
license = "MIT",
122+
keywords = (
123+
"dicom pydicom python medicalimaging radiotherapy oncology imaging "
124+
"radiology nuclearmedicine rle pylibjpeg"
125+
),
126+
classifiers = [
127+
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
128+
"Intended Audience :: Developers",
129+
"Intended Audience :: Healthcare Industry",
130+
"Intended Audience :: Science/Research",
131+
"Development Status :: 3 - Alpha",
132+
#"Development Status :: 4 - Beta",
133+
#"Development Status :: 5 - Production/Stable",
134+
"Natural Language :: English",
135+
"Programming Language :: C++",
136+
"Programming Language :: Python :: 3.6",
137+
"Programming Language :: Python :: 3.7",
138+
"Programming Language :: Python :: 3.8",
139+
"Operating System :: MacOS :: MacOS X",
140+
"Operating System :: POSIX :: Linux",
141+
"Operating System :: Microsoft :: Windows",
142+
"Topic :: Scientific/Engineering :: Medical Science Apps.",
143+
"Topic :: Software Development :: Libraries",
144+
],
145+
packages = find_packages(),
146+
package_data = {'': ['*.txt', '*.cpp', '*.h', '*.hpp', '*.pyx']},
147+
include_package_data = True,
148+
zip_safe = False,
149+
python_requires = ">=3.6",
150+
setup_requires = ['setuptools>=18.0', 'cython', 'numpy>=1.16.0'],
151+
install_requires = ["numpy>=1.16.0"],
152+
cmdclass = {'build': build},
153+
ext_modules = extensions,
154+
# Plugin registrations
155+
entry_points={
156+
'pylibjpeg.pixel_data_decoders': [
157+
"1.2.840.10008.1.2.5 = rle:decode_pixel_data",
158+
],
159+
},
160+
)

0 commit comments

Comments
 (0)