[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