text: /*
   *
   *  Copyright (C) 1996-2014, OFFIS e.V.
   *  All rights reserved.  See COPYRIGHT file for details.
   *
   *  This software and supporting documentation were developed by
   *
   *    OFFIS e.V.
   *    R&D Division Health
   *    Escherweg 2
   *    D-26121 Oldenburg, Germany
   *
   *
   *  Module:  dcmimage
   *
   *  Authors: Marco Eichelberg, Joerg Riesmeier
   *
   *  Purpose: Convert DICOM Images to PPM or PGM using the dcmimage library.
   *
   */
  
  
  #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
  
  #define INCLUDE_CSTDIO
  #define INCLUDE_CSTRING
  #include "dcmtk/ofstd/ofstdinc.h"
  
  #ifdef HAVE_GUSI_H
  #include <GUSI.h>
  #endif
  
  #include "dcmtk/dcmdata/dctk.h"          /* for various dcmdata headers */
  #include "dcmtk/dcmdata/cmdlnarg.h"      /* for prepareCmdLineArgs */
  #include "dcmtk/dcmdata/dcuid.h"         /* for dcmtk version name */
  #include "dcmtk/dcmdata/dcrledrg.h"      /* for DcmRLEDecoderRegistration */
  
  #include "dcmtk/dcmimgle/dcmimage.h"     /* for DicomImage */
  #include "dcmtk/dcmimgle/digsdfn.h"      /* for DiGSDFunction */
  #include "dcmtk/dcmimgle/diciefn.h"      /* for DiCIELABFunction */
  
  #include "dcmtk/ofstd/ofconapp.h"        /* for OFConsoleApplication */
  #include "dcmtk/ofstd/ofcmdln.h"         /* for OFCommandLine */
  
  #include "dcmtk/dcmimage/diregist.h"     /* include to support color images */
  #include "dcmtk/ofstd/ofstd.h"           /* for OFStandard */
  
  #ifdef BUILD_DCM2PNM_AS_DCMJ2PNM
  #include "dcmtk/dcmjpeg/djdecode.h"      /* for dcmjpeg decoders */
  #include "dcmtk/dcmjpeg/dipijpeg.h"      /* for dcmimage JPEG plugin */
  #endif
  
  #ifdef BUILD_DCM2PNM_AS_DCML2PNM
  #include "dcmtk/dcmjpls/djdecode.h"      /* for dcmjpls decoders */
  #endif
  
  #ifdef WITH_LIBTIFF
  #include "dcmtk/dcmimage/dipitiff.h"     /* for dcmimage TIFF plugin */
  #endif
  
  #ifdef WITH_LIBPNG
  #include "dcmtk/dcmimage/dipipng.h"      /* for dcmimage PNG plugin */
  #endif
  
  #ifdef WITH_ZLIB
  #include <zlib.h>                        /* for zlibVersion() */
  #endif
  
  #include "dcmtk/ofstd/ofstream.h"
  #include "dcmtk/oflog/oflog.h"
  
  #define OFFIS_OUTFILE_DESCRIPTION "output filename to be written (default: stdout)"
  
  #ifdef BUILD_DCM2PNM_AS_DCML2PNM
  # define OFFIS_CONSOLE_APPLICATION "dcml2pnm"
  #elif defined(BUILD_DCM2PNM_AS_DCMJ2PNM)
  # define OFFIS_CONSOLE_APPLICATION "dcmj2pnm"
  #else
  # define OFFIS_CONSOLE_APPLICATION "dcm2pnm"
  #endif
  
  static OFLogger dcm2pnmLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION);
  
  static const char *consoleDescription = "Convert DICOM images to PGM/PPM"
  #ifdef WITH_LIBPNG
    ", PNG"
  #endif
  #ifdef WITH_LIBTIFF
    ", TIFF"
  #endif
  #ifdef BUILD_DCM2PNM_AS_DCMJ2PNM
    ", JPEG"
  #endif
    " or BMP";
  
  static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v"
    OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $";
  
  #define SHORTCOL 4
  #define LONGCOL 20
  
  /* output file types */
  enum E_FileType
  {
      EFT_RawPNM,
      EFT_8bitPNM,
      EFT_16bitPNM,
      EFT_NbitPNM,
      EFT_BMP,
      EFT_8bitBMP,
      EFT_24bitBMP,
      EFT_32bitBMP,
      EFT_JPEG,
      EFT_TIFF,
      EFT_PNG,
      EFT_16bitPNG
  #ifdef PASTEL_COLOR_OUTPUT
     ,EFT_PastelPNM
  #endif
  };
  
  
  // ********************************************
  
  int main(int argc, char *argv[])
  {
      OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION, consoleDescription, rcsid);
      OFCommandLine cmd;
  
      E_FileReadMode      opt_readMode = ERM_autoDetect;    /* default: fileformat or dataset */
      E_TransferSyntax    opt_transferSyntax = EXS_Unknown; /* default: xfer syntax recognition */
  
      unsigned long       opt_compatibilityMode = CIF_MayDetachPixelData | CIF_TakeOverExternalDataset;
      OFBool              opt_ignoreVoiLutDepth = OFFalse;  /* default: do not ignore VOI LUT bit depth */
      OFCmdUnsignedInt    opt_frame = 1;                    /* default: first frame */
      OFCmdUnsignedInt    opt_frameCount = 1;               /* default: one frame */
      OFBool              opt_useFrameNumber = OFFalse;     /* default: use frame counter */
      OFBool              opt_multiFrame = OFFalse;         /* default: no multiframes */
      int                 opt_convertToGrayscale = 0;       /* default: color or grayscale */
      int                 opt_changePolarity = 0;           /* default: normal polarity */
      int                 opt_useAspectRatio = 1;           /* default: use aspect ratio for scaling */
      OFCmdUnsignedInt    opt_useInterpolation = 1;         /* default: use interpolation method '1' for scaling */
      int                 opt_useClip = 0;                  /* default: don't clip */
      OFCmdSignedInt      opt_left = 0, opt_top = 0;        /* clip region (origin) */
      OFCmdUnsignedInt    opt_width = 0, opt_height = 0;    /* clip region (extension) */
      int                 opt_rotateDegree = 0;             /* default: no rotation */
      int                 opt_flipType = 0;                 /* default: no flipping */
      int                 opt_scaleType = 0;                /* default: no scaling */
                          /* 1 = X-factor, 2 = Y-factor, 3=X-size, 4=Y-size */
      OFCmdFloat          opt_scale_factor = 1.0;
      OFCmdUnsignedInt    opt_scale_size = 1;
      int                 opt_windowType = 0;               /* default: no windowing */
                          /* 1=Wi, 2=Wl, 3=Wm, 4=Wh, 5=Ww, 6=Wn, 7=Wr */
      OFCmdUnsignedInt    opt_windowParameter = 0;
      OFCmdUnsignedInt    opt_roiLeft = 0, opt_roiTop = 0, opt_roiWidth = 0, opt_roiHeight = 0;
      OFCmdFloat          opt_windowCenter = 0.0, opt_windowWidth = 0.0;
  
      EF_VoiLutFunction   opt_voiFunction = EFV_Default;
      ES_PresentationLut  opt_presShape = ESP_Default;
      OFString            opt_displayFile;
      int                 opt_displayFunction = 0;          /* default: GSDF */
                          /* 0=GSDF, 1=CIELAB */
      OFCmdFloat          opt_ambientLight = -1;            /* default: not set */
      OFCmdFloat          opt_illumination = -1;            /* default: not set */
      OFCmdFloat          opt_minDensity = -1;              /* default: not set */
      OFCmdFloat          opt_maxDensity = -1;              /* default: not set */
      DiDisplayFunction::E_DeviceType deviceType = DiDisplayFunction::EDT_Monitor;
  
  #ifdef WITH_LIBTIFF
      // TIFF parameters
  #ifdef HAVE_LIBTIFF_LZW_COMPRESSION
      DiTIFFCompression   opt_tiffCompression = E_tiffLZWCompression;
  #else
      DiTIFFCompression   opt_tiffCompression = E_tiffPackBitsCompression;
  #endif
      DiTIFFLZWPredictor  opt_lzwPredictor = E_tiffLZWPredictorDefault;
      OFCmdUnsignedInt    opt_rowsPerStrip = 0;
  #endif
  
  #ifdef WITH_LIBPNG
      // PNG parameters
      DiPNGInterlace      opt_interlace = E_pngInterlaceAdam7;
      DiPNGMetainfo       opt_metainfo  = E_pngFileMetainfo;
  #endif
  
  #ifdef BUILD_DCM2PNM_AS_DCMJ2PNM
      // JPEG parameters
      OFCmdUnsignedInt    opt_quality = 90;                 /* default: 90% JPEG quality */
      E_SubSampling       opt_sampling = ESS_422;           /* default: 4:2:2 sub-sampling */
      E_DecompressionColorSpaceConversion opt_decompCSconversion = EDC_photometricInterpretation;
  #endif
  
      int                 opt_Overlay[16];
      int                 opt_O_used = 0;                   /* flag for +O parameter */
      EM_Overlay          opt_OverlayMode = EMO_Default;    /* default: Replace or ROI */
  
      OFCmdFloat          opt_foregroundDensity = 1.0;
      OFCmdFloat          opt_thresholdDensity  = 0.5;
  
      int                 opt_imageInfo = 0;                /* default: no info */
      int                 opt_suppressOutput = 0;           /* default: create output */
      E_FileType          opt_fileType = EFT_RawPNM;        /* default: 8-bit PGM/PPM */
                                                            /* (binary for file output and ASCII for stdout) */
      OFCmdUnsignedInt    opt_fileBits = 0;                 /* default: 0 */
      const char *        opt_ifname = NULL;
      const char *        opt_ofname = NULL;
  
      unsigned long i;
      for (i = 0; i < 16; i++)
          opt_Overlay[i] = 2;                               /* default: display all overlays if present */
  
      prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION);
      cmd.setOptionColumns(LONGCOL, SHORTCOL);
  
      cmd.addParam("dcmfile-in",  "DICOM input filename to be converted");
      cmd.addParam("bitmap-out", OFFIS_OUTFILE_DESCRIPTION, OFCmdParam::PM_Optional);
  
      cmd.addGroup("general options:", LONGCOL, SHORTCOL + 2);
       cmd.addOption("--help",                "-h",      "print this help text and exit", OFCommandLine::AF_Exclusive);
       cmd.addOption("--version",                        "print version information and exit", OFCommandLine::AF_Exclusive);
       OFLog::addOptions(cmd);
  
      cmd.addGroup("input options:");
  
       cmd.addSubGroup("input file format:");
        cmd.addOption("--read-file",          "+f",      "read file format or data set (default)");
        cmd.addOption("--read-file-only",     "+fo",     "read file format only");
        cmd.addOption("--read-dataset",       "-f",      "read data set without file meta information");
  
       cmd.addSubGroup("input transfer syntax:");
        cmd.addOption("--read-xfer-auto",     "-t=",     "use TS recognition (default)");
        cmd.addOption("--read-xfer-detect",   "-td",     "ignore TS specified in the file meta header");
        cmd.addOption("--read-xfer-little",   "-te",     "read with explicit VR little endian TS");
        cmd.addOption("--read-xfer-big",      "-tb",     "read with explicit VR big endian TS");
        cmd.addOption("--read-xfer-implicit", "-ti",     "read with implicit VR little endian TS");
  
      cmd.addGroup("image processing options:");
  
       cmd.addSubGroup("frame selection:");
        cmd.addOption("--frame",              "+F",   1, "[n]umber: integer",
                                                          "select specified frame (default: 1)");
        cmd.addOption("--frame-range",        "+Fr",  2, "[n]umber [c]ount: integer",
                                                         "select c frames beginning with frame n");
        cmd.addOption("--all-frames",         "+Fa",     "select all frames");
  
       cmd.addSubGroup("rotation:");
        cmd.addOption("--rotate-left",        "+Rl",     "rotate image left (-90 degrees)");
        cmd.addOption("--rotate-right",       "+Rr",     "rotate image right (+90 degrees)");
        cmd.addOption("--rotate-top-down",    "+Rtd",    "rotate image top-down (180 degrees)");
  
       cmd.addSubGroup("flipping:");
        cmd.addOption("--flip-horizontally",  "+Lh",     "flip image horizontally");
        cmd.addOption("--flip-vertically",    "+Lv",     "flip image vertically");
        cmd.addOption("--flip-both-axes",     "+Lhv",    "flip image horizontally and vertically");
  
       cmd.addSubGroup("scaling:");
        cmd.addOption("--recognize-aspect",   "+a",      "recognize pixel aspect ratio (default)");
        cmd.addOption("--ignore-aspect",      "-a",      "ignore pixel aspect ratio when scaling");
        cmd.addOption("--interpolate",        "+i",   1, "[n]umber of algorithm: integer",
                                                         "use interpolation when scaling (1..4, def: 1)");
        cmd.addOption("--no-interpolation",   "-i",      "no interpolation when scaling");
        cmd.addOption("--no-scaling",         "-S",      "no scaling, ignore pixel aspect ratio (default)");
        cmd.addOption("--scale-x-factor",     "+Sxf", 1, "[f]actor: float",
                                                         "scale x axis by factor, auto-compute y axis");
        cmd.addOption("--scale-y-factor",     "+Syf", 1, "[f]actor: float",
                                                         "scale y axis by factor, auto-compute x axis");
        cmd.addOption("--scale-x-size",       "+Sxv", 1, "[n]umber: integer",
                                                         "scale x axis to n pixels, auto-compute y axis");
        cmd.addOption("--scale-y-size",       "+Syv", 1, "[n]umber: integer",
                                                         "scale y axis to n pixels, auto-compute x axis");
  #ifdef BUILD_DCM2PNM_AS_DCMJ2PNM
       cmd.addSubGroup("color space conversion (compressed images only):");
        cmd.addOption("--conv-photometric",   "+cp",     "convert if YCbCr photometric interpr. (default)");
        cmd.addOption("--conv-lossy",         "+cl",     "convert YCbCr to RGB if lossy JPEG");
        cmd.addOption("--conv-guess",         "+cg",     "convert to RGB if YCbCr is guessed by library");
        cmd.addOption("--conv-guess-lossy",   "+cgl",    "convert to RGB if lossy JPEG and YCbCr is\nguessed by the underlying JPEG library");
        cmd.addOption("--conv-always",        "+ca",     "always convert YCbCr to RGB");
        cmd.addOption("--conv-never",         "+cn",     "never convert color space");
  #endif
  
       cmd.addSubGroup("modality LUT transformation:");
        cmd.addOption("--no-modality",        "-M",      "ignore stored modality LUT transformation");
        cmd.addOption("--use-modality",       "+M",      "use modality LUT transformation (default)");
  
       cmd.addSubGroup("VOI LUT transformation:");
        cmd.addOption("--no-windowing",       "-W",      "no VOI windowing (default)");
        cmd.addOption("--use-window",         "+Wi",  1, "[n]umber: integer",
                                                         "use the n-th VOI window from image file");
        cmd.addOption("--use-voi-lut",        "+Wl",  1, "[n]umber: integer",
                                                         "use the n-th VOI look up table from image file");
        cmd.addOption("--min-max-window",     "+Wm",     "compute VOI window using min-max algorithm");
        cmd.addOption("--min-max-window-n",   "+Wn",     "compute VOI window using min-max algorithm,\nignoring extreme values");
        cmd.addOption("--roi-min-max-window", "+Wr",  4, "[l]eft [t]op [w]idth [h]eight: integer",
                                                         "compute ROI window using min-max algorithm,\nregion of interest is specified by l,t,w,h");
        cmd.addOption("--histogram-window",   "+Wh",  1, "[n]umber: integer",
                                                         "compute VOI window using Histogram algorithm,\nignoring n percent");
        cmd.addOption("--set-window",         "+Ww",  2, "[c]enter [w]idth: float",
                                                         "compute VOI window using center c and width w");
        cmd.addOption("--linear-function",    "+Wfl",    "set VOI LUT function to LINEAR");
        cmd.addOption("--sigmoid-function",   "+Wfs",    "set VOI LUT function to SIGMOID");
  
       cmd.addSubGroup("presentation LUT transformation:");
        cmd.addOption("--identity-shape",     "+Pid",    "set presentation LUT shape to IDENTITY");
        cmd.addOption("--inverse-shape",      "+Piv",    "set presentation LUT shape to INVERSE");
        cmd.addOption("--lin-od-shape",       "+Pod",    "set presentation LUT shape to LIN OD");
  
       cmd.addSubGroup("overlay:");
        cmd.addOption("--no-overlays",        "-O",      "do not display overlays");
        cmd.addOption("--display-overlay",    "+O" ,  1, "[n]umber: integer",
                                                         "display overlay n (0..16, 0=all, default: +O 0)");
        cmd.addOption("--ovl-replace",        "+Omr",    "use overlay mode \"Replace\"\n(default for Graphic overlays)");
        cmd.addOption("--ovl-threshold",      "+Omt",    "use overlay mode \"Threshold Replace\"");
        cmd.addOption("--ovl-complement",     "+Omc",    "use overlay mode \"Complement\"");
        cmd.addOption("--ovl-invert",         "+Omv",    "use overlay mode \"Invert Bitmap\"");
        cmd.addOption("--ovl-roi",            "+Omi",    "use overlay mode \"Region of Interest\"\n(default for ROI overlays)");
        cmd.addOption("--set-foreground",     "+Osf", 1, "[d]ensity: float",
                                                         "set overlay foreground density (0..1, def: 1)");
        cmd.addOption("--set-threshold",      "+Ost", 1, "[d]ensity: float",
                                                         "set overlay threshold density (0..1, def: 0.5)");
  
       cmd.addSubGroup("display LUT transformation:");
        cmd.addOption("--monitor-file",       "+Dm",  1, "[f]ilename: string",
                                                         "calibrate output according to monitor\ncharacteristics defined in f");
        cmd.addOption("--printer-file",       "+Dp",  1, "[f]ilename: string",
                                                         "calibrate output according to printer\ncharacteristics defined in f");
        cmd.addOption("--ambient-light",      "+Da",  1, "[a]mbient light: float",
                                                         "ambient light value (cd/m^2, default: file f)");
        cmd.addOption("--illumination",       "+Di",  1, "[i]llumination: float",
                                                         "illumination value (cd/m^2, default: file f)");
        cmd.addOption("--min-density",        "+Dn", 1,  "[m]inimum optical density: float",
                                                         "Dmin value (default: off, only with +Dp)");
        cmd.addOption("--max-density",        "+Dx", 1,  "[m]aximum optical density: float",
                                                         "Dmax value (default: off, only with +Dp)");
        cmd.addOption("--gsd-function",       "+Dg",     "use GSDF for calibration (default for +Dm/+Dp)");
        cmd.addOption("--cielab-function",    "+Dc",     "use CIELAB function for calibration ");
  
       cmd.addSubGroup("compatibility:");
        cmd.addOption("--accept-acr-nema",    "+Ma",     "accept ACR-NEMA images without photometric\ninterpretation");
        cmd.addOption("--accept-palettes",    "+Mp",     "accept incorrect palette attribute tags\n(0028,111x) and (0028,121x)");
        cmd.addOption("--check-lut-depth",    "+Mc",     "check 3rd value of the LUT descriptor, compare\nwith expected bit depth based on LUT data");
        cmd.addOption("--ignore-mlut-depth",  "+Mm",     "ignore 3rd value of the modality LUT descriptor,\ndetermine bits per table entry automatically");
        cmd.addOption("--ignore-vlut-depth",  "+Mv",     "ignore 3rd value of the VOI LUT descriptor,\ndetermine bits per table entry automatically");
  
  #ifdef WITH_LIBTIFF
       cmd.addSubGroup("TIFF format:");
  #ifdef HAVE_LIBTIFF_LZW_COMPRESSION
        cmd.addOption("--compr-lzw",          "+Tl",     "LZW compression (default)");
        cmd.addOption("--compr-rle",          "+Tr",     "RLE compression");
        cmd.addOption("--compr-none",         "+Tn",     "uncompressed");
        cmd.addOption("--predictor-default",  "+Pd",     "no LZW predictor (default)");
        cmd.addOption("--predictor-none",     "+Pn",     "LZW predictor 1 (no prediction)");
        cmd.addOption("--predictor-horz",     "+Ph",     "LZW predictor 2 (horizontal differencing)");
  #else
        cmd.addOption("--compr-rle",          "+Tr",     "RLE compression (default)");
        cmd.addOption("--compr-none",         "+Tn",     "uncompressed");
  #endif
        cmd.addOption("--rows-per-strip",     "+Rs",  1, "[r]ows: integer (default: 0)",
                                                         "rows per strip, default 8K per strip");
  #endif
  
  #ifdef WITH_LIBPNG
       cmd.addSubGroup("PNG format:");
        cmd.addOption("--interlace",          "+il",     "create interlaced file (default)");
        cmd.addOption("--nointerlace",        "-il",     "create non-interlaced file");
        cmd.addOption("--meta-file",          "+mf",     "create PNG file meta information (default)");
        cmd.addOption("--meta-none",          "-mf",     "no PNG file meta information");
  #endif
  
  #ifdef BUILD_DCM2PNM_AS_DCMJ2PNM
       cmd.addSubGroup("JPEG format");
        cmd.addOption("--compr-quality",      "+Jq",  1, "[q]uality: integer (0..100, default: 90)",
                                                         "quality value for compression (in percent)");
        cmd.addOption("--sample-444",         "+Js4",    "4:4:4 sampling (no subsampling)");
        cmd.addOption("--sample-422",         "+Js2",    "4:2:2 subsampling (horizontal subsampling of\nchroma components, default)");
        cmd.addOption("--sample-411",         "+Js1",    "4:1:1 subsampling (horizontal and vertical\nsubsampling of chroma components)");
  #endif
  
       cmd.addSubGroup("other transformations:");
        cmd.addOption("--grayscale",          "+G",      "convert to grayscale if necessary");
        cmd.addOption("--change-polarity",    "+P",      "change polarity (invert pixel output)");
        cmd.addOption("--clip-region",        "+C",   4, "[l]eft [t]op [w]idth [h]eight: integer",
                                                         "clip image region (l, t, w, h)");
  
      cmd.addGroup("output options:");
       cmd.addSubGroup("general:");
        cmd.addOption("--image-info",         "-im",     "print image details (requires verbose mode)");
        cmd.addOption("--no-output",          "-o",      "do not create any output (useful with -im)");
       cmd.addSubGroup("filename generation (only with --frame-range or --all-frames):");
        cmd.addOption("--use-frame-counter",  "+Fc",     "use 0-based counter for filenames (default)");
        cmd.addOption("--use-frame-number",   "+Fn",     "use absolute frame number for filenames");
       cmd.addSubGroup("image format:");
        cmd.addOption("--write-raw-pnm",      "+op",     "write 8-bit binary PGM/PPM (default for files)");
        cmd.addOption("--write-8-bit-pnm",    "+opb",    "write 8-bit ASCII PGM/PPM (default for stdout)");
        cmd.addOption("--write-16-bit-pnm",   "+opw",    "write 16-bit ASCII PGM/PPM");
        cmd.addOption("--write-n-bit-pnm",    "+opn", 1, "[n]umber: integer",
                                                         "write n-bit ASCII PGM/PPM (1..32)");
        cmd.addOption("--write-bmp",          "+ob",     "write 8-bit (monochrome) or 24-bit (color) BMP");
        cmd.addOption("--write-8-bit-bmp",    "+obp",    "write 8-bit palette BMP (monochrome only)");
        cmd.addOption("--write-24-bit-bmp",   "+obt",    "write 24-bit truecolor BMP");
        cmd.addOption("--write-32-bit-bmp",   "+obr",    "write 32-bit truecolor BMP");
  #ifdef WITH_LIBTIFF
        cmd.addOption("--write-tiff",         "+ot",     "write 8-bit (monochrome) or 24-bit (color) TIFF");
  #endif
  #ifdef WITH_LIBPNG
        cmd.addOption("--write-png",          "+on",     "write 8-bit (monochrome) or 24-bit (color) PNG");
        cmd.addOption("--write-16-bit-png",   "+on2",    "write 16-bit (monochrome) or 48-bit (color) PNG");
  #endif
  #ifdef BUILD_DCM2PNM_AS_DCMJ2PNM
        cmd.addOption("--write-jpeg",         "+oj",     "write 8-bit lossy JPEG (baseline)");
  #endif
  #ifdef PASTEL_COLOR_OUTPUT
        cmd.addOption("--write-pastel-pnm",   "+op",     "write 8-bit binary PPM with pastel colors\n(early experimental version)");
  #endif
  
      if (app.parseCommandLine(cmd, argc, argv))
      {
          /* check exclusive options first */
          if (cmd.hasExclusiveOption())
          {
              if (cmd.findOption("--version"))
              {
                  app.printHeader(OFTrue /*print host identifier*/);
                  COUT << OFendl << "External libraries used:";
  #if !defined(WITH_ZLIB) && !defined(BUILD_DCM2PNM_AS_DCMJ2PNM) && !defined(BUILD_DCM2PNM_AS_DCML2PNM) && !defined(WITH_LIBTIFF) && !defined(WITH_LIBPNG)
                  COUT << " none" << OFendl;
  #else
                  COUT << OFendl;
  #endif
  #ifdef WITH_ZLIB
                  COUT << "- ZLIB, Version " << zlibVersion() << OFendl;
  #endif
  #ifdef BUILD_DCM2PNM_AS_DCMJ2PNM
                  COUT << "- " << DiJPEGPlugin::getLibraryVersionString() << OFendl;
  #endif
  #ifdef BUILD_DCM2PNM_AS_DCML2PNM
                  COUT << "- " << DJLSDecoderRegistration::getLibraryVersionString() << OFendl;
  #endif
  #ifdef WITH_LIBTIFF
                  COUT << "- " << DiTIFFPlugin::getLibraryVersionString() << OFendl;
  #ifdef HAVE_LIBTIFF_LZW_COMPRESSION
                  COUT << "  with LZW compression support" << OFendl;
  #else
                  COUT << "  without LZW compression support" << OFendl;
  #endif
  #endif
  #ifdef WITH_LIBPNG
                  COUT << "- " << DiPNGPlugin::getLibraryVersionString() << OFendl;
  #endif
                  return 0;
              }
          }
  
          /* command line parameters */
  
          cmd.getParam(1, opt_ifname);
          cmd.getParam(2, opt_ofname);
  
          /* general options */
  
          OFLog::configureFromCommandLine(cmd, app);
  
          /* input options: input file format */
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--read-file")) opt_readMode = ERM_autoDetect;
          if (cmd.findOption("--read-file-only")) opt_readMode = ERM_fileOnly;
          if (cmd.findOption("--read-dataset")) opt_readMode = ERM_dataset;
          cmd.endOptionBlock();
  
          /* input options: input transfer syntax */
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--read-xfer-auto"))
              opt_transferSyntax = EXS_Unknown;
          if (cmd.findOption("--read-xfer-detect"))
              dcmAutoDetectDatasetXfer.set(OFTrue);
          if (cmd.findOption("--read-xfer-little"))
          {
              app.checkDependence("--read-xfer-little", "--read-dataset", opt_readMode == ERM_dataset);
              opt_transferSyntax = EXS_LittleEndianExplicit;
          }
          if (cmd.findOption("--read-xfer-big"))
          {
              app.checkDependence("--read-xfer-big", "--read-dataset", opt_readMode == ERM_dataset);
              opt_transferSyntax = EXS_BigEndianExplicit;
          }
          if (cmd.findOption("--read-xfer-implicit"))
          {
              app.checkDependence("--read-xfer-implicit", "--read-dataset", opt_readMode == ERM_dataset);
              opt_transferSyntax = EXS_LittleEndianImplicit;
          }
          cmd.endOptionBlock();
  
          /* image processing options: compatibility options */
  
          if (cmd.findOption("--accept-acr-nema"))
              opt_compatibilityMode |= CIF_AcrNemaCompatibility;
          if (cmd.findOption("--accept-palettes"))
              opt_compatibilityMode |= CIF_WrongPaletteAttributeTags;
          if (cmd.findOption("--check-lut-depth"))
              opt_compatibilityMode |= CIF_CheckLutBitDepth;
          if (cmd.findOption("--ignore-mlut-depth"))
              opt_compatibilityMode |= CIF_IgnoreModalityLutBitDepth;
          if (cmd.findOption("--ignore-vlut-depth"))
              opt_ignoreVoiLutDepth = OFTrue;
  
          /* image processing options: frame selection */
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--frame"))
              app.checkValue(cmd.getValueAndCheckMin(opt_frame, 1));
          if (cmd.findOption("--frame-range"))
          {
              app.checkValue(cmd.getValueAndCheckMin(opt_frame, 1));
              app.checkValue(cmd.getValueAndCheckMin(opt_frameCount, 1));
              opt_multiFrame = OFTrue;
          }
          if (cmd.findOption("--all-frames"))
          {
              opt_frameCount = 0;
              opt_multiFrame = OFTrue;
          }
          cmd.endOptionBlock();
  
          /* image processing options: other transformations */
  
          if (cmd.findOption("--grayscale"))
              opt_convertToGrayscale = 1;
          if (cmd.findOption("--change-polarity"))
              opt_changePolarity = 1;
  
          if (cmd.findOption("--clip-region"))
          {
              app.checkValue(cmd.getValue(opt_left));
              app.checkValue(cmd.getValue(opt_top));
              app.checkValue(cmd.getValue(opt_width));
              app.checkValue(cmd.getValue(opt_height));
              opt_useClip = 1;
          }
  
          /* image processing options: rotation */
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--rotate-left"))
              opt_rotateDegree = 270;
          if (cmd.findOption("--rotate-right"))
              opt_rotateDegree = 90;
          if (cmd.findOption("--rotate-top-down"))
              opt_rotateDegree = 180;
          cmd.endOptionBlock();
  
          /* image processing options: flipping */
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--flip-horizontally"))
              opt_flipType = 1;
          if (cmd.findOption("--flip-vertically"))
              opt_flipType = 2;
          if (cmd.findOption("--flip-both-axes"))
              opt_flipType = 3;
          cmd.endOptionBlock();
  
          /* image processing options: scaling */
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--recognize-aspect"))
              opt_useAspectRatio = 1;
          if (cmd.findOption("--ignore-aspect"))
              opt_useAspectRatio = 0;
          cmd.endOptionBlock();
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--interpolate"))
              app.checkValue(cmd.getValueAndCheckMinMax(opt_useInterpolation, 1, 4));
          if (cmd.findOption("--no-interpolation"))
              opt_useInterpolation = 0;
          cmd.endOptionBlock();
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--no-scaling"))
              opt_scaleType = 0;
          if (cmd.findOption("--scale-x-factor"))
          {
              opt_scaleType = 1;
              app.checkValue(cmd.getValueAndCheckMin(opt_scale_factor, 0.0, OFFalse));
          }
          if (cmd.findOption("--scale-y-factor"))
          {
              opt_scaleType = 2;
              app.checkValue(cmd.getValueAndCheckMin(opt_scale_factor, 0.0, OFFalse));
          }
          if (cmd.findOption("--scale-x-size"))
          {
              opt_scaleType = 3;
              app.checkValue(cmd.getValueAndCheckMin(opt_scale_size, 1));
          }
          if (cmd.findOption("--scale-y-size"))
          {
              opt_scaleType = 4;
              app.checkValue(cmd.getValueAndCheckMin(opt_scale_size, 1));
          }
          cmd.endOptionBlock();
  
          /* image processing options: color space conversion */
  
  #ifdef BUILD_DCM2PNM_AS_DCMJ2PNM
          cmd.beginOptionBlock();
          if (cmd.findOption("--conv-photometric"))
              opt_decompCSconversion = EDC_photometricInterpretation;
          if (cmd.findOption("--conv-lossy"))
              opt_decompCSconversion = EDC_lossyOnly;
          if (cmd.findOption("--conv-guess"))
              opt_decompCSconversion = EDC_guess;
          if (cmd.findOption("--conv-guess-lossy"))
              opt_decompCSconversion = EDC_guessLossyOnly;
          if (cmd.findOption("--conv-always"))
              opt_decompCSconversion = EDC_always;
          if (cmd.findOption("--conv-never"))
              opt_decompCSconversion = EDC_never;
          cmd.endOptionBlock();
  #endif
  
          /* image processing options: modality LUT transformation */
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--no-modality"))
              opt_compatibilityMode |= CIF_IgnoreModalityTransformation;
          if (cmd.findOption("--use-modality"))
              opt_compatibilityMode &= ~CIF_IgnoreModalityTransformation;
          cmd.endOptionBlock();
  
          /* image processing options: VOI LUT transformation */
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--no-windowing"))
              opt_windowType = 0;
          if (cmd.findOption("--use-window"))
          {
              opt_windowType = 1;
              app.checkValue(cmd.getValueAndCheckMin(opt_windowParameter, 1));
          }
          if (cmd.findOption("--use-voi-lut"))
          {
              opt_windowType = 2;
              app.checkValue(cmd.getValueAndCheckMin(opt_windowParameter, 1));
          }
          if (cmd.findOption("--min-max-window"))
              opt_windowType = 3;
          if (cmd.findOption("--min-max-window-n"))
              opt_windowType = 6;
          if (cmd.findOption("--roi-min-max-window"))
          {
              opt_windowType = 7;
              app.checkValue(cmd.getValue(opt_roiLeft));
              app.checkValue(cmd.getValue(opt_roiTop));
              app.checkValue(cmd.getValueAndCheckMin(opt_roiWidth, 1));
              app.checkValue(cmd.getValueAndCheckMin(opt_roiHeight, 1));
          }
          if (cmd.findOption("--histogram-window"))
          {
              opt_windowType = 4;
              app.checkValue(cmd.getValueAndCheckMinMax(opt_windowParameter, 0, 100));
          }
          if (cmd.findOption("--set-window"))
          {
              opt_windowType = 5;
              app.checkValue(cmd.getValue(opt_windowCenter));
              app.checkValue(cmd.getValueAndCheckMin(opt_windowWidth, 1.0));
          }
          cmd.endOptionBlock();
          cmd.beginOptionBlock();
          if (cmd.findOption("--linear-function"))
              opt_voiFunction = EFV_Linear;
          if (cmd.findOption("--sigmoid-function"))
              opt_voiFunction = EFV_Sigmoid;
          cmd.endOptionBlock();
  
          /* image processing options: presentation LUT transformation */
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--identity-shape"))
              opt_presShape = ESP_Identity;
          if (cmd.findOption("--inverse-shape"))
              opt_presShape = ESP_Inverse;
          if (cmd.findOption("--lin-od-shape"))
              opt_presShape = ESP_LinOD;
          cmd.endOptionBlock();
  
          /* image processing options: display LUT transformation */
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--monitor-file"))
          {
              app.checkValue(cmd.getValue(opt_displayFile));
              deviceType = DiDisplayFunction::EDT_Monitor;
          }
          if (cmd.findOption("--printer-file"))
          {
              app.checkValue(cmd.getValue(opt_displayFile));
              deviceType = DiDisplayFunction::EDT_Printer;
          }
          cmd.endOptionBlock();
  
          if (cmd.findOption("--ambient-light"))
              app.checkValue(cmd.getValueAndCheckMin(opt_ambientLight, 0));
          if (cmd.findOption("--illumination"))
              app.checkValue(cmd.getValueAndCheckMin(opt_illumination, 0));
          if (cmd.findOption("--min-density"))
          {
              app.checkDependence("--min-density", "--printer-file", deviceType == DiDisplayFunction::EDT_Printer);
              app.checkValue(cmd.getValueAndCheckMin(opt_minDensity, 0));
          }
          if (cmd.findOption("--max-density"))
          {
              app.checkDependence("--max-density", "--printer-file", deviceType == DiDisplayFunction::EDT_Printer);
              app.checkValue(cmd.getValueAndCheckMin(opt_maxDensity, (opt_minDensity < 0) ? 0.0 : opt_minDensity, OFFalse /*incl*/));
          }
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--gsd-function"))
              opt_displayFunction = 0;
          if (cmd.findOption("--cielab-function"))
              opt_displayFunction = 1;
          cmd.endOptionBlock();
  
          /* image processing options: overlay */
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--no-overlays"))
          {
              opt_O_used = 1;
              for (i = 0; i < 16; i++)
                  opt_Overlay[i] = 0;
          }
          if (cmd.findOption("--display-overlay", 0, OFCommandLine::FOM_First))
          {
              do {
                  unsigned long l;
                  app.checkValue(cmd.getValueAndCheckMinMax(l, 1, 16));
                  if (!opt_O_used)
                  {
                      for (i = 0; i < 16; i++) opt_Overlay[i] = 0;
                      opt_O_used = 1;
                  }
                  if (l > 0)
                      opt_Overlay[l - 1]=1;
                  else
                  {
                      for (i = 0; i < 16; i++)
                          opt_Overlay[i] = 2;
                  }
              } while (cmd.findOption("--display-overlay", 0, OFCommandLine::FOM_Next));
          }
          cmd.endOptionBlock();
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--ovl-replace"))
              opt_OverlayMode = EMO_Replace;
          if (cmd.findOption("--ovl-threshold"))
              opt_OverlayMode = EMO_ThresholdReplace;
          if (cmd.findOption("--ovl-complement"))
              opt_OverlayMode = EMO_Complement;
          if (cmd.findOption("--ovl-invert"))
              opt_OverlayMode = EMO_InvertBitmap;
          if (cmd.findOption("--ovl-roi"))
              opt_OverlayMode = EMO_RegionOfInterest;
          cmd.endOptionBlock();
  
          if (cmd.findOption("--set-foreground"))
              app.checkValue(cmd.getValueAndCheckMinMax(opt_foregroundDensity, 0.0, 1.0));
          if (cmd.findOption("--set-threshold"))
              app.checkValue(cmd.getValueAndCheckMinMax(opt_thresholdDensity, 0.0, 1.0));
  
          /* image processing options: TIFF options */
  
  #ifdef WITH_LIBTIFF
          cmd.beginOptionBlock();
  #ifdef HAVE_LIBTIFF_LZW_COMPRESSION
          if (cmd.findOption("--compr-lzw")) opt_tiffCompression = E_tiffLZWCompression;
  #endif
          if (cmd.findOption("--compr-rle")) opt_tiffCompression = E_tiffPackBitsCompression;
          if (cmd.findOption("--compr-none")) opt_tiffCompression = E_tiffNoCompression;
          cmd.endOptionBlock();
  
  #ifdef HAVE_LIBTIFF_LZW_COMPRESSION
          cmd.beginOptionBlock();
          if (cmd.findOption("--predictor-default")) opt_lzwPredictor = E_tiffLZWPredictorDefault;
          if (cmd.findOption("--predictor-none")) opt_lzwPredictor = E_tiffLZWPredictorNoPrediction;
          if (cmd.findOption("--predictor-horz")) opt_lzwPredictor = E_tiffLZWPredictorHDifferencing;
          cmd.endOptionBlock();
  #endif
  
          if (cmd.findOption("--rows-per-strip"))
              app.checkValue(cmd.getValueAndCheckMinMax(opt_rowsPerStrip, 0, 65535));
  #endif
  
          /* image processing options: PNG options */
  
  #ifdef WITH_LIBPNG
          cmd.beginOptionBlock();
          if (cmd.findOption("--interlace"))   opt_interlace = E_pngInterlaceAdam7;
          if (cmd.findOption("--nointerlace")) opt_interlace = E_pngInterlaceNone;
          cmd.endOptionBlock();
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--meta-none"))    opt_metainfo = E_pngNoMetainfo;
          if (cmd.findOption("--meta-file"))    opt_metainfo = E_pngFileMetainfo;
          cmd.endOptionBlock();
  #endif
  
          /* image processing options: JPEG options */
  
  #ifdef BUILD_DCM2PNM_AS_DCMJ2PNM
          if (cmd.findOption("--compr-quality"))
              app.checkValue(cmd.getValueAndCheckMinMax(opt_quality, 0, 100));
          cmd.beginOptionBlock();
          if (cmd.findOption("--sample-444"))
              opt_sampling = ESS_444;
          if (cmd.findOption("--sample-422"))
              opt_sampling = ESS_422;
          if (cmd.findOption("--sample-411"))
              opt_sampling = ESS_411;
          cmd.endOptionBlock();
  #endif
  
          /* output options */
  
          if (cmd.findOption("--image-info"))
          {
              app.checkDependence("--image-info", "verbose mode", dcm2pnmLogger.isEnabledFor(OFLogger::INFO_LOG_LEVEL));
              opt_imageInfo = 1;
          }
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--use-frame-counter"))
          {
              app.checkDependence("--use-frame-counter", "--frame-range or --all-frames", opt_multiFrame);
              opt_useFrameNumber = OFFalse;
          }
          if (cmd.findOption("--use-frame-number"))
          {
              app.checkDependence("--use-frame-number", "--frame-range or --all-frames", opt_multiFrame);
              opt_useFrameNumber = OFTrue;
          }
          cmd.endOptionBlock();
  
          cmd.beginOptionBlock();
          if (cmd.findOption("--no-output"))
              opt_suppressOutput = 1;
          if (cmd.findOption("--write-raw-pnm"))
              opt_fileType = EFT_RawPNM;
          if (cmd.findOption("--write-8-bit-pnm"))
              opt_fileType = EFT_8bitPNM;
          if (cmd.findOption("--write-16-bit-pnm"))
              opt_fileType = EFT_16bitPNM;
          if (cmd.findOption("--write-n-bit-pnm"))
          {
              opt_fileType = EFT_NbitPNM;
              app.checkValue(cmd.getValueAndCheckMinMax(opt_fileBits, 1, 32));
          }
          if (cmd.findOption("--write-bmp"))
              opt_fileType = EFT_BMP;
          if (cmd.findOption("--write-8-bit-bmp"))
              opt_fileType = EFT_8bitBMP;
          if (cmd.findOption("--write-24-bit-bmp"))
              opt_fileType = EFT_24bitBMP;
          if (cmd.findOption("--write-32-bit-bmp"))
              opt_fileType = EFT_32bitBMP;
  #ifdef BUILD_DCM2PNM_AS_DCMJ2PNM
          if (cmd.findOption("--write-jpeg"))
              opt_fileType = EFT_JPEG;
  #endif
  #ifdef WITH_LIBTIFF
          if (cmd.findOption("--write-tiff"))
              opt_fileType = EFT_TIFF;
  #endif
  #ifdef WITH_LIBPNG
          if (cmd.findOption("--write-png"))
              opt_fileType = EFT_PNG;
          if (cmd.findOption("--write-16-bit-png"))
              opt_fileType = EFT_16bitPNG;
  #endif
  #ifdef PASTEL_COLOR_OUTPUT
          if (cmd.findOption("--write-pastel-pnm"))
              opt_fileType = EFT_PastelPNM;
  #endif
          cmd.endOptionBlock();
      }
  
      /* print resource identifier */
      OFLOG_DEBUG(dcm2pnmLogger, rcsid << OFendl);
  
      /* make sure data dictionary is loaded */
      if (!dcmDataDict.isDictionaryLoaded())
      {
          OFLOG_WARN(dcm2pnmLogger, "no data dictionary loaded, check environment variable: "
              << DCM_DICT_ENVIRONMENT_VARIABLE);
      }
  
      OFLOG_INFO(dcm2pnmLogger, "reading DICOM file: " << opt_ifname);
  
      // register RLE decompression codec
      DcmRLEDecoderRegistration::registerCodecs();
  #ifdef BUILD_DCM2PNM_AS_DCMJ2PNM
      // register JPEG decompression codecs
      DJDecoderRegistration::registerCodecs(opt_decompCSconversion);
  #endif
  #ifdef BUILD_DCM2PNM_AS_DCML2PNM
      // register JPEG-LS decompression codecs
      DJLSDecoderRegistration::registerCodecs();
  #endif
  
      DcmFileFormat *dfile = new DcmFileFormat();
      OFCondition cond = dfile->loadFile(opt_ifname, opt_transferSyntax, EGL_withoutGL, DCM_MaxReadLength, opt_readMode);
  
      if (cond.bad())
      {
          OFLOG_FATAL(dcm2pnmLogger, cond.text() << ": reading file: " << opt_ifname);
          return 1;
      }
  
      OFLOG_INFO(dcm2pnmLogger, "preparing pixel data");
  
      DcmDataset *dataset = dfile->getDataset();
      E_TransferSyntax xfer = dataset->getOriginalXfer();
  
      Sint32 frameCount;
      if (dataset->findAndGetSint32(DCM_NumberOfFrames, frameCount).bad())
          frameCount = 1;
      Sint32 realFrameCount = frameCount;
      if ((opt_frameCount == 0) || ((opt_frame == 1) && (opt_frameCount == OFstatic_cast(Uint32, frameCount))))
      {
          // since we process all frames anyway, decompress the complete pixel data (if required)
          //opt_compatibilityMode |= CIF_DecompressCompletePixelData;
          opt_frame = 1;
          opt_frameCount = OFstatic_cast(Uint32, frameCount);
      }
  
      if (realFrameCount > 1 && !(opt_compatibilityMode & CIF_DecompressCompletePixelData))
      {
          // use partial read access to pixel data (only in case of multiple frames, but not for all frames)
          opt_compatibilityMode |= CIF_UsePartialAccessToPixelData;
      }
  
  unsigned int FrameCount = opt_frameCount;  opt_frameCount = 1;
  for ( ;  opt_frame <= FrameCount; opt_frame++)
  {
      DcmFileFormat* dfileSV = new DcmFileFormat(*dfile);
      DcmDataset* datasetSV = dfileSV->getDataset();
      E_TransferSyntax xferSV = datasetSV->getOriginalXfer();
  
      DicomImage *di = new DicomImage(dfileSV, xferSV, opt_compatibilityMode, opt_frame - 1, 1);
      if (di == NULL)
      {
          OFLOG_FATAL(dcm2pnmLogger, "Out of memory");
          return 1;
      }
  
      if (di->getStatus() != EIS_Normal)
      {
          OFLOG_FATAL(dcm2pnmLogger, DicomImage::getString(di->getStatus()));
          return 1;
      }
  
      /* create & set display function */
      DiDisplayFunction *disp = NULL;
      if (!opt_displayFile.empty())
      {
          if (opt_displayFunction == 1)
              disp = new DiCIELABFunction(opt_displayFile.c_str(), deviceType);
          else
              disp = new DiGSDFunction(opt_displayFile.c_str(), deviceType);
          if (disp != NULL)
          {
              if (opt_ambientLight >= 0)
                  disp->setAmbientLightValue(opt_ambientLight);
              if (opt_illumination >= 0)
                  disp->setIlluminationValue(opt_illumination);
              if (opt_minDensity >= 0)
                  disp->setMinDensityValue(opt_minDensity);
              if (opt_maxDensity >= 0)
                  disp->setMaxDensityValue(opt_maxDensity);
              if ((di != NULL) && (disp->isValid()))
              {
                  OFLOG_INFO(dcm2pnmLogger, "activating "
                      << ((opt_displayFunction == 1) ? "CIELAB" : "GSDF")
                      << " display function for "
                      << ((deviceType == DiDisplayFunction::EDT_Monitor) ? "softcopy" : "hardcopy")
                      << " devices");
                  if (!di->setDisplayFunction(disp))
                      OFLOG_WARN(dcm2pnmLogger, "cannot select display function");
              }
          }
      }
  
      if (opt_imageInfo)
      {
          /* dump image parameters */
          OFLOG_INFO(dcm2pnmLogger, "dumping image parameters");
  
          double minVal = 0.0;
          double maxVal = 0.0;
          const char *colorModel;
          const char *SOPClassUID = NULL;
          const char *SOPInstanceUID = NULL;
          const char *SOPClassText = NULL;
          const char *XferText = DcmXfer(xferSV).getXferName();
  
          int minmaxValid = di->getMinMaxValues(minVal, maxVal);
          colorModel = di->getString(di->getPhotometricInterpretation());
          if (colorModel == NULL)
              colorModel = "unknown";
  
          datasetSV->findAndGetString(DCM_SOPClassUID, SOPClassUID);
          datasetSV->findAndGetString(DCM_SOPInstanceUID, SOPInstanceUID);
  
          if (SOPInstanceUID == NULL)
              SOPInstanceUID = "not present";
          if (SOPClassUID == NULL)
              SOPClassText = "not present";
          else
              SOPClassText = dcmFindNameOfUID(SOPClassUID);
          if (SOPClassText == NULL)
              SOPClassText = SOPClassUID;
  
          char aspectRatio[30];
          OFStandard::ftoa(aspectRatio, sizeof(aspectRatio), di->getHeightWidthRatio(), OFStandard::ftoa_format_f, 0, 2);
  
          /* dump some general information */
          OFLOG_INFO(dcm2pnmLogger, "  filename            : " << opt_ifname << OFendl
              << "  transfer syntax     : " << XferText << OFendl
              << "  SOP class           : " << SOPClassText << OFendl
              << "  SOP instance UID    : " << SOPInstanceUID << OFendl
              << "  columns x rows      : " << di->getWidth() << " x " << di->getHeight() << OFendl
              << "  bits per sample     : " << di->getDepth() << OFendl
              << "  color model         : " << colorModel << OFendl
              << "  pixel aspect ratio  : " << aspectRatio << OFendl
              << "  number of frames    : " << di->getNumberOfFrames() << " (" << di->getFrameCount() << " processed)");
          if (di->getFrameTime() > 0)
              OFLOG_INFO(dcm2pnmLogger, "  frame time (in ms)  : " << di->getFrameTime());
  
          /* dump VOI windows */
          unsigned long count;
          OFString explStr, funcStr;
          count = di->getWindowCount();
          switch (di->getVoiLutFunction())
          {
              case EFV_Default:
                  funcStr = "<default>";
                  break;
              case EFV_Linear:
                  funcStr = "LINEAR";
                  break;
              case EFV_Sigmoid:
                  funcStr = "SIGMOID";
                  break;
          }
          OFLOG_INFO(dcm2pnmLogger, "  VOI LUT function    : " << funcStr);
          OFLOG_INFO(dcm2pnmLogger, "  VOI windows in file : " << di->getWindowCount());
          for (i = 0; i < count; i++)
          {
              if (di->getVoiWindowExplanation(i, explStr) == NULL)
                  OFLOG_INFO(dcm2pnmLogger, "  - <no explanation>");
              else
                  OFLOG_INFO(dcm2pnmLogger, "  - " << explStr);
          }
  
          /* dump VOI LUTs */
          count = di->getVoiLutCount();
          OFLOG_INFO(dcm2pnmLogger, "  VOI LUTs in file    : " << count);
          for (i = 0; i < count; i++)
          {
              if (di->getVoiLutExplanation(i, explStr) == NULL)
                  OFLOG_INFO(dcm2pnmLogger, "  - <no explanation>");
              else
                  OFLOG_INFO(dcm2pnmLogger, "  - " << explStr);
          }
  
          /* dump presentation LUT shape */
          OFString shapeStr;
          switch (di->getPresentationLutShape())
          {
              case ESP_Default:
                  shapeStr = "<default>";
                  break;
              case ESP_Identity:
                  shapeStr = "IDENTITY";
                  break;
              case ESP_Inverse:
                  shapeStr = "INVERSE";
                  break;
              case ESP_LinOD:
                  shapeStr = "LIN OD";
                  break;
          }
          OFLOG_INFO(dcm2pnmLogger, "  presentation shape  : " << shapeStr);
  
          /* dump overlays */
          OFLOG_INFO(dcm2pnmLogger, "  overlays in file    : " << di->getOverlayCount());
  
          if (minmaxValid)
          {
            char minmaxText[30];
            OFStandard::ftoa(minmaxText, sizeof(minmaxText), maxVal, OFStandard::ftoa_format_f, 0, 0);
            OFLOG_INFO(dcm2pnmLogger, "  maximum pixel value : " << minmaxText);
            OFStandard::ftoa(minmaxText, sizeof(minmaxText), minVal, OFStandard::ftoa_format_f, 0, 0);
            OFLOG_INFO(dcm2pnmLogger, "  minimum pixel value : " << minmaxText);
          }
      }
  
      if (!opt_suppressOutput)
      {
          /* try to select frame */
          if (opt_frame != di->getFirstFrame() + 1)
          {
              OFLOG_FATAL(dcm2pnmLogger, "cannot select frame " << opt_frame << ", invalid frame number");
              return 1;
          }
  
          /* convert to grayscale if necessary */
          if ((opt_convertToGrayscale) && (!di->isMonochrome()))
          {
               OFLOG_INFO(dcm2pnmLogger, "converting image to grayscale");
  
               DicomImage *newimage = di->createMonochromeImage();
               if (newimage == NULL)
               {
                  OFLOG_FATAL(dcm2pnmLogger, "Out of memory or cannot convert to monochrome image");
                  return 1;
               }
               else if (newimage->getStatus() != EIS_Normal)
               {
                  OFLOG_FATAL(dcm2pnmLogger, DicomImage::getString(newimage->getStatus()));
                  return 1;
               }
               else
               {
                   delete di;
                   di = newimage;
               }
          }
  
          /* process overlay parameters */
          di->hideAllOverlays();
          for (unsigned int k = 0; k < 16; k++)
          {
              if (opt_Overlay[k])
              {
                  if ((opt_Overlay[k] == 1) || (k < di->getOverlayCount()))
                  {
                      OFLOG_INFO(dcm2pnmLogger, "activating overlay plane " << k + 1);
                      if (opt_OverlayMode != EMO_Default)
                      {
                          if (!di->showOverlay(k, opt_OverlayMode, opt_foregroundDensity, opt_thresholdDensity))
                              OFLOG_WARN(dcm2pnmLogger, "cannot display overlay plane " << k + 1);
                      } else {
                          if (!di->showOverlay(k)) /* use default values */
                              OFLOG_WARN(dcm2pnmLogger, "cannot display overlay plane " << k + 1);
                      }
                  }
              }
          }
  
          /* process VOI parameters */
          switch (opt_windowType)
          {
              case 1: /* use the n-th VOI window from the image file */
                  if ((opt_windowParameter < 1) || (opt_windowParameter > di->getWindowCount()))
                  {
                      OFLOG_FATAL(dcm2pnmLogger, "cannot select VOI window " << opt_windowParameter << ", only "
                          << di->getWindowCount() << " window(s) in file");
                      return 1;
                  }
                  OFLOG_INFO(dcm2pnmLogger, "activating VOI window " << opt_windowParameter);
                  if (!di->setWindow(opt_windowParameter - 1))
                      OFLOG_WARN(dcm2pnmLogger, "cannot select VOI window " << opt_windowParameter);
                  break;
              case 2: /* use the n-th VOI look up table from the image file */
                  if ((opt_windowParameter < 1) || (opt_windowParameter > di->getVoiLutCount()))
                  {
                      OFLOG_FATAL(dcm2pnmLogger, "cannot select VOI LUT " << opt_windowParameter << ", only "
                          << di->getVoiLutCount() << " LUT(s) in file");
                      return 1;
                  }
                  OFLOG_INFO(dcm2pnmLogger, "activating VOI LUT " << opt_windowParameter);
                  if (!di->setVoiLut(opt_windowParameter - 1, opt_ignoreVoiLutDepth ? ELM_IgnoreValue : ELM_UseValue))
                      OFLOG_WARN(dcm2pnmLogger, "cannot select VOI LUT " << opt_windowParameter);
                  break;
              case 3: /* Compute VOI window using min-max algorithm */
                  OFLOG_INFO(dcm2pnmLogger, "activating VOI window min-max algorithm");
                  if (!di->setMinMaxWindow(0))
                      OFLOG_WARN(dcm2pnmLogger, "cannot compute min/max VOI window");
                  break;
              case 4: /* Compute VOI window using Histogram algorithm, ignoring n percent */
                  OFLOG_INFO(dcm2pnmLogger, "activating VOI window histogram algorithm, ignoring " << opt_windowParameter << "%");
                  if (!di->setHistogramWindow(OFstatic_cast(double, opt_windowParameter)/100.0))
                      OFLOG_WARN(dcm2pnmLogger, "cannot compute histogram VOI window");
                  break;
              case 5: /* Compute VOI window using center and width */
                  OFLOG_INFO(dcm2pnmLogger, "activating VOI window center=" << opt_windowCenter << ", width=" << opt_windowWidth);
                  if (!di->setWindow(opt_windowCenter, opt_windowWidth))
                      OFLOG_WARN(dcm2pnmLogger, "cannot set VOI window to specified values");
                  break;
              case 6: /* Compute VOI window using min-max algorithm ignoring extremes */
                  OFLOG_INFO(dcm2pnmLogger, "activating VOI window min-max algorithm, ignoring extreme values");
                  if (!di->setMinMaxWindow(1))
                      OFLOG_WARN(dcm2pnmLogger, "cannot compute min/max VOI window");
                  break;
              case 7: /* Compute region of interest VOI window */
                  OFLOG_INFO(dcm2pnmLogger, "activating region of interest VOI window");
                  if (!di->setRoiWindow(opt_roiLeft, opt_roiTop, opt_roiWidth, opt_roiHeight))
                      OFLOG_WARN(dcm2pnmLogger, "cannot compute region of interest VOI window");
                  break;
              default: /* no VOI windowing */
                  if (di->isMonochrome())
                  {
                      OFLOG_INFO(dcm2pnmLogger, "disabling VOI window computation");
                      if (!di->setNoVoiTransformation())
                          OFLOG_WARN(dcm2pnmLogger, "cannot ignore VOI window");
                  }
                  break;
          }
          /* VOI LUT function */
          if (opt_voiFunction != EFV_Default)
          {
              if (opt_voiFunction == EFV_Linear)
                  OFLOG_INFO(dcm2pnmLogger, "setting VOI LUT function to LINEAR");
              else if (opt_voiFunction == EFV_Sigmoid)
                  OFLOG_INFO(dcm2pnmLogger, "setting VOI LUT function to SIGMOID");
              if (!di->setVoiLutFunction(opt_voiFunction))
                  OFLOG_WARN(dcm2pnmLogger, "cannot set VOI LUT function");
          }
  
          /* process presentation LUT parameters */
          if (opt_presShape != ESP_Default)
          {
              if (opt_presShape == ESP_Identity)
                  OFLOG_INFO(dcm2pnmLogger, "setting presentation LUT shape to IDENTITY");
              else if (opt_presShape == ESP_Inverse)
                  OFLOG_INFO(dcm2pnmLogger, "setting presentation LUT shape to INVERSE");
              else if (opt_presShape == ESP_LinOD)
                  OFLOG_INFO(dcm2pnmLogger, "setting presentation LUT shape to LIN OD");
              if (!di->setPresentationLutShape(opt_presShape))
                  OFLOG_WARN(dcm2pnmLogger, "cannot set presentation LUT shape");
          }
  
          /* change polarity */
          if (opt_changePolarity)
          {
              OFLOG_INFO(dcm2pnmLogger, "setting polarity to REVERSE");
              if (!di->setPolarity(EPP_Reverse))
                  OFLOG_WARN(dcm2pnmLogger, "cannot set polarity");
          }
  
          /* perform clipping */
          if (opt_useClip && (opt_scaleType == 0))
          {
               OFLOG_INFO(dcm2pnmLogger, "clipping image to (" << opt_left << "," << opt_top << "," << opt_width
                   << "," << opt_height << ")");
               DicomImage *newimage = di->createClippedImage(opt_left, opt_top, opt_width, opt_height);
               if (newimage == NULL)
               {
                   OFLOG_FATAL(dcm2pnmLogger, "clipping to (" << opt_left << "," << opt_top << "," << opt_width
                       << "," << opt_height << ") failed");
                   return 1;
               } else if (newimage->getStatus() != EIS_Normal)
               {
                   OFLOG_FATAL(dcm2pnmLogger, DicomImage::getString(newimage->getStatus()));
                   return 1;
               }
               else
               {
                   delete di;
                   di = newimage;
               }
          }
  
          /* perform rotation */
          if (opt_rotateDegree > 0)
          {
              OFLOG_INFO(dcm2pnmLogger, "rotating image by " << opt_rotateDegree << " degrees");
              if (!di->rotateImage(opt_rotateDegree))
                  OFLOG_WARN(dcm2pnmLogger, "cannot rotate image");
          }
  
          /* perform flipping */
          if (opt_flipType > 0)
          {
              switch (opt_flipType)
              {
                  case 1:
                      OFLOG_INFO(dcm2pnmLogger, "flipping image horizontally");
                      if (!di->flipImage(1, 0))
                          OFLOG_WARN(dcm2pnmLogger, "cannot flip image");
                      break;
                  case 2:
                      OFLOG_INFO(dcm2pnmLogger, "flipping image vertically");
                      if (!di->flipImage(0, 1))
                          OFLOG_WARN(dcm2pnmLogger, "cannot flip image");
                      break;
                  case 3:
                      OFLOG_INFO(dcm2pnmLogger, "flipping image horizontally and vertically");
                      if (!di->flipImage(1, 1))
                          OFLOG_WARN(dcm2pnmLogger, "cannot flip image");
                      break;
                  default:
                      break;
              }
          }
  
          /* perform scaling */
          if (opt_scaleType > 0)
          {
              DicomImage *newimage;
              if (opt_useClip)
                  OFLOG_INFO(dcm2pnmLogger, "clipping image to (" << opt_left << "," << opt_top << "," << opt_width << "," << opt_height << ")");
              switch (opt_scaleType)
              {
                  case 1:
                      OFLOG_INFO(dcm2pnmLogger, "scaling image, X factor=" << opt_scale_factor
                          << ", Interpolation=" << OFstatic_cast(int, opt_useInterpolation)
                          << ", Aspect Ratio=" << (opt_useAspectRatio ? "yes" : "no"));
                      if (opt_useClip)
                          newimage = di->createScaledImage(opt_left, opt_top, opt_width, opt_height, opt_scale_factor, 0.0,
                              OFstatic_cast(int, opt_useInterpolation), opt_useAspectRatio);
                      else
                          newimage = di->createScaledImage(opt_scale_factor, 0.0, OFstatic_cast(int, opt_useInterpolation),
                              opt_useAspectRatio);
                      break;
                  case 2:
                      OFLOG_INFO(dcm2pnmLogger, "scaling image, Y factor=" << opt_scale_factor
                          << ", Interpolation=" << OFstatic_cast(int, opt_useInterpolation)
                          << ", Aspect Ratio=" << (opt_useAspectRatio ? "yes" : "no"));
                      if (opt_useClip)
                          newimage = di->createScaledImage(opt_left, opt_top, opt_width, opt_height, 0.0, opt_scale_factor,
                              OFstatic_cast(int, opt_useInterpolation), opt_useAspectRatio);
                      else
                          newimage = di->createScaledImage(0.0, opt_scale_factor, OFstatic_cast(int, opt_useInterpolation),
                              opt_useAspectRatio);
                      break;
                  case 3:
                      OFLOG_INFO(dcm2pnmLogger, "scaling image, X size=" << opt_scale_size
                          << ", Interpolation=" << OFstatic_cast(int, opt_useInterpolation)
                          << ", Aspect Ratio=" << (opt_useAspectRatio ? "yes" : "no"));
                      if (opt_useClip)
                          newimage = di->createScaledImage(opt_left, opt_top, opt_width, opt_height, opt_scale_size, 0,
                              OFstatic_cast(int, opt_useInterpolation), opt_useAspectRatio);
                      else
                          newimage = di->createScaledImage(opt_scale_size, 0, OFstatic_cast(int, opt_useInterpolation),
                              opt_useAspectRatio);
                      break;
                  case 4:
                      OFLOG_INFO(dcm2pnmLogger, "scaling image, Y size=" << opt_scale_size
                          << ", Interpolation=" << OFstatic_cast(int, opt_useInterpolation)
                          << ", Aspect Ratio=" << (opt_useAspectRatio ? "yes" : "no"));
                      if (opt_useClip)
                          newimage = di->createScaledImage(opt_left, opt_top, opt_width, opt_height, 0, opt_scale_size,
                              OFstatic_cast(int, opt_useInterpolation), opt_useAspectRatio);
                      else
                          newimage = di->createScaledImage(0, opt_scale_size, OFstatic_cast(int, opt_useInterpolation),
                              opt_useAspectRatio);
                      break;
                  default:
                      OFLOG_INFO(dcm2pnmLogger, "internal error: unknown scaling type");
                      newimage = NULL;
                      break;
              }
              if (newimage == NULL)
              {
                  OFLOG_FATAL(dcm2pnmLogger, "Out of memory or cannot scale image");
                  return 1;
              }
              else if (newimage->getStatus() != EIS_Normal)
              {
                  OFLOG_FATAL(dcm2pnmLogger, DicomImage::getString(newimage->getStatus()));
                  return 1;
              }
              else
              {
                  delete di;
                  di = newimage;
              }
          }
  
          /* write selected frame(s) to file */
  
          int result = 0;
          FILE *ofile = NULL;
          OFString ofname;
          unsigned int fcount = OFstatic_cast(unsigned int, ((opt_frameCount > 0) && (opt_frameCount <= di->getFrameCount())) ? opt_frameCount : di->getFrameCount());
          const char *ofext = NULL;
          /* determine default file extension */
          switch (opt_fileType)
          {
            case EFT_BMP:
            case EFT_8bitBMP:
            case EFT_24bitBMP:
            case EFT_32bitBMP:
              ofext = "bmp";
              break;
            case EFT_JPEG:
              ofext = "jpg";
              break;
            case EFT_TIFF:
              ofext = "tif";
              break;
            case EFT_PNG:
            case EFT_16bitPNG:
              ofext = "png";
              break;
            default:
              if (di->isMonochrome()) ofext = "pgm"; else ofext = "ppm";
              break;
          }
  
          if (fcount < opt_frameCount)
          {
              OFLOG_WARN(dcm2pnmLogger, "cannot select " << opt_frameCount << " frames, limiting to "
                  << fcount << " frames");
          }
  
          for (unsigned int frame = 0; frame < fcount; frame++)
          {
              if (opt_ofname)
              {
                  /* output to file */
                  if (opt_multiFrame)
                  {
                      OFOStringStream stream;
                      /* generate output filename */
                      stream << opt_ofname << ".";
                      if (opt_useFrameNumber)
                          stream << "f" << (opt_frame + frame);
                      else
                          stream << frame;
                      stream << "." << ofext << OFStringStream_ends;
                      /* convert string stream into a character string */
                      OFSTRINGSTREAM_GETSTR(stream, buffer_str)
                      ofname.assign(buffer_str);
                      OFSTRINGSTREAM_FREESTR(buffer_str)
                  } else
                      ofname.assign(opt_ofname);
                  OFLOG_INFO(dcm2pnmLogger, "writing frame " << (opt_frame + frame) << " to " << ofname);
                  ofile = fopen(ofname.c_str(), "wb");
                  if (ofile == NULL)
                  {
                      OFLOG_FATAL(dcm2pnmLogger, "cannot create file " << ofname);
                      return 1;
                  }
              } else {
                  /* output to stdout */
                  ofile = stdout;
                  OFLOG_INFO(dcm2pnmLogger, "writing frame " << (opt_frame + frame) << " to stdout");
              }
  
              /* finally create output image file */
  
              switch (opt_fileType)
              {
                  case EFT_RawPNM:
                      result = di->writeRawPPM(ofile, 8, frame);
                      break;
                  case EFT_8bitPNM:
                      result = di->writePPM(ofile, 8, frame);
                      break;
                  case EFT_16bitPNM:
                      result = di->writePPM(ofile, 16, frame);
                      break;
                  case EFT_NbitPNM:
                      result = di->writePPM(ofile, OFstatic_cast(int, opt_fileBits), frame);
                      break;
                  case EFT_BMP:
                      result = di->writeBMP(ofile, 0, frame);
                      break;
                  case EFT_8bitBMP:
                      result = di->writeBMP(ofile, 8, frame);
                      break;
                  case EFT_24bitBMP:
                      result = di->writeBMP(ofile, 24, frame);
                      break;
                  case EFT_32bitBMP:
                      result = di->writeBMP(ofile, 32, frame);
                      break;
  #ifdef BUILD_DCM2PNM_AS_DCMJ2PNM
                  case EFT_JPEG:
                      {
                          /* initialize JPEG plugin */
                          DiJPEGPlugin plugin;
                          plugin.setQuality(OFstatic_cast(unsigned int, opt_quality));
                          plugin.setSampling(opt_sampling);
                          result = di->writePluginFormat(&plugin, ofile, frame);
                      }
                      break;
  #endif
  #ifdef WITH_LIBTIFF
                  case EFT_TIFF:
                      {
                          /* initialize TIFF plugin */
                          DiTIFFPlugin tiffPlugin;
                          tiffPlugin.setCompressionType(opt_tiffCompression);
                          tiffPlugin.setLZWPredictor(opt_lzwPredictor);
                          tiffPlugin.setRowsPerStrip(OFstatic_cast(unsigned long, opt_rowsPerStrip));
                          result = di->writePluginFormat(&tiffPlugin, ofile, frame);
                      }
                      break;
  #endif
  #ifdef WITH_LIBPNG
                  case EFT_PNG:
                  case EFT_16bitPNG:
                      {
                          /* initialize PNG plugin */
                          DiPNGPlugin pngPlugin;
                          pngPlugin.setInterlaceType(opt_interlace);
                          pngPlugin.setMetainfoType(opt_metainfo);
                          if (opt_fileType == EFT_16bitPNG)
                              pngPlugin.setBitsPerSample(16);
                          result = di->writePluginFormat(&pngPlugin, ofile, frame);
                      }
                      break;
  #endif
  #ifdef PASTEL_COLOR_OUTPUT
                  case EFT_PastelPNM:
                      result = di->writePPM(ofile, MI_PastelColor, frame);
                      break;
  #endif
                  default:
                      if (opt_ofname)
                          result = di->writeRawPPM(ofile, 8, frame);
                      else /* stdout */
                          result = di->writePPM(ofile, 8, frame);
                      break;
              }
  
              if (opt_ofname)
                  fclose(ofile);
  
              if (!result)
              {
                  OFLOG_FATAL(dcm2pnmLogger, "cannot write frame");
                  return 1;
              }
          }
      }
  
      /* done, now cleanup. */
      OFLOG_INFO(dcm2pnmLogger, "cleaning up memory");
      delete di;
      delete disp;
  }
  
      // deregister RLE decompression codec
      DcmRLEDecoderRegistration::cleanup();
  #ifdef BUILD_DCM2PNM_AS_DCMJ2PNM
      // deregister JPEG decompression codecs
      DJDecoderRegistration::cleanup();
  #endif
  #ifdef BUILD_DCM2PNM_AS_DCML2PNM
      // deregister JPEG-LS decompression codecs
      DJLSDecoderRegistration::cleanup();
  #endif
  
      return 0;
  }
  