[med-svn] [pixelmed-codec] 06/08: New upstream version 20141206

Andreas Tille tille at debian.org
Thu Sep 14 16:48:56 UTC 2017


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository pixelmed-codec.

commit 6d44338d060ace522bb36ede52443febada42a60
Author: Andreas Tille <tille at debian.org>
Date:   Thu Sep 14 18:46:53 2017 +0200

    New upstream version 20141206
---
 COPYRIGHT                                          |   29 +
 Doxyfile                                           | 1310 ++++++++++++++++++++
 Makefile                                           |  166 +++
 Makefile.common.mk                                 |   25 +
 README                                             |    6 +
 com/pixelmed/codec/jpeg/EntropyCodedSegment.java   |  401 ++++++
 com/pixelmed/codec/jpeg/HuffmanTable.java          |  188 +++
 com/pixelmed/codec/jpeg/Makefile                   |   53 +
 com/pixelmed/codec/jpeg/MarkerSegmentAPP0JFIF.java |   44 +
 com/pixelmed/codec/jpeg/MarkerSegmentDHT.java      |   83 ++
 com/pixelmed/codec/jpeg/MarkerSegmentDQT.java      |   75 ++
 com/pixelmed/codec/jpeg/MarkerSegmentSOF.java      |   71 ++
 com/pixelmed/codec/jpeg/MarkerSegmentSOS.java      |   68 +
 com/pixelmed/codec/jpeg/Markers.java               |  317 +++++
 com/pixelmed/codec/jpeg/Parse.java                 |  358 ++++++
 com/pixelmed/codec/jpeg/QuantizationTable.java     |   38 +
 com/pixelmed/codec/jpeg/Utilities.java             |   73 ++
 com/pixelmed/codec/jpeg/package.html               |   36 +
 debian/changelog                                   |   13 -
 debian/compat                                      |    1 -
 debian/control                                     |   28 -
 debian/copyright                                   |   41 -
 debian/docs                                        |    1 -
 debian/libpixelmed-codec-java.jlibs                |    1 -
 debian/patches/debian_jars.patch                   |   40 -
 debian/patches/reproducible_build.patch            |   19 -
 debian/patches/series                              |    3 -
 debian/patches/set_java_home.patch                 |   15 -
 debian/rules                                       |   13 -
 debian/source/format                               |    1 -
 debian/source/options                              |    2 -
 debian/watch                                       |    2 -
 32 files changed, 3341 insertions(+), 180 deletions(-)

diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100755
index 0000000..81cf8b9
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,29 @@
+Copyright (c) 2014, David A. Clunie DBA PixelMed Publishing. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of
+   conditions and the following disclaimers.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of
+   conditions and the following disclaimers in the documentation and/or other materials
+   provided with the distribution.
+
+3. Neither the name of PixelMed Publishing nor the names of its contributors may
+   be used to endorse or promote products derived from this software.
+
+This software is provided by the copyright holders and contributors "as is" and any
+express or implied warranties, including, but not limited to, the implied warranties
+of merchantability and fitness for a particular purpose are disclaimed. In no event
+shall the copyright owner or contributors be liable for any direct, indirect, incidental,
+special, exemplary, or consequential damages (including, but not limited to, procurement
+of substitute goods or services; loss of use, data or profits; or business interruption)
+however caused and on any theory of liability, whether in contract, strict liability, or
+tort (including negligence or otherwise) arising in any way out of the use of this software,
+even if advised of the possibility of such damage.
+
+This software has neither been tested nor approved for clinical use or for incorporation in
+a medical device. It is the redistributor's or user's responsibility to comply with any
+applicable local, state, national or international regulations.
+
diff --git a/Doxyfile b/Doxyfile
new file mode 100755
index 0000000..6093d19
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,1310 @@
+# Doxyfile 1.5.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file that 
+# follow. The default is UTF-8 which is also the encoding used for all text before 
+# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into 
+# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of 
+# possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = pixelmed
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = docs/doxygen
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = YES
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, 
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, 
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, 
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
+# interpret the first line (until the first dot) of a Qt-style 
+# comment as the brief description. If set to NO, the comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for Java. 
+# For instance, namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to 
+# include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
+# Doxygen will parse them like normal C++ but will assume all classes use public 
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct (or union) is 
+# documented as struct with the name of the typedef. So 
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
+# with name TypeT. When disabled the typedef will appear as a member of a file, 
+# namespace, or class. And the struct will be named TypeS. This can typically 
+# be useful for C code where the coding convention is that all structs are 
+# typedef'ed and only the typedef is referenced never the struct's name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be extracted 
+# and appear in the documentation as a namespace called 'anonymous_namespace{file}', 
+# where file will be replaced with the base name of the file that contains the anonymous 
+# namespace. By default anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = NO
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from the 
+# version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = com
+
+# This tag can be used to specify the character encoding of the source files that 
+# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default 
+# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. 
+# See http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.java
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = com/pixelmed/hl7
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = YES
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = 
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the output. 
+# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, 
+# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH 
+# then you must also enable this option. If you don't then doxygen will produce 
+# a warning and turn it on anyway
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.  Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
+# documentation will contain sections that can be hidden and shown after the 
+# page has loaded. For this to work a browser that supports 
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to 
+# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to 
+# specify the directory where the mscgen tool resides. If left empty the tool is assumed to 
+# be found in the default search path.
+
+MSCGEN_PATH            = 
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will 
+# generate a call dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable call graphs for selected 
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will 
+# generate a caller dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable caller graphs for selected 
+# functions only using the \callergraph command.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen if the number 
+# of direct children of the root node in a graph is already larger than 
+# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note 
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that the size of a graph can be further restricted by 
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, which results in a white background. 
+# Warning: Depending on the platform used, enabling this option may lead to 
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to 
+# read).
+
+DOT_TRANSPARENT        = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/Makefile b/Makefile
new file mode 100755
index 0000000..e6e395f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,166 @@
+all:	pixelmed_codec.jar
+
+TAR = gnutar
+#TAR = tar
+COMPRESS = bzip2
+COMPRESSEXT = bz2
+
+SUBDIRS = \
+	com/pixelmed/codec/jpeg
+	
+SUBPACKAGES = \
+	com.pixelmed.codec.jpeg
+
+ADDITIONALFILES = \
+	COPYRIGHT \
+	Makefile \
+	Makefile.common.mk \
+	README
+
+ADDITIONALSOURCEFILES = \
+	Doxyfile
+
+BINARYRELEASEFILES = \
+	pixelmed_codec.jar \
+	BUILDDATE \
+	${ADDITIONALFILES}
+
+SOURCERELEASEFILES = \
+	${ADDITIONALFILES} \
+	${ADDITIONALSOURCEFILES} \
+	${SUBDIRS}
+
+DEPENDENCYRELEASEFILESWITHOUTREADME = \
+	lib/junit/junit-4.8.1.jar \
+	LICENSES
+
+DEPENDENCYRELEASEFILES = \
+	${DEPENDENCYRELEASEFILESWITHOUTREADME} \
+	README
+
+JAVADOCRELEASEFILES = \
+	${JAVADOCFILES}
+
+DOXYGENRELEASEFILES = \
+	${DOXYGENFILES}
+
+JAVADOCFILES = \
+	docs/javadoc
+
+DOXYGENFILES = \
+        docs/doxygen
+
+OTHERDOCRELEASEFILES = \
+
+PATHTOROOT = .
+
+include ${PATHTOROOT}/Makefile.common.mk
+
+pixelmed_codec.jar:
+	(cd com/pixelmed/codec/jpeg; make all)
+	date >BUILDDATE
+	jar -cvf $@ BUILDDATE COPYRIGHT \
+		com/pixelmed/codec/jpeg/*.class
+changelog:
+	rm -f CHANGES
+	cvsps -u -q | egrep -v '^(PatchSet|Author:|Branch:|Tag:|Members:|Log:)' | fgrep -v '*** empty log message ***' | grep -v '^[ ]*$$' | sed -e 's/:[0-9.]*->[0-9.]*//' -e 's/:INITIAL->[0-9.]*//' -e 's/^Date: \([0-9][0-9][0-9][0-9]\/[0-9][0-9]\/[0-9][0-9]\) [0-9:]*$$/\1/' >CHANGES
+	bzip2 <CHANGES >CHANGES.bz2
+	
+clean:	cleanallexceptjar
+	rm -f pixelmed_codec.jar
+
+cleanallexceptjar:	cleansubdirs
+	rm -f *~ *.class .exclude.list
+
+cleansubdirs:
+	for d in ${SUBDIRS}; \
+	do \
+		if [ -d $$d ]; then \
+			(cd $$d; echo "Cleaning in $$d"; make clean); \
+		fi; \
+	done
+
+archivesource: clean .exclude.list
+	export COPYFILE_DISABLE=true; \
+	export COPY_EXTENDED_ATTRIBUTES_DISABLE=true; \
+	${TAR} -cv -X .exclude.list -f - Makefile ${ADDITIONALFILES} ${SUBDIRS} | ${COMPRESS} > pixelmedjavacodec_source_archive.`date '+%Y%m%d'`.tar.${COMPRESSEXT}
+
+archivejavadoc: .exclude.list #javadoc
+	export COPYFILE_DISABLE=true; \
+	export COPY_EXTENDED_ATTRIBUTES_DISABLE=true; \
+	${TAR} -cv -X .exclude.list -f - ${JAVADOCFILES} | ${COMPRESS} > pixelmedjavacodec_javadoc_archive.`date '+%Y%m%d'`.tar.${COMPRESSEXT}
+
+archivedoxygen: .exclude.list #doxygen
+	export COPYFILE_DISABLE=true; \
+	export COPY_EXTENDED_ATTRIBUTES_DISABLE=true; \
+	${TAR} -cv -X .exclude.list -f - ${DOXYGENFILES} | ${COMPRESS} > pixelmedjavacodec_javadoc_archive.`date '+%Y%m%d'`.tar.${COMPRESSEXT}
+
+releaseall:	changelog sourcerelease javadocrelease doxygenrelease binaryrelease dependencyrelease otherdocrelease
+
+binaryrelease: cleanallexceptjar .exclude.list pixelmed_codec.jar #javadoc doxygen
+	export COPYFILE_DISABLE=true; \
+	export COPY_EXTENDED_ATTRIBUTES_DISABLE=true; \
+	${TAR} -cv -X .exclude.list -f - ${BINARYRELEASEFILES} | ${COMPRESS} > pixelmedjavacodec_binaryrelease.`date '+%Y%m%d'`.tar.${COMPRESSEXT}
+
+otherdocrelease:
+	export COPYFILE_DISABLE=true; \
+	export COPY_EXTENDED_ATTRIBUTES_DISABLE=true; \
+	${TAR} -cv -f - ${OTHERDOCRELEASEFILES} | ${COMPRESS} > pixelmedjavacodec_otherdocsrelease.`date '+%Y%m%d'`.tar.${COMPRESSEXT}
+
+dependencyrelease:	.exclude.list
+	export COPYFILE_DISABLE=true; \
+	export COPY_EXTENDED_ATTRIBUTES_DISABLE=true; \
+	${TAR} -cv -X .exclude.list -f - ${DEPENDENCYRELEASEFILES} | ${COMPRESS} > pixelmedjavacodec_dependencyrelease.`date '+%Y%m%d'`.tar.${COMPRESSEXT}
+
+sourcerelease: clean .exclude.list #clean javadoc doxygen
+	export COPYFILE_DISABLE=true; \
+	export COPY_EXTENDED_ATTRIBUTES_DISABLE=true; \
+	${TAR} -cv -X .exclude.list -f - ${SOURCERELEASEFILES} | ${COMPRESS} > pixelmedjavacodec_sourcerelease.`date '+%Y%m%d'`.tar.${COMPRESSEXT}
+
+javadocrelease:  .exclude.list #clean javadoc doxygen
+	export COPYFILE_DISABLE=true; \
+	export COPY_EXTENDED_ATTRIBUTES_DISABLE=true; \
+	${TAR} -cv -X .exclude.list -f - ${JAVADOCRELEASEFILES} | ${COMPRESS} > pixelmedjavacodec_javadocrelease.`date '+%Y%m%d'`.tar.${COMPRESSEXT}
+
+doxygenrelease: .exclude.list #clean javadoc doxygen
+	export COPYFILE_DISABLE=true; \
+	export COPY_EXTENDED_ATTRIBUTES_DISABLE=true; \
+	${TAR} -cv -X .exclude.list -f - ${DOXYGENRELEASEFILES} | ${COMPRESS} > pixelmedjavacodec_doxygenrelease.`date '+%Y%m%d'`.tar.${COMPRESSEXT}
+
+.exclude.list:	Makefile
+	echo "Making .exclude.list"
+	echo ".DS_Store" > $@
+	echo ".directory" >> $@
+	echo "*.tar.gz" >> $@
+	echo "*.tar.bz2" >> $@
+	echo "*.tar.bz2" >> $@
+	#ls *.jar | grep -v 'pixelmed_codec.jar' >> $@
+	echo "cleanerdst.*" >> $@
+	echo "cleanersrc.*" >> $@
+	#find . -path  '*/cleanerdst.*' | sed 's/[.][/]//' >>$@
+	#find . -path  '*/cleanersrc.*' | sed 's/[.][/]//' >>$@
+	find . -path '*/NOTES*' | sed 's/[.][/]//' >>$@
+	find . -path '*/CVS*' | sed 's/[.][/]//' >>$@
+	echo "com/pixelmed/web/favicon.ill" >> $@
+	#cat $@
+
+# used to link to "http://www.junit.org/apidocs/" but this no longer works ... use version-specific "http://javasourcecode.org/html/open-source/junit/junit-4.8.1/" instead
+javadoc:
+	rm -rf docs/javadoc
+	javadoc \
+		-classpath .:lib/additional/excalibur-bzip2-1.0.jar:lib/additional/hsqldb.jar:lib/additional/vecmath1.2-1.14.jar:lib/additional/commons-codec-1.3.jar:lib/additional/commons-net-ftp-2.0.jar:lib/additional/jmdns.jar:lib/additional/jpedalSTD.jar:lib/junit/junit-4.8.1.jar \
+		-link http://download.oracle.com/javase/1.5.0/docs/api/ \
+		-link http://jpedal.org/javadoc/ \
+		-link http://www.hsqldb.org/doc/src/ \
+		-link http://javasourcecode.org/html/open-source/junit/junit-4.8.1/ \
+		-protected -d docs/javadoc \
+		-encoding "UTF8" \
+		${SUBPACKAGES}
+
+doxygen:
+	rm -rf docs/doxygen
+	doxygen Doxyfile
+
+installinpixelmed:	pixelmed_codec.jar
+	cp $< ../pixelmed/imgbook/lib/additional/
+
diff --git a/Makefile.common.mk b/Makefile.common.mk
new file mode 100644
index 0000000..04001cc
--- /dev/null
+++ b/Makefile.common.mk
@@ -0,0 +1,25 @@
+#
+# Note that PATHTOROOT must have been specified prior to including this file
+#
+
+JUNITJAR = ${PATHTOROOT}/lib/junit/junit-4.8.1.jar
+
+PATHTOTESTFILESFROMROOT = ./testpaths
+
+PATHTOTESTRESULTSFROMROOT = ./testresults
+
+JAVAVERSIONTARGET=1.7
+
+JAVACTARGETOPTIONS=-target ${JAVAVERSIONTARGET} -source ${JAVAVERSIONTARGET} -bootclasspath $${JAVAVERSIONTARGETJARFILE}
+
+.SUFFIXES:	.class .java .ico .png
+
+JAVACOPTIONS = -O ${JAVACTARGETOPTIONS} -encoding "UTF8" -Xlint:deprecation
+
+.java.class:
+	export JAVAVERSIONTARGETJARFILE=`/usr/libexec/java_home -v ${JAVAVERSIONTARGET} | tail -1`/jre/lib/rt.jar; javac ${JAVACOPTIONS} \
+		-classpath ${PATHTOROOT} \
+		-sourcepath ${PATHTOROOT} $<
+
+clean:
+	rm -f *~ *.class core *.bak
diff --git a/README b/README
new file mode 100644
index 0000000..66e3383
--- /dev/null
+++ b/README
@@ -0,0 +1,6 @@
+20141206. DAC.
+
+This is the PixelMed Publishing pure Java codec for selective block redaction of
+baseline process (8 bit, DCT, Huffman coded) JPEG images.
+
+Development of this package was supported by funding from MDDX Research and Informatics.
diff --git a/com/pixelmed/codec/jpeg/EntropyCodedSegment.java b/com/pixelmed/codec/jpeg/EntropyCodedSegment.java
new file mode 100644
index 0000000..c084b79
--- /dev/null
+++ b/com/pixelmed/codec/jpeg/EntropyCodedSegment.java
@@ -0,0 +1,401 @@
+/* Copyright (c) 2014, David A. Clunie DBA Pixelmed Publishing. All rights reserved. */
+
+package com.pixelmed.codec.jpeg;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+/**
+ * <p>A JPEG Entropy Coded Segment.</p>
+ *
+ * <p>Development of this class was supported by funding from MDDX Research and Informatics.</p>
+ *
+ * @author	dclunie
+ */
+public class EntropyCodedSegment {
+
+	private static final String identString = "@(#) $Header: /userland/cvs/codec/com/pixelmed/codec/jpeg/EntropyCodedSegment.java,v 1.13 2014/03/29 21:58:47 dclunie Exp $";
+
+	private boolean copying;
+
+	private ByteArrayOutputStream copiedBytes;
+		
+	private final int restartinterval;
+ 	private final MarkerSegmentSOS sos;
+ 	private final MarkerSegmentSOF sof;
+ 	private final Map<String,HuffmanTable> htByClassAndIdentifer;
+ 	private final Map<String,QuantizationTable> qtByIdentifer;
+	
+	// copied from com.pixelmed.scpecg.HuffmanDecoder ...
+	private byte[] bytesToDecompress;
+	private int availableBytes;
+	private int byteIndex;
+	private int bitIndex;
+	private int currentByte;
+	private int currentBits;
+	private int haveBits;
+
+	private static final int[] extractBitFromByteMask = { 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01 };
+	
+	private final void getEnoughBits(int wantBits) throws Exception {
+		while (haveBits < wantBits) {
+			if (bitIndex > 7) {
+				if (byteIndex < availableBytes) {
+					currentByte=bytesToDecompress[byteIndex++];
+//System.err.println("currentByte["+byteIndex+"] now = 0x"+Integer.toHexString(currentByte&0xff)+" "+Integer.toBinaryString(currentByte&0xff));
+					bitIndex=0;
+				}
+				else {
+					throw new Exception("No more bits (having decompressed "+byteIndex+" dec bytes)");
+				}
+			}
+			int newBit = (currentByte & extractBitFromByteMask[bitIndex++]) == 0 ? 0 : 1;
+			currentBits = (currentBits << 1) + newBit;
+			++haveBits;
+		}
+//System.err.println("getEnoughBits(): returning "+haveBits+" bits "+Integer.toBinaryString(currentBits)+" (ending at byte "+byteIndex+" bit "+(bitIndex-1)+")");
+	}
+	
+	private int writeByte;		// only contains meaningful content when writeBitIndex > 0
+	private int writeBitIndex;	// 0 means ready to write 1st (high) bit to writeByte, 7 means ready to write last (low) bit to writeByte, will transiently (inside writeBits only) be 8 to signal new byte needed
+	
+	private final void initializeWriteBits() {
+		copiedBytes = new ByteArrayOutputStream();
+		writeByte = 0;
+		writeBitIndex = 0;	// start writing into 1st (high) bit of writeByte
+	}
+	
+	private final void flushWriteBits() {
+		if (writeBitIndex > 0) {
+			// bits have been written to writeByte so need to pad it with 1s and write it
+			while (writeBitIndex < 8) {
+				writeByte = writeByte | extractBitFromByteMask[writeBitIndex];
+				++writeBitIndex;
+			}
+			copiedBytes.write(writeByte);
+			if ((writeByte&0xff) == 0xff) {
+				copiedBytes.write(0);	// stuffed zero byte after 0xff to prevent being considered marker
+			}
+			writeByte=0;
+			writeBitIndex=0;
+		}
+		// else have not written any bits to writeByte, so do nothing
+	}
+	
+	private final void writeBits(int bits,int nBits) {
+//System.err.println("writeBits(): writing "+nBits+" bits "+Integer.toBinaryString(bits));
+		if (nBits > 0) {
+			for (int i=nBits-1; i>=0; --i) {
+				final int whichBitMask = 1 << i;			// bits are "big endian"
+				final int bitIsSet = bits & whichBitMask;	// zero or not zero
+				// do not need to check writeBitIndex before "writing" ... will always be "ready"
+				if (bitIsSet != 0) {
+					writeByte = writeByte | extractBitFromByteMask[writeBitIndex];
+				}
+				++writeBitIndex;
+				if (writeBitIndex > 7) {
+//System.err.println("writeBits(): wrote = 0x"+Integer.toHexString(writeByte&0xff)+" "+Integer.toBinaryString(writeByte&0xff));
+					copiedBytes.write(writeByte);
+					if ((writeByte&0xff) == 0xff) {
+						copiedBytes.write(0);	// stuffed zero byte after 0xff to prevent being considered marker
+					}
+					writeByte=0;
+					writeBitIndex=0;
+				}
+			}
+		}
+	}
+
+
+	
+	private HuffmanTable usingTable = null;
+	
+//int counter = 0;
+	
+	// Use 10918-1 F.2 Figure F.16 decode procedure
+	
+	/**
+	 * <p>Decode a single value.</p>
+	 *
+	 * @return	the decoded value
+	 */
+	private final int decode()  throws Exception {
+		final int[] MINCODE = usingTable.getMINCODE();
+		final int[] MAXCODE = usingTable.getMAXCODE();
+		final int[] VALPTR  = usingTable.getVALPTR();
+		final int[] HUFFVAL = usingTable.getHUFFVAL();
+	
+		int I=1;
+		getEnoughBits(I);		// modifies currentBits
+		int CODE = currentBits;
+		while (I<MAXCODE.length && CODE > MAXCODE[I]) {
+		//while (CODE > MAXCODE[I]) {
+			++I;
+//System.err.println("I = "+I);
+			getEnoughBits(I);	// modifies currentBits
+			CODE = currentBits;
+//System.err.println("CODE "+Integer.toBinaryString(CODE));
+//System.err.println("compare to MAXCODE[I] "+(I<MAXCODE.length ? Integer.toBinaryString(MAXCODE[I]) : "out of MAXCODE entries"));
+		}
+//System.err.println("Found CODE "+Integer.toBinaryString(CODE));
+		int VALUE = 0;
+		if (I<MAXCODE.length) {
+			int J = VALPTR[I];
+//System.err.println("Found VALPTR base "+J);
+			J = J + CODE - MINCODE[I];
+//System.err.println("Found VALPTR offset by code "+J);
+			VALUE = HUFFVAL[J];
+//System.err.println("Found VALUE "+VALUE+" dec (0x"+Integer.toHexString(VALUE)+")");
+//System.err.println("HUFF_DECODE: "+VALUE+" COUNTER "+counter);
+//++counter;
+		}
+		else {
+			//we have exceeded the maximum coded value specified :(
+			// copy IJG behavior in this situation from jdhuff.c "With garbage input we may reach the sentinel value l = 17" ... "fake a zero as the safest result"
+//System.err.println("Bad Huffman code "+Integer.toBinaryString(CODE)+" so use VALUE "+VALUE+" dec (0x"+Integer.toHexString(VALUE)+")");
+		}
+		if (copying) { writeBits(currentBits,haveBits); }
+		currentBits=0;
+		haveBits=0;
+		return VALUE;
+	}
+	
+	private final int getValueOfRequestedLength(int wantBits) throws Exception {
+		getEnoughBits(wantBits);	// modifies currentBits
+		final int value = currentBits;
+//System.err.println("getValueOfRequestedLength(): wantBits="+wantBits+" : Got value "+value+" dec (0x"+Integer.toHexString(value)+")");
+		if (copying) { writeBits(currentBits,haveBits); }
+		currentBits=0;
+		haveBits=0;
+		return value;
+	}
+
+	// values above index 11 only occur for 12 bit process ...
+	private int[] dcSignBitMask = { 0x00/*na*/,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x100,0x200,0x400,0x800,0x1000,0x2000,0x4000 /*no entry for 16*/};
+
+	private final int convertSignAndAmplitudeBitsToValue(int value,int length) throws Exception {
+		// see P&M Table 11-1 page 190 and Table 11-4 page 193 (same for DC and AC)
+		if (length > 0) {
+//System.err.println("dcSignBitMask = "+Integer.toHexString(dcSignBitMask[length]));
+			if ((value & dcSignBitMask[length]) == 0) {
+//System.err.println("Have sign bit");
+				value = - value - 1;
+			}
+		}
+		return value;
+	}
+	
+	private final void writeEntropyCodedAllZeroACCoefficients() {
+		// write a single EOB code, which is rrrrssss = 0x00;
+		writeBits(usingTable.getEOBCode(),usingTable.getEOBCodeLength());
+	}
+	
+	
+	public EntropyCodedSegment(int restartinterval,MarkerSegmentSOS sos,MarkerSegmentSOF sof,Map<String,HuffmanTable> htByClassAndIdentifer,Map<String,QuantizationTable> qtByIdentifer,boolean copying,boolean dumping) {
+ 		this.restartinterval = restartinterval;
+ 		this.sos = sos;
+ 		this.sof = sof;
+ 		this.htByClassAndIdentifer = htByClassAndIdentifer;
+ 		this.qtByIdentifer = qtByIdentifer;
+		this.copying = copying;
+		
+		if (dumping) dumpHuffmanTables();
+		//dumpQuantizationTables();
+	}
+	
+	// A "data unit" is the "smallest logical unit that can be processed", which in the case of DCT-based processes is one 8x8 block of coefficients (P&M page 101)
+	private final void getOneDCTDataUnit(int dcEntropyCodingTableSelector,int acEntropyCodingTableSelector,boolean redact) throws Exception {
+		usingTable = htByClassAndIdentifer.get("0+"+Integer.toString(dcEntropyCodingTableSelector));
+		{
+			final int ssss = decode();	// number of DC bits encoded next
+			// see P&M Table 11-1 page 190
+			int dcValue = 0;
+			if (ssss == 0) {
+				dcValue = 0;
+			}
+			else if (ssss == 16) {	// only occurs for lossless
+				dcValue = 32768;
+			}
+			else {
+				final int dcBits = getValueOfRequestedLength(ssss);
+				dcValue = convertSignAndAmplitudeBitsToValue(dcBits,ssss);
+			}
+//System.err.println("Got DC value "+dcValue+" dec (0x"+Integer.toHexString(dcValue)+")");
+		}
+		
+		usingTable = htByClassAndIdentifer.get("1+"+Integer.toString(acEntropyCodingTableSelector));
+		
+		final boolean restoreCopying = copying;
+		if (redact && copying) {
+			copying = false;
+			writeEntropyCodedAllZeroACCoefficients();
+		}
+		
+		int i=1;
+		while (i<64) {
+//System.err.println("AC ["+i+"]:");
+			final int rrrrssss = decode();
+			if (rrrrssss == 0) {
+//System.err.println("AC ["+i+"]: "+"EOB");
+				break; // EOB
+			}
+			else if (rrrrssss == 0xF0) {
+//System.err.println("AC ["+i+"]: "+"ZRL: 16 zeroes");
+				i+=16;
+			}
+			else {
+				// note that ssss of zero is not used for AC (unlike DC) in sequential mode
+				final int rrrr = rrrrssss >>> 4;
+				final int ssss = rrrrssss & 0x0f;
+//System.err.println("AC ["+i+"]: rrrr="+rrrr+" ssss="+ssss);
+				final int acBits = getValueOfRequestedLength(ssss);
+				final int acValue = convertSignAndAmplitudeBitsToValue(acBits,ssss);
+//System.err.println("AC ["+i+"]: "+rrrr+" zeroes then value "+acValue);
+				i+=rrrr;	// the number of zeroes
+				++i;		// the value we read (ssss is always non-zero, so we always read something
+			}
+		}
+		
+		copying = restoreCopying;
+	}
+	
+	private final boolean redactionDecision(int colMCU,int rowMCU,int thisHorizontalSamplingFactor,int thisVerticalSamplingFactor,int maxHorizontalSamplingFactor,int maxVerticalSamplingFactor,int h,int v,Vector<Shape> redactionShapes) {
+		final int vMCUSize = 8 * maxVerticalSamplingFactor;
+		final int hMCUSize = 8 * maxHorizontalSamplingFactor;
+//System.err.println("MCUSize in pixels = "+hMCUSize+" * "+vMCUSize);
+		
+		final int hMCUOffset = colMCU * hMCUSize;
+		final int vMCUOffset = rowMCU * vMCUSize;
+//System.err.println("MCUOffset in pixels = "+hMCUOffset+" * "+vMCUOffset);
+		
+		final int hBlockSize = 8 * maxHorizontalSamplingFactor/thisHorizontalSamplingFactor;
+		final int vBlockSize = 8 * maxVerticalSamplingFactor/thisVerticalSamplingFactor;
+//System.err.println("BlockSize in pixels = "+hBlockSize+" * "+vBlockSize);
+		
+		final int xBlock = hMCUOffset + h * hBlockSize;
+		final int yBlock = vMCUOffset + v * vBlockSize;
+		
+		Rectangle blockShape = new Rectangle(xBlock,yBlock,hBlockSize,vBlockSize);
+//System.err.println("blockShape "+blockShape);
+		
+		boolean redact = false;
+		if (redactionShapes != null) {
+			for (Shape redactionShape : redactionShapes) {
+				if (redactionShape.intersects(blockShape)) {
+					redact = true;
+					break;
+				}
+			}
+		}
+		return redact;
+	}
+	
+	private final void getOneMinimumCodedUnit(int nComponents,int[] DCEntropyCodingTableSelector,int[] ACEntropyCodingTableSelector,int[] HorizontalSamplingFactor,int[] VerticalSamplingFactor,int maxHorizontalSamplingFactor,int maxVerticalSamplingFactor,int colMCU,int rowMCU,Vector<Shape> redactionShapes) throws Exception {
+		for (int c=0; c<nComponents; ++c) {
+			// See discussion of interleaving of data units within MCUs in P&M section 7.3.5 pages 101-105; always interleaved in sequential mode
+			for (int v=0; v<VerticalSamplingFactor[c]; ++v) {
+				for (int h=0; h<HorizontalSamplingFactor[c]; ++h) {
+//System.err.println("Component "+c+" v "+v+" h "+h);
+					boolean redact = redactionDecision(colMCU,rowMCU,HorizontalSamplingFactor[c],VerticalSamplingFactor[c],maxHorizontalSamplingFactor,maxVerticalSamplingFactor,h,v,redactionShapes);
+					getOneDCTDataUnit(DCEntropyCodingTableSelector[c],ACEntropyCodingTableSelector[c],redact);
+				}
+			}
+		}
+	}
+	
+	private static final int max(int[] a) {
+		int m = Integer.MIN_VALUE;
+		for (int i : a) {
+			if (i > m) m = i;
+		}
+		return m;
+	}
+	
+	/**
+	 * <p>Decode the supplied bytes that comprise a complete EntropyCodedSeqment and redact or copy them as required.</p>
+	 *
+	 * @param	bytesToDecompress	the bytes in the EntropyCodedSeqment
+	 * @param	mcuCount			the number of MCUs encoded by this EntropyCodedSeqment
+	 * @param	nMCUHorizontally	the number of MCUs in a single row
+	 * @param	mcuOffset			the number of MCUs that have previously been read for the frame containing this EntropyCodedSeqment
+	 * @param	redactionShapes		a Vector of Shape that are Rectangle
+	 * @return						the bytes in a copy of the EntropyCodedSeqment appropriately redacted
+	 * @exception Exception			if bad things happen parsing the EntropyCodedSeqment, like running out of bits, caused by malformed input
+	 * @exception IOException		if bad things happen reading or writing the bytes
+	 */
+	public final byte[] finish(byte[] bytesToDecompress,int mcuCount,int nMCUHorizontally,int mcuOffset,Vector<Shape> redactionShapes) throws Exception, IOException {
+		this.bytesToDecompress = bytesToDecompress;
+		availableBytes = this.bytesToDecompress.length;
+		byteIndex = 0;
+		bitIndex = 8;	// force fetching byte the first time
+		haveBits = 0;	// don't have any bits to start with
+		
+		if (copying) {
+			initializeWriteBits();		// will create a new ByteArrayOutputStream
+		}
+		
+		//try {
+		
+		final int nComponents = sos.getNComponentsPerScan();
+		final int[] DCEntropyCodingTableSelector = sos.getDCEntropyCodingTableSelector();
+		final int[] ACEntropyCodingTableSelector = sos.getACEntropyCodingTableSelector();
+		final int[] HorizontalSamplingFactor = sof.getHorizontalSamplingFactor();
+		final int[] VerticalSamplingFactor   = sof.getVerticalSamplingFactor();
+		
+		final int maxHorizontalSamplingFactor = max(HorizontalSamplingFactor);
+//System.err.println("maxHorizontalSamplingFactor "+maxHorizontalSamplingFactor);
+		final int maxVerticalSamplingFactor   = max(VerticalSamplingFactor);
+//System.err.println("maxVerticalSamplingFactor "+maxVerticalSamplingFactor);
+		
+		for (int mcu=0; mcu<mcuCount; ++mcu) {
+			int rowMCU = mcuOffset / nMCUHorizontally;
+			int colMCU = mcuOffset % nMCUHorizontally;
+//System.err.println("MCU ("+colMCU+","+rowMCU+")");
+			getOneMinimumCodedUnit(nComponents,DCEntropyCodingTableSelector,ACEntropyCodingTableSelector,HorizontalSamplingFactor,VerticalSamplingFactor,maxHorizontalSamplingFactor,maxVerticalSamplingFactor,colMCU,rowMCU,redactionShapes);
+			++mcuOffset;
+		}
+
+//System.err.println("Finished ...");
+//System.err.println("availableBytes = "+availableBytes);
+//System.err.println("byteIndex = "+byteIndex);
+//System.err.println("bitIndex = "+bitIndex);
+//System.err.println("currentByte = "+currentByte);
+//System.err.println("currentBits = "+currentBits);
+//System.err.println("haveBits = "+haveBits);
+		
+		//}
+		//catch (Exception e) {
+		//	e.printStackTrace(System.err);
+		//}
+
+		if (copying) {
+			flushWriteBits();		// will pad appropriately to byte boundary
+		}
+		
+		return copying ? copiedBytes.toByteArray() : null;
+	}
+		
+	private final void dumpHuffmanTables() {
+		System.err.print("\n");
+		for (HuffmanTable ht : htByClassAndIdentifer.values()) {
+			System.err.print(ht.toString());
+		}
+	}
+	
+	private final void dumpQuantizationTables() {
+		System.err.print("\n");
+		for (QuantizationTable qt : qtByIdentifer.values()) {
+			System.err.print(qt.toString());
+		}
+	}
+	
+}
+
diff --git a/com/pixelmed/codec/jpeg/HuffmanTable.java b/com/pixelmed/codec/jpeg/HuffmanTable.java
new file mode 100644
index 0000000..d2da3e9
--- /dev/null
+++ b/com/pixelmed/codec/jpeg/HuffmanTable.java
@@ -0,0 +1,188 @@
+/* Copyright (c) 2014, David A. Clunie DBA Pixelmed Publishing. All rights reserved. */
+
+package com.pixelmed.codec.jpeg;
+
+/**
+ * <p>A JPEG Huffman Table.</p>
+ *
+ * @author	dclunie
+ */
+public class HuffmanTable {
+
+	private static final String identString = "@(#) $Header: /userland/cvs/codec/com/pixelmed/codec/jpeg/HuffmanTable.java,v 1.4 2014/03/23 11:41:54 dclunie Exp $";
+
+	private int TableClass;
+	private int HuffmanTableIdentifier;
+	private int[] nHuffmanCodesOfLengthI;
+	private int[][] ValueOfHuffmanCodeIJ;
+	
+	public HuffmanTable(int TableClass,int HuffmanTableIdentifier,int[] nHuffmanCodesOfLengthI,int[][] ValueOfHuffmanCodeIJ) {
+		this.TableClass = TableClass;
+		this.HuffmanTableIdentifier = HuffmanTableIdentifier;
+		this.nHuffmanCodesOfLengthI = nHuffmanCodesOfLengthI;
+		this.ValueOfHuffmanCodeIJ = ValueOfHuffmanCodeIJ;
+		expand();
+	}
+	
+	private int countNumberOfCodes() {
+		int count=0;
+		for (int i=0; i<nHuffmanCodesOfLengthI.length; ++i) {
+			count += nHuffmanCodesOfLengthI[i];
+		}
+		return count;
+	}
+	
+	// a literal implementation of 10918-1 F.2.2.3 and figure F.15
+	
+	private int[] BITS = new int[17];		// number of codes of each size for code size I 1-16 (index 0 unused)
+	
+	private int[] HUFFVAL;		// array of values in same order as encoded in ValueOfHuffmanCodeIJ with dimension nCodes + 1 to account for unused 0 index
+	private int[] HUFFSIZE;
+	private int[] HUFFCODE;
+	
+	private int[] MINCODE = new int[17];	// the smallest code value for code size I 1-16 (index 0 unused)
+	private int[] MAXCODE = new int[17];	// the largest  code value for code size I 1-16 (index 0 unused)
+	private int[] VALPTR  = new int[17];	// index to the start of the list of values in HUFFVAL (indexed from 1 not 0)
+
+	public int[] getMINCODE() { return MINCODE; };
+	public int[] getMAXCODE() { return MAXCODE; };
+	public int[] getVALPTR()  { return VALPTR; };
+	public int[] getHUFFVAL() { return HUFFVAL; };
+	
+	// for our redaction purposes, we need to replace AC coefficients with all zeroes (EOB), so take note of this code whilst expanding tables
+	private int EOBCode;
+	private int EOBCodeLength;
+	
+	public int getEOBCode()			{ return EOBCode; }
+	public int getEOBCodeLength()	{ return EOBCodeLength; }
+
+		
+	private void expand() {
+//System.err.println("HuffmanTable.expand(): class="+TableClass+" identifier="+HuffmanTableIdentifier);
+
+		// list BITS(1..16) number of codes of each size ... is nHuffmanCodesOfLengthI(0..15)
+		for (int I=1; I<=16; ++I) {
+//System.err.println("HuffmanTable.expand(): I="+I);
+			BITS[I] = nHuffmanCodesOfLengthI[I-1];
+		}
+		
+		int nCodes = countNumberOfCodes();
+		// HUFFVAL is a flat list of codes in the order read they are encoded in the DHT segment, which is already sorted into ascending orded
+		{
+			HUFFVAL = new int[nCodes+1];
+			int J = 0;	// N.B. This is one of the few tables in ISO 10918-1 that starts with an index of zero, not one; must match VALPTR values used as indices into HUFFVAL
+			for (int i=0; i<nHuffmanCodesOfLengthI.length; ++i) {
+				int nCodesThisLength = nHuffmanCodesOfLengthI[i];
+				if (nCodesThisLength > 0) {
+					for (int j=0; j<nCodesThisLength; ++j) {
+						HUFFVAL[J] = ValueOfHuffmanCodeIJ[i][j];
+						++J;
+					}
+				}
+			}
+		}
+		
+		// 10918-1 C.2 Figure C.1 Generate_size_table
+		// HUFFSIZE contains a list of code lengths
+		//int LASTK = 0;
+		HUFFSIZE = new int[nCodes+1];
+		{
+			int K=0;
+			int I=1;
+			int J=1;
+			while (true) {
+				if (J > BITS[I]) {
+					++I;
+					J=1;
+					if (I > 16) {
+						HUFFSIZE[K] = 0;
+						//LASTK = K;
+						break;
+					}
+				}
+				else {
+					HUFFSIZE[K] = I;
+					++K;
+					++J;
+				}
+			}
+		}
+
+		// 10918-1 C.2 Figure C.2 Generate_code_table
+		// HUFFCODE contains a code for each size in HUFFSIZE
+		HUFFCODE = new int[nCodes+1];
+		{
+			int K=0;
+			int CODE=0;
+			int SI = HUFFSIZE[0];
+			while (true) {
+				HUFFCODE[K] = CODE;
+				++CODE;
+				++K;
+				if (SI != HUFFSIZE[K]) {
+					if (HUFFSIZE[K] == 0) break;
+					do {
+						CODE = CODE << 1;
+						++SI;
+					} while (SI != HUFFSIZE[K]);
+				}
+			
+			}
+		}
+		
+		// 10918-1 C.2 Figure F.15 Decoder_tables generation
+		{
+			int I=0;
+			int J=0;
+			while (true) {
+				++I;
+				if (I > 16) break;
+				if (BITS[I] == 0) {
+					MAXCODE[I] = -1;
+				}
+				else {
+					VALPTR[I] = J;
+					MINCODE[I] = HUFFCODE[J];
+					J = J + BITS[I] - 1;
+					MAXCODE[I] = HUFFCODE[J];
+					++J;
+				}
+			}
+		}
+		
+		// walk the arrays to find the EOB code and its length
+		{
+			for (int I=1; I<=16; ++I) {
+				for (int J = VALPTR[I]; J < VALPTR[I] + BITS[I]; ++J) {
+					if (HUFFVAL[J] == 0) {	// 0x00 is the EOB code (rrrrssss == 0)
+						EOBCode = HUFFCODE[J];
+						EOBCodeLength = I;
+					}
+				}
+			}
+		}
+	}
+	
+	public String toString() {
+		StringBuffer buf = new StringBuffer();
+		buf.append("Huffman Table:\n");
+		buf.append("\t TableClass = "            +TableClass+"\n");
+		buf.append("\t HuffmanTableIdentifier = "+HuffmanTableIdentifier+"\n");
+		for (int i=0; i<16; ++i) {
+			buf.append("\t\t nHuffmanCodesOfLength "+i+" = "+nHuffmanCodesOfLengthI[i]+"\n");
+			for (int j=0; j<nHuffmanCodesOfLengthI[i];++j) {
+				buf.append("\t\t\t ValueOfHuffmanCode "+j+" = "+ValueOfHuffmanCodeIJ[i][j]+"\n");
+			}
+		}
+		buf.append("\t Expanded:\n");
+		for (int I=1; I<=16; ++I) {
+			buf.append("\t\t["+I+"] MINCODE="+Integer.toBinaryString(MINCODE[I])+" MAXCODE="+Integer.toBinaryString(MAXCODE[I])+""+" VALPTR="+VALPTR[I]+"\n");
+		}
+		for (int J=0; J<HUFFVAL.length; ++J) {
+			buf.append("\t\t["+J+"] HUFFVAL=0x"+Integer.toHexString(HUFFVAL[J])+"\n");
+		}
+		buf.append("\t\tEOBCode="+Integer.toBinaryString(EOBCode)+" 0x"+Integer.toHexString(EOBCode)+" (length "+EOBCodeLength+" dec)\n");
+		return buf.toString();
+	}
+
+}
diff --git a/com/pixelmed/codec/jpeg/Makefile b/com/pixelmed/codec/jpeg/Makefile
new file mode 100755
index 0000000..ff9a849
--- /dev/null
+++ b/com/pixelmed/codec/jpeg/Makefile
@@ -0,0 +1,53 @@
+OBJS = \
+	EntropyCodedSegment.class \
+	HuffmanTable.class \
+	Markers.class \
+	MarkerSegmentAPP0JFIF.class \
+	MarkerSegmentDHT.class \
+	MarkerSegmentDQT.class \
+	MarkerSegmentSOF.class \
+	MarkerSegmentSOS.class \
+	Parse.class \
+	QuantizationTable.class \
+	Utilities.class
+
+all:	${OBJS}
+
+PATHTOROOT = ../../../..
+
+include ${PATHTOROOT}/Makefile.common.mk
+
+clean:
+	rm -f *~ *.class core *.bak
+
+testparse:	${OBJS}
+	rm -f /tmp/crap_copied.jpg
+	rm -f /tmp/crap_source.jpg
+	cp -v \
+		"$${HOME}/Documents/Clients/MDDX/Experiment20130905/crap.jpg" \
+		/tmp/crap_source.jpg
+	java -cp ${PATHTOROOT} com.pixelmed.codec.jpeg.Parse \
+		/tmp/crap_source.jpg \
+		/tmp/crap_copied.jpg
+	@echo "Comparing source and copied ... may fail with EOF if padding after EOI marker that is not copied, which is OK"
+	cmp /tmp/crap_source.jpg /tmp/crap_copied.jpg
+	@echo "Finished comparing"
+	hexdump -C /tmp/crap_source.jpg | tail -3
+	hexdump -C /tmp/crap_copied.jpg | tail -3
+
+# without restart and working
+		#"$${HOME}/Documents/Medical/compression/JPEG/10918-1/jpeg-6/testimg.jpg"
+		#"${PATHTOROOT}/${PATHTOTESTFILESFROMROOT}/colorpngresavedfrompreview.jpg"
+		#"${PATHTOROOT}/${PATHTOTESTFILESFROMROOT}/huff_simple0.jpg"
+		#"$${HOME}/Documents/Clients/MDDX/Experiment20130905/crap.jpg"
+		#"${PATHTOROOT}/${PATHTOTESTFILESFROMROOT}/smpte_8_q1.jpg"
+
+# without restart and not working
+
+# with restart and working
+		#"$${HOME}/Pictures/Interesting/clunie_737_cropped_close.jpg"
+		#"${PATHTOROOT}/${PATHTOTESTFILESFROMROOT}/smpte_8_cjpeg_rst1.jpg"
+		#"/tmp/crap.jpg"
+
+# with restart and not working
+
diff --git a/com/pixelmed/codec/jpeg/MarkerSegmentAPP0JFIF.java b/com/pixelmed/codec/jpeg/MarkerSegmentAPP0JFIF.java
new file mode 100644
index 0000000..e774c71
--- /dev/null
+++ b/com/pixelmed/codec/jpeg/MarkerSegmentAPP0JFIF.java
@@ -0,0 +1,44 @@
+/* Copyright (c) 2014, David A. Clunie DBA Pixelmed Publishing. All rights reserved. */
+
+package com.pixelmed.codec.jpeg;
+
+/**
+ * <p>A JPEG APP0 JFIF Marker Segment.</p>
+ *
+ * @author	dclunie
+ */
+public class MarkerSegmentAPP0JFIF {
+
+	private static final String identString = "@(#) $Header: /userland/cvs/codec/com/pixelmed/codec/jpeg/MarkerSegmentAPP0JFIF.java,v 1.1 2014/03/21 15:28:07 dclunie Exp $";
+	
+	private int version;
+	private int units;
+	private int Xdensity;
+	private int Ydensity;
+	private int Xthumbnail;
+	private int Ythumbnail;
+
+	public MarkerSegmentAPP0JFIF(byte[] b,int length) {
+		// identifier is 4 bytes plus a zero byte
+		version=Utilities.extract16be(b,5);
+		units=Utilities.extract8(b,7);
+		Xdensity=Utilities.extract16be(b,8);
+		Ydensity=Utilities.extract16be(b,10);
+		Xthumbnail=Utilities.extract8(b,12);
+		Ythumbnail=Utilities.extract8(b,13);
+	}
+
+	public String toString() {
+		StringBuffer buf = new StringBuffer();
+		buf.append("\n\tAPP0 JFIF:\n");
+		buf.append("\t\t Version = "+Utilities.toPaddedHexString(version,2)+"\n");
+		buf.append("\t\t Units for the X and Y densities = "+units+"\n");
+		buf.append("\t\t Horizontal pixel density = "+Xdensity+"\n");
+		buf.append("\t\t Vertical pixel density = "+Ydensity+"\n");
+		buf.append("\t\t Thumbnail horizontal pixel count = "+Xthumbnail+"\n");
+		buf.append("\t\t Thumbnail vertical pixel count = "+Ythumbnail+"\n");
+		return buf.toString();
+	}
+
+}
+
diff --git a/com/pixelmed/codec/jpeg/MarkerSegmentDHT.java b/com/pixelmed/codec/jpeg/MarkerSegmentDHT.java
new file mode 100644
index 0000000..74cd47f
--- /dev/null
+++ b/com/pixelmed/codec/jpeg/MarkerSegmentDHT.java
@@ -0,0 +1,83 @@
+/* Copyright (c) 2014, David A. Clunie DBA Pixelmed Publishing. All rights reserved. */
+
+package com.pixelmed.codec.jpeg;
+
+import java.util.Map;
+
+/**
+ * <p>A JPEG DHT Marker Segment.</p>
+ *
+ * @author	dclunie
+ */
+public class MarkerSegmentDHT {
+
+	private static final String identString = "@(#) $Header: /userland/cvs/codec/com/pixelmed/codec/jpeg/MarkerSegmentDHT.java,v 1.2 2014/03/21 21:46:20 dclunie Exp $";
+	
+	private int nTables;
+
+	private int[] TableClass;
+	private int[] HuffmanTableIdentifier;
+	private int[][] nHuffmanCodesOfLengthI;
+	private int[][][] ValueOfHuffmanCodeIJ;
+
+	public MarkerSegmentDHT(byte[] b,int length) throws Exception {
+		TableClass             = new int [4];
+		HuffmanTableIdentifier = new int [4];
+		nHuffmanCodesOfLengthI = new int [4][];
+		ValueOfHuffmanCodeIJ   = new int [4][][];
+	
+		nTables=0;
+		int offset=0;
+		while (length > 0) {
+			if (nTables >= 4) {
+				throw new Exception("Only 4 tables are permitted");
+			}
+			TableClass[nTables] = Utilities.extract8(b,offset) >> 4;
+			HuffmanTableIdentifier[nTables] = Utilities.extract8(b,offset) & 0x0f;
+			++offset; --length;
+			
+			nHuffmanCodesOfLengthI[nTables] = new int[16];
+			for (int i=0; i<16; ++i) {
+				nHuffmanCodesOfLengthI[nTables][i] = Utilities.extract8(b,offset);
+				++offset; --length;
+			}
+			
+			ValueOfHuffmanCodeIJ[nTables] = new int[16][];
+			for (int i=0; i<16; ++i) {
+				ValueOfHuffmanCodeIJ[nTables][i] = new int[nHuffmanCodesOfLengthI[nTables][i]];
+				for (int j=0; j<nHuffmanCodesOfLengthI[nTables][i]; ++j) {
+					ValueOfHuffmanCodeIJ[nTables][i][j] = Utilities.extract8(b,offset);
+					++offset; --length;
+				}
+			}
+			++nTables;
+		}
+	}
+	
+	public void addToMapByClassAndIdentifier(Map<String,HuffmanTable> htByClassAndIdentifer) {
+		for (int t=0; t<nTables; ++t) {
+			int cl = TableClass[t];
+			int id = HuffmanTableIdentifier[t];
+			String key = Integer.toString(cl) + "+" + Integer.toString(id);
+			htByClassAndIdentifer.put(key,new HuffmanTable(cl,id,nHuffmanCodesOfLengthI[t],ValueOfHuffmanCodeIJ[t]));
+		}
+	}
+
+	public String toString() {
+		StringBuffer buf = new StringBuffer();
+		buf.append("\n\tDHT:\n");
+		for (int t=0; t<nTables; ++t) {
+			buf.append("\t\t TableClass = "            +TableClass[t]+"\n");
+			buf.append("\t\t HuffmanTableIdentifier = "+HuffmanTableIdentifier[t]+"\n");
+			for (int i=0; i<16; ++i) {
+				buf.append("\t\t\t nHuffmanCodesOfLength "+i+" = "+nHuffmanCodesOfLengthI[t][i]+"\n");
+				for (int j=0; j<nHuffmanCodesOfLengthI[t][i];++j) {
+					buf.append("\t\t\t\t ValueOfHuffmanCode "+j+" = "+ValueOfHuffmanCodeIJ[t][i][j]+"\n");
+				}
+			}
+		}
+		return buf.toString();
+	}
+
+}
+
diff --git a/com/pixelmed/codec/jpeg/MarkerSegmentDQT.java b/com/pixelmed/codec/jpeg/MarkerSegmentDQT.java
new file mode 100644
index 0000000..504c6c4
--- /dev/null
+++ b/com/pixelmed/codec/jpeg/MarkerSegmentDQT.java
@@ -0,0 +1,75 @@
+/* Copyright (c) 2014, David A. Clunie DBA Pixelmed Publishing. All rights reserved. */
+
+package com.pixelmed.codec.jpeg;
+
+import java.util.Map;
+
+/**
+ * <p>A JPEG DQT Marker Segment.</p>
+ *
+ * @author	dclunie
+ */
+public class MarkerSegmentDQT {
+
+	private static final String identString = "@(#) $Header: /userland/cvs/codec/com/pixelmed/codec/jpeg/MarkerSegmentDQT.java,v 1.2 2014/03/21 21:46:20 dclunie Exp $";
+	
+	private int nTables;
+
+	private int[] QuantizationTableElementPrecision;
+	private int[] QuantizationTableIdentifier;
+	private int[][] QuantizationTableElement;
+
+	public MarkerSegmentDQT(byte[] b,int length) throws Exception {
+		QuantizationTableElementPrecision = new int [4];
+		QuantizationTableIdentifier       = new int [4];
+		QuantizationTableElement          = new int [4][];
+	
+		nTables=0;
+		int offset=0;
+		while (length > 0) {
+			if (nTables >= 4) {
+				throw new Exception("Only 4 tables are permitted");
+			}
+			
+			QuantizationTableElementPrecision[nTables] = Utilities.extract8(b,offset) >> 4;
+			QuantizationTableIdentifier[nTables]       = Utilities.extract8(b,offset) & 0x0f;
+			QuantizationTableElement[nTables]          = new int[64];
+			++offset; --length;
+			
+			for (int i=0; i<64; ++i) {
+				if (QuantizationTableElementPrecision[nTables] > 0) {
+					QuantizationTableElement[nTables][i] = Utilities.extract16be(b,offset);
+					offset+=2; length-=2;
+				}
+				else {
+					QuantizationTableElement[nTables][i] = Utilities.extract8(b,offset);
+					++offset; --length;
+				}
+			}
+			++nTables;
+		}
+	}
+
+	public void addToMapByIdentifier(Map<String,QuantizationTable> qtByIdentifer) {
+		for (int t=0; t<nTables; ++t) {
+			int id = QuantizationTableIdentifier[t];
+			String key = Integer.toString(id);
+			qtByIdentifer.put(key,new QuantizationTable(id,QuantizationTableElementPrecision[t],QuantizationTableElement[t]));
+		}
+	}
+
+	public String toString() {
+		StringBuffer buf = new StringBuffer();
+		buf.append("\n\tDQT:\n");
+		for (int t=0; t<nTables; ++t) {
+			buf.append("\t\t QuantizationTableElementPrecision = "+QuantizationTableElementPrecision[t]+"\n");
+			buf.append("\t\t QuantizationTableIdentifier = "      +QuantizationTableIdentifier[t]+"\n");
+			for (int i=0; i<64; ++i) {
+				buf.append("\t\t\t QuantizationTableElement "+i+" = "+QuantizationTableElement[t][i]+"\n");
+			}
+		}
+		return buf.toString();
+	}
+
+}
+
diff --git a/com/pixelmed/codec/jpeg/MarkerSegmentSOF.java b/com/pixelmed/codec/jpeg/MarkerSegmentSOF.java
new file mode 100644
index 0000000..067f668
--- /dev/null
+++ b/com/pixelmed/codec/jpeg/MarkerSegmentSOF.java
@@ -0,0 +1,71 @@
+/* Copyright (c) 2014, David A. Clunie DBA Pixelmed Publishing. All rights reserved. */
+
+package com.pixelmed.codec.jpeg;
+
+/**
+ * <p>A JPEG SOF Marker Segment.</p>
+ *
+ * @author	dclunie
+ */
+public class MarkerSegmentSOF {
+
+	private static final String identString = "@(#) $Header: /userland/cvs/codec/com/pixelmed/codec/jpeg/MarkerSegmentSOF.java,v 1.2 2014/03/22 09:06:13 dclunie Exp $";
+	
+	private int  SamplePrecision;
+	private int  nLines;
+	private int  nSamplesPerLine;
+	private int  nComponentsInFrame;
+	private int[] ComponentIdentifier;
+	private int[] HorizontalSamplingFactor;
+	private int[] VerticalSamplingFactor;
+	private int[] QuantizationTableDestinationSelector;
+
+	public int  getNLines() { return nLines; }
+	public int  getNSamplesPerLine() { return nSamplesPerLine; }
+
+	public int[] getHorizontalSamplingFactor() { return HorizontalSamplingFactor; }
+	public int[] getVerticalSamplingFactor()   { return VerticalSamplingFactor; }
+
+	public MarkerSegmentSOF(byte[] b,int length) throws Exception {
+		SamplePrecision    = Utilities.extract8(b,0);
+		nLines             = Utilities.extract16be(b,1);
+		nSamplesPerLine    = Utilities.extract16be(b,3);
+		nComponentsInFrame = Utilities.extract8(b,5);
+		
+		int lengthExpected = 6+nComponentsInFrame*3;
+		 if (length != lengthExpected) {
+			throw new Exception("Incorrect length of SOF Parameters Marker Segment, expected "+lengthExpected+" (based on nComponentsInFrame "+nComponentsInFrame+") but was "+length);
+		}
+		
+		ComponentIdentifier                 = new int[nComponentsInFrame];
+		HorizontalSamplingFactor            = new int[nComponentsInFrame];
+		VerticalSamplingFactor              = new int[nComponentsInFrame];
+		QuantizationTableDestinationSelector= new int[nComponentsInFrame];
+
+		for (int i=0; i<nComponentsInFrame; ++i) {
+			ComponentIdentifier[i]                  = Utilities.extract8(b,6+i*3);
+			HorizontalSamplingFactor[i]             = Utilities.extract8(b,6+i*3+1) >> 4;
+			VerticalSamplingFactor[i]               = Utilities.extract8(b,6+i*3+1) & 0x0f;
+			QuantizationTableDestinationSelector[i] = Utilities.extract8(b,6+i*3+2);
+		}
+	}
+
+	public String toString() {
+		StringBuffer buf = new StringBuffer();
+		buf.append("\n\tSOF:\n");
+		buf.append("\t\t SamplePrecision = "	+SamplePrecision+"\n");
+		buf.append("\t\t nLines = "             +nLines+"\n");
+		buf.append("\t\t nSamplesPerLine = "    +nSamplesPerLine+"\n");
+		buf.append("\t\t nComponentsInFrame = " +nComponentsInFrame+"\n");
+		for (int i=0; i<nComponentsInFrame; ++i) {
+			buf.append("\t\t component " +i+"\n");
+			buf.append("\t\t\t ComponentIdentifier = "                  +ComponentIdentifier[i]+"\n");
+			buf.append("\t\t\t HorizontalSamplingFactor = "             +HorizontalSamplingFactor[i]+"\n");
+			buf.append("\t\t\t VerticalSamplingFactor = "               +VerticalSamplingFactor[i]+"\n");
+			buf.append("\t\t\t QuantizationTableDestinationSelector = " +QuantizationTableDestinationSelector[i]+"\n");
+		}
+		return buf.toString();
+	}
+
+}
+
diff --git a/com/pixelmed/codec/jpeg/MarkerSegmentSOS.java b/com/pixelmed/codec/jpeg/MarkerSegmentSOS.java
new file mode 100644
index 0000000..188a916
--- /dev/null
+++ b/com/pixelmed/codec/jpeg/MarkerSegmentSOS.java
@@ -0,0 +1,68 @@
+/* Copyright (c) 2014, David A. Clunie DBA Pixelmed Publishing. All rights reserved. */
+
+package com.pixelmed.codec.jpeg;
+
+/**
+ * <p>A JPEG SOS Marker Segment.</p>
+ *
+ * @author	dclunie
+ */
+public class MarkerSegmentSOS {
+
+	private static final String identString = "@(#) $Header: /userland/cvs/codec/com/pixelmed/codec/jpeg/MarkerSegmentSOS.java,v 1.2 2014/03/22 09:06:13 dclunie Exp $";
+	
+	private int nComponentsPerScan;
+	private int[] ScanComponentSelector;
+	private int[] DCEntropyCodingTableSelector;
+	private int[] ACEntropyCodingTableSelector;
+	private int[] MappingTableSelector;			// LS
+	private int StartOfSpectralOrPredictorSelection;
+	private int EndOfSpectralSelection;
+	private int SuccessiveApproximationBitPositionHigh;
+	private int SuccessiveApproximationBitPositionLowOrPointTransform;
+	
+	public int   getNComponentsPerScan() { return nComponentsPerScan; }
+	public int[] getDCEntropyCodingTableSelector() { return DCEntropyCodingTableSelector; }
+	public int[] getACEntropyCodingTableSelector() { return ACEntropyCodingTableSelector; }
+
+	public MarkerSegmentSOS(byte[] b,int length) throws Exception {
+		nComponentsPerScan=Utilities.extract8(b,0);
+		int lengthExpected = 1+nComponentsPerScan*2+3;
+		 if (length != lengthExpected) {
+			throw new Exception("Incorrect length of SOS Parameters Marker Segment, expected "+lengthExpected+" (based on nComponentsPerScan "+nComponentsPerScan+") but was "+length);
+		}
+		ScanComponentSelector       =new int[nComponentsPerScan];
+		DCEntropyCodingTableSelector=new int[nComponentsPerScan];
+		ACEntropyCodingTableSelector=new int[nComponentsPerScan];
+		MappingTableSelector        =new int[nComponentsPerScan];	// LS
+		for (int i=0; i<nComponentsPerScan; ++i) {
+			ScanComponentSelector[i]       =Utilities.extract8(b,1+i*2);
+			DCEntropyCodingTableSelector[i]=Utilities.extract8(b,1+i*2+1) >> 4;
+			ACEntropyCodingTableSelector[i]=Utilities.extract8(b,1+i*2+1) & 0x0f;
+			MappingTableSelector[i]        =Utilities.extract8(b,1+i*2+1);	// LS
+		}
+		StartOfSpectralOrPredictorSelection                  =Utilities.extract8(b,1+nComponentsPerScan*2);
+		EndOfSpectralSelection                               =Utilities.extract8(b,1+nComponentsPerScan*2+1);
+		SuccessiveApproximationBitPositionHigh               =Utilities.extract8(b,1+nComponentsPerScan*2+2) >> 4;
+		SuccessiveApproximationBitPositionLowOrPointTransform=Utilities.extract8(b,1+nComponentsPerScan*2+2) & 0x0f;
+	}
+
+	public String toString() {
+		StringBuffer buf = new StringBuffer();
+		buf.append("\n\tSOS:\n");
+		buf.append("\t\t nComponentsPerScan = "+nComponentsPerScan+"\n");
+		for (int i=0; i<nComponentsPerScan; ++i) {
+			buf.append("\t\t component "+i+"\n");
+			buf.append("\t\t\t ScanComponentSelector = "+ScanComponentSelector[i]+"\n");
+			buf.append("\t\t\t DCEntropyCodingTableSelector = "+DCEntropyCodingTableSelector[i]+"\n");
+			buf.append("\t\t\t ACEntropyCodingTableSelector = "+ACEntropyCodingTableSelector[i]+"\n");
+			buf.append("\t\t\t MappingTableSelector(LS) = "+MappingTableSelector[i]+"\n");	// LS
+		}
+		buf.append("\t\t StartOfSpectralOrPredictorSelection/NearLosslessDifferenceBound(LS) = "+StartOfSpectralOrPredictorSelection+"\n");
+		buf.append("\t\t EndOfSpectralSelection/InterleaveMode(LS) = "+EndOfSpectralSelection+"\n");
+		buf.append("\t\t SuccessiveApproximationBitPositionHigh = "+SuccessiveApproximationBitPositionHigh+"\n");
+		return buf.toString();
+	}
+
+}
+
diff --git a/com/pixelmed/codec/jpeg/Markers.java b/com/pixelmed/codec/jpeg/Markers.java
new file mode 100644
index 0000000..ab29947
--- /dev/null
+++ b/com/pixelmed/codec/jpeg/Markers.java
@@ -0,0 +1,317 @@
+/* Copyright (c) 2014, David A. Clunie DBA Pixelmed Publishing. All rights reserved. */
+
+package com.pixelmed.codec.jpeg;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <p>A class containing static definitions of JPEG marker segments and related methods.</p>
+ *
+ * @author	dclunie
+ */
+public class Markers {
+
+	private static final String identString = "@(#) $Header: /userland/cvs/codec/com/pixelmed/codec/jpeg/Markers.java,v 1.1 2014/03/21 15:28:07 dclunie Exp $";
+	
+	// modified from dicom3tools appsrc/misc/jpegdump.cc ...
+
+	public static final int APP0 = 0xffe0;
+	public static final int APP1 = 0xffe1;
+	public static final int APP2 = 0xffe2;
+	public static final int APP3 = 0xffe3;
+	public static final int APP4 = 0xffe4;
+	public static final int APP5 = 0xffe5;
+	public static final int APP6 = 0xffe6;
+	public static final int APP7 = 0xffe7;
+	public static final int APP8 = 0xffe8;
+	public static final int APP9 = 0xffe9;
+	public static final int APPA = 0xffea;
+	public static final int APPB = 0xffeb;
+	public static final int APPC = 0xffec;
+	public static final int APPD = 0xffed;
+	public static final int APPE = 0xffee;
+	public static final int APPF = 0xffef;
+
+	public static final int COM = 0xfffe;
+	public static final int DAC = 0xffcc;
+	public static final int DHP = 0xffde;
+	public static final int DHT = 0xffc4;
+	public static final int DNL = 0xffdc;
+	public static final int DQT = 0xffdb;
+	public static final int DRI = 0xffdd;
+	public static final int EOI = 0xffd9;          // also JPEG 2000 "EOC"
+	public static final int EXP = 0xffdf;
+
+	public static final int JPG = 0xffc8;
+
+	// left out reserved JPGn and RES
+	// (especially those with first bit (not just byte) zero ... new LS 0 stuffing)
+
+	public static final int RST0 = 0xffd0;
+	public static final int RST1 = 0xffd1;
+	public static final int RST2 = 0xffd2;
+	public static final int RST3 = 0xffd3;
+	public static final int RST4 = 0xffd4;
+	public static final int RST5 = 0xffd5;
+	public static final int RST6 = 0xffd6;
+	public static final int RST7 = 0xffd7;
+
+	public static final int SOF0 = 0xffc0;
+	public static final int SOF1 = 0xffc1;
+	public static final int SOF2 = 0xffc2;
+	public static final int SOF3 = 0xffc3;
+
+	public static final int SOF5 = 0xffc5;
+	public static final int SOF6 = 0xffc6;
+	public static final int SOF7 = 0xffc7;
+
+	public static final int SOF9 = 0xffc9;
+	public static final int SOFA = 0xffca;
+	public static final int SOFB = 0xffcb;
+
+	public static final int SOFD = 0xffcd;
+	public static final int SOFE = 0xffce;
+	public static final int SOFF = 0xffcf;
+
+	public static final int SOI = 0xffd8;
+	public static final int SOS = 0xffda;
+	public static final int TEM = 0xff01;
+
+	// New for JPEG-LS (14495-1:1997)
+
+	public static final int SOF55 = 0xfff7;
+	public static final int LSE   = 0xfff8;
+
+	public static final int LSE_ID_L1 = 0x01;
+	public static final int LSE_ID_L2 = 0x02;
+	public static final int LSE_ID_L3 = 0x03;
+	public static final int LSE_ID_L4 = 0x04;
+
+	// New for JPEG 2000 (15444-1:2000)
+
+	public static final int SOC = 0xff4f;
+	public static final int SOT = 0xff90;
+	public static final int SOD = 0xff93;
+//	public static final int EOC = 0xffd9;        // same as JPEG EOI
+	public static final int SIZ = 0xff51;
+	public static final int COD = 0xff52;
+	public static final int COC = 0xff53;
+	public static final int RGN = 0xff5e;
+	public static final int QCD = 0xff5c;
+	public static final int QCC = 0xff5d;
+	public static final int POC = 0xff5f;
+	public static final int TLM = 0xff55;
+	public static final int PLM = 0xff57;
+	public static final int PLT = 0xff58;
+	public static final int PPM = 0xff60;
+	public static final int PPT = 0xff61;
+	public static final int SOP = 0xff91;
+	public static final int EPH = 0xff92;
+	public static final int CRG = 0xff63;
+	public static final int COM2K = 0xff64;
+
+	public static final int FF30 = 0xff30;
+	public static final int FF31 = 0xff31;
+	public static final int FF32 = 0xff32;
+	public static final int FF33 = 0xff33;
+	public static final int FF34 = 0xff34;
+	public static final int FF35 = 0xff35;
+	public static final int FF36 = 0xff36;
+	public static final int FF37 = 0xff37;
+	public static final int FF38 = 0xff38;
+	public static final int FF39 = 0xff39;
+	public static final int FF3A = 0xff3a;
+	public static final int FF3B = 0xff3b;
+	public static final int FF3C = 0xff3c;
+	public static final int FF3D = 0xff3d;
+	public static final int FF3E = 0xff3e;
+	public static final int FF3F = 0xff3f;
+
+	public static final int isFixedLengthJPEGSegment(int marker) {
+		int length;
+		switch (marker) {
+			case EXP:
+				length=3; break;
+			default:
+				length=0; break;
+		}
+		return length;
+	}
+	
+	public static final boolean isNoLengthJPEGSegment(int marker) {
+		boolean nolength;
+		switch (marker) {
+			case SOI:
+			case EOI:
+			case TEM:
+			case RST0:
+			case RST1:
+			case RST2:
+			case RST3:
+			case RST4:
+			case RST5:
+			case RST6:
+			case RST7:
+			case FF30:
+			case FF31:
+			case FF32:
+			case FF33:
+			case FF34:
+			case FF35:
+			case FF36:
+			case FF37:
+			case FF38:
+			case FF39:
+			case FF3A:
+			case FF3B:
+			case FF3C:
+			case FF3D:
+			case FF3E:
+			case FF3F:
+			case SOC:
+			case SOD:
+			//case EOC:         // same as JPEG EOI
+			case EPH:
+				nolength=true; break;
+			default:
+				nolength=false; break;
+		}
+		return nolength;
+	}
+	
+	public static final boolean isVariableLengthJPEGSegment(int marker) {
+		return !isNoLengthJPEGSegment(marker) && isFixedLengthJPEGSegment(marker) == 0;
+	}
+	
+	private static class MarkerDictionaryEntry {
+		int markercode;
+		String abbreviation;
+		String description;
+		
+		MarkerDictionaryEntry(int markercode,String abbreviation,String description) {
+			this.markercode = markercode;
+			this.abbreviation = abbreviation;
+			this.description = description;
+		}
+	};
+	
+	private static final MarkerDictionaryEntry[] markerDictionaryTable = {
+		new MarkerDictionaryEntry(APP0, "APP0", "Reserved for Application Use"),
+		new MarkerDictionaryEntry(APP1, "APP1", "Reserved for Application Use"),
+		new MarkerDictionaryEntry(APP2, "APP2", "Reserved for Application Use"),
+		new MarkerDictionaryEntry(APP3, "APP3", "Reserved for Application Use"),
+		new MarkerDictionaryEntry(APP4, "APP4", "Reserved for Application Use"),
+		new MarkerDictionaryEntry(APP5, "APP5", "Reserved for Application Use"),
+		new MarkerDictionaryEntry(APP6, "APP6", "Reserved for Application Use"),
+		new MarkerDictionaryEntry(APP7, "APP7", "Reserved for Application Use"),
+		new MarkerDictionaryEntry(APP8, "APP8", "Reserved for Application Use"),
+		new MarkerDictionaryEntry(APP9, "APP9", "Reserved for Application Use"),
+		new MarkerDictionaryEntry(APPA, "APPA", "Reserved for Application Use"),
+		new MarkerDictionaryEntry(APPB, "APPB", "Reserved for Application Use"),
+		new MarkerDictionaryEntry(APPC, "APPC", "Reserved for Application Use"),
+		new MarkerDictionaryEntry(APPD, "APPD", "Reserved for Application Use"),
+		new MarkerDictionaryEntry(APPE, "APPE", "Reserved for Application Use"),
+		new MarkerDictionaryEntry(APPF, "APPF", "Reserved for Application Use"),
+
+		new MarkerDictionaryEntry(COM, "COM", "Comment"),
+		new MarkerDictionaryEntry(DAC, "DAC", "Define Arithmetic Conditioning Table(s)"),
+		new MarkerDictionaryEntry(DHP, "DHP", "Define Hierarchical Progression"),
+		new MarkerDictionaryEntry(DHT, "DHT", "Define Huffman Table(s)"),
+		new MarkerDictionaryEntry(DNL, "DNL", "Define Number of Lines"),
+		new MarkerDictionaryEntry(DQT, "DQT", "Define Quantization Table(s)"),
+		new MarkerDictionaryEntry(DRI, "DRI", "Define Restart Interval"),
+		new MarkerDictionaryEntry(EOI, "EOI", "End of Image (JPEG 2000 EOC End of codestream)"),
+		new MarkerDictionaryEntry(EXP, "EXP", "Expand Reference Image(s)"),
+
+		new MarkerDictionaryEntry(JPG, "JPG", "Reserved for JPEG extensions"),
+
+		new MarkerDictionaryEntry(RST0, "RST0", "Restart with modulo 8 counter 0"),
+		new MarkerDictionaryEntry(RST1, "RST1", "Restart with modulo 8 counter 1"),
+		new MarkerDictionaryEntry(RST2, "RST2", "Restart with modulo 8 counter 2"),
+		new MarkerDictionaryEntry(RST3, "RST3", "Restart with modulo 8 counter 3"),
+		new MarkerDictionaryEntry(RST4, "RST4", "Restart with modulo 8 counter 4"),
+		new MarkerDictionaryEntry(RST5, "RST5", "Restart with modulo 8 counter 5"),
+		new MarkerDictionaryEntry(RST6, "RST6", "Restart with modulo 8 counter 6"),
+		new MarkerDictionaryEntry(RST7, "RST7", "Restart with modulo 8 counter 7"),
+
+		new MarkerDictionaryEntry(SOF0, "SOF0", "Huffman Baseline DCT"),
+		new MarkerDictionaryEntry(SOF1, "SOF1", "Huffman Extended Sequential DCT"),
+		new MarkerDictionaryEntry(SOF2, "SOF2", "Huffman Progressive DCT"),
+		new MarkerDictionaryEntry(SOF3, "SOF3", "Huffman Lossless Sequential"),
+		new MarkerDictionaryEntry(SOF5, "SOF5", "Huffman Differential Sequential DCT"),
+		new MarkerDictionaryEntry(SOF6, "SOF6", "Huffman Differential Progressive DCT"),
+		new MarkerDictionaryEntry(SOF7, "SOF7", "Huffman Differential Lossless"),
+		new MarkerDictionaryEntry(SOF9, "SOF9", "Arithmetic Extended Sequential DCT"),
+		new MarkerDictionaryEntry(SOFA, "SOFA", "Arithmetic Progressive DCT"),
+		new MarkerDictionaryEntry(SOFB, "SOFB", "Arithmetic Lossless Sequential"),
+		new MarkerDictionaryEntry(SOFD, "SOFD", "Arithmetic Differential Sequential DCT"),
+		new MarkerDictionaryEntry(SOFE, "SOFE", "Arithmetic Differential Progressive DCT"),
+		new MarkerDictionaryEntry(SOFF, "SOFF", "Arithmetic Differential Lossless"),
+
+		new MarkerDictionaryEntry(SOF55, "SOF55", "LS"),
+
+		new MarkerDictionaryEntry(SOI, "SOI", "Start of Image"),
+		new MarkerDictionaryEntry(SOS, "SOS", "Start of Scan"),
+		new MarkerDictionaryEntry(TEM, "TEM", "Temporary use with Arithmetic Encoding"),
+
+		new MarkerDictionaryEntry(SOC, "SOC", "Start of codestream"),
+		new MarkerDictionaryEntry(SOT, "SOT", "Start of tile-part"),
+		new MarkerDictionaryEntry(SOD, "SOD", "Start of data"),
+        //new MarkerDictionaryEntry(EOC, "EOC", "End of codestream"),          // same as JPEG EOI
+		new MarkerDictionaryEntry(SIZ, "SIZ", "Image and tile size"),
+		new MarkerDictionaryEntry(COD, "COD", "Coding style default"),
+		new MarkerDictionaryEntry(COC, "COC", "Coding style component"),
+		new MarkerDictionaryEntry(RGN, "RGN", "Rgeion-of-interest"),
+		new MarkerDictionaryEntry(QCD, "QCD", "Quantization default"),
+		new MarkerDictionaryEntry(QCC, "QCC", "Quantization component"),
+		new MarkerDictionaryEntry(POC, "POC", "Progression order change"),
+		new MarkerDictionaryEntry(TLM, "TLM", "Tile-part lengths"),
+		new MarkerDictionaryEntry(PLM, "PLM", "Packet length, main header"),
+		new MarkerDictionaryEntry(PLT, "PLT", "Packet length, tile-part header"),
+		new MarkerDictionaryEntry(PPM, "PPM", "Packet packer headers, main header"),
+		new MarkerDictionaryEntry(PPT, "PPT", "Packet packer headers, tile-part header"),
+		new MarkerDictionaryEntry(SOP, "SOP", "Start of packet"),
+		new MarkerDictionaryEntry(EPH, "EPH", "End of packet header"),
+		new MarkerDictionaryEntry(CRG, "CRG", "Component registration"),
+		new MarkerDictionaryEntry(COM2K, "COM", "Comment (JPEG 2000)"),
+
+		new MarkerDictionaryEntry(FF30, "FF30", "Reserved"),
+		new MarkerDictionaryEntry(FF31, "FF31", "Reserved"),
+		new MarkerDictionaryEntry(FF32, "FF32", "Reserved"),
+		new MarkerDictionaryEntry(FF33, "FF33", "Reserved"),
+		new MarkerDictionaryEntry(FF34, "FF34", "Reserved"),
+		new MarkerDictionaryEntry(FF35, "FF35", "Reserved"),
+		new MarkerDictionaryEntry(FF36, "FF36", "Reserved"),
+		new MarkerDictionaryEntry(FF37, "FF37", "Reserved"),
+		new MarkerDictionaryEntry(FF38, "FF38", "Reserved"),
+		new MarkerDictionaryEntry(FF39, "FF39", "Reserved"),
+		new MarkerDictionaryEntry(FF3A, "FF3A", "Reserved"),
+		new MarkerDictionaryEntry(FF3B, "FF3B", "Reserved"),
+		new MarkerDictionaryEntry(FF3C, "FF3C", "Reserved"),
+		new MarkerDictionaryEntry(FF3D, "FF3D", "Reserved"),
+		new MarkerDictionaryEntry(FF3E, "FF3E", "Reserved"),
+		new MarkerDictionaryEntry(FF3F, "FF3F", "Reserved")
+	};
+
+	private static final Map<Integer,MarkerDictionaryEntry> mapOfMarkerToDictionaryEntry = new HashMap<Integer,MarkerDictionaryEntry>();
+	
+	static {
+		for (MarkerDictionaryEntry e : markerDictionaryTable) {
+			mapOfMarkerToDictionaryEntry.put(new Integer(e.markercode),e);
+		}
+	}
+	
+	public static final String getAbbreviation(int marker) {
+		MarkerDictionaryEntry e = mapOfMarkerToDictionaryEntry.get(new Integer(marker));
+		return e == null ? "" : e.abbreviation;
+	}
+
+	
+	public static final String getDescription(int marker) {
+		MarkerDictionaryEntry e = mapOfMarkerToDictionaryEntry.get(new Integer(marker));
+		return e == null ? "" : e.description;
+	}
+
+}
+
diff --git a/com/pixelmed/codec/jpeg/Parse.java b/com/pixelmed/codec/jpeg/Parse.java
new file mode 100644
index 0000000..54e0171
--- /dev/null
+++ b/com/pixelmed/codec/jpeg/Parse.java
@@ -0,0 +1,358 @@
+/* Copyright (c) 2014, David A. Clunie DBA Pixelmed Publishing. All rights reserved. */
+
+package com.pixelmed.codec.jpeg;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+/**
+ * <p>A class to parse a JPEG bitstream.</p>
+ *
+ * <p>Includes the ability to selectively redact blocks and leave other blocks alone, to permit "lossless" redaction.</p>
+ *
+ * <p>Development of this class was supported by funding from MDDX Research and Informatics.</p>
+ *
+ * @author	dclunie
+ */
+public class Parse {
+
+	private static final String identString = "@(#) $Header: /userland/cvs/codec/com/pixelmed/codec/jpeg/Parse.java,v 1.6 2014/03/29 21:58:58 dclunie Exp $";
+	
+	private static int getLargestSamplingFactor(int[] factors) {
+		int largest = 0;
+		for (int factor : factors) {
+			if (factor > largest) {
+				largest = factor;
+			}
+		}
+		return largest;
+	}
+	
+	private static final void writeMarkerAndLength(OutputStream out, int marker,int length) throws IOException {
+		out.write(0xff);
+		out.write(marker&0xff);
+		out.write((length>>>8)&0xff);
+		out.write(length&0xff);
+	}
+	
+	private static final void writeVariableLengthMarkerSegment(OutputStream out, int marker,int length,byte[] b) throws IOException {
+		writeMarkerAndLength(out,marker,length);
+		out.write(b,0,length-2);
+	}
+	
+	// follows pattern of dicom3tools appsrc/misc/jpegdump.cc
+	
+	/**
+	 * <p>Parse a JPEG bitstream and copying to the output redacting any blocks that intersect with the specified locations.</p>
+	 *
+	 * @param	in				the input JPEG bitstream
+	 * @param	out				the output JPEG bitsream, redacted as specified
+	 * @param	redactionShapes	a Vector of Shape that are Rectangle
+	 * @exception Exception			if bad things happen parsing the JPEG bit stream, caused by malformed input
+	 * @exception IOException		if bad things happen reading or writing
+	 */
+	public static void parse(InputStream in,OutputStream out,Vector<Shape> redactionShapes) throws Exception, IOException {
+		boolean dumping = false;
+		boolean copying = out != null;
+	
+		EntropyCodedSegment ecs = null;					// lazy instantiation of EntropyCodedSegment ... wait until we have relevant marker segments for its constructor
+		
+		ByteArrayOutputStream byteAccumulator = null;	// recreated for first byte of each EntropyCodedSegment (at start and at each subsequent restart interval)
+		
+		MarkerSegmentSOS sos = null;
+		MarkerSegmentSOF sof = null;
+		Map<String,HuffmanTable> htByClassAndIdentifer = new HashMap<String,HuffmanTable>();
+		Map<String,QuantizationTable> qtByIdentifer = new HashMap<String,QuantizationTable>();
+		int restartinterval = 0;
+		
+		int mcuOffset = 0;
+		int nMCUHorizontally = 0;
+		int mcuCountPerEntropyCodedSegment = 0;
+
+		int offset=0;
+		int markerprefix = in.read();
+		while (true) {
+			if (markerprefix == -1) {
+				if (dumping) System.err.print("End of file\n");
+				break;
+			}
+			if (markerprefix != 0xff) {		// byte of entropy-coded segment
+				if (byteAccumulator == null) {
+					if (dumping) System.err.print("Offset "+Utilities.toPaddedHexString(offset,4)+" Starting new Entropy Coded Segment\n");
+					byteAccumulator = new ByteArrayOutputStream();
+				}
+				byteAccumulator.write(markerprefix);
+				++offset;
+				markerprefix=in.read();
+				continue;
+			}
+			int marker=in.read();
+			if (marker == -1) {
+				if (dumping) System.err.print("End of file immediately after marker flag 0xff ... presumably was padding\n");
+				break;
+			}
+			else if (marker == 0xff) {		// 0xff byte of padding
+				if (dumping) System.err.print("Offset "+Utilities.toPaddedHexString(offset,4)+" Fill byte 0xff\n");
+				++offset;
+				markerprefix=marker;		// the first 0xff is padding, the 2nd may be the start of a marker
+				continue;
+			}
+			// ignore doing_jpeg2k_tilepart for now :(
+			else if (marker == 0) {			// 0xff byte of entropy-coded segment ... ignore following zero byte
+				if (dumping) System.err.print("Offset "+Utilities.toPaddedHexString(offset,4)+" Encoded 0xff in entropy-coded segment followed by stuffed zero byte\n");
+				if (byteAccumulator == null) {
+					if (dumping) System.err.print("Offset "+Utilities.toPaddedHexString(offset,4)+" Starting new Entropy Coded Segment\n");
+					byteAccumulator = new ByteArrayOutputStream();
+				}
+				byteAccumulator.write(markerprefix);
+				markerprefix=in.read();
+				offset+=2;
+				continue;
+			}
+			// ignore doing_jpegls and zero stuffed bit instead of byte for now :(
+
+			// Definitely have a marker ...
+			
+			if (byteAccumulator != null) {
+				// process any Entropy Coded Segment bytes accumulated so far ...
+				if (ecs == null) {
+					ecs = new EntropyCodedSegment(restartinterval,sos,sof,htByClassAndIdentifer,qtByIdentifer,copying,dumping);
+					
+					// need to figure out the sampling factors if this is the first Entropy Coded Segment, so that EntropyCodedSegment.finish() knows how many to process and where it is at
+					
+					int horizontalSamplesPerMCU = 8 * getLargestSamplingFactor(sof.getHorizontalSamplingFactor());
+//System.err.println("horizontalSamplesPerMCU "+horizontalSamplesPerMCU);
+					nMCUHorizontally = (sof.getNSamplesPerLine()-1)/horizontalSamplesPerMCU + 1;
+//System.err.println("nMCUHorizontally "+nMCUHorizontally);
+		
+					int verticalSamplesPerMCU = 8 * getLargestSamplingFactor(sof.getVerticalSamplingFactor());
+//System.err.println("verticalSamplesPerMCU "+verticalSamplesPerMCU);
+					int nMCUVertically = (sof.getNLines()-1)/verticalSamplesPerMCU + 1;					// may need to update this from DNL marker :(
+//System.err.println("nMCUVertically "+nMCUVertically);
+		
+					mcuCountPerEntropyCodedSegment = (restartinterval == 0) ? nMCUHorizontally * nMCUVertically : restartinterval;
+					mcuOffset = 0;
+				}
+				byte[] bytesToDecompress = byteAccumulator.toByteArray();
+//System.err.println("bytesToDecompress length="+bytesToDecompress.length);
+				byte[] bytesToCopy = ecs.finish(bytesToDecompress,mcuCountPerEntropyCodedSegment,nMCUHorizontally,mcuOffset,redactionShapes);
+				if (copying) {
+					out.write(bytesToCopy);		// NB. EntropyCodedSegment.finish() has already done the zero byte stuffing after 0xff values
+				}
+				byteAccumulator = null;
+				mcuOffset += mcuCountPerEntropyCodedSegment;
+			}
+
+			marker|=0xff00;			// convention is to express them with the leading ff, so that is what we look up
+			
+			if (dumping) System.err.print("Offset "+Utilities.toPaddedHexString(offset,4)+" Marker "+Utilities.toPaddedHexString(marker,4)+" "+Markers.getAbbreviation(marker)+" "+Markers.getDescription(marker)+" ");
+
+			offset+=2;	// wait till after we have printed it to increment it
+			
+			if (Markers.isVariableLengthJPEGSegment(marker)) {
+				int length=Utilities.read16be(in);
+				if (length == -1) {
+					throw new Exception("Error - variable length marker without length at Offset "+Utilities.toPaddedHexString(offset,4));
+				}
+				else {
+					offset+=2;
+					if (dumping) System.err.print("length variable "+Utilities.toPaddedHexString(length,2)+" ");
+				}
+				
+				if (length > 2) {
+					byte[] b = new byte[length-2];
+					int count = in.read(b,0,length-2);
+					if (count != length-2) {
+						throw new Exception("Error - couldn't read variable length parameter sequence at Offset "+Utilities.toPaddedHexString(offset,4));
+					}
+					else {
+						switch (marker) {
+							case Markers.SOS:
+								sos = new MarkerSegmentSOS(b,length-2);
+								if (dumping) System.err.print(sos);
+								if (copying) writeVariableLengthMarkerSegment(out,marker,length,b);
+								break;
+							case Markers.SOF0:
+							case Markers.SOF1:
+							case Markers.SOF2:
+							case Markers.SOF3:
+							case Markers.SOF5:
+							case Markers.SOF6:
+							case Markers.SOF7:
+							case Markers.SOF9:
+							case Markers.SOFA:
+							case Markers.SOFB:
+							case Markers.SOFD:
+							case Markers.SOFE:
+							case Markers.SOFF:
+							case Markers.SOF55:
+								sof = new MarkerSegmentSOF(b,length-2);
+								if (dumping) System.err.print(sof);
+								if (copying) writeVariableLengthMarkerSegment(out,marker,length,b);
+								break;
+							case Markers.DHT:
+								MarkerSegmentDHT dht = new MarkerSegmentDHT(b,length-2);
+								dht.addToMapByClassAndIdentifier(htByClassAndIdentifer);	// hokey, but sometimes multiple tables in one segment, sometimes multiple segments
+								if (dumping) System.err.print(dht);
+								if (copying) writeVariableLengthMarkerSegment(out,marker,length,b);
+								break;
+							case Markers.DQT:
+								MarkerSegmentDQT dqt = new MarkerSegmentDQT(b,length-2);
+								dqt.addToMapByIdentifier(qtByIdentifer);					// hokey, but sometimes multiple tables in one segment, sometimes multiple segments
+								if (dumping) System.err.print(dqt);
+								if (copying) writeVariableLengthMarkerSegment(out,marker,length,b);
+								break;
+							//case Markers.LSE
+							//	break;
+							case Markers.DRI:
+								if (length == 4) {
+									restartinterval = Utilities.extract16be(b,0);
+								}
+								else if (length == 5) {
+									restartinterval = (int)Utilities.extract24be(b,0);
+								}
+								else if (length == 6) {
+									restartinterval = (int)Utilities.extract32be(b,0);
+								}
+								else {
+									throw new Exception("Illegal length "+length+" of restart interval at Offset "+Utilities.toPaddedHexString(offset,4));
+								}
+								if (dumping) System.err.print("\n\tDRI - Define Restart Interval = "+Utilities.toPaddedHexString(restartinterval,4)+"\n");
+								if (copying) writeVariableLengthMarkerSegment(out,marker,length,b);
+								break;
+							case Markers.DNL:
+								long numberoflines;
+								if (length == 4) {
+									numberoflines = Utilities.extract16be(b,0);
+								}
+								else if (length == 5) {
+									numberoflines = Utilities.extract24be(b,0);
+								}
+								else if (length == 6) {
+									numberoflines = Utilities.extract32be(b,0);
+								}
+								else {
+									throw new Exception("Illegal length "+length+" of number of lines at Offset "+Utilities.toPaddedHexString(offset,4));
+								}
+								if (dumping) System.err.print("\n\tDNL - Define Number of Lines = "+Utilities.toPaddedHexString(numberoflines,4)+"\n");
+								if (copying) writeVariableLengthMarkerSegment(out,marker,length,b);
+								break;
+							//case Markers.COD:
+							//	break;
+							//case Markers.COM:
+							//	// do NOT copy COM marker segments ... may leak identity
+							//	break;
+							case Markers.APP0:
+							case Markers.APP1:
+							case Markers.APP2:
+								String magic = "";
+								{
+									StringBuffer magicbuf = new StringBuffer();
+									for (int i=0; i<b.length && b[i] != 0; ++i) {
+										magicbuf.append(Character.valueOf((char)b[i]));
+									}
+									magic = magicbuf.toString();
+								}
+								if (dumping) System.err.print(magic);
+								if (marker == Markers.APP0 && magic.equals("JFIF")) {
+									if (dumping) System.err.print(new MarkerSegmentAPP0JFIF(b,length-2));
+									//if (copying) writeVariableLengthMarkerSegment(out,marker,length,b);
+								}
+								// may want to consider not copying unrecognized APPn segments ... may leak identity ... copy everything for now :(
+								if (copying) writeVariableLengthMarkerSegment(out,marker,length,b);
+								break;
+							default:
+								// may want to consider not copying unrecognized segments ... may leak identity ... copy everything for now :(
+								if (copying) writeVariableLengthMarkerSegment(out,marker,length,b);
+								break;
+						}
+					}
+				}
+				else {
+					if (dumping) System.err.print("Warning - variable length marker without \"zero\" length (really 2)");
+				}
+				offset+=(length-2);
+			}
+			else if (Markers.isNoLengthJPEGSegment(marker)) {
+				if (copying) { out.write(0xff); out.write(marker&0xff);}
+				if (marker == Markers.EOI) {
+					// stop rather than process padding to end of file, so as not to create spurious empty EntropyCodedSegment
+					if (dumping) System.err.print("\n");
+					break;
+				}
+			}
+			else {
+				int length=Markers.isFixedLengthJPEGSegment(marker);
+				switch (length) {
+					case 0:
+						break;
+					case 3:
+						{
+							int value = in.read();
+							if (value != -1) {
+								offset+=1;
+								if (dumping) System.err.print("length fixed 3 value "+Utilities.toPaddedHexString(value,2)+" ");
+								if (copying) { writeMarkerAndLength(out,marker,length); out.write(value&0xff); }
+							}
+							else {
+								throw new Exception("Error - fixed length 3 marker without value at Offset "+Utilities.toPaddedHexString(offset,4));
+							}
+						}
+						break;
+					case 4:
+						{
+							int value=Utilities.read16be(in);
+							if (value != -1) {
+								offset+=2;
+								if (dumping) System.err.print("length fixed 4 value "+Utilities.toPaddedHexString(value,2)+" ");
+								if (copying) { writeMarkerAndLength(out,marker,length); out.write((value>>>8)&0xff); out.write(value&0xff); }
+							}
+							else {
+								throw new Exception("Error - fixed length 4 marker without value at Offset "+Utilities.toPaddedHexString(offset,4));
+							}
+						}
+						break;
+					default:
+						throw new Exception("Error - fixed length marker with unexpected length "+length+" at Offset "+Utilities.toPaddedHexString(offset,4));
+						//break;
+				}
+			}
+
+			if (dumping) System.err.print("\n");
+			markerprefix=in.read();
+		}
+	}
+	
+	/**
+	 * <p>Test utility to read and write a JPEG file to check parsing is sound.</p>
+	 *
+	 * @param	arg	two parameters, the input file and the output file
+	 */
+	public static void main(String arg[]) {
+		try {
+			InputStream in = new FileInputStream(arg[0]);
+			OutputStream out = arg.length > 1 ? new FileOutputStream(arg[1]) : null;
+			long startTime = System.currentTimeMillis();
+			parse(in,out,null);
+			long currentTime = System.currentTimeMillis();
+			long runTime = currentTime-startTime;
+System.err.println("Took = "+runTime+" ms");
+		}
+		catch (Exception e) {
+			e.printStackTrace(System.err);
+		}
+	}
+
+}
+
diff --git a/com/pixelmed/codec/jpeg/QuantizationTable.java b/com/pixelmed/codec/jpeg/QuantizationTable.java
new file mode 100644
index 0000000..3a5fd47
--- /dev/null
+++ b/com/pixelmed/codec/jpeg/QuantizationTable.java
@@ -0,0 +1,38 @@
+/* Copyright (c) 2014, David A. Clunie DBA Pixelmed Publishing. All rights reserved. */
+
+package com.pixelmed.codec.jpeg;
+
+/**
+ * <p>A JPEG Quantization Table.</p>
+ *
+ * @author	dclunie
+ */
+public class QuantizationTable {
+
+	private static final String identString = "@(#) $Header: /userland/cvs/codec/com/pixelmed/codec/jpeg/QuantizationTable.java,v 1.1 2014/03/21 21:46:20 dclunie Exp $";
+
+	private int QuantizationTableElementPrecision;
+	private int QuantizationTableIdentifier;
+	private int[] QuantizationTableElement;
+	
+	public QuantizationTable(int QuantizationTableIdentifier,int QuantizationTableElementPrecision,int[] QuantizationTableElement) {
+		this.QuantizationTableElementPrecision = QuantizationTableElementPrecision;
+		this.QuantizationTableIdentifier = QuantizationTableIdentifier;
+		this.QuantizationTableElement = QuantizationTableElement;
+	}
+
+	public String toString() {
+		StringBuffer buf = new StringBuffer();
+		buf.append("Quantization Table:\n");
+		buf.append("\t QuantizationTableElementPrecision = "+QuantizationTableElementPrecision+"\n");
+		buf.append("\t QuantizationTableIdentifier = "      +QuantizationTableIdentifier+"\n");
+		for (int i=0; i<64; ++i) {
+			buf.append("\t\t QuantizationTableElement "+i+" = "+QuantizationTableElement[i]+"\n");
+		}
+		return buf.toString();
+	}
+
+}
+
+
+	
diff --git a/com/pixelmed/codec/jpeg/Utilities.java b/com/pixelmed/codec/jpeg/Utilities.java
new file mode 100644
index 0000000..713de96
--- /dev/null
+++ b/com/pixelmed/codec/jpeg/Utilities.java
@@ -0,0 +1,73 @@
+/* Copyright (c) 2014, David A. Clunie DBA Pixelmed Publishing. All rights reserved. */
+
+package com.pixelmed.codec.jpeg;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * <p>A class with various utitilies for handling byte and bit extraction.</p>
+ *
+ * @author	dclunie
+ */
+public class Utilities {
+
+	private static final String identString = "@(#) $Header: /userland/cvs/codec/com/pixelmed/codec/jpeg/Utilities.java,v 1.1 2014/03/21 15:28:07 dclunie Exp $";
+
+	// modified from com.pixelmed.utils.HexDump.toPaddedHexString()
+	public static String toPaddedHexString(int i,int length) {
+		StringBuffer sb = new StringBuffer();
+		sb.append("0x");
+		String s=Integer.toHexString(i);
+		int ls=s.length();
+		while(ls++ < length) {
+			sb.append("0");
+		}
+		sb.append(s);	// even if it is longer than length wanted
+		return sb.toString();
+	}
+
+	public static String toPaddedHexString(long i,int length) {
+		StringBuffer sb = new StringBuffer();
+		sb.append("0x");
+		String s=Long.toHexString(i);
+		int ls=s.length();
+		while(ls++ < length) {
+			sb.append("0");
+		}
+		sb.append(s);	// even if it is longer than length wanted
+		return sb.toString();
+	}
+	
+	public static final int extract8(byte[] b,int offset) {
+		return b[offset]&0xff;
+	}
+	
+	public static final int extract16be(byte[] b,int offset) {
+		return ((b[offset]&0xff)<<8) + (b[offset+1]&0xff);
+	}
+	
+	public static final long extract24be(byte[] b,int offset) {
+		return ((b[offset]&0xff)<<16) + ((b[offset+1]&0xff)<<8) + (b[offset+2]&0xff);
+	}
+	
+	public static final long extract32be(byte[] b,int offset) {
+		return ((b[offset]&0xff)<<24) + ((b[offset+1]&0xff)<<16) + ((b[offset+2]&0xff)<<8) + (b[offset+3]&0xff);
+	}
+	
+	public static final int read16be(InputStream in) throws IOException {
+		// big-endian
+		int u;
+		byte b[] = new byte[2];
+		int count = in.read(b,0,2);
+		if (count == 2) {
+			u = extract16be(b,0);
+		}
+		else {
+			u = -1;		// OK as EOF/failure value since int is 32 bits and valid can only be 16
+		}
+		return u;
+	}
+	
+}
+
diff --git a/com/pixelmed/codec/jpeg/package.html b/com/pixelmed/codec/jpeg/package.html
new file mode 100755
index 0000000..3572859
--- /dev/null
+++ b/com/pixelmed/codec/jpeg/package.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+
+  @(#)package.html	1.60 98/01/27
+
+  Copyright (c) 2001-2014, David A. Clunie DBA Pixelmed Publishing. All rights reserved.
+
+-->
+</head>
+<body bgcolor="white">
+<p>JPEG selective block redaction codec.</p>
+
+<h2>Package Specification</h2>
+
+<p>This package contains a pure Java codec for selective block redaction of
+baseline process (8 bit, DCT, Huffman coded) JPEG images.</p>
+
+<p>Development of this package was supported by funding from MDDX Research and Informatics.</p>
+
+<ul>
+  <li><a href=""></a>
+</ul>
+
+<h2>Related Documentation</h2>
+
+For overviews, tutorials, examples, guides, and tool documentation, please see:
+<ul>
+  <li><a href=""></a>
+</ul>
+
+<!-- Put @see and @since tags down here. -->
+
+</body>
+</html>
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644
index 5f0c2eb..0000000
--- a/debian/changelog
+++ /dev/null
@@ -1,13 +0,0 @@
-pixelmed-codec (20141206-2) unstable; urgency=medium
-
-  * Make build reproducible (thanks for the patch to Chris Lamb)
-    Closes: #834052
-  * cme fix dpkg-control
-
- -- Andreas Tille <tille at debian.org>  Fri, 12 Aug 2016 15:25:19 +0200
-
-pixelmed-codec (20141206-1) unstable; urgency=low
-
-  * Initial release. (Closes: #808152)
-
- -- Andreas Tille <tille at debian.org>  Wed, 16 Dec 2015 16:38:12 +0100
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index ec63514..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-9
diff --git a/debian/control b/debian/control
deleted file mode 100644
index 1c3bc12..0000000
--- a/debian/control
+++ /dev/null
@@ -1,28 +0,0 @@
-Source: pixelmed-codec
-Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.org>
-Uploaders: Andreas Tille <tille at debian.org>
-Section: graphics
-Priority: optional
-Build-Depends: debhelper (>= 9)
-Build-Depends-Indep: default-jdk,
-                     javahelper,
-                     junit4,
-                     libhsqldb-java
-Standards-Version: 3.9.8
-Vcs-Browser: https://anonscm.debian.org/viewvc/debian-med/trunk/packages/pixelmed-codec/trunk/
-Vcs-Svn: svn://anonscm.debian.org/debian-med/trunk/packages/pixelmed-codec/trunk/
-Homepage: http://www.pixelmed.com
-
-Package: libpixelmed-codec-java
-Architecture: all
-Section: java
-Depends: ${java:Depends},
-         ${misc:Depends}
-Description: some imaging codecs for pixelmed DICOM image and ECG viewer
- Pixelmed is a stand-alone DICOM toolkit that implements code for reading
- and creating DICOM data, DICOM network and file support, a database of
- DICOM objects, support for display of directories, images, reports and
- spectra, and DICOM object validation.
- .
- This package contains some file format codecs used by pixelmed but
- provided as a separate tarball.
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100644
index 5d07dbc..0000000
--- a/debian/copyright
+++ /dev/null
@@ -1,41 +0,0 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: PixelMed Java DICOM Toolkit
-Upstream-Contact: pixelmed_dicom at yahoogroups.com
-Source: http://www.dclunie.com/pixelmed/software/codec/
-
-Files: *
-Copyright: 2014, David A. Clunie DBA PixelMed Publishing. All rights reserved.
-License: BSD-3-clause
-
-Files: debian/*
-Copyright: 2015, Andreas Tille <tille at debian.org>
-License: BSD-3-clause
-
-License: BSD-3-clause
- Redistribution and use in source and binary forms, with or without modification, are
- permitted provided that the following conditions are met:
- .
- 1. Redistributions of source code must retain the above copyright notice, this list of
-    conditions and the following disclaimers.
- .
- 2. Redistributions in binary form must reproduce the above copyright notice, this list of
-    conditions and the following disclaimers in the documentation and/or other materials
-    provided with the distribution.
- .
- 3. Neither the name of PixelMed Publishing nor the names of its contributors may
-    be used to endorse or promote products derived from this software.
- .
- This software is provided by the copyright holders and contributors "as is" and any
- express or implied warranties, including, but not limited to, the implied warranties
- of merchantability and fitness for a particular purpose are disclaimed. In no event
- shall the copyright owner or contributors be liable for any direct, indirect, incidental,
- special, exemplary, or consequential damages (including, but not limited to, procurement
- of substitute goods or services; loss of use, data or profits; or business interruption)
- however caused and on any theory of liability, whether in contract, strict liability, or
- tort (including negligence or otherwise) arising in any way out of the use of this software,
- even if advised of the possibility of such damage.
- .
- This software has neither been tested nor approved for clinical use or for incorporation in
- a medical device. It is the redistributor's or user's responsibility to comply with any
- applicable local, state, national or international regulations.
-
diff --git a/debian/docs b/debian/docs
deleted file mode 100644
index e845566..0000000
--- a/debian/docs
+++ /dev/null
@@ -1 +0,0 @@
-README
diff --git a/debian/libpixelmed-codec-java.jlibs b/debian/libpixelmed-codec-java.jlibs
deleted file mode 100644
index 2554543..0000000
--- a/debian/libpixelmed-codec-java.jlibs
+++ /dev/null
@@ -1 +0,0 @@
-pixelmed_codec.jar
diff --git a/debian/patches/debian_jars.patch b/debian/patches/debian_jars.patch
deleted file mode 100644
index de2488b..0000000
--- a/debian/patches/debian_jars.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-Author: Andreas Tille <tille at debian.org>
-Last-Update: Thu, 08 Oct 2015 10:39:14 +0200
-Description: Set explicit PATH to Debian jars
- Might be only needed to generate javadoc
-
---- a/Makefile.common.mk
-+++ b/Makefile.common.mk
-@@ -2,7 +2,7 @@
- # Note that PATHTOROOT must have been specified prior to including this file
- #
- 
--JUNITJAR = ${PATHTOROOT}/lib/junit/junit-4.8.1.jar
-+JUNITJAR = /usr/share/java/junit4.jar
- 
- PATHTOTESTFILESFROMROOT = ./testpaths
- 
---- a/Makefile
-+++ b/Makefile
-@@ -31,7 +31,7 @@ SOURCERELEASEFILES = \
- 	${SUBDIRS}
- 
- DEPENDENCYRELEASEFILESWITHOUTREADME = \
--	lib/junit/junit-4.8.1.jar \
-+	/usr/share/java/junit4.jar \
- 	LICENSES
- 
- DEPENDENCYRELEASEFILES = \
-@@ -148,11 +148,7 @@ doxygenrelease: .exclude.list #clean jav
- javadoc:
- 	rm -rf docs/javadoc
- 	javadoc \
--		-classpath .:lib/additional/excalibur-bzip2-1.0.jar:lib/additional/hsqldb.jar:lib/additional/vecmath1.2-1.14.jar:lib/additional/commons-codec-1.3.jar:lib/additional/commons-net-ftp-2.0.jar:lib/additional/jmdns.jar:lib/additional/jpedalSTD.jar:lib/junit/junit-4.8.1.jar \
--		-link http://download.oracle.com/javase/1.5.0/docs/api/ \
--		-link http://jpedal.org/javadoc/ \
--		-link http://www.hsqldb.org/doc/src/ \
--		-link http://javasourcecode.org/html/open-source/junit/junit-4.8.1/ \
-+		-classpath .:lib/additional/excalibur-bzip2-1.0.jar:/usr/share/java/hsqldb.jar:lib/additional/vecmath1.2-1.14.jar:lib/additional/commons-codec-1.3.jar:lib/additional/commons-net-ftp-2.0.jar:lib/additional/jmdns.jar:lib/additional/jpedalSTD.jar:/usr/share/java/junit4.jar \
- 		-protected -d docs/javadoc \
- 		-encoding "UTF8" \
- 		${SUBPACKAGES}
diff --git a/debian/patches/reproducible_build.patch b/debian/patches/reproducible_build.patch
deleted file mode 100644
index ef99733..0000000
--- a/debian/patches/reproducible_build.patch
+++ /dev/null
@@ -1,19 +0,0 @@
-Description: Make the build reproducible
-Author: Chris Lamb <lamby at debian.org>
-Last-Update: 2016-08-11
-Bug-Debian: https://bugs.debian.org/834052
-
---- pixelmed-codec-20141206.orig/Makefile
-+++ pixelmed-codec-20141206/Makefile
-@@ -58,7 +58,11 @@ include ${PATHTOROOT}/Makefile.common.mk
- 
- pixelmed_codec.jar:
- 	(cd com/pixelmed/codec/jpeg; make all)
-+ifdef SOURCE_DATE_EPOCH
-+	LC_ALL=C date --utc --date="@$$SOURCE_DATE_EPOCH" >BUILDDATE
-+else
- 	date >BUILDDATE
-+endif
- 	jar -cvf $@ BUILDDATE COPYRIGHT \
- 		com/pixelmed/codec/jpeg/*.class
- changelog:
diff --git a/debian/patches/series b/debian/patches/series
deleted file mode 100644
index 03dc144..0000000
--- a/debian/patches/series
+++ /dev/null
@@ -1,3 +0,0 @@
-set_java_home.patch
-# debian_jars.patch
-reproducible_build.patch
diff --git a/debian/patches/set_java_home.patch b/debian/patches/set_java_home.patch
deleted file mode 100644
index 67f12b3..0000000
--- a/debian/patches/set_java_home.patch
+++ /dev/null
@@ -1,15 +0,0 @@
-Author: Andreas Tille <tille at debian.org>
-Last-Update: Thu, 08 Oct 2015 10:39:14 +0200
-Description: Work around OSX specific way to set JAVA_HOME
-
---- a/Makefile.common.mk
-+++ b/Makefile.common.mk
-@@ -17,7 +17,7 @@ JAVACTARGETOPTIONS=-target ${JAVAVERSION
- JAVACOPTIONS = -O ${JAVACTARGETOPTIONS} -encoding "UTF8" -Xlint:deprecation
- 
- .java.class:
--	export JAVAVERSIONTARGETJARFILE=`/usr/libexec/java_home -v ${JAVAVERSIONTARGET} | tail -1`/jre/lib/rt.jar; javac ${JAVACOPTIONS} \
-+	export JAVAVERSIONTARGETJARFILE=${JAVA_HOME}/jre/lib/rt.jar; javac ${JAVACOPTIONS} \
- 		-classpath ${PATHTOROOT} \
- 		-sourcepath ${PATHTOROOT} $<
- 
diff --git a/debian/rules b/debian/rules
deleted file mode 100755
index c044063..0000000
--- a/debian/rules
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/make -f
-#export DH_VERBOSE=1
-
-export JAVA_HOME=/usr/lib/jvm/default-java
-
-VERSION = $(shell dpkg-parsechangelog | grep '^Version' | cut -d' ' -f2 | cut -f1 -d- | cut -f2 -d~)
-
-%:
-	dh $@ --with javahelper
-
-#override_dh_auto_build:
-#	$(MAKE) all
-#	$(MAKE) javadoc
diff --git a/debian/source/format b/debian/source/format
deleted file mode 100644
index 163aaf8..0000000
--- a/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/debian/source/options b/debian/source/options
deleted file mode 100644
index 22a4de9..0000000
--- a/debian/source/options
+++ /dev/null
@@ -1,2 +0,0 @@
-compression = xz
-compression-level = 9
diff --git a/debian/watch b/debian/watch
deleted file mode 100644
index e814f9d..0000000
--- a/debian/watch
+++ /dev/null
@@ -1,2 +0,0 @@
-version=3
-http://www.dclunie.com/pixelmed/software/codec/([b\d]+)_current/pixelmedjavacodec_sourcerelease.([\d]+).tar.bz2

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/pixelmed-codec.git



More information about the debian-med-commit mailing list