URL:
https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
ChangeLog:
2009-02-27 Fabien Freling <fabien.freling(a)lrde.epita.fr>
Clean sandbox.
* fabien/dcmtk/Makefile: New.
* fabien/dcmtk/dicom.cc: New.
* fabien/dcmtk: New.
* fabien/dicom/load.hh: Remove.
* fabien/dicom/save.hh: Remove.
* fabien/dicom: Remove.
* fabien/gdcm/Makefile: Remove.
* fabien/gdcm/dump2pgm.cc: Remove.
* fabien/gdcm/gdcm.cc: Remove.
* fabien/gdcm/load.hh: Remove.
* fabien/gdcm: Remove.
* fabien/igr/Makefile: New.
* fabien/igr/dump2pbm.cc: New.
* fabien/igr/seg_vol_irm.cc: New.
---
dcmtk/Makefile | 2
dcmtk/dicom.cc | 14
dcmtk/load.hh | 388 +++++++++++++++++++++
dcmtk/save.hh | 951 +++++++++++++++++++++++++++++++++++++++++++++++++++++
igr/Makefile | 15
igr/dump2pbm.cc | 35 +
igr/seg_vol_irm.cc | 267 ++++++++++++++
7 files changed, 1672 insertions(+)
Index: trunk/milena/sandbox/fabien/igr/seg_vol_irm.cc
===================================================================
--- trunk/milena/sandbox/fabien/igr/seg_vol_irm.cc (revision 0)
+++ trunk/milena/sandbox/fabien/igr/seg_vol_irm.cc (revision 3432)
@@ -0,0 +1,267 @@
+// Copyright (C) 2007, 2008, 2009 EPITA Research and Development
+// Laboratory (LRDE)
+//
+// This file is part of the Olena Library. This library is free
+// software; you can redistribute it and/or modify it under the terms
+// of the GNU General Public License version 2 as published by the
+// Free Software Foundation.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this library; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02111-1307, USA.
+//
+// As a special exception, you may use this file as part of a free
+// software library without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to
+// produce an executable, this file does not by itself cause the
+// resulting executable to be covered by the GNU General Public
+// License. This exception does not however invalidate any other
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+
+#include <mln/core/concept/image.hh>
+#include <mln/core/concept/neighborhood.hh>
+#include <mln/core/alias/neighb1d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/core/alias/neighb3d.hh>
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/image3d.hh>
+
+#include <mln/value/int_u8.hh>
+#include <mln/value/int_u12.hh>
+#include <mln/value/int_u16.hh>
+#include <mln/value/rgb8.hh>
+
+#include <mln/io/pgm/all.hh>
+#include <mln/io/pbm/all.hh>
+#include <mln/io/ppm/all.hh>
+#include <mln/io/cloud/all.hh>
+#include <mln/io/dump/all.hh>
+#include <mln/io/dicom/load.hh>
+
+#include <mln/labeling/flat_zones.hh>
+#include <mln/labeling/background.hh>
+#include <mln/literal/colors.hh>
+#include <mln/norm/l1.hh>
+
+#include <mln/geom/bbox.hh>
+
+#include <mln/labeling/blobs.hh>
+#include <mln/labeling/compute.hh>
+#include <mln/labeling/fill_holes.hh>
+#include <mln/labeling/n_max.hh>
+
+#include <mln/level/compare.hh>
+#include <mln/level/compute.hh>
+#include <mln/level/transform.hh>
+
+#include <mln/fun/internal/selector.hh>
+
+#include <mln/fun/v2b/threshold.hh>
+#include <mln/level/transform.hh>
+
+#include <mln/accu/count.hh>
+#include <mln/accu/center.hh>
+#include <mln/accu/max.hh>
+
+#include <mln/histo/compute.hh>
+
+#include <mln/set/compute.hh>
+#include <mln/value/label_16.hh>
+#include <mln/data/fill.hh>
+#include <mln/pw/all.hh>
+
+#include <mln/morpho/elementary/gradient_internal.hh>
+#include <mln/morpho/opening_area.hh>
+
+#include <mln/convert/from_to.hh>
+
+//FIXME: remove
+#include <mln/essential/2d.hh>
+#include <iostream>
+#include <mln/debug/println.hh>
+
+using namespace mln;
+using value::int_u8;
+using value::int_u12;
+using value::int_u16;
+using value::rgb8;
+using value::label_16;
+
+
+
+template <typename T>
+struct L_to_int_u8
+: mln::fun::internal::selector_<int_u8, T, L_to_int_u8<T> >::ret
+{
+ typedef int_u8 result;
+ int_u8 operator()(const T& t) const;
+};
+
+
+template <typename T>
+inline
+int_u8
+L_to_int_u8<T>::operator()(const T& t) const
+{
+ return static_cast<int_u8>(t == 0 ? 0 : 1 + ((unsigned) t - 1) % 255);
+}
+
+
+template <typename I>
+unsigned
+find_threshold_value(const Image<I>& input_)
+{
+ const I& input = exact(input_);
+
+ histo::array<mln_value(I)> arr_histo = histo::compute(input);
+
+ image1d<unsigned> ima_histo;
+ convert::from_to(arr_histo, ima_histo);
+
+ ima_histo(point1d(0)) = 0;
+
+ //ima_histo = morpho::opening_area(ima_histo, c2(), 5);
+ //mln_fwd_piter(image1d<unsigned>) p(ima_histo.domain());
+ for (unsigned int i = 1; i < ima_histo.nelements(); ++i)
+ {
+ ima_histo(point1d(i)) += ima_histo(point1d(i - 1));
+ }
+ accu::max<unsigned> max_accu;
+ unsigned max = level::compute(max_accu, ima_histo);
+ for (unsigned int i = 0; i < ima_histo.nelements(); ++i)
+ {
+ //std::cout << "[" << i << "] => " <<
((ima_histo(point1d(i)) * 100) / max) << std::endl;
+ if (((ima_histo(point1d(i)) * 100) / max) > 70)
+ return i;
+ }
+}
+
+
+template <typename I, typename N, typename L>
+mln_ch_value(I, bool)
+igr(const Image<I>& input_, const mln::Neighborhood<N>& nbh_, L&
nlabels)
+{
+ const I& input = exact(input_);
+ const N& nbh = exact(nbh_);
+
+ // Threshold.
+
+ unsigned threshold_value = find_threshold_value(input_);
+ mln_ch_value(I, bool) ima_thres;
+ initialize(ima_thres, input);
+ data::fill((ima_thres | pw::value(input) < pw::cst(threshold_value)).rw(), true);
+
+ return ima_thres;
+
+ // Labeling.
+
+ /*mln_ch_value(I, L) labels = labeling::flat_zones(threshold, nbh, nlabels);
+ accu::count<int_u8> a_;
+ util::array<unsigned> a = labeling::compute(a_, threshold, labels, nlabels);
+
+ // We keep the third and second biggest object.
+
+ mln_ch_value(I, bool) big_second;
+ initialize(big_second, input);
+ data::fill(big_second, false);
+
+ util::array<L> arr_big = labeling::n_max<L>(a, 3);
+ data::fill((big_second | (pw::value(labels) == arr_big[2])).rw(), true);
+ mln_VAR(big_third, threshold | pw::value(labels) == arr_big[3]);
+
+ // Fill holes.
+
+ big_second = labeling::fill_holes(big_second, nbh, nlabels);
+
+ // Gradient.
+
+ mln_ch_value(I, bool) gradient = morpho::elementary::gradient_internal(big_second,
nbh);
+ mln_VAR(gradient_map, gradient | pw::value(gradient) == true);
+
+ mln_ch_value(I, rgb8) result = level::convert(rgb8(), input);
+ data::fill((result | gradient_map.domain()).rw(), literal::red);
+
+ // Center.
+
+ accu::center<mln_site(I)> center_;
+ mln_site(I) center = set::compute(center_, big_third.domain());
+ result(center) = literal::blue;
+
+ // Distance.
+
+ mln_fwd_piter(gradient_map_t) p(gradient_map.domain());
+ p_array<mln_site(I)> arr;
+ for_all(p)
+ {
+ if (mln::norm::l1_distance(p.to_site().to_vec(), center.to_vec()) < 200)
+ {
+ result(p) = literal::green;
+
+ arr.append(p);
+ }
+ }
+
+ // Save the cloud in a file.
+
+ io::cloud::save(arr, "cloud.txt");
+
+ return result;*/
+}
+
+int main()
+{
+ //trace::quiet = false;
+
+ label_16 nlabels;
+
+ std::cout << "Processing IM_0043..." << std::endl;
+ image3d<int_u12> im43;
+ io::dicom::load(im43, "/Users/HiSoKa/Work/IGR/souris18/irm/IM_0043.dcm");
+ io::dump::save(igr(im43, c6(), nlabels), "IM_0043.dump");
+
+ std::cout << "Processing IM_0046..." << std::endl;
+ image3d<int_u12> im46;
+ io::dicom::load(im46, "/Users/HiSoKa/Work/IGR/souris18/irm/IM_0046.dcm");
+ io::dump::save(igr(im46, c6(), nlabels), "IM_0046.dump");
+
+ std::cout << "Processing IM_0049..." << std::endl;
+ image2d<int_u12> im49;
+ io::dicom::load(im49, "/Users/HiSoKa/Work/IGR/souris18/irm/IM_0049.dcm");
+ io::pbm::save(igr(im49, c6(), nlabels), "IM_0049.pbm");
+
+ std::cout << "Processing IM_0052..." << std::endl;
+ image3d<int_u12> im52;
+ io::dicom::load(im52, "/Users/HiSoKa/Work/IGR/souris18/irm/IM_0052.dcm");
+ io::dump::save(igr(im52, c6(), nlabels), "IM_0052.dump");
+
+ std::cout << "Processing IM_0055..." << std::endl;
+ image2d<int_u12> im55;
+ io::dicom::load(im55, "/Users/HiSoKa/Work/IGR/souris18/irm/IM_0055.dcm");
+ io::pbm::save(igr(im55, c6(), nlabels), "IM_0055.pbm");
+
+ std::cout << "Processing IM_0058..." << std::endl;
+ image2d<int_u12> im58;
+ io::dicom::load(im58, "/Users/HiSoKa/Work/IGR/souris18/irm/IM_0058.dcm");
+ io::pbm::save(igr(im58, c6(), nlabels), "IM_0058.pbm");
+
+ std::cout << "Processing IM_0061..." << std::endl;
+ image3d<int_u12> im61;
+ io::dicom::load(im61, "/Users/HiSoKa/Work/IGR/souris18/irm/IM_0061.dcm");
+ io::dump::save(igr(im61, c6(), nlabels), "IM_0061.dump");
+
+ std::cout << "Processing IM_0064..." << std::endl;
+ image3d<int_u12> im64;
+ io::dicom::load(im64, "/Users/HiSoKa/Work/IGR/souris18/irm/IM_0064.dcm");
+ io::dump::save(igr(im64, c6(), nlabels), "IM_0064.dump");
+
+ return 0;
+}
Index: trunk/milena/sandbox/fabien/igr/dump2pbm.cc
===================================================================
--- trunk/milena/sandbox/fabien/igr/dump2pbm.cc (revision 0)
+++ trunk/milena/sandbox/fabien/igr/dump2pbm.cc (revision 3432)
@@ -0,0 +1,35 @@
+
+#include <mln/core/image/image2d.hh>
+#include <mln/make/image3d.hh>
+#include <mln/debug/slices_2d.hh>
+
+#include <mln/value/int_u16.hh>
+#include <mln/io/dump/load.hh>
+#include <mln/io/pbm/save.hh>
+
+#include <mln/literal/colors.hh>
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.dump
output.pbm" << std::endl;
+ abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u16;
+
+ if (argc != 3)
+ usage(argv);
+
+ image3d<bool> vol;
+ io::dump::load(vol, argv[1]);
+
+ int_u16 bg = 0;
+ image2d<bool> ima = debug::slices_2d(vol, 1.f, bg);
+ io::pbm::save(ima, argv[2]);
+}
Index: trunk/milena/sandbox/fabien/igr/Makefile
===================================================================
--- trunk/milena/sandbox/fabien/igr/Makefile (revision 0)
+++ trunk/milena/sandbox/fabien/igr/Makefile (revision 3432)
@@ -0,0 +1,15 @@
+all: seg_vol_irm.cc
+ g++ -I../../../ \
+ -I/Users/HiSoKa/Downloads/gdcm-2.0.10/Source/Common/ \
+ -I/Users/HiSoKa/Downloads/gdcmbin/Source/Common/ \
+ -I/Users/HiSoKa/Downloads/gdcm-2.0.10/Source/DataDictionary/ \
+ -I/Users/HiSoKa/Downloads/gdcm-2.0.10/Source/MediaStorageAndFileFormat/ \
+ -I/Users/HiSoKa/Downloads/gdcm-2.0.10/Source/DataStructureAndEncodingDefinition/ \
+ -L/Users/HiSoKa/Downloads/gdcmbin/bin \
+ -lgdcmCommon -lgdcmDICT -lgdcmDSED -lgdcmIOD -lgdcmMSFF -lgdcmexpat -lgdcmjpeg12
-lgdcmjpeg16 -lgdcmjpeg8 -lgdcmopenjpeg -lgdcmuuid -lgdcmzlib \
+ -framework CoreFoundation \
+ -g \
+ seg_vol_irm.cc -o seg_vol_irm
+
+clean:
+ rm -rf *.dump *.p?m
Index: trunk/milena/sandbox/fabien/dcmtk/dicom.cc
===================================================================
--- trunk/milena/sandbox/fabien/dcmtk/dicom.cc (revision 0)
+++ trunk/milena/sandbox/fabien/dcmtk/dicom.cc (revision 3432)
@@ -0,0 +1,14 @@
+#include <mln/core/image/image2d.hh>
+#include <mln/value/int_u8.hh>
+
+#include "load.hh"
+
+int main()
+{
+ using namespace mln;
+ using value::int_u8;
+
+ image2d<int_u8> lena;
+
+ io::dicom::load(lena,
"/Users/HiSoKa/Work/LRDE/Olena/resources/data/IM_0001");
+}
Index: trunk/milena/sandbox/fabien/dcmtk/save.hh
===================================================================
--- trunk/milena/sandbox/fabien/dcmtk/save.hh (revision 0)
+++ trunk/milena/sandbox/fabien/dcmtk/save.hh (revision 3432)
@@ -0,0 +1,951 @@
+/*
+ *
+ * Copyright (C) 1994-2005, OFFIS
+ *
+ * This software and supporting documentation were developed by
+ *
+ * Kuratorium OFFIS e.V.
+ * Healthcare Information and Communication Systems
+ * Escherweg 2
+ * D-26121 Oldenburg, Germany
+ *
+ * THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND OFFIS MAKES NO WARRANTY
+ * REGARDING THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY OR
+ * FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES OR
+ * ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
+ *
+ * Module: dcmdata
+ *
+ * Author: Andreas Barth
+ *
+ * Purpose: create a Dicom FileFormat or DataSet from an ASCII-dump
+ *
+ * Last Update: $Author: onken $
+ * Update Date: $Date: 2005/12/16 09:07:03 $
+ * CVS/RCS Revision: $Revision: 1.51 $
+ * Status: $State: Exp $
+ *
+ * CVS/RCS Log at end of file
+ *
+ */
+
+/*
+ * Input File Description:
+ * The input file be an output of dcmdump. One element (Tag, VR, value) must
+ * be written into one line separated by arbitrary spaces or tab characters.
+ * A # begins a comment that ends at the line end. Empty lines are allowed.
+ * This parts of a line have the following syntax:
+ * Tag: (gggg,eeee)
+ * with gggg and eeee are 4 character hexadecimal values representing
+ * group- and element-tag. Spaces and Tabs can be anywhere in a Tag
+ * specification
+ * VR: Value Representation must be written as 2 characters as in Part 6
+ * of the DICOM 3.0 standard. No Spaces or Tabs are allowed between the
+ * two characters. If the VR can determined from the Tag, this part of
+ * a line is optional.
+ * Value: There are several rules for writing values:
+ * 1. US, SS, SL, UL, FD, FL are written as
+ * decimal strings that can be read by scanf.
+ * 2. AT is written as (gggg,eeee) with additional spaces stripped off
+ * automatically and gggg and eeee being decimal strings that
+ * can be read by scanf.
+ * 3. OB, OW values are written as byte or word hexadecimal values
+ * separated by '\' character. Alternatively, OB or OW values can
+ * be read from a separate file by writing the filename prefixed
+ * by a '=' character (e.g. =largepixeldata.dat). The contents of
+ * the file will be read as is. OW data is expected to be little
+ * endian ordered and will be swapped if necessary. No checks will
+ * be made to ensure that the amount of data is reasonable in terms
+ * of other attributes such as Rows or Columns.
+ * 4. UI is written as =Name in data dictionary or as
+ * unique identifer string (see 6.) , e.g. [1.2.840.....]
+ * 5. Strings without () <> [] spaces, tabs and # can be
+ * written directly
+ * 6. Other strings with must be surrounded by [ ]. No
+ * bracket structure is passed. The value ends at the last ] in
+ * the line. Anything after the ] is interpreted as comment.
+ * 7. ( < are interpreted special and may not be used when writing
+ * an input file by hand as beginning characters of a string.
+ * Multiple Value are separated by \
+ * The sequence of lines must not be ordered but they can.
+ * References in DICOM Directories are not supported.
+ * Semantic errors are not detected.
+ *
+ * Examples:
+ * (0008,0020) DA [19921012] # 8, 1 StudyDate
+ * (0008,0016) UI =MRImageStorage # 26, 1 SOPClassUID
+ * (0002,0012) UI [1.2.276.0.7230010.100.1.1]
+ * (0020,0032) DS [0.0\0.0] # 8, 2 ImagePositionPatient
+ * (0028,0009) AT (3004,000c) # 4, 1 FrameIncrementPointer
+ * (0028,0010) US 256 # 4, 1 Rows
+ * (0002,0001) OB 01\00
+ *
+ */
+
+#include "dcmtk/config/osconfig.h"
+
+#define INCLUDE_CSTDLIB
+#define INCLUDE_CSTDIO
+#define INCLUDE_CCTYPE
+#include "dcmtk/ofstd/ofstdinc.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_STAT_H
+#include <stat.h>
+#endif
+#ifdef HAVE_GUSI_H
+#include <GUSI.h>
+#endif
+
+#include "dcmtk/ofstd/ofstream.h"
+#include "dcmtk/dcmdata/dctk.h"
+#include "dcmtk/dcmdata/dcdebug.h"
+#include "dcmtk/dcmdata/cmdlnarg.h"
+#include "dcmtk/ofstd/ofconapp.h"
+#include "dcmtk/ofstd/ofstd.h"
+#include "dcmtk/dcmdata/dcuid.h" /* for dcmtk version name */
+
+#ifdef WITH_ZLIB
+#include <zlib.h> /* for zlibVersion() */
+#endif
+
+#define OFFIS_CONSOLE_APPLICATION "dump2dcm"
+
+static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v"
+ OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $";
+
+#define SHORTCOL 3
+#define LONGCOL 21
+
+// Maximum Line Size
+
+const unsigned int DCM_DumpMaxLineSize = 4096;
+
+
+// Field definition separators
+
+#define DCM_DumpCommentChar '#'
+#define DCM_DumpTagDelim ')'
+#define DCM_DumpOpenString '['
+#define DCM_DumpCloseString ']'
+#define DCM_DumpOpenDescription '('
+#define DCM_DumpOpenFile '<'
+#define DCM_DumpCloseFile '>'
+
+static void
+stripWhitespace(char* s)
+{
+ char* p;
+
+ if (s == NULL) return;
+
+ p = s;
+ while (*s != '\0') {
+ if (isspace(*s) == OFFalse) {
+ *p++ = *s;
+ }
+ s++;
+ }
+ *p = '\0';
+}
+
+static char*
+stripTrailingWhitespace(char* s)
+{
+ int i, n;
+ if (s == NULL) return s;
+
+ n = strlen(s);
+ for (i = n - 1; i >= 0 && isspace(s[i]); i--)
+ s[i] = '\0';
+ return s;
+}
+
+
+static char *
+stripPrecedingWhitespace(char * s)
+{
+ char * p;
+ if (s == NULL) return s;
+
+ for(p = s; *p && isspace(*p); p++)
+ ;
+
+ return p;
+}
+
+static OFBool
+onlyWhitespace(const char* s)
+{
+ int len = strlen(s);
+ int charsFound = OFFalse;
+
+ for (int i=0; (!charsFound) && (i<len); i++) {
+ charsFound = !isspace(s[i]);
+ }
+ return (!charsFound)?(OFTrue):(OFFalse);
+}
+
+static char*
+getLine(char* line, int maxLineLen, FILE* f, const unsigned long lineNumber)
+{
+ char* s;
+
+ s = fgets(line, maxLineLen, f);
+
+ // if line is too long, throw rest of it away
+ if (s && strlen(s) == size_t(maxLineLen-1) && s[maxLineLen-2] !=
'\n')
+ {
+ int c = fgetc(f);
+ while(c != '\n' && c != EOF)
+ c = fgetc(f);
+ CERR << "line " << lineNumber << " too
long." << endl;
+ }
+
+ /* strip any trailing white space */
+ stripTrailingWhitespace(s);
+
+ return s;
+}
+
+static OFBool
+isaCommentLine(const char* s)
+{
+ OFBool isComment = OFFalse; /* assumption */
+ int len = strlen(s);
+ int i = 0;
+ for (i=0; i<len && isspace(s[i]); i++) /*loop*/;
+ isComment = (s[i] == DCM_DumpCommentChar);
+ return isComment;
+}
+
+static OFBool
+parseTag(char* & s, DcmTagKey& key)
+{
+ OFBool ok = OFTrue;
+ char * p;
+ unsigned int g, e;
+
+ // find tag begin
+ p = strchr(s, DCM_DumpTagDelim);
+ if (p)
+ {
+ // string all white spaces and read tag
+ int len = p-s+1;
+ p = new char[len+1];
+ OFStandard::strlcpy(p, s, len+1);
+ stripWhitespace(p);
+ s += len;
+
+ if (sscanf(p, "(%x,%x)", &g, &e) == 2) {
+ key.set(g, e);
+ } else {
+ ok = OFFalse;
+ }
+ delete[] p;
+ }
+ else ok = OFFalse;
+
+ return ok;
+}
+
+
+static OFBool
+parseVR(char * & s, DcmEVR & vr)
+{
+ OFBool ok = OFTrue;
+
+ s = stripPrecedingWhitespace(s);
+
+ // Are there two upper characters?
+ if (isupper(*s) && isupper(*(s+1)))
+ {
+ char c_vr[3];
+ OFStandard::strlcpy(c_vr, s, 3);
+ // Convert to VR
+ DcmVR dcmVR(c_vr);
+ vr = dcmVR.getEVR();
+ s+=2;
+ }
+ else if ((*s == 'p')&&(*(s+1) == 'i'))
+ {
+ vr = EVR_pixelItem;
+ s+=2;
+ }
+ else if (((*s == 'o')&&(*(s+1) == 'x')) || ((*s ==
'x')&&(*(s+1) == 's')) ||
+ (*s == 'n')&&(*(s+1) == 'a') || ((*s ==
'u')&&(*(s+1) == 'p')))
+ {
+ // swallow internal VRs
+ vr = EVR_UNKNOWN;
+ s+=2;
+ }
+ else ok = OFFalse;
+
+ return ok;
+}
+
+
+static int
+searchLastClose(char *s, char closeChar)
+{
+ // search last close bracket in a line
+ // no bracket structure will be considered
+
+ char * found = NULL;
+ char * p = s;
+
+ while(p && *p)
+ {
+ p = strchr(p, closeChar);
+ if (p)
+ {
+ found = p;
+ p++;
+ }
+ }
+
+ if (found)
+ return (found - s) + 1;
+ else
+ return 0;
+}
+
+
+static int
+searchCommentOrEol(char *s)
+{
+ char * comment = strchr(s, DCM_DumpCommentChar);
+ if (comment)
+ return comment - s;
+ else if (s)
+ return strlen(s);
+ else
+ return 0;
+}
+
+
+static char*
+convertNewlineCharacters(char* s)
+{
+ // convert the string "\n" into the \r\n combination required by DICOM
+ if (s == NULL || s[0] == '\0') return s;
+ int len = strlen(s);
+ int i = 0;
+ for (i=0; i<(len-1); i++) {
+ if (s[i] == '\\' && s[i+1] == 'n') {
+ s[i] = '\r';
+ s[i+1] = '\n';
+ i++;
+ }
+ }
+
+ return s;
+}
+
+static OFBool
+parseValue(char * & s, char * & value, const DcmEVR & vr)
+{
+ OFBool ok = OFTrue;
+ int len;
+ value = NULL;
+
+ s = stripPrecedingWhitespace(s);
+
+ switch (*s)
+ {
+ case DCM_DumpOpenString:
+ len = searchLastClose(s, DCM_DumpCloseString);
+ if (len == 0)
+ ok = OFFalse;
+ else if (len > 2)
+ {
+ value = new char[len-1];
+ OFStandard::strlcpy(value, s+1, len-1);
+ value = convertNewlineCharacters(value);
+ }
+ else
+ value = NULL;
+ break;
+
+ case DCM_DumpOpenDescription:
+ /* need to distinguish vr=AT from description field */
+ /* NB: if the vr is unknown this workaround will not succeed */
+ if (vr == EVR_AT)
+ {
+ len = searchLastClose(s, DCM_DumpTagDelim);
+ if (len >= 11) // (gggg,eeee) allow non-significant spaces
+ {
+ char *pv = s;
+ DcmTagKey tag;
+ if (parseTag(pv, tag)) // check for valid tag format
+ {
+ value = new char[len+1];
+ OFStandard::strlcpy(value, s, len+1);
+ stripWhitespace(value);
+ } else
+ ok = OFFalse; // skip description
+ }
+ else
+ ok = OFFalse; // skip description
+ }
+ break;
+
+ case DCM_DumpOpenFile:
+ ok = OFFalse; // currently not supported
+ break;
+
+ case DCM_DumpCommentChar:
+ break;
+
+ default:
+ len = searchCommentOrEol(s);
+ if (len)
+ {
+ value = new char[len+1];
+ OFStandard::strlcpy(value, s, len+1);
+ stripTrailingWhitespace(value);
+ }
+ break;
+ }
+ return ok;
+}
+
+
+static unsigned long
+fileSize(const char *fname)
+{
+ struct stat s;
+ unsigned long nbytes = 0;
+
+ if (stat(fname, &s) == 0) {
+ nbytes = s.st_size;
+ }
+ return nbytes;
+}
+
+static OFCondition
+putFileContentsIntoElement(DcmElement* elem, const char* filename)
+{
+ FILE* f = NULL;
+ OFCondition ec = EC_Normal;
+
+ if ((f = fopen(filename, "rb")) == NULL) {
+ CERR << "ERROR: cannot open binary data file: " << filename
<< endl;
+ return EC_InvalidTag;
+ }
+
+ unsigned long len = fileSize(filename);
+ unsigned long buflen = len;
+ if (buflen & 1) buflen++; /* if odd then make even (DICOM required even length
values) */
+
+ Uint8* buf = new Uint8[buflen];
+ if (buf == NULL) {
+ CERR << "ERROR: out of memory reading binary data file: "
<< filename << endl;
+ ec = EC_MemoryExhausted;
+ } else if (fread(buf, 1, OFstatic_cast(size_t, len), f) != len) {
+ CERR << "ERROR: error reading binary data file: " <<
filename << ": ";
+ perror(NULL);
+ ec = EC_CorruptedData;
+ } else {
+ /* assign buffer to attribute */
+ DcmEVR evr = elem->getVR();
+ if (evr == EVR_OB) {
+ /* put 8 bit OB data into the attribute */
+ ec = elem->putUint8Array(buf, buflen);
+ } else if (evr == EVR_OW) {
+ /* put 16 bit OW data into the attribute */
+ swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, buf, buflen,
sizeof(Uint16));
+ ec = elem->putUint16Array(OFreinterpret_cast(Uint16 *, buf), buflen / 2);
+ } else if (evr == EVR_pixelItem) {
+ /* pixel item not yet supported */
+ }
+ }
+
+ fclose(f);
+ delete[] buf;
+ return ec;
+}
+
+static OFCondition
+insertIntoSet(DcmStack & stack, DcmTagKey tagkey, DcmEVR vr, char * value)
+{
+ // insert new Element into dataset or metaheader
+
+ OFCondition l_error = EC_Normal;
+ OFCondition newElementError = EC_Normal;
+
+ if (stack.empty())
+ l_error = EC_CorruptedData;
+
+ if (l_error == EC_Normal)
+ {
+ DcmElement * newElement = NULL;
+ DcmObject * topOfStack = stack.top();
+
+ // convert tagkey to tag including VR
+ DcmTag tag(tagkey);
+ DcmVR dcmvr(vr);
+
+ const DcmEVR tagvr = tag.getEVR();
+ if (tagvr != vr && vr != EVR_UNKNOWN && tagvr != EVR_UNKNOWN
&&
+ (tagkey != DCM_LUTData || (vr != EVR_US && vr != EVR_SS && vr
!= EVR_OW)) &&
+ (tagvr != EVR_xs || (vr != EVR_US && vr != EVR_SS)) &&
+ (tagvr != EVR_ox || (vr != EVR_OB && vr != EVR_OW)) &&
+ (tagvr != EVR_na || vr != EVR_pixelItem))
+ {
+ CERR << "Warning: Tag " << tag << " with
wrong VR "
+ << dcmvr.getVRName() << " found, correct is "
+ << tag.getVR().getVRName() << endl;
+ }
+
+ if (vr != EVR_UNKNOWN)
+ tag.setVR(dcmvr);
+
+ // create new element
+ newElementError = newDicomElement(newElement, tag);
+
+ if (newElementError == EC_Normal)
+ {
+ // tag describes an Element
+ if (!newElement)
+ // Tag was ambiguous
+ l_error = EC_InvalidVR;
+ else
+ {
+ // fill value
+ if (value)
+ {
+ if (value[0] == '=' && (tag.getEVR() == EVR_OB ||
tag.getEVR() == EVR_OW))
+ {
+ /*
+ * Special case handling for OB or OW data.
+ * Allow a value beginning with a '=' character to
represent
+ * a file containing data to be used as the attribute value.
+ * A '=' character is not a normal value since OB and OW
values
+ * must be written as multivalued hexidecimal (e.g.
"00\ff\0d\8f");
+ */
+ l_error = putFileContentsIntoElement(newElement, value+1);
+ }
+ else if (tag.getEVR() == EVR_pixelItem)
+ {
+ /* pixel items not yet supported */
+ l_error = EC_InvalidTag;
+ } else {
+ l_error = newElement->putString(value);
+ }
+ }
+
+ // insert element into hierarchy
+ if (l_error == EC_Normal)
+ {
+ switch(topOfStack->ident())
+ {
+ case EVR_item:
+ case EVR_dirRecord:
+ case EVR_dataset:
+ case EVR_metainfo:
+ {
+ DcmItem *item = OFstatic_cast(DcmItem *, topOfStack);
+ item -> insert(newElement);
+ if (newElement->ident() == EVR_SQ || newElement->ident()
== EVR_pixelSQ)
+ stack.push(newElement);
+ }
+ break;
+ default:
+ l_error = EC_InvalidTag;
+ break;
+ }
+ }
+ }
+ }
+ else if (newElementError == EC_SequEnd)
+ {
+ // pop stack if stack object was a sequence
+ if (topOfStack->ident() == EVR_SQ || topOfStack->ident() ==
EVR_pixelSQ)
+ stack.pop();
+ else
+ l_error = EC_InvalidTag;
+ }
+ else if (newElementError == EC_ItemEnd)
+ {
+ // pop stack if stack object was an item
+ switch (topOfStack->ident())
+ {
+ case EVR_item:
+ case EVR_dirRecord:
+ case EVR_dataset:
+ case EVR_metainfo:
+ stack.pop();
+ break;
+
+ default:
+ l_error = EC_InvalidTag;
+ break;
+ }
+ }
+ else if (newElementError == EC_InvalidTag)
+ {
+ if (tag.getXTag() == DCM_Item)
+ {
+ DcmItem * item = NULL;
+ if (topOfStack->getTag().getXTag() == DCM_DirectoryRecordSequence)
+ {
+ // an Item must be pushed to the stack
+ item = new DcmDirectoryRecord(tag, 0);
+ OFstatic_cast(DcmSequenceOfItems *, topOfStack) -> insert(item);
+ stack.push(item);
+ }
+ else if (topOfStack->ident() == EVR_SQ)
+ {
+ // an item must be pushed to the stack
+ item = new DcmItem(tag);
+ OFstatic_cast(DcmSequenceOfItems *, topOfStack) -> insert(item);
+ stack.push(item);
+ }
+ else
+ l_error = EC_InvalidTag;
+ }
+ else
+ l_error = EC_InvalidTag;
+ }
+ else
+ {
+ l_error = EC_InvalidTag;
+ }
+ }
+
+ return l_error;
+}
+
+static OFBool
+readDumpFile(DcmMetaInfo * metaheader, DcmDataset * dataset,
+ FILE * infile, const char * ifname, const OFBool stopOnErrors,
+ const unsigned long maxLineLength)
+{
+ char * lineBuf = new char[maxLineLength];
+ int lineNumber = 0;
+ OFBool errorOnThisLine = OFFalse;
+ char * parse = NULL;
+ char * value = NULL;
+ DcmEVR vr = EVR_UNKNOWN;
+ int errorsEncountered = 0;
+ DcmTagKey tagkey;
+ DcmStack metaheaderStack;
+ DcmStack datasetStack;
+
+ if (metaheader)
+ metaheaderStack.push(metaheader);
+
+ datasetStack.push(dataset);
+
+ while(getLine(lineBuf, int(maxLineLength), infile, lineNumber+1))
+ {
+ lineNumber++;
+
+ // ignore empty lines and comment lines
+ if (onlyWhitespace(lineBuf))
+ continue;
+ if (isaCommentLine(lineBuf))
+ continue;
+
+ errorOnThisLine = OFFalse;
+
+ parse = &lineBuf[0];
+
+ // parse tag an the line
+ if (!parseTag(parse, tagkey))
+ {
+ CERR << OFFIS_CONSOLE_APPLICATION ": "<< ifname
<< ": "
+ << "no Tag found (line " << lineNumber <<
")"<< endl;
+ errorOnThisLine = OFTrue;
+ }
+
+ // parse optional VR
+ if (!errorOnThisLine && !parseVR(parse, vr))
+ vr = EVR_UNKNOWN;
+
+ // parse optional value
+ if (!errorOnThisLine && !parseValue(parse, value, vr))
+ {
+ CERR << OFFIS_CONSOLE_APPLICATION ": "<< ifname
<< ": "
+ << "incorrect value specification (line " <<
lineNumber << ")"<< endl;
+ errorOnThisLine = OFTrue;
+ }
+
+
+ // insert new element that consists of tag, VR, and value
+ if (!errorOnThisLine)
+ {
+ OFCondition l_error = EC_Normal;
+ if (tagkey.getGroup() == 2)
+ {
+ if (metaheader)
+ l_error = insertIntoSet(metaheaderStack, tagkey, vr, value);
+ }
+ else
+ l_error = insertIntoSet(datasetStack, tagkey, vr, value);
+
+ if (value)
+ {
+ delete[] value;
+ value = NULL;
+ }
+ if (l_error != EC_Normal)
+ {
+ errorOnThisLine = OFTrue;
+ CERR << OFFIS_CONSOLE_APPLICATION ": " << ifname
<< ": Error in creating Element: "
+ << l_error.text() << " (line " <<
lineNumber << ")"<< endl;
+ }
+
+ }
+
+ if (errorOnThisLine)
+ errorsEncountered++;
+ }
+
+
+ // test blocking structure
+ if (metaheader && metaheaderStack.card() != 1)
+ {
+ CERR << OFFIS_CONSOLE_APPLICATION ": " << ifname <<
": Block Error in metaheader" << endl;
+ errorsEncountered++;
+ }
+
+ if (datasetStack.card() != 1)
+ {
+ CERR << OFFIS_CONSOLE_APPLICATION ": " << ifname <<
": Block Error in dataset" << endl;
+ errorsEncountered++;
+ }
+
+ delete[] lineBuf;
+
+ if (errorsEncountered)
+ {
+ CERR << errorsEncountered << " Errors found in " <<
ifname << endl;
+ return !stopOnErrors;
+ }
+ else
+ return OFTrue;
+}
+
+// ********************************************
+
+int main(int argc, char *argv[])
+{
+#ifdef HAVE_GUSI_H
+ GUSISetup(GUSIwithSIOUXSockets);
+ GUSISetup(GUSIwithInternetSockets);
+#endif
+
+ SetDebugLevel(( 0 ));
+
+ OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION , "Convert ASCII dump to
DICOM file", rcsid);
+ OFCommandLine cmd;
+
+ cmd.setOptionColumns(LONGCOL, SHORTCOL);
+ cmd.setParamColumn(LONGCOL + SHORTCOL + 4);
+
+ cmd.addParam("dumpfile-in", "dump input filename");
+ cmd.addParam("dcmfile-out", "DICOM output filename");
+
+ cmd.addGroup("general options:", LONGCOL, SHORTCOL + 2);
+ cmd.addOption("--help", "-h",
"print this help text and exit");
+ cmd.addOption("--version", "print
version information and exit", OFTrue /* exclusive */);
+ cmd.addOption("--verbose", "-v",
"verbose mode, print processing details");
+ cmd.addOption("--debug", "-d",
"debug mode, print debug information");
+
+ cmd.addGroup("input options:", LONGCOL, SHORTCOL + 2);
+ cmd.addOption("--line", "+l", 1,
"[m]ax-length: integer",
+ "maximum line length
m (default 4096)");
+
+ cmd.addGroup("output options:");
+ cmd.addSubGroup("output file format:");
+ cmd.addOption("--write-file", "+F",
"write file format (default)");
+ cmd.addOption("--write-dataset", "-F",
"write data set without file meta information");
+ cmd.addSubGroup("output transfer syntax:");
+ cmd.addOption("--write-xfer-little", "+te",
"write with explicit VR little endian (default)");
+ cmd.addOption("--write-xfer-big", "+tb",
"write with explicit VR big endian TS");
+ cmd.addOption("--write-xfer-implicit", "+ti",
"write with implicit VR little endian TS");
+ cmd.addSubGroup("error handling:");
+ cmd.addOption("--stop-on-error", "-E",
"do not write if dump is damaged (default)");
+ cmd.addOption("--ignore-errors", "+E",
"attempt to write even if dump is damaged");
+ cmd.addSubGroup("post-1993 value representations:");
+ cmd.addOption("--enable-new-vr", "+u",
"enable support for new VRs (UN/UT) (default)");
+ cmd.addOption("--disable-new-vr", "-u",
"disable support for new VRs, convert to OB");
+ cmd.addSubGroup("group length encoding:");
+ cmd.addOption("--group-length-recalc", "+g=",
"recalculate group lengths if present (default)");
+ cmd.addOption("--group-length-create", "+g",
"always write with group length elements");
+ cmd.addOption("--group-length-remove", "-g",
"always write without group length elements");
+ cmd.addSubGroup("length encoding in sequences and items:");
+ cmd.addOption("--length-explicit", "+e",
"write with explicit lengths (default)");
+ cmd.addOption("--length-undefined", "-e",
"write with undefined lengths");
+ cmd.addSubGroup("data set trailing padding (not with
--write-dataset):");
+ cmd.addOption("--padding-retain", "-p=",
"do not change padding\n(default if not --write-dataset)");
+ cmd.addOption("--padding-off", "-p",
"no padding (implicit if --write-dataset)");
+ cmd.addOption("--padding-create", "+p", 2,
"[f]ile-pad [i]tem-pad: integer",
+ "align file on
multiple of f bytes\nand items on multiple of i bytes");
+
+ int opt_debugMode = 0;
+ const char* ifname = NULL;
+ const char* ofname = NULL;
+ E_TransferSyntax oxfer = EXS_LittleEndianExplicit;
+ E_EncodingType oenctype = EET_ExplicitLength;
+ E_GrpLenEncoding oglenc = EGL_recalcGL;
+ E_PaddingEncoding opadenc = EPD_withoutPadding;
+ OFCmdUnsignedInt opt_filepad = 0;
+ OFCmdUnsignedInt opt_itempad = 0;
+ OFCmdUnsignedInt opt_linelength = DCM_DumpMaxLineSize;
+ OFBool verbosemode = OFFalse;
+ OFBool stopOnErrors = OFTrue;
+ OFBool createFileFormat = OFTrue;
+
+ /* evaluate command line */
+ prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION);
+ if (app.parseCommandLine(cmd, argc, argv, OFCommandLine::ExpandWildcards))
+ {
+ /* check exclusive options first */
+
+ if (cmd.getParamCount() == 0)
+ {
+ if (cmd.findOption("--version"))
+ {
+ app.printHeader(OFTrue /*print host identifier*/); // uses
ofConsole.lockCerr()
+ CERR << endl << "External libraries used:";
+#ifdef WITH_ZLIB
+ CERR << endl << "- ZLIB, Version " <<
zlibVersion() << endl;
+#else
+ CERR << " none" << endl;
+#endif
+ return 0;
+ }
+ }
+
+ /* command line parameters */
+
+ cmd.getParam(1, ifname);
+ cmd.getParam(2, ofname);
+
+ if (cmd.findOption("--verbose")) verbosemode = OFTrue;
+ if (cmd.findOption("--debug")) opt_debugMode = 5;
+
+ if (cmd.findOption("--line"))
+ {
+ app.checkValue(cmd.getValueAndCheckMin(opt_linelength, 80));
+ }
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--write-file")) createFileFormat = OFTrue;
+ if (cmd.findOption("--write-dataset")) createFileFormat = OFFalse;
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--write-xfer-little")) oxfer =
EXS_LittleEndianExplicit;
+ if (cmd.findOption("--write-xfer-big")) oxfer = EXS_BigEndianExplicit;
+ if (cmd.findOption("--write-xfer-implicit")) oxfer =
EXS_LittleEndianImplicit;
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--stop-on-error")) stopOnErrors = OFTrue;
+ if (cmd.findOption("--ignore-errors")) stopOnErrors = OFFalse;
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--enable-new-vr"))
+ {
+ dcmEnableUnknownVRGeneration.set(OFTrue);
+ dcmEnableUnlimitedTextVRGeneration.set(OFTrue);
+ }
+ if (cmd.findOption("--disable-new-vr"))
+ {
+ dcmEnableUnknownVRGeneration.set(OFFalse);
+ dcmEnableUnlimitedTextVRGeneration.set(OFFalse);
+ }
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--group-length-recalc")) oglenc = EGL_recalcGL;
+ if (cmd.findOption("--group-length-create")) oglenc = EGL_withGL;
+ if (cmd.findOption("--group-length-remove")) oglenc = EGL_withoutGL;
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--length-explicit")) oenctype = EET_ExplicitLength;
+ if (cmd.findOption("--length-undefined")) oenctype =
EET_UndefinedLength;
+ cmd.endOptionBlock();
+
+ cmd.beginOptionBlock();
+ if (cmd.findOption("--padding-retain"))
+ {
+ if (!createFileFormat) app.printError("--padding-retain not allowed with
--write-dataset");
+ opadenc = EPD_noChange;
+ }
+ if (cmd.findOption("--padding-off")) opadenc = EPD_withoutPadding;
+ if (cmd.findOption("--padding-create"))
+ {
+ if (!createFileFormat) app.printError("--padding-create not allowed with
--write-dataset");
+ app.checkValue(cmd.getValueAndCheckMin(opt_filepad, 0));
+ app.checkValue(cmd.getValueAndCheckMin(opt_itempad, 0));
+ opadenc = EPD_withPadding;
+ }
+ cmd.endOptionBlock();
+
+ }
+
+ DcmFileFormat fileformat;
+ DcmMetaInfo * metaheader = fileformat.getMetaInfo();
+ DcmDataset * dataset = fileformat.getDataset();
+
+ SetDebugLevel((opt_debugMode));
+
+ /* make sure data dictionary is loaded */
+ if (!dcmDataDict.isDictionaryLoaded()) {
+ CERR << "Warning: no data dictionary loaded, "
+ << "check environment variable: "
+ << DCM_DICT_ENVIRONMENT_VARIABLE << endl;
+ }
+
+ if (verbosemode)
+ COUT << "reading dump file: " << ifname << endl;
+
+ // open input dump file
+ if ((ifname == NULL) || (strlen(ifname) == 0))
+ {
+ CERR << "invalid input filename: <empty string>" <<
endl;
+ return 1;
+ }
+ FILE * dumpfile = fopen(ifname, "r");
+ if (!dumpfile)
+ {
+ CERR << "input file does not exist: " << ifname <<
endl;
+ return 1;
+ }
+
+ // read dump file into metaheader and dataset
+ if (readDumpFile(metaheader, dataset, dumpfile, ifname, stopOnErrors,
+ OFstatic_cast(unsigned long, opt_linelength)))
+ {
+ // write into file format or dataset
+ if (verbosemode)
+ COUT << "writing DICOM file" << endl;
+
+ OFCondition l_error = fileformat.saveFile(ofname, oxfer, oenctype, oglenc,
opadenc,
+ OFstatic_cast(Uint32, opt_filepad), OFstatic_cast(Uint32, opt_itempad),
!createFileFormat);
+
+ if (l_error == EC_Normal)
+ COUT << "dump successfully converted." << endl;
+ else
+ {
+ CERR << "Error: " << l_error.text()
+ << ": writing file: " << ofname << endl;
+ return 1;
+ }
+ }
+
+ return 0;
+}
Index: trunk/milena/sandbox/fabien/dcmtk/Makefile
===================================================================
--- trunk/milena/sandbox/fabien/dcmtk/Makefile (revision 0)
+++ trunk/milena/sandbox/fabien/dcmtk/Makefile (revision 3432)
@@ -0,0 +1,2 @@
+all: dicom.cc
+ g++-4.2 -DHAVE_CONFIG_H -I../../../ -I/opt/local/include/ -L/opt/local/lib/ -ldcmdata
-ldcmdsig -ldcmimage -ldcmimgle -ldcmjpeg -ldcmnet -ldcmpstat -ldcmqrdb -ldcmsr -ldcmtls
-ldcmwlm dicom.cc -o dicom
Index: trunk/milena/sandbox/fabien/dcmtk/load.hh
===================================================================
--- trunk/milena/sandbox/fabien/dcmtk/load.hh (revision 0)
+++ trunk/milena/sandbox/fabien/dcmtk/load.hh (revision 3432)
@@ -0,0 +1,388 @@
+// Copyright (C) 2009 EPITA Research and Development Laboratory
+//
+// This file is part of the Olena Library. This library is free
+// software; you can redistribute it and/or modify it under the terms
+// of the GNU General Public License version 2 as published by the
+// Free Software Foundation.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this library; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02111-1307, USA.
+//
+// As a special exception, you may use this file as part of a free
+// software library without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to
+// produce an executable, this file does not by itself cause the
+// resulting executable to be covered by the GNU General Public
+// License. This exception does not however invalidate any other
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+
+/*
+ *
+ * Copyright (C) 1994-2005, OFFIS
+ *
+ * This software and supporting documentation were developed by
+ *
+ * Kuratorium OFFIS e.V.
+ * Healthcare Information and Communication Systems
+ * Escherweg 2
+ * D-26121 Oldenburg, Germany
+ *
+ * THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND OFFIS MAKES NO WARRANTY
+ * REGARDING THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY OR
+ * FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES OR
+ * ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
+ *
+ * Module: dcmdata
+ *
+ * Author: Gerd Ehlers
+ *
+ * Purpose: List the contents of a dicom file
+ *
+ * Last Update: $Author: meichel $
+ * Update Date: $Date: 2005/12/08 15:40:46 $
+ * CVS/RCS Revision: $Revision: 1.55 $
+ * Status: $State: Exp $
+ *
+ * CVS/RCS Log at end of file
+ *
+ */
+
+#ifndef MLN_IO_DICOM_LOAD_HH
+# define MLN_IO_DICOM_LOAD_HH
+
+/*!
+ * \file mln/io/dicom/load.hh
+ *
+ * \brief Define a function which loads an image of kind dicom with
+ * given path.
+ *
+ */
+
+# include <mln/io/pnm/load.hh>
+
+# include <dcmtk/config/osconfig.h> /* make sure OS specific configuration is
included first */
+# include <dcmtk/ofstd/ofstream.h>
+# include <dcmtk/dcmdata/dctk.h>
+# include <dcmtk/dcmdata/dcdebug.h>
+# include <dcmtk/dcmdata/cmdlnarg.h>
+# include <dcmtk/ofstd/ofconapp.h>
+# include <dcmtk/dcmdata/dcuid.h> /* for dcmtk version name */
+# include <dcmtk/dcmdata/dcistrmz.h> /* for dcmZlibExpectRFC1950Encoding */
+
+# define INCLUDE_CSTDLIB
+# define INCLUDE_CSTRING
+# include <dcmtk/ofstd/ofstdinc.h>
+
+# ifdef WITH_ZLIB
+# include <zlib.h> /* for zlibVersion() */
+# endif
+
+# define SHORTCOL 3
+# define LONGCOL 20
+# define PATH_SEPARATOR '/'
+
+
+
+namespace mln
+{
+
+ namespace io
+ {
+
+ namespace dicom
+ {
+
+ /*! Load a dicom image in a Milena image.
+ *
+ * \param[out] ima A reference to the image which will receive
+ * data.
+ * \param[in] filename The source.
+ */
+ template <typename I>
+ void load(Image<I>& ima,
+ const std::string& filename);
+
+ /*! Load a dicom image in a Milena image. To use this routine, you
+ * should specialize the template whith the value type of the
+ * image loaded. (ex : load<value::int_u8>("...") )
+ *
+ * \param[in] filename The image source.
+ *
+ * \return An image2d which contains loaded data.
+ */
+ template <typename V>
+ image2d<V> load(const std::string& filename);
+
+ /*! Load a dicom image in a Milena image. To use this routine, you
+ * should specialize the template whith the value type of the
+ * image loaded. (ex : load<value::int_u8>("...") )
+ *
+ * \param[in] filename The image source.
+ *
+ * \return An image2d which contains loaded data.
+ */
+ template <typename V>
+ image3d<V> load(const std::string& filename);
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename V>
+ inline
+ image2d<V> load(const std::string& filename)
+ {
+ trace::entering("mln::io::dicom::load");
+ image2d<V> ima;// = io::pnm::load<V>(DICOM, filename);
+ trace::exiting("mln::io::dicom::load");
+ return ima;
+ }
+
+ template <typename V>
+ inline
+ image3d<V> load(const std::string& filename)
+ {
+ trace::entering("mln::io::dicom::load");
+ image2d<V> ima;// = io::pnm::load<V>(DICOM, filename);
+ trace::exiting("mln::io::dicom::load");
+ return ima;
+ }
+
+
+
+
+
+
+ static OFBool printAllInstances = OFTrue;
+ static OFBool prependSequenceHierarchy = OFFalse;
+ static int printTagCount = 0;
+ static const int MAX_PRINT_TAG_NAMES = 1024;
+ static const char* printTagNames[MAX_PRINT_TAG_NAMES];
+ static const DcmTagKey* printTagKeys[MAX_PRINT_TAG_NAMES];
+ static OFCmdUnsignedInt maxReadLength = 4096; // default is 4 KB
+
+ static OFBool addPrintTagName(const char* tagName)
+ {
+ if (printTagCount >= MAX_PRINT_TAG_NAMES) {
+ std::cerr << "error: too many print Tag options (max: " <<
MAX_PRINT_TAG_NAMES << ")" << endl;
+ return OFFalse;
+ }
+
+ unsigned int group = 0xffff;
+ unsigned int elem = 0xffff;
+ if (sscanf(tagName, "%x,%x", &group, &elem) != 2)
+ {
+ /* it is a name */
+ const DcmDataDictionary& globalDataDict = dcmDataDict.rdlock();
+ const DcmDictEntry *dicent = globalDataDict.findEntry(tagName);
+ if (dicent == NULL)
+ {
+ std::cerr << "error: unrecognised tag name: '" << tagName
<< "'" << endl;
+ dcmDataDict.unlock();
+ return OFFalse;
+ }
+ else
+ {
+ /* note for later */
+ printTagKeys[printTagCount] = new DcmTagKey(dicent->getKey());
+ }
+ dcmDataDict.unlock();
+ }
+ else
+ {
+ /* tag name has format xxxx,xxxx */
+ /* do not lookup in dictionary, tag could be private */
+ printTagKeys[printTagCount] = NULL;
+ }
+
+ printTagNames[printTagCount] = strcpy(OFstatic_cast(char*, malloc(strlen(tagName)+1)),
tagName);
+ printTagCount++;
+ return OFTrue;
+ }
+
+
+ template <typename I>
+ static void printResult(Image<I>& ima, DcmStack& stack, size_t
printFlags)
+ {
+ unsigned long n = stack.card();
+ if (n == 0)
+ return;
+
+ if (prependSequenceHierarchy) {
+ /* print the path leading up to the top stack elem */
+ for (unsigned long i = n - 1; i >= 1; i--) {
+ DcmObject *dobj = stack.elem(i);
+ /* do not print if a DCM_Item as this is not
+ * very helpful to distinguish instances.
+ */
+ if (dobj != NULL && dobj->getTag().getXTag() != DCM_Item) {
+ char buf[512];
+ sprintf(buf, "(%x,%x).",
+ OFstatic_cast(unsigned, dobj->getGTag()),
+ OFstatic_cast(unsigned, dobj->getETag()));
+ std::cout << buf;
+ }
+ }
+ }
+
+ /* print the tag and its value */
+ DcmObject *dobj = stack.top();
+ dobj->print(std::cout, printFlags);
+ }
+
+ template <typename I>
+ static int dumpFile(Image<I>& ima,
+ const char *ifname,
+ const E_FileReadMode readMode,
+ const E_TransferSyntax xfer,
+ const size_t printFlags,
+ const OFBool loadIntoMemory,
+ const OFBool stopOnErrors,
+ const OFBool writePixelData,
+ const char *pixelDirectory)
+ {
+ int result = 0;
+
+ DcmFileFormat dfile;
+ DcmObject *dset = &dfile;
+
+ if (readMode == ERM_dataset)
+ dset = dfile.getDataset();
+
+ // Load file
+
+ OFCondition cond = dfile.loadFile(ifname, xfer, EGL_noChange, maxReadLength, readMode);
+
+ // Read error
+
+ if (!cond.good())
+ {
+ std::cerr << "error: " << dfile.error().text()
+ << ": reading file: "<< ifname << endl;
+ result = 1;
+ if (stopOnErrors)
+ return result;
+ }
+
+ if (loadIntoMemory)
+ dfile.loadAllDataIntoMemory();
+
+ if (printTagCount == 0)
+ {
+ if (writePixelData)
+ {
+ OFString str = ifname;
+ OFString rname = pixelDirectory;
+ if ((rname.length() > 0) && (rname[rname.length() - 1] !=
PATH_SEPARATOR))
+ rname += PATH_SEPARATOR;
+ size_t pos = str.find_last_of(PATH_SEPARATOR);
+ if (pos == OFString_npos)
+ rname += str;
+ else
+ rname += str.substr(pos + 1);
+ size_t counter = 0;
+ dset->print(std::cout, printFlags, 0 /*level*/, rname.c_str(), &counter);
+ }
+ else
+ dset->print(std::cout, printFlags);
+ }
+ else
+ {
+ /* only print specified tags */
+ for (int i = 0; i < printTagCount; i++)
+ {
+ unsigned int group = 0xffff;
+ unsigned int elem = 0xffff;
+ DcmTagKey searchKey;
+ const char* tagName = printTagNames[i];
+ if (printTagKeys[i])
+ searchKey = *printTagKeys[i];
+ else
+ {
+ if (sscanf(tagName, "%x,%x", &group, &elem) == 2)
+ searchKey.set(group, elem);
+ else
+ {
+ std::cerr << "Internal ERROR in File " << __FILE__ <<
", Line "
+ << __LINE__ << std::endl
+ << "-- Named tag inconsistency" << std::endl;
+ abort();
+ }
+ }
+
+ DcmStack stack;
+ if (dset->search(searchKey, stack, ESM_fromHere, OFTrue) == EC_Normal)
+ {
+ printResult(ima, stack, printFlags);
+ if (printAllInstances)
+ {
+ while (dset->search(searchKey, stack, ESM_afterStackTop, OFTrue) == EC_Normal)
+ printResult(ima, stack, printFlags);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+
+ template <typename I>
+ inline
+ void load(Image<I>& ima,
+ const std::string& filename)
+ {
+ trace::entering("mln::io::dicom::load");
+
+ std::ifstream file(filename.c_str());
+ if (! file)
+ {
+ std::cerr << "error: cannot open file '" << filename
<< "'!";
+ abort();
+ }
+
+ int opt_debugMode = 0;
+ OFBool loadIntoMemory = OFTrue;
+ size_t printFlags = DCMTypes::PF_shortenLongTagValues /*|
DCMTypes::PF_showTreeStructure*/;
+ OFBool printFilename = OFFalse;
+ OFBool writePixelData = OFFalse;
+ E_FileReadMode readMode = ERM_autoDetect;
+ E_TransferSyntax xfer = EXS_Unknown;
+ OFBool stopOnErrors = OFTrue;
+ const char *current = NULL;
+ const char *pixelDirectory = NULL;
+
+
+ /* make sure data dictionary is loaded */
+ if (!dcmDataDict.isDictionaryLoaded())
+ {
+ std::cerr << "Warning: no data dictionary loaded, "
+ << "check environment variable: "
+ << DCM_DICT_ENVIRONMENT_VARIABLE;
+ }
+
+ int errorCount = 0;
+ dumpFile(ima, current, readMode, xfer, printFlags, loadIntoMemory, stopOnErrors,
+ writePixelData, pixelDirectory);
+
+ trace::exiting("mln::io::dicom::load");
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::io::dicom
+
+ } // end of namespace mln::io
+
+} // end of namespace mln
+
+
+#endif // ! MLN_IO_DICOM_LOAD_HH