/* * * Copyright (C) 2002-2017, 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: dcmdata * * Author: Marco Eichelberg * * Purpose: Decompress RLE-compressed DICOM file * */ #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #define INCLUDE_CSTDLIB #define INCLUDE_CSTDIO #define INCLUDE_CSTRING #include "dcmtk/ofstd/ofstdinc.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk/dcmdata/cmdlnarg.h" #include "dcmtk/ofstd/ofconapp.h" #include "dcmtk/dcmdata/dcuid.h" /* for dcmtk version name */ #include "dcmtk/dcmdata/dcrledrg.h" /* for DcmRLEDecoderRegistration */ #ifdef WITH_ZLIB #include /* for zlibVersion() */ #endif #define OFFIS_CONSOLE_APPLICATION "dcmdrle" static OFLogger dcmdrleLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION); static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v" OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $"; // ******************************************** #define SHORTCOL 3 #define LONGCOL 21 int main(int argc, char *argv[]) { const char *opt_ifname = NULL; const char *opt_ofname = NULL; E_TransferSyntax opt_oxfer = EXS_LittleEndianExplicit; E_GrpLenEncoding opt_oglenc = EGL_recalcGL; E_EncodingType opt_oenctype = EET_ExplicitLength; E_PaddingEncoding opt_opadenc = EPD_noChange; OFCmdUnsignedInt opt_filepad = 0; OFCmdUnsignedInt opt_itempad = 0; E_FileReadMode opt_readMode = ERM_autoDetect; E_FileWriteMode opt_writeMode = EWM_fileformat; E_TransferSyntax opt_ixfer = EXS_Unknown; // RLE parameters OFBool opt_uidcreation = OFFalse; OFBool opt_reversebyteorder = OFFalse; OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION, "Decode RLE-compressed DICOM file", rcsid); OFCommandLine cmd; cmd.setOptionColumns(LONGCOL, SHORTCOL); cmd.setParamColumn(LONGCOL + SHORTCOL + 4); cmd.addParam("dcmfile-in", "DICOM input filename to be converted"); cmd.addParam("dcmfile-out", "DICOM output filename"); 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.addGroup("processing options:"); cmd.addSubGroup("SOP Instance UID:"); cmd.addOption("--uid-default", "+ud", "keep same SOP Instance UID (default)"); cmd.addOption("--uid-always", "+ua", "always assign new UID"); cmd.addSubGroup("RLE byte segment order:"); cmd.addOption("--byte-order-default", "+bd", "most significant byte first (default)"); cmd.addOption("--byte-order-reverse", "+br", "least significant byte first"); 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("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"); /* evaluate command line */ prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION); 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:"; #ifdef WITH_ZLIB COUT << OFendl << "- ZLIB, Version " << zlibVersion() << OFendl; #else COUT << " none" << OFendl; #endif return 0; } } /* command line parameters */ cmd.getParam(1, opt_ifname); cmd.getParam(2, opt_ofname); OFLog::configureFromCommandLine(cmd, app); cmd.beginOptionBlock(); if (cmd.findOption("--uid-default")) opt_uidcreation = OFFalse; if (cmd.findOption("--uid-always")) opt_uidcreation = OFTrue; cmd.endOptionBlock(); cmd.beginOptionBlock(); if (cmd.findOption("--byte-order-default")) opt_reversebyteorder = OFFalse; if (cmd.findOption("--byte-order-reverse")) opt_reversebyteorder = OFTrue; cmd.endOptionBlock(); cmd.beginOptionBlock(); if (cmd.findOption("--read-file")) { opt_readMode = ERM_autoDetect; opt_ixfer = EXS_Unknown; } if (cmd.findOption("--read-file-only")) { opt_readMode = ERM_fileOnly; opt_ixfer = EXS_Unknown; } if (cmd.findOption("--read-dataset")) { opt_readMode = ERM_dataset; opt_ixfer = EXS_RLELossless; } cmd.endOptionBlock(); cmd.beginOptionBlock(); if (cmd.findOption("--write-file")) opt_writeMode = EWM_fileformat; if (cmd.findOption("--write-dataset")) opt_writeMode = EWM_dataset; cmd.endOptionBlock(); cmd.beginOptionBlock(); if (cmd.findOption("--write-xfer-little")) opt_oxfer = EXS_LittleEndianExplicit; if (cmd.findOption("--write-xfer-big")) opt_oxfer = EXS_BigEndianExplicit; if (cmd.findOption("--write-xfer-implicit")) opt_oxfer = EXS_LittleEndianImplicit; cmd.endOptionBlock(); cmd.beginOptionBlock(); if (cmd.findOption("--enable-new-vr")) dcmEnableGenerationOfNewVRs(); if (cmd.findOption("--disable-new-vr")) dcmDisableGenerationOfNewVRs(); cmd.endOptionBlock(); cmd.beginOptionBlock(); if (cmd.findOption("--group-length-recalc")) opt_oglenc = EGL_recalcGL; if (cmd.findOption("--group-length-create")) opt_oglenc = EGL_withGL; if (cmd.findOption("--group-length-remove")) opt_oglenc = EGL_withoutGL; cmd.endOptionBlock(); cmd.beginOptionBlock(); if (cmd.findOption("--length-explicit")) opt_oenctype = EET_ExplicitLength; if (cmd.findOption("--length-undefined")) opt_oenctype = EET_UndefinedLength; cmd.endOptionBlock(); cmd.beginOptionBlock(); if (cmd.findOption("--padding-retain")) { app.checkConflict("--padding-retain", "--write-dataset", opt_writeMode == EWM_dataset); opt_opadenc = EPD_noChange; } if (cmd.findOption("--padding-off")) opt_opadenc = EPD_withoutPadding; if (cmd.findOption("--padding-create")) { app.checkConflict("--padding-create", "--write-dataset", opt_writeMode == EWM_dataset); app.checkValue(cmd.getValueAndCheckMin(opt_filepad, 0)); app.checkValue(cmd.getValueAndCheckMin(opt_itempad, 0)); opt_opadenc = EPD_withPadding; } cmd.endOptionBlock(); } /* print resource identifier */ OFLOG_DEBUG(dcmdrleLogger, rcsid << OFendl); // register global decompression codecs DcmRLEDecoderRegistration::registerCodecs(opt_uidcreation, opt_reversebyteorder); /* make sure data dictionary is loaded */ if (!dcmDataDict.isDictionaryLoaded()) { OFLOG_WARN(dcmdrleLogger, "no data dictionary loaded, check environment variable: " << DCM_DICT_ENVIRONMENT_VARIABLE); } // open inputfile if ((opt_ifname == NULL) || (strlen(opt_ifname) == 0)) { OFLOG_FATAL(dcmdrleLogger, "invalid filename: "); return 1; } DcmFileFormat fileformat; DcmDataset * dataset = fileformat.getDataset(); OFLOG_INFO(dcmdrleLogger, "open input file " << opt_ifname); OFCondition error = fileformat.loadFile(opt_ifname, opt_ixfer, EGL_noChange, DCM_MaxReadLength, opt_readMode); if (error.bad()) { OFLOG_FATAL(dcmdrleLogger, error.text() << ": reading file: " << opt_ifname); return 1; } OFLOG_INFO(dcmdrleLogger, "decompressing file"); DcmXfer opt_oxferSyn(opt_oxfer); DcmXfer original_xfer(dataset->getOriginalXfer()); error = dataset->chooseRepresentation(opt_oxfer, NULL); if (error.bad()) { OFLOG_FATAL(dcmdrleLogger, error.text() << ": decompressing file: " << opt_ifname); if (error == EC_CannotChangeRepresentation) OFLOG_FATAL(dcmdrleLogger, "input transfer syntax " << original_xfer.getXferName() << " not supported"); return 1; } if (! dataset->canWriteXfer(opt_oxfer)) { OFLOG_FATAL(dcmdrleLogger, "no conversion to transfer syntax " << opt_oxferSyn.getXferName() << " possible"); return 1; } OFLOG_INFO(dcmdrleLogger, "create output file " << opt_ofname); // update file meta information with new SOP Instance UID if (opt_uidcreation && (opt_writeMode == EWM_fileformat)) opt_writeMode = EWM_updateMeta; fileformat.loadAllDataIntoMemory(); error = fileformat.saveFile(opt_ofname, opt_oxfer, opt_oenctype, opt_oglenc, opt_opadenc, OFstatic_cast(Uint32, opt_filepad), OFstatic_cast(Uint32, opt_itempad), opt_writeMode); if (error.bad()) { OFLOG_FATAL(dcmdrleLogger, error.text() << ": writing file: " << opt_ofname); return 1; } OFLOG_INFO(dcmdrleLogger, "conversion successful"); // deregister RLE codec DcmRLEDecoderRegistration::cleanup(); return 0; }