r3432: Clean sandbox

URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox ChangeLog: 2009-02-27 Fabien Freling <fabien.freling@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
participants (1)
-
Fabien Freling