dicom3tools 20260901__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dicom3tools/__init__.py +138 -0
- dicom3tools/_version.py +24 -0
- dicom3tools/_version.pyi +2 -0
- dicom3tools/bin/ancp.exe +0 -0
- dicom3tools/bin/ancreate.exe +0 -0
- dicom3tools/bin/andiff +21 -0
- dicom3tools/bin/andump.exe +0 -0
- dicom3tools/bin/antodc.all +40 -0
- dicom3tools/bin/antodc.exe +0 -0
- dicom3tools/bin/binpatch.exe +0 -0
- dicom3tools/bin/bmpdump.exe +0 -0
- dicom3tools/bin/cygX11-6.dll +0 -0
- dicom3tools/bin/cygXau-6.dll +0 -0
- dicom3tools/bin/cygXdmcp-6.dll +0 -0
- dicom3tools/bin/cyggcc_s-seh-1.dll +0 -0
- dicom3tools/bin/cygiconv-2.dll +0 -0
- dicom3tools/bin/cygintl-8.dll +0 -0
- dicom3tools/bin/cygstdc++-6.dll +0 -0
- dicom3tools/bin/cygwin1.dll +0 -0
- dicom3tools/bin/cygxcb-1.dll +0 -0
- dicom3tools/bin/dcacqmap +340 -0
- dicom3tools/bin/dcanon +604 -0
- dicom3tools/bin/dcarith.exe +0 -0
- dicom3tools/bin/dcbriggs.exe +0 -0
- dicom3tools/bin/dcburn.exe +0 -0
- dicom3tools/bin/dcbzip2 +15 -0
- dicom3tools/bin/dccidump.exe +0 -0
- dicom3tools/bin/dcckovly +62 -0
- dicom3tools/bin/dccmp +21 -0
- dicom3tools/bin/dccomb.exe +0 -0
- dicom3tools/bin/dccp.exe +0 -0
- dicom3tools/bin/dccreate.exe +0 -0
- dicom3tools/bin/dccsdump.exe +0 -0
- dicom3tools/bin/dcdecmpr.exe +0 -0
- dicom3tools/bin/dcdeflate +11 -0
- dicom3tools/bin/dcdict.exe +0 -0
- dicom3tools/bin/dcdiff +21 -0
- dicom3tools/bin/dcdirdmp.exe +0 -0
- dicom3tools/bin/dcdirmk.exe +0 -0
- dicom3tools/bin/dcdisp.exe +0 -0
- dicom3tools/bin/dcdtchg.exe +0 -0
- dicom3tools/bin/dcdump.exe +0 -0
- dicom3tools/bin/dcencap.exe +0 -0
- dicom3tools/bin/dcentvfy.exe +0 -0
- dicom3tools/bin/dcfile.exe +0 -0
- dicom3tools/bin/dchist.exe +0 -0
- dicom3tools/bin/dcinflate +17 -0
- dicom3tools/bin/dcinfo.exe +0 -0
- dicom3tools/bin/dciodvfy.exe +0 -0
- dicom3tools/bin/dcj2k +80 -0
- dicom3tools/bin/dcjls +58 -0
- dicom3tools/bin/dcjpeg +58 -0
- dicom3tools/bin/dckey.exe +0 -0
- dicom3tools/bin/dclutburn.exe +0 -0
- dicom3tools/bin/dclutdmp.exe +0 -0
- dicom3tools/bin/dclutmix.exe +0 -0
- dicom3tools/bin/dcmerge.exe +0 -0
- dicom3tools/bin/dcmkpres.exe +0 -0
- dicom3tools/bin/dcmulti.exe +0 -0
- dicom3tools/bin/dcmvhier +73 -0
- dicom3tools/bin/dcmvhier.8only +90 -0
- dicom3tools/bin/dcmvhier.all +23 -0
- dicom3tools/bin/dcmvhier.datedesc +85 -0
- dicom3tools/bin/dcmvhier.datedescnoid +77 -0
- dicom3tools/bin/dcmvhier.uid +73 -0
- dicom3tools/bin/dcortho.exe +0 -0
- dicom3tools/bin/dcostosr.exe +0 -0
- dicom3tools/bin/dcpatmpl +51 -0
- dicom3tools/bin/dcposn.exe +0 -0
- dicom3tools/bin/dcpost.exe +0 -0
- dicom3tools/bin/dcproj.exe +0 -0
- dicom3tools/bin/dcrmmeta.exe +0 -0
- dicom3tools/bin/dcrmsfx.all +15 -0
- dicom3tools/bin/dcsmpte.exe +0 -0
- dicom3tools/bin/dcsort.exe +0 -0
- dicom3tools/bin/dcsqextr.exe +0 -0
- dicom3tools/bin/dcsrdiff +24 -0
- dicom3tools/bin/dcsrdump.exe +0 -0
- dicom3tools/bin/dcsrmrg.exe +0 -0
- dicom3tools/bin/dcstats.exe +0 -0
- dicom3tools/bin/dcsub.exe +0 -0
- dicom3tools/bin/dcswab +21 -0
- dicom3tools/bin/dctable.exe +0 -0
- dicom3tools/bin/dctable_decompressingprn +30 -0
- dicom3tools/bin/dctopdf.exe +0 -0
- dicom3tools/bin/dctopgm8.exe +0 -0
- dicom3tools/bin/dctopgx.exe +0 -0
- dicom3tools/bin/dctopnm.exe +0 -0
- dicom3tools/bin/dctoraw.exe +0 -0
- dicom3tools/bin/dcuidchg.exe +0 -0
- dicom3tools/bin/dcunbzip2 +17 -0
- dicom3tools/bin/dcuncat.exe +0 -0
- dicom3tools/bin/dcunjls +46 -0
- dicom3tools/bin/dcunjpeg +146 -0
- dicom3tools/bin/dcunjpeg.all +32 -0
- dicom3tools/bin/dcunmeta.exe +0 -0
- dicom3tools/bin/dcunrgb +125 -0
- dicom3tools/bin/dumptiff.exe +0 -0
- dicom3tools/bin/dumpwhat.exe +0 -0
- dicom3tools/bin/gawdump.exe +0 -0
- dicom3tools/bin/gawtodc.exe +0 -0
- dicom3tools/bin/ge9800dump.exe +0 -0
- dicom3tools/bin/ge9800todc.exe +0 -0
- dicom3tools/bin/ge98id.exe +0 -0
- dicom3tools/bin/ge98topgm.exe +0 -0
- dicom3tools/bin/gendump.exe +0 -0
- dicom3tools/bin/gentodc.dat.all +34 -0
- dicom3tools/bin/gentodc.exe +0 -0
- dicom3tools/bin/gentopgm.exe +0 -0
- dicom3tools/bin/himrdump.exe +0 -0
- dicom3tools/bin/himrtodc.exe +0 -0
- dicom3tools/bin/imtndump.exe +0 -0
- dicom3tools/bin/imtntodc.exe +0 -0
- dicom3tools/bin/jpegdump.exe +0 -0
- dicom3tools/bin/jpegsplit.exe +0 -0
- dicom3tools/bin/pacedump.exe +0 -0
- dicom3tools/bin/pacetodc.exe +0 -0
- dicom3tools/bin/pacetopgm.exe +0 -0
- dicom3tools/bin/paceunid +31 -0
- dicom3tools/bin/pbmswbit.exe +0 -0
- dicom3tools/bin/pbmtoovl.exe +0 -0
- dicom3tools/bin/pdftodc.exe +0 -0
- dicom3tools/bin/pgmtobmp.exe +0 -0
- dicom3tools/bin/pgxtodc.exe +0 -0
- dicom3tools/bin/pnmpred.exe +0 -0
- dicom3tools/bin/pnmtodc.exe +0 -0
- dicom3tools/bin/pnmtoraw.exe +0 -0
- dicom3tools/bin/pqdump.exe +0 -0
- dicom3tools/bin/pqsplit.exe +0 -0
- dicom3tools/bin/pqtodc.exe +0 -0
- dicom3tools/bin/rawarith.exe +0 -0
- dicom3tools/bin/rawdiff.exe +0 -0
- dicom3tools/bin/rawftodc.exe +0 -0
- dicom3tools/bin/rawmask.exe +0 -0
- dicom3tools/bin/rawnjl.exe +0 -0
- dicom3tools/bin/rawnjl2.exe +0 -0
- dicom3tools/bin/rawtodc.exe +0 -0
- dicom3tools/bin/sgndump.exe +0 -0
- dicom3tools/bin/sgntodc.exe +0 -0
- dicom3tools/bin/sgntopgm.exe +0 -0
- dicom3tools/bin/shimdump.exe +0 -0
- dicom3tools/bin/shimtodc.exe +0 -0
- dicom3tools/bin/sompdump.exe +0 -0
- dicom3tools/bin/somptodc.exe +0 -0
- dicom3tools/bin/somtopgm.exe +0 -0
- dicom3tools/bin/syttopgm.exe +0 -0
- dicom3tools/bin/toshtodc +68 -0
- dicom3tools/bin/vsntopgm.exe +0 -0
- dicom3tools/py.typed +0 -0
- dicom3tools/share/COPYRIGHT +28 -0
- dicom3tools/share/VERSION.txt +1 -0
- dicom3tools-20260901.dist-info/METADATA +361 -0
- dicom3tools-20260901.dist-info/RECORD +156 -0
- dicom3tools-20260901.dist-info/WHEEL +5 -0
- dicom3tools-20260901.dist-info/entry_points.txt +28 -0
- dicom3tools-20260901.dist-info/licenses/LICENSE +212 -0
dicom3tools/__init__.py
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""
|
|
2
|
+
dicom3tools: Python distribution of David Clunie's dicom3tools command line utilities.
|
|
3
|
+
|
|
4
|
+
The wheels wrap the official dicom3tools programs, built by the workflows in
|
|
5
|
+
ImagingDataCommons/dicom3tools. A curated set of them is installed on PATH as console scripts
|
|
6
|
+
(see binaries.txt), and every program in the wheel is callable from Python, so that
|
|
7
|
+
|
|
8
|
+
dcdump some.dcm
|
|
9
|
+
|
|
10
|
+
and
|
|
11
|
+
|
|
12
|
+
from dicom3tools import dcdump
|
|
13
|
+
|
|
14
|
+
behave the same way. Programs with no console script are reached the same way::
|
|
15
|
+
|
|
16
|
+
from dicom3tools import pnmtodc
|
|
17
|
+
pnmtodc() # argv-driven, like the command line
|
|
18
|
+
|
|
19
|
+
and the handful whose names are not Python identifiers -- the `dcmvhier.all` family -- through
|
|
20
|
+
``run()``::
|
|
21
|
+
|
|
22
|
+
from dicom3tools import run
|
|
23
|
+
run("dcmvhier.all", ["/some/dir"])
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import os
|
|
29
|
+
import subprocess
|
|
30
|
+
import sys
|
|
31
|
+
from collections.abc import Callable, Sequence
|
|
32
|
+
from importlib.metadata import distribution
|
|
33
|
+
from pathlib import Path, PurePosixPath
|
|
34
|
+
from typing import NoReturn
|
|
35
|
+
|
|
36
|
+
from ._version import version as __version__
|
|
37
|
+
|
|
38
|
+
_PACKAGE = "dicom3tools"
|
|
39
|
+
|
|
40
|
+
# The Windows wheels ship the Cygwin runtime DLLs in the same directory as the executables;
|
|
41
|
+
# those are dependencies of the programs, not tools, and must not become callables.
|
|
42
|
+
_LIBRARY_SUFFIXES = frozenset({".dll"})
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _installed_tools() -> dict[str, Path]:
|
|
46
|
+
"""Map every program in dicom3tools/bin to its installed path, keyed without .exe."""
|
|
47
|
+
files = distribution(_PACKAGE).files
|
|
48
|
+
tools: dict[str, Path] = {}
|
|
49
|
+
for _file in files or []:
|
|
50
|
+
# Distribution file paths are always posix-flavoured, on every platform.
|
|
51
|
+
parts = PurePosixPath(str(_file)).parts
|
|
52
|
+
if len(parts) != 3 or parts[0] != _PACKAGE or parts[1] != "bin":
|
|
53
|
+
continue
|
|
54
|
+
name = parts[2]
|
|
55
|
+
if PurePosixPath(name).suffix.lower() in _LIBRARY_SUFFIXES:
|
|
56
|
+
continue
|
|
57
|
+
stem = name[:-4] if name.lower().endswith(".exe") else name
|
|
58
|
+
tools[stem] = Path(_file.locate())
|
|
59
|
+
return tools
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
_TOOLS = _installed_tools()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def bin_dir() -> Path:
|
|
66
|
+
"""Return the directory holding the packaged dicom3tools programs.
|
|
67
|
+
|
|
68
|
+
Useful for the programs that have no console script, and for putting the whole toolkit on
|
|
69
|
+
PATH in a subprocess of your own.
|
|
70
|
+
"""
|
|
71
|
+
for path in _TOOLS.values():
|
|
72
|
+
return path.parent.resolve(strict=True)
|
|
73
|
+
msg = f"No dicom3tools programs are installed in '{_PACKAGE}/bin'."
|
|
74
|
+
raise FileNotFoundError(msg)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _lookup(name: str) -> Path:
|
|
78
|
+
path = _TOOLS.get(name)
|
|
79
|
+
if path is None:
|
|
80
|
+
msg = (
|
|
81
|
+
f"'{name}' is not among the programs installed in '{_PACKAGE}/bin'. "
|
|
82
|
+
f"Installed: {', '.join(sorted(_TOOLS))}"
|
|
83
|
+
)
|
|
84
|
+
raise FileNotFoundError(msg)
|
|
85
|
+
return path.resolve(strict=True)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def run(name: str, args: Sequence[str] = ()) -> int:
|
|
89
|
+
"""Run a packaged dicom3tools program and return its exit status.
|
|
90
|
+
|
|
91
|
+
The child inherits this process's streams, and note where dicom3tools writes: diagnostics
|
|
92
|
+
go to stderr, and for the reporting tools that is *all* their output -- ``dcdump`` prints
|
|
93
|
+
its entire dump there, so redirecting only stdout captures nothing. Exit statuses are also
|
|
94
|
+
less informative than they look: ``dcdump`` and ``dciodvfy`` do return 1 when they report an
|
|
95
|
+
error, but others (``dcfile``) return 0 on input they could not make sense of.
|
|
96
|
+
"""
|
|
97
|
+
executable = _lookup(name)
|
|
98
|
+
|
|
99
|
+
if os.name == "nt" and executable.suffix.lower() != ".exe":
|
|
100
|
+
msg = (
|
|
101
|
+
f"'{name}' is a /bin/sh script from the Cygwin build and cannot be run natively on "
|
|
102
|
+
"Windows. Run it under a shell that can, or use the programs it wraps directly."
|
|
103
|
+
)
|
|
104
|
+
raise RuntimeError(msg)
|
|
105
|
+
|
|
106
|
+
# Several of the packaged tools are shell scripts that call their siblings by bare name
|
|
107
|
+
# (dccmp runs dctoraw, dcanon runs dcdump and dckey). Those lookups go through PATH, which
|
|
108
|
+
# only happens to contain the packaged bin directory when the caller installed into an
|
|
109
|
+
# active virtualenv and is invoking a console script. Prepending it here makes the tools
|
|
110
|
+
# behave the same whether they are reached from PATH, from Python, or from a subprocess of
|
|
111
|
+
# an application that never activated anything.
|
|
112
|
+
env = dict(os.environ)
|
|
113
|
+
env["PATH"] = os.pathsep.join(
|
|
114
|
+
part for part in (str(executable.parent), env.get("PATH", "")) if part
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return subprocess.call([str(executable), *args], close_fds=False, env=env)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _make_wrapper(name: str) -> Callable[[], NoReturn]:
|
|
121
|
+
def _wrapper() -> NoReturn:
|
|
122
|
+
raise SystemExit(run(name, sys.argv[1:]))
|
|
123
|
+
|
|
124
|
+
_wrapper.__name__ = name
|
|
125
|
+
_wrapper.__qualname__ = name
|
|
126
|
+
_wrapper.__doc__ = (
|
|
127
|
+
f"Run the {name} program with arguments passed to a Python script."
|
|
128
|
+
)
|
|
129
|
+
return _wrapper
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
# A callable for every installed program whose name can be an attribute. That excludes the
|
|
133
|
+
# `dcmvhier.all`-style variants, whose names contain dots; run() reaches those.
|
|
134
|
+
_callable_tools = sorted(name for name in _TOOLS if name.isidentifier())
|
|
135
|
+
for _name in _callable_tools:
|
|
136
|
+
globals()[_name] = _make_wrapper(_name)
|
|
137
|
+
|
|
138
|
+
__all__ = ["__version__", "bin_dir", "run", *_callable_tools] # noqa: PLE0604
|
dicom3tools/_version.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '20260901'
|
|
22
|
+
__version_tuple__ = version_tuple = (20260901,)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = 'g088efa4'
|
dicom3tools/_version.pyi
ADDED
dicom3tools/bin/ancp.exe
ADDED
|
Binary file
|
|
Binary file
|
dicom3tools/bin/andiff
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
# compare the dumps of two ACR-NEMA files
|
|
4
|
+
|
|
5
|
+
if [ $# != 2 ]
|
|
6
|
+
then
|
|
7
|
+
echo "usage: `basename $0` file1 file2"
|
|
8
|
+
exit 1
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
TMPFILE1=/tmp/`basename $0`.$$.tmp1
|
|
12
|
+
TMPFILE2=/tmp/`basename $0`.$$.tmp2
|
|
13
|
+
|
|
14
|
+
andump "$1" >"$TMPFILE1" 2>&1
|
|
15
|
+
andump "$2" >"$TMPFILE2" 2>&1
|
|
16
|
+
diff "$TMPFILE1" "$TMPFILE2"
|
|
17
|
+
|
|
18
|
+
rm "$TMPFILE1" "$TMPFILE2"
|
|
19
|
+
|
|
20
|
+
exit 0
|
|
21
|
+
|
|
Binary file
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
# Usage: antodc.all dirname
|
|
4
|
+
#
|
|
5
|
+
# where dirname is the directory name where images are
|
|
6
|
+
#
|
|
7
|
+
# converts files in place and adds .dcm extension
|
|
8
|
+
#
|
|
9
|
+
# removes private tags to avoid UN VR in explicit endian
|
|
10
|
+
# for those private tags that aren't in the dictionary
|
|
11
|
+
#
|
|
12
|
+
# removes any (obvious) sequences since they mess up some viewers
|
|
13
|
+
#
|
|
14
|
+
|
|
15
|
+
DCMSUFFIX="dcm"
|
|
16
|
+
|
|
17
|
+
STAMP=`date +%Y%m%d%H%M%S`.$$
|
|
18
|
+
|
|
19
|
+
ANTODC="antodc"
|
|
20
|
+
|
|
21
|
+
if [ ! $# = 1 ]
|
|
22
|
+
then
|
|
23
|
+
echo 1>&2 "Usage: `basename $0` dirname"
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
for i in `find "$1" -type f -a ! -name '.*' -print`
|
|
28
|
+
do
|
|
29
|
+
if [ -f "$i" ]
|
|
30
|
+
then
|
|
31
|
+
echo "Converting $i to $i.$DCMSUFFIX"
|
|
32
|
+
|
|
33
|
+
$ANTODC -output-vr explicit -output-endian little -stamp "$STAMP" \
|
|
34
|
+
-removeprivate \
|
|
35
|
+
-d ReferencedImageSequence -d IconImageSequence -d SourceImageSequence \
|
|
36
|
+
"$i" "$i.$DCMSUFFIX"
|
|
37
|
+
fi
|
|
38
|
+
done
|
|
39
|
+
|
|
40
|
+
exit 0
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
dicom3tools/bin/dcacqmap
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
#
|
|
3
|
+
# not tolerant of spaces in file names
|
|
4
|
+
#
|
|
5
|
+
|
|
6
|
+
usage() {
|
|
7
|
+
echo 1>&2 "Usage: $1 [-byacqnumber] [-byslicelocation] [-byscanoptions] [-bytemporalpositionidentifier] [-locationtolerance n] [-iconsize n] [-nodump] [-xhtml] [-isonames] [-nostyle] filenamesfile resultfolder"
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
ACQUISITIONPARAMETER=AcquisitionTime
|
|
11
|
+
POSITIONPARAMETER=ImagePositionPatient
|
|
12
|
+
LOCATIONTOLERANCE=""
|
|
13
|
+
ICONSIZE=128
|
|
14
|
+
INCLUDEREPORT="yes"
|
|
15
|
+
MAKEXHTML="no"
|
|
16
|
+
USEUIDFORFILENAME="yes"
|
|
17
|
+
USESTYLESHEET="yes"
|
|
18
|
+
SHORTAGTERMINATOR=""
|
|
19
|
+
|
|
20
|
+
while [ $# -gt 2 ]
|
|
21
|
+
do
|
|
22
|
+
if [ "$1" = "-byacqnumber" ]
|
|
23
|
+
then
|
|
24
|
+
ACQUISITIONPARAMETER=AcquisitionNumber
|
|
25
|
+
elif [ "$1" = "-byorientation" ]
|
|
26
|
+
then
|
|
27
|
+
# useful for series with different angulations
|
|
28
|
+
ACQUISITIONPARAMETER=ImageOrientationPatient
|
|
29
|
+
elif [ "$1" = "-byscanoptions" ]
|
|
30
|
+
then
|
|
31
|
+
# useful for Siemens Cardiac acquisitions where %RR is embedded in this attribute
|
|
32
|
+
ACQUISITIONPARAMETER=ScanOptions
|
|
33
|
+
elif [ "$1" = "-bytemporalpositionidentifier" ]
|
|
34
|
+
then
|
|
35
|
+
# useful for Philips perfusion acquisitions, within set of images all with the same AcquisitionNumber
|
|
36
|
+
ACQUISITIONPARAMETER=TemporalPositionIdentifier
|
|
37
|
+
elif [ "$1" = "-byslicelocation" ]
|
|
38
|
+
then
|
|
39
|
+
POSITIONPARAMETER=SliceLocation
|
|
40
|
+
elif [ "$1" = "-nodump" ]
|
|
41
|
+
then
|
|
42
|
+
INCLUDEREPORT="no"
|
|
43
|
+
elif [ "$1" = "-xhtml" ]
|
|
44
|
+
then
|
|
45
|
+
MAKEXHTML="yes"
|
|
46
|
+
SHORTAGTERMINATOR="/"
|
|
47
|
+
elif [ "$1" = "-isonames" ]
|
|
48
|
+
then
|
|
49
|
+
USEUIDFORFILENAME="no"
|
|
50
|
+
elif [ "$1" = "-nostyle" ]
|
|
51
|
+
then
|
|
52
|
+
USESTYLESHEET="no"
|
|
53
|
+
elif [ "$1" = "-locationtolerance" ]
|
|
54
|
+
then
|
|
55
|
+
shift
|
|
56
|
+
LOCATIONTOLERANCE="$1"
|
|
57
|
+
elif [ "$1" = "-iconsize" ]
|
|
58
|
+
then
|
|
59
|
+
shift
|
|
60
|
+
ICONSIZE="$1"
|
|
61
|
+
else
|
|
62
|
+
usage `basename $0`
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
shift
|
|
66
|
+
done
|
|
67
|
+
|
|
68
|
+
FILENAMESFILE="$1"
|
|
69
|
+
RESULTFOLDERNAME="$2"
|
|
70
|
+
|
|
71
|
+
if [ $# -ne 2 -o ! -f "${FILENAMESFILE}" ]
|
|
72
|
+
then
|
|
73
|
+
usage `basename $0`
|
|
74
|
+
exit 1
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
HTMLFILE="index.html"
|
|
78
|
+
ICONSDIR="icons"
|
|
79
|
+
REPORTSDIR="reports"
|
|
80
|
+
STYLESHEET="style.css"
|
|
81
|
+
|
|
82
|
+
mkdir -p "${RESULTFOLDERNAME}"
|
|
83
|
+
|
|
84
|
+
FQHTMLFILE="${RESULTFOLDERNAME}/${HTMLFILE}"
|
|
85
|
+
FQICONSDIR="${RESULTFOLDERNAME}/${ICONSDIR}"
|
|
86
|
+
FQSTYLESHEET="${RESULTFOLDERNAME}/${STYLESHEET}"
|
|
87
|
+
FQREPORTSDIR="${RESULTFOLDERNAME}/${REPORTSDIR}"
|
|
88
|
+
|
|
89
|
+
mkdir -p "${FQICONSDIR}"
|
|
90
|
+
if [ "${INCLUDEREPORT}" = "yes" ]
|
|
91
|
+
then
|
|
92
|
+
mkdir -p "${FQREPORTSDIR}"
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
TMPROOT=/tmp/`basename $0`.$$.
|
|
96
|
+
|
|
97
|
+
SORTEDBYPOSITION="${TMPROOT}sortedbyposition.dat"
|
|
98
|
+
POSITIONLIST="${TMPROOT}positionlist.dat"
|
|
99
|
+
SUBKEYS="${TMPROOT}subkeys.dat"
|
|
100
|
+
UNIQUESUBKEYS="${TMPROOT}uniquesubkeys.dat"
|
|
101
|
+
PARAMETERSBYFILE="${TMPROOT}parametersbyfile.dat"
|
|
102
|
+
|
|
103
|
+
CURRENTPOSITIONFILES="${TMPROOT}currentpositionfiles.dat"
|
|
104
|
+
SORTEDWITHINPOSITION="${TMPROOT}sortedwithinposition.dat"
|
|
105
|
+
ROWFILE="${TMPROOT}rowfile.dat"
|
|
106
|
+
|
|
107
|
+
useTitle=""
|
|
108
|
+
|
|
109
|
+
echo 1>&2 "Stage 1: identifying unique values of position and sorting"
|
|
110
|
+
if [ -z "${LOCATIONTOLERANCE}" ]
|
|
111
|
+
then
|
|
112
|
+
dcsort -index -show -k "${POSITIONPARAMETER}" `cat "${FILENAMESFILE}"` >"${SORTEDBYPOSITION}" 2>&1
|
|
113
|
+
else
|
|
114
|
+
dcsort -index -show -k "${POSITIONPARAMETER}" `cat "${FILENAMESFILE}"` 2>&1 | awk -v locationtolerance="${LOCATIONTOLERANCE}" '{print $1 "\t" $2 "\t" (int($3*locationtolerance+0.5)/locationtolerance)}' >"${SORTEDBYPOSITION}"
|
|
115
|
+
fi
|
|
116
|
+
#cat 1>&2 "${SORTEDBYPOSITION}"
|
|
117
|
+
awk < "${SORTEDBYPOSITION}" '{print $3}' | sort -u -n -r > "${POSITIONLIST}" # -r here makes head to toe, rather than -descending in dcsort
|
|
118
|
+
#cat 1>&2 "${POSITIONLIST}"
|
|
119
|
+
|
|
120
|
+
echo 1>&2 "Stage 2: making icons, extracting other key values than position and identifying unique combinations of those keys"
|
|
121
|
+
rm -f "${UNIQUESUBKEYS}"
|
|
122
|
+
rm -f "${PARAMETERSBYFILE}"
|
|
123
|
+
for i in `cat "${FILENAMESFILE}"`
|
|
124
|
+
do
|
|
125
|
+
if [ -z "${useTitle}" ]
|
|
126
|
+
then
|
|
127
|
+
useTitle=`dckey -noerror -k PatientName "$i" 2>&1 | egrep -iv '(error|warning)' | head -1`
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
dckey -brief -k SliceThickness -k ConvolutionKernel -k "${ACQUISITIONPARAMETER}" -k SOPInstanceUID "$i" >"${SUBKEYS}" 2>&1
|
|
131
|
+
#cat "${SUBKEYS}"
|
|
132
|
+
sopInstanceUID=`grep SOPInstanceUID "${SUBKEYS}"| sed -e 's/^SOPInstanceUID=//'`
|
|
133
|
+
if [ ! -f "${FQICONSDIR}/${sopInstanceUID}.jpg" ]
|
|
134
|
+
then
|
|
135
|
+
dctopgm8 -quiet "$i" 2>/dev/null | pamscale -xsize "${ICONSIZE}" -ysize "${ICONSIZE}" | cjpeg >"${FQICONSDIR}/${sopInstanceUID}.jpg"
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
sliceThickness=`grep SliceThickness "${SUBKEYS}"| sed -e 's/^SliceThickness=//'`
|
|
139
|
+
if [ -z "${sliceThickness}" ]; then sliceThickness="0.0"; fi
|
|
140
|
+
convolutionKernel=`grep ConvolutionKernel "${SUBKEYS}"| sed -e 's/^ConvolutionKernel=//' -e 's/[^A-Za-z0-9_]/_/g'`
|
|
141
|
+
if [ -z "${convolutionKernel}" ]; then convolutionKernel="NONE"; fi
|
|
142
|
+
acquisitionParameter=`grep "${ACQUISITIONPARAMETER}" "${SUBKEYS}"| sed -e "s/^${ACQUISITIONPARAMETER}=//" -e 's/ $//g' -e 's/^ //g' -e 's/[^0-9a-zA-Z+-]/_/g'`
|
|
143
|
+
#echo "${acquisitionParameter}"
|
|
144
|
+
if [ -z "${acquisitionParameter}" ]; then acquisitionParameter="999999"; fi
|
|
145
|
+
echo "${acquisitionParameter} ${convolutionKernel} ${sliceThickness}" | awk '{print $1 " " $2 " " $3}' >>"${UNIQUESUBKEYS}" # awk is to get spaces same as later
|
|
146
|
+
echo "${acquisitionParameter} ${convolutionKernel} ${sliceThickness} ${sopInstanceUID} $i" >>"${PARAMETERSBYFILE}"
|
|
147
|
+
|
|
148
|
+
rm -f "${SUBKEYS}"
|
|
149
|
+
done
|
|
150
|
+
mv "${UNIQUESUBKEYS}" "${UNIQUESUBKEYS}.bak"
|
|
151
|
+
sort -u <"${UNIQUESUBKEYS}.bak" | sort -n -k1,1 -d -k2,2 -n -k3,3 >"${UNIQUESUBKEYS}" # why twice ? in case different alphas interpreted as same numeric
|
|
152
|
+
rm -f "${UNIQUESUBKEYS}.bak"
|
|
153
|
+
|
|
154
|
+
#cat 1>&2 "${PARAMETERSBYFILE}"
|
|
155
|
+
#cat 1>&2 "${UNIQUESUBKEYS}"
|
|
156
|
+
numberofuniquekeys=`wc -l "${UNIQUESUBKEYS}" | awk '{print $1}'` # is the number of html columns we will need
|
|
157
|
+
#echo 1>&2 "numberofuniquekeys = ${numberofuniquekeys}"
|
|
158
|
+
|
|
159
|
+
echo 1>&2 "Stage 3: building HTML file"
|
|
160
|
+
if [ "${MAKEXHTML}" = "yes" ]
|
|
161
|
+
then
|
|
162
|
+
echo > "${FQHTMLFILE}" '<?xml version="1.0" encoding="utf-8" ?>'
|
|
163
|
+
echo >>"${FQHTMLFILE}" '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">'
|
|
164
|
+
echo >>"${FQHTMLFILE}" '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'
|
|
165
|
+
else
|
|
166
|
+
echo >"${FQHTMLFILE}" "<html>"
|
|
167
|
+
fi
|
|
168
|
+
echo >>"${FQHTMLFILE}" "<head>"
|
|
169
|
+
echo >>"${FQHTMLFILE}" "<title>${useTitle}</title>"
|
|
170
|
+
if [ "${USESTYLESHEET}" = "yes" ]
|
|
171
|
+
then
|
|
172
|
+
echo >>"${FQHTMLFILE}" "<link rel=\"stylesheet\" type=\"text/css\" href=\"${STYLESHEET}\"${SHORTAGTERMINATOR}>"
|
|
173
|
+
fi
|
|
174
|
+
echo >>"${FQHTMLFILE}" "</head>"
|
|
175
|
+
if [ "${USESTYLESHEET}" = "yes" ]
|
|
176
|
+
then
|
|
177
|
+
echo >>"${FQHTMLFILE}" "<body>"
|
|
178
|
+
else
|
|
179
|
+
if [ "${MAKEXHTML}" = "yes" ]
|
|
180
|
+
then
|
|
181
|
+
echo >>"${FQHTMLFILE}" '<body style="color: lavender; background-color : black; font-family: Arial, sans-serif;">'
|
|
182
|
+
else
|
|
183
|
+
echo >>"${FQHTMLFILE}" "<body bgcolor=\"black\" text=\"lavender\">"
|
|
184
|
+
# note that the face attribute is only supported by IE (see "http://www.blooberry.com/indexdot/html/tagpages/b/basefont.htm"); size of 3 is default
|
|
185
|
+
echo >>"${FQHTMLFILE}" "<basefont size=\"3\" face=\"Arial, sans-serif\"${SHORTAGTERMINATOR}>"
|
|
186
|
+
fi
|
|
187
|
+
fi
|
|
188
|
+
echo >>"${FQHTMLFILE}" "<table>"
|
|
189
|
+
echo >>"${FQHTMLFILE}" "<tr><th>Position</th>"
|
|
190
|
+
xargs <"${UNIQUESUBKEYS}" -L1 -J% echo '<th align="center">' % '</th>' >>"${FQHTMLFILE}"
|
|
191
|
+
echo >>"${FQHTMLFILE}" "</tr>"
|
|
192
|
+
|
|
193
|
+
countForFileName=0
|
|
194
|
+
for position in `cat "${POSITIONLIST}"`
|
|
195
|
+
do
|
|
196
|
+
#echo 1>&2 "Position = ${position}"
|
|
197
|
+
echo >>"${FQHTMLFILE}" "<tr><td>${position}</td>"
|
|
198
|
+
positionWithPeriodEscaped=`echo "${position}" | sed -e 's/[.]/[.]/'`
|
|
199
|
+
#echo 1>&2 "positionWithPeriodEscaped = ${positionWithPeriodEscaped}"
|
|
200
|
+
grepstring="[^.0-9-]${positionWithPeriodEscaped}\$"
|
|
201
|
+
#echo 1>&2 "grepstring = ${grepstring}"
|
|
202
|
+
egrep "${grepstring}" "${SORTEDBYPOSITION}" | awk '{print $2}' >"${CURRENTPOSITIONFILES}"
|
|
203
|
+
#cat 1>&2 <"${CURRENTPOSITIONFILES}"
|
|
204
|
+
rm -f "${ROWFILE}"
|
|
205
|
+
for i in `cat "${CURRENTPOSITIONFILES}"`
|
|
206
|
+
do
|
|
207
|
+
#echo 1>&2 "i = $i"
|
|
208
|
+
whichfileentry=`grep "$i" "${PARAMETERSBYFILE}" | head -1`
|
|
209
|
+
#echo 1>&2 "whichfileentry = ${whichfileentry}"
|
|
210
|
+
parameters=`echo "${whichfileentry}" | awk '{print $1 " " $2 " " $3}'` # awk is to get spaces same as in UNIQUESUBKEYS (see grep later)
|
|
211
|
+
#echo 1>&2 "parameters = ${parameters}"
|
|
212
|
+
sopInstanceUID=`echo "${whichfileentry}" | awk '{print $4}'`
|
|
213
|
+
#echo 1>&2 "sopInstanceUID = ${sopInstanceUID}"
|
|
214
|
+
whichuniquesubkey=`grep -n "${parameters}" "${UNIQUESUBKEYS}" | sed -e 's/:.*$//'`
|
|
215
|
+
#echo 1>&2 "whichuniquesubkey = ${whichuniquesubkey}"
|
|
216
|
+
echo "${whichuniquesubkey}: ${sopInstanceUID} $i" >>"${ROWFILE}"
|
|
217
|
+
done
|
|
218
|
+
firstfile=""
|
|
219
|
+
count=1
|
|
220
|
+
while [ ${count} -le ${numberofuniquekeys} ]
|
|
221
|
+
do
|
|
222
|
+
row=`egrep "^$count: " "${ROWFILE}" | head -1 | sed -e 's/^[0-9]*:[ ]*//'`
|
|
223
|
+
if [ -z "${row}" ]
|
|
224
|
+
then
|
|
225
|
+
echo >>"${FQHTMLFILE}" "<td></td>"
|
|
226
|
+
else
|
|
227
|
+
#echo 1>&2 "Got row = ${row}"
|
|
228
|
+
sopInstanceUID=`echo "${row}" | sed -e 's/^\([0-9][0-9.]*\).*$/\1/'`
|
|
229
|
+
#echo 1>&2 "Got sopInstanceUID = ${sopInstanceUID}"
|
|
230
|
+
if [ "${USEUIDFORFILENAME}" = "yes" ]
|
|
231
|
+
then
|
|
232
|
+
baseForFileName="${sopInstanceUID}"
|
|
233
|
+
else
|
|
234
|
+
baseForFileName="${countForFileName}"
|
|
235
|
+
mv "${FQICONSDIR}/${sopInstanceUID}.jpg" "${FQICONSDIR}/${baseForFileName}.jpg"
|
|
236
|
+
fi
|
|
237
|
+
if [ "${INCLUDEREPORT}" = "no" ]
|
|
238
|
+
then
|
|
239
|
+
echo "<td align=\"center\"><img src=\"${ICONSDIR}/${baseForFileName}.jpg\" alt=\"NONE\"${SHORTAGTERMINATOR}></td>" >>"${FQHTMLFILE}"
|
|
240
|
+
else
|
|
241
|
+
fileName=`echo "${row}" | sed -e 's/^[^ ]*[ ]*\(.*\)$/\1/'`
|
|
242
|
+
#echo 1>&2 "Got fileName = ${fileName}"
|
|
243
|
+
report="${baseForFileName}.txt"
|
|
244
|
+
if [ -z "${firstfile}" ]
|
|
245
|
+
then
|
|
246
|
+
dcdump "$fileName" 2>&1 | grep -v 'Warning - Overriding UN With Dictionary VR' >"${FQREPORTSDIR}/${report}"
|
|
247
|
+
firstfile="$fileName"
|
|
248
|
+
else
|
|
249
|
+
dcdiff "${firstfile}" "$fileName" >"${FQREPORTSDIR}/${report}" 2>&1
|
|
250
|
+
fi
|
|
251
|
+
#echo "${whichuniquesubkey}: <td align=\"center\"><a href=\"${REPORTSDIR}/${report}\"><img src=\"${ICONSDIR}/${baseForFileName}.jpg\"${SHORTAGTERMINATOR}></a></td>" >>"${FQHTMLFILE}"
|
|
252
|
+
echo "<td align=\"center\"><a href=\"javascript:void(0)\" onclick=\"window.open('${REPORTSDIR}/${report}')\"><img src=\"${ICONSDIR}/${baseForFileName}.jpg\" alt=\"NONE\"${SHORTAGTERMINATOR}></a></td>" >>"${FQHTMLFILE}"
|
|
253
|
+
fi
|
|
254
|
+
fi
|
|
255
|
+
count=`expr ${count} + 1`
|
|
256
|
+
countForFileName=`expr ${countForFileName} + 1`
|
|
257
|
+
done
|
|
258
|
+
echo >>"${FQHTMLFILE}" "</tr>"
|
|
259
|
+
rm -f "${CURRENTPOSITIONFILES}"
|
|
260
|
+
rm -f "${ROWFILE}"
|
|
261
|
+
done
|
|
262
|
+
echo >>"${FQHTMLFILE}" "</table></body></html>"
|
|
263
|
+
|
|
264
|
+
rm -f "${UNIQUESUBKEYS}"
|
|
265
|
+
rm -f "${PARAMETERSBYFILE}"
|
|
266
|
+
rm -f "${SORTEDBYPOSITION}"
|
|
267
|
+
rm -f "${POSITIONLIST}"
|
|
268
|
+
|
|
269
|
+
if [ "${USESTYLESHEET}" = "yes" ]
|
|
270
|
+
then
|
|
271
|
+
cat <<EOF >"${FQSTYLESHEET}"
|
|
272
|
+
body {
|
|
273
|
+
color: lavender;
|
|
274
|
+
background-color: #000000;
|
|
275
|
+
text-decoration: none;
|
|
276
|
+
font-family: Arial, sans-serif;
|
|
277
|
+
font-size: 100%;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
frame {
|
|
281
|
+
color: lavender;
|
|
282
|
+
background-color: #000000;
|
|
283
|
+
text-decoration: none;
|
|
284
|
+
font-family: Arial, sans-serif;
|
|
285
|
+
font-size: 100%;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
p {
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
table {
|
|
292
|
+
border: 0px solid;
|
|
293
|
+
border-color: lavender;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
th {
|
|
297
|
+
border: 1px solid;
|
|
298
|
+
padding-left: 2px;
|
|
299
|
+
padding-right: 2px;
|
|
300
|
+
border-color: feldspar;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
td {
|
|
304
|
+
border: 1px solid;
|
|
305
|
+
padding-left: 0px;
|
|
306
|
+
padding-right: 0px;
|
|
307
|
+
border-color: feldspar;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
a:link {
|
|
311
|
+
/* Applies to all unvisited links */
|
|
312
|
+
text-decoration: none;
|
|
313
|
+
color: black;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
a:visited {
|
|
317
|
+
/* Applies to all visited links */
|
|
318
|
+
text-decoration: none;
|
|
319
|
+
color: black;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
a:hover {
|
|
323
|
+
/* Applies to links under the pointer */
|
|
324
|
+
text-decoration: none;
|
|
325
|
+
background-color: lavender;
|
|
326
|
+
color: dimgray;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
a:active {
|
|
330
|
+
/* Applies to activated links */
|
|
331
|
+
text-decoration: none;
|
|
332
|
+
color: black;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.centered {
|
|
336
|
+
text-align: center;
|
|
337
|
+
}
|
|
338
|
+
EOF
|
|
339
|
+
fi
|
|
340
|
+
|