/* * * Copyright (C) 1998-2018, 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: dcmpstat * * Authors: Joerg Riesmeier, Marco Eichelberg * * Purpose * sample application that reads a DICOM image and (optionally) * a presentation state and creates a PGM bitmap using the settings * of the presentation state. Non-grayscale transformations are * ignored. If no presentation state is loaded, a default is created. * */ #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/ofstd/ofstream.h" #include "dcmtk/dcmpstat/dviface.h" #include "dcmtk/dcmpstat/dvpstx.h" /* for DVPSTextObject */ #include "dcmtk/dcmpstat/dvpsgr.h" /* for DVPSGraphicObject */ #include "dcmtk/dcmpstat/dvpscu.h" /* for DVPSCurve */ #include "dcmtk/dcmimgle/dcmimage.h" #include "dcmtk/dcmdata/cmdlnarg.h" #include "dcmtk/ofstd/ofcmdln.h" #include "dcmtk/ofstd/ofconapp.h" #include "dcmtk/dcmdata/dcuid.h" /* for dcmtk version name */ #ifdef WITH_ZLIB #include /* for zlibVersion() */ #endif #define OFFIS_CONSOLE_APPLICATION "dcmp2pgm" static OFLogger dcmp2pgmLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION); static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v" OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $"; static void dumpPresentationState(DVPresentationState &ps) { size_t i, j, max; const char *c; OFOStringStream oss; oss << "DUMPING PRESENTATION STATE" << OFendl << "--------------------------" << OFendl << OFendl; c = ps.getPresentationLabel(); oss << "Presentation Label: "; if (c) oss << c << OFendl; else oss << "none" << OFendl; c = ps.getPresentationDescription(); oss << "Presentation Description: "; if (c) oss << c << OFendl; else oss << "none" << OFendl; c = ps.getPresentationCreatorsName(); oss << "Presentation Creator's Name: "; if (c) oss << c << OFendl; else oss << "none" << OFendl; oss << "VOI transformation: "; if (ps.haveActiveVOIWindow()) { double width=0.0, center=0.0; ps.getCurrentWindowWidth(width); ps.getCurrentWindowCenter(center); oss << "window center=" << center << " width=" << width << " description=\""; c = ps.getCurrentVOIDescription(); if (c) oss << c << "\"" << OFendl; else oss << "(none)\"" << OFendl; } else if (ps.haveActiveVOILUT()) { oss << "lut description=\""; c = ps.getCurrentVOIDescription(); if (c) oss << c << "\"" << OFendl; else oss << "(none)\"" << OFendl; } else oss << "none" << OFendl; oss << "Rotation: "; switch (ps.getRotation()) { case DVPSR_0_deg: oss << "none"; break; case DVPSR_90_deg: oss << "90 degrees"; break; case DVPSR_180_deg: oss << "180 degrees"; break; case DVPSR_270_deg: oss << "270 degrees"; break; } oss << OFendl; oss << "Flip: "; if (ps.getFlip()) oss << "yes" << OFendl; else oss << "no" << OFendl; Sint32 tlhcX=0; Sint32 tlhcY=0; Sint32 brhcX=0; Sint32 brhcY=0; oss << "Displayed area:" << OFendl; DVPSPresentationSizeMode sizemode = ps.getDisplayedAreaPresentationSizeMode(); double factor=1.0; switch (sizemode) { case DVPSD_scaleToFit: oss << " presentation size mode: SCALE TO FIT" << OFendl; break; case DVPSD_trueSize: oss << " presentation size mode: TRUE SIZE" << OFendl; break; case DVPSD_magnify: ps.getDisplayedAreaPresentationPixelMagnificationRatio(factor); oss << " presentation size mode: MAGNIFY factor=" << factor << OFendl; break; } ps.getStandardDisplayedArea(tlhcX, tlhcY, brhcX, brhcY); oss << " displayed area TLHC=" << tlhcX << "\\" << tlhcY << " BRHC=" << brhcX << "\\" << brhcY << OFendl; double x, y; if (EC_Normal == ps.getDisplayedAreaPresentationPixelSpacing(x,y)) { oss << " presentation pixel spacing: X=" << x << "mm Y=" << y << " mm" << OFendl; } else { oss << " presentation pixel aspect ratio: " << ps.getDisplayedAreaPresentationPixelAspectRatio() << OFendl; } oss << "Rectangular shutter: "; if (ps.haveShutter(DVPSU_rectangular)) { oss << "LV=" << ps.getRectShutterLV() << " RV=" << ps.getRectShutterRV() << " UH=" << ps.getRectShutterUH() << " LH=" << ps.getRectShutterLH() << OFendl; } else oss << "none" << OFendl; oss << "Circular shutter: "; if (ps.haveShutter(DVPSU_circular)) { oss << "center=" << ps.getCenterOfCircularShutter_x() << "\\" << ps.getCenterOfCircularShutter_y() << " radius=" << ps.getRadiusOfCircularShutter() << OFendl; } else oss << "none" << OFendl; oss << "Polygonal shutter: "; if (ps.haveShutter(DVPSU_polygonal)) { oss << "points=" << ps.getNumberOfPolyShutterVertices() << " coordinates="; j = ps.getNumberOfPolyShutterVertices(); Sint32 polyX, polyY; for (i=0; igetText() << "\"" << OFendl; oss << " anchor point: "; if (ptext->haveAnchorPoint()) { oss << ptext->getAnchorPoint_x() << "\\" << ptext->getAnchorPoint_y() << " units="; if (ptext->getAnchorPointAnnotationUnits()==DVPSA_display) oss << "display"; else oss << "pixel"; oss << " visible="; if (ptext->anchorPointIsVisible()) oss << "yes"; else oss << "no"; oss << OFendl; } else oss << "none" << OFendl; oss << " bounding box: "; if (ptext->haveBoundingBox()) { oss << "TLHC="; oss << ptext->getBoundingBoxTLHC_x() << "\\" << ptext->getBoundingBoxTLHC_y() << " BRHC=" << ptext->getBoundingBoxBRHC_x() << "\\" << ptext->getBoundingBoxBRHC_y() << " units="; if (ptext->getBoundingBoxAnnotationUnits()==DVPSA_display) oss << "display"; else oss << "pixel"; DVPSTextJustification justification = ptext->getBoundingBoxHorizontalJustification(); oss << " justification="; switch (justification) { case DVPSX_left: oss << "left"; break; case DVPSX_right: oss << "right"; break; case DVPSX_center: oss << "center"; break; } oss << OFendl; } else oss << "none" << OFendl; } } // graphic objects max = ps.getNumberOfGraphicObjects(layer); oss << " Number of graphic objects: " << max << OFendl; DVPSGraphicObject *pgraphic = NULL; for (size_t graphicidx=0; graphicidxgetNumberOfPoints(); Float32 fx=0.0, fy=0.0; for (i=0; igetPoint(i,fx,fy)) { oss << fx << "\\" << fy << ", "; } else oss << "???\\???, "; } oss << OFendl; } } // curve objects max = ps.getNumberOfCurves(layer); oss << " Number of activated curves: " << max << OFendl; DVPSCurve *pcurve = NULL; for (size_t curveidx=0; curveidxgetCurveAxisUnitsY(); if (c && (strlen(c)>0)) oss << c << OFendl; else oss << "(none)" << OFendl; oss << " label="; c = pcurve->getCurveLabel(); if (c && (strlen(c)>0)) oss << c << " description="; else oss << "(none) description="; c = pcurve->getCurveDescription(); if (c && (strlen(c)>0)) oss << c << OFendl; else oss << "(none)" << OFendl; oss << " coordinates: "; j = pcurve->getNumberOfPoints(); double dx=0.0, dy=0.0; for (i=0; igetPoint(i,dx,dy)) { oss << dx << "\\" << dy << ", "; } else oss << "???\\???, "; } oss << OFendl; } else oss << " curve " << curveidx+1 << " not present in image." << OFendl; } // overlay objects const void *overlayData=NULL; unsigned int overlayWidth=0, overlayHeight=0, overlayLeft=0, overlayTop=0; OFBool overlayROI=OFFalse; Uint16 overlayTransp=0; char overlayfile[100]; FILE *ofile=NULL; max = ps.getNumberOfActiveOverlays(layer); oss << " Number of activated overlays: " << max << OFendl; for (size_t ovlidx=0; ovlidx 1) cmd.getParam(2, opt_pgmName); OFLog::configureFromCommandLine(cmd, app); opt_dump_pstate = dcmp2pgmLogger.isEnabledFor(OFLogger::INFO_LOG_LEVEL); if (cmd.findOption("--pstate")) app.checkValue(cmd.getValue(opt_pstName)); if (cmd.findOption("--config")) app.checkValue(cmd.getValue(opt_cfgName)); if (cmd.findOption("--frame")) app.checkValue(cmd.getValueAndCheckMin(opt_frame, 1)); if (cmd.findOption("--pgm")) opt_dicom_mode = OFFalse; if (cmd.findOption("--dicom")) opt_dicom_mode = OFTrue; if (cmd.findOption("--save-pstate")) app.checkValue(cmd.getValue(opt_savName)); } /* print resource identifier */ OFLOG_DEBUG(dcmp2pgmLogger, rcsid << OFendl); if (opt_cfgName) { FILE *cfgfile = fopen(opt_cfgName, "rb"); if (cfgfile) fclose(cfgfile); else { OFLOG_FATAL(dcmp2pgmLogger, "can't open configuration file '" << opt_cfgName << "'"); return 10; } } DVInterface dvi(opt_cfgName); OFCondition status = EC_Normal; if (opt_pstName == NULL) { OFLOG_DEBUG(dcmp2pgmLogger, "reading DICOM image file: " << opt_imgName); status = dvi.loadImage(opt_imgName); } else { OFLOG_DEBUG(dcmp2pgmLogger, "reading DICOM pstate file: " << opt_pstName); OFLOG_DEBUG(dcmp2pgmLogger, "reading DICOM image file: " << opt_imgName); status = dvi.loadPState(opt_pstName, opt_imgName); } if (status == EC_Normal) { if (opt_dump_pstate) dumpPresentationState(dvi.getCurrentPState()); if (opt_pgmName != NULL) { const void *pixelData = NULL; unsigned long width = 0; unsigned long height = 0; OFLOG_DEBUG(dcmp2pgmLogger, "creating pixel data"); if ((opt_frame > 0) && (dvi.getCurrentPState().selectImageFrameNumber(opt_frame) != EC_Normal)) OFLOG_ERROR(dcmp2pgmLogger, "cannot select frame " << opt_frame); if ((dvi.getCurrentPState().getPixelData(pixelData, width, height) == EC_Normal) && (pixelData != NULL)) { if (opt_dicom_mode) { double pixelAspectRatio = dvi.getCurrentPState().getPrintBitmapPixelAspectRatio(); // works for rotated images OFLOG_DEBUG(dcmp2pgmLogger, "writing DICOM SC file: " << opt_pgmName); if (EC_Normal != dvi.saveDICOMImage(opt_pgmName, pixelData, width, height, pixelAspectRatio)) { OFLOG_ERROR(dcmp2pgmLogger, "error during creation of DICOM file"); } } else { FILE *outfile = fopen(opt_pgmName, "wb"); if (outfile) { OFLOG_DEBUG(dcmp2pgmLogger, "writing PGM file: " << opt_pgmName); fprintf(outfile, "P5\n%ld %ld 255\n", width, height); if (fwrite(pixelData, OFstatic_cast(size_t, width), OFstatic_cast(size_t, height), outfile) != OFstatic_cast(size_t, height)) OFLOG_FATAL(dcmp2pgmLogger, "Can't write output data to file."); fclose(outfile); } else { OFLOG_FATAL(dcmp2pgmLogger, "Can't create output file."); return 10; } } } else { OFLOG_FATAL(dcmp2pgmLogger, "Can't create output data."); return 10; } } if (opt_savName != NULL) { OFLOG_DEBUG(dcmp2pgmLogger, "writing pstate file: " << opt_savName); if (dvi.savePState(opt_savName, OFFalse) != EC_Normal) { OFLOG_FATAL(dcmp2pgmLogger, "Can't write pstate file."); return 10; } } } else { OFLOG_FATAL(dcmp2pgmLogger, "Can't open input file(s)."); return 10; } #ifdef DEBUG dcmDataDict.clear(); /* useful for debugging with dmalloc */ #endif return (status != EC_Normal); }