/*
 *
 *  Copyright (C) 1996-2024, 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:  dcmimgle
 *
 *  Author:  Joerg Riesmeier
 *
 *  Purpose: Provides main interface to the "DICOM image toolkit"
 *
 */


#ifndef DCMIMAGE_H
#define DCMIMAGE_H

#include "dcmtk/config/osconfig.h"

#include "dcmtk/dcmimgle/dimoimg.h"
#include "dcmtk/dcmimgle/didispfn.h"
#include "dcmtk/dcmimgle/diutils.h"


/*------------------------*
 *  forward declarations  *
 *------------------------*/

class DcmXfer;
class DcmObject;
class DcmOverlayData;
class DcmLongString;
class DcmUnsignedShort;

class DiPixel;
class DiDocument;
class DiPluginFormat;


/*---------------------*
 *  class declaration  *
 *---------------------*/

/** Interface class for dcmimgle/dcmimage module.
 *  The main purpose of these modules is image display.
 */
class DCMTK_DCMIMGLE_EXPORT DicomImage
{

 public:

 // --- constructors and destructor

    /** constructor, open a DICOM file.
     *  Opens specified file and reads image related data, creates internal representation
     *  of image data.  Use getStatus() to obtain detailed information about any errors.
     *
     ** @param  filename  the DICOM file specified by its filename
     *  @param  flags     configuration flags (see diutils.h, CIF_MayDetachPixelData is set automatically)
     *  @param  fstart    first frame to be processed (optional, 0 = 1st frame), all subsequent use
     *                    of parameters labeled 'frame' in this class refers to this start frame.
     *  @param  fcount    number of frames (optional, 0 = all frames)
     */
    DicomImage(const OFFilename &filename,
               const unsigned long flags = 0,
               const unsigned long fstart = 0,
               const unsigned long fcount = 0);

#ifndef STARVIEW
    /** constructor, use a given DcmObject
     *
     ** @param  object  pointer to DICOM data structures (fileformat, dataset or item).
     *                  (do not delete while referenced, i.e. while this image object or any
     *                   descendant exists; not deleted within dcmimage unless configuration flag
     *                   CIF_TakeOverExternalDataset is set - in this case do not delete it at all)
     *  @param  xfer    transfer syntax of the 'object'.
     *                  (could also be EXS_Unknown in case of fileformat or dataset)
     *  @param  flags   configuration flags (CIF_xxx, see diutils.h)
     *  @param  fstart  first frame to be processed (optional, 0 = 1st frame), all subsequent use
     *                  of parameters labeled 'frame' in this class refers to this start frame.
     *  @param  fcount  number of frames (optional, 0 = all frames)
     */
    DicomImage(DcmObject *object,
               const E_TransferSyntax xfer,
               const unsigned long flags = 0,
               const unsigned long fstart = 0,
               const unsigned long fcount = 0);

    /** constructor, use a given DcmObject with specified rescale/slope.
     *  NB: This constructor ignores the Photometric Interpretation stored in the DICOM dataset
     *      and always creates a MONOCHROME2 image - useful in combination with Presentation States.
     *
     ** @param  object     pointer to DICOM data structures (fileformat, dataset or item).
     *                     (do not delete while referenced, i.e. while this image object or any
     *                      descendant exists; not deleted within dcmimage unless configuration flag
     *                      CIF_TakeOverExternalDataset is set - in this case do not delete it at all)
     *  @param  xfer       transfer syntax of the 'object'.
     *                     (could also be EXS_Unknown in case of fileformat or dataset)
     *  @param  slope      rescale slope (modality transformation)
     *  @param  intercept  rescale intercept (modality transformation)
     *  @param  flags      configuration flags (CIF_xxx, see diutils.h)
     *  @param  fstart     first frame to be processed (optional, 0 = 1st frame), all subsequent use
     *                     of parameters labeled 'frame' in this class refers to this start frame.
     *  @param  fcount     number of frames (optional, 0 = all frames)
     */
    DicomImage(DcmObject *object,
               const E_TransferSyntax xfer,
               const double slope,
               const double intercept,
               const unsigned long flags = 0,
               const unsigned long fstart = 0,
               const unsigned long fcount = 0);

    /** constructor, use a given DcmObject with specified modality LUT.
     *  NB: This constructor ignores the Photometric Interpretation stored in the DICOM dataset
     *      and always creates a MONOCHROME2 image - useful in combination with Presentation States.
     *
     ** @param  object       pointer to DICOM data structures (fileformat, dataset or item).
     *                       (do not delete while referenced, i.e. while this image object or any
     *                        descendant exists; not deleted within dcmimage unless configuration flag
     *                        CIF_TakeOverExternalDataset is set - in this case do not delete it at all)
     *  @param  xfer         transfer syntax of the 'object'.
     *                       (could also be EXS_Unknown in case of fileformat or dataset)
     *  @param  data         dataset element containing modality LUT data
     *  @param  descriptor   dataset element containing modality LUT descriptor
     *  @param  explanation  dataset element containing modality LUT explanation
     *  @param  flags        configuration flags (CIF_xxx, see diutils.h)
     *  @param  fstart       first frame to be processed (optional, 0 = 1st frame), all subsequent use
     *                       of parameters labeled 'frame' in this class refers to this start frame.
     *  @param  fcount       number of frames (optional, 0 = all frames)
     */
    DicomImage(DcmObject *object,
               E_TransferSyntax xfer,
               const DcmUnsignedShort &data,
               const DcmUnsignedShort &descriptor,
               const DcmLongString *explanation = NULL,
               const unsigned long flags = 0,
               const unsigned long fstart = 0,
               const unsigned long fcount = 0);
#endif

    /** destructor
     */
    virtual ~DicomImage();


 // --- multi-frame handling

    /** process next couple of frames.  If the image object has been created with less than the number
     *  of frames stored in the DICOM image, this function allows for accessing the subsequent frames.
     *  Multiple calls to this function allow for successively processing all frames stored in the
     *  file or dataset.  See parameters 'fstart' and 'fcount' of the constructor for how to initially
     *  create an instance of this class.
     *  NB: Only "original" images can be processed in this way, i.e. images that were created by one
     *      of the above constructors.  Images that were created by one of the createXXX() methods can
     *      not be processed since they are derived from original image data in a certain way, e.g.
     *      scaled.
     *
     ** @param  fcount  number of frames to be processed (0 = same number as before)
     *
     ** @return status, true if successful, false otherwise
     */
    inline int processNextFrames(const unsigned long fcount = 0)
    {
        return (Image != NULL) ?
            Image->processNextFrames(fcount) : 0;
    }


 // --- information: return requested value if successful

    /** convert status code to status string
     *
     ** @param  status  code of current internal status
     *
     ** @return pointer to status string
     */
    static const char *getString(const EI_Status status);

    /** convert photometric interpretation code to interpretation string (defined term)
     *
     ** @param  interpret  code of image's photometric interpretation
     *
     ** @return pointer to photometric interpretation string
     */
    static const char *getString(const EP_Interpretation interpret);

    /** get current status information
     *
     ** @return status code
     */
    inline EI_Status getStatus() const
    {
        return (Image != NULL) ?
            Image->getStatus() : ImageStatus;
    }

    /** get number of frames.
     *  Please note that this function does not return the number of frames stored in the
     *  DICOM file/dataset (use getNumberOfFrames() instead).  It rather refers to the
     *  number of frames processed by this class (see constructors for details).
     *
     ** @return number of frames processed by this class
     */
    inline unsigned long getFrameCount() const
    {
        return (Image != NULL) ?
            Image->getNumberOfFrames() : 0;
    }

    /** get index of first frame.
     *  This functions returns the index of the first frame processed by this class (see
     *  constructors for details).
     *
     ** @return index of first frame (0..n-1)
     */
    inline unsigned long getFirstFrame() const
    {
        return (Image != NULL) ?
            Image->getFirstFrame() : 0;
    }

    /** get number of frames stored in the DICOM file/dataset.
     *  This attribute is mandatory for DICOM images with multiple frames.
     *  For single frame images, the value defaults to 1.
     *
     ** @return number of frames stored in the DICOM file/dataset
     */
    inline unsigned long getNumberOfFrames() const
    {
        return (Image != NULL) ?
            Image->getTotalNumberOfFrames() : 0;
    }

    /** get index of representative frame.
     *  This attribute is optionally stored in the DICOM dataset (type 3).
     *
     ** @return index of representative frame (0..n-1)
     */
    inline unsigned long getRepresentativeFrame() const
    {
        return (Image != NULL) ?
            Image->getRepresentativeFrame() : 0;
    }

    /** get nominal time (in milliseconds) between individual frames.
     *  This attribute might not always be stored in the DICOM dataset.
     *
     ** @return nominal time between individual frames, 0 if absent
     */
    inline double getFrameTime() const
    {
        return (Image != NULL) ?
            Image->getFrameTime() : 0;
    }

    /** get image width in pixels
     *
     ** @return number of pixels in one row
     */
    inline unsigned long getWidth() const
    {
        return (Image != NULL) ?
            Image->getColumns() : 0;
    }

    /** get image height in pixels
     *
     ** @return number of pixels in one column
     */
    inline unsigned long getHeight() const
    {
        return (Image != NULL) ?
            Image->getRows() : 0;
    }

    /** get image depth
     *
     ** @return number of bits per sample of the internal representation
     */
    inline int getDepth() const
    {
        return (Image != NULL) ?
            Image->getBits() : 0;
    }

    /** get minimum and maximum pixel values.
     *  the resulting pixel values are stored in 'double' variables to avoid problems
     *  with different number ranges, limited to monochrome images.
     *  Please note that the min/max values refer to the full pixel data (i.e. including
     *  all possible present frames as specified in the constructor of this class).
     *
     ** @param  min   minimum pixel value (reference parameter)
     *  @param  max   maximum pixel value (reference parameter)
     *  @param  mode  0 = min/max 'used' pixel values,
     *                1 = min/max 'possible' pixel values (absolute min/max)
     *
     ** @return status code (true if successful)
     */
    inline int getMinMaxValues(double &min,
                               double &max,
                               const int mode = 0) const
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->getMinMaxValues(min, max, mode) : 0;
    }

    /** get width height ratio (pixel aspect ratio: x/y).
     *  If present in the dataset and not overwritten using setWidthHeightRatio(), the following
     *  attributes are checked in order to determine this value:
     *  - Pixel Spacing, Imager Pixel Spacing, Nominal Scanned Pixel Spacing, Pixel Aspect Ratio.
     *  The first attribute (Pixel Spacing) is checked both on the main dataset level and within
     *  the Pixel Measures Sequence of the Shared Functional Groups Sequence (if present).
     *
     ** @return pixel aspect ratio (floating point value)
     */
    inline double getWidthHeightRatio() const
    {
        return (Image != NULL) ?
            Image->getColumnRowRatio() : 0;
    }

    /** get height width ratio (pixel aspect ratio: y/x).
     *  If present in the dataset and not overwritten using setWidthHeightRatio(), the following
     *  attributes are checked in order to determine this value:
     *  - Pixel Spacing, Imager Pixel Spacing, Nominal Scanned Pixel Spacing, Pixel Aspect Ratio
     *  The first attribute (Pixel Spacing) is checked both on the main dataset level and within
     *  the Pixel Measures Sequence of the Shared Functional Groups Sequence (if present).
     *
     ** @return pixel aspect ratio (floating point value)
     */
    inline double getHeightWidthRatio() const
    {
        return (Image != NULL) ?
            Image->getRowColumnRatio() : 0;
    }

    /** set width height ratio (pixel aspect ratio: x/y)
     *
     ** @param  ratio  pixel aspect ratio (x/y)
     *
     ** @return status code (true if successful)
     */
    inline int setWidthHeightRatio(const double ratio) const
    {
        return (Image != NULL) ?
            Image->setColumnRowRatio(ratio) : 0;
    }

    /** set height width ratio (pixel aspect ratio: y/x)
     *
     ** @param  ratio  pixel aspect ratio (y/x)
     *
     ** @return status code (true if successful)
     */
    inline int setHeightWidthRatio(const double ratio) const
    {
        return (Image != NULL) ?
            Image->setRowColumnRatio(ratio) : 0;
    }

    /** check whether given output value is unused
     *
     ** @param  value  output value to be checked
     *
     ** @return status, true if unused (1 = within output range, 2 = out of range), false otherwise
     */
    inline int isOutputValueUnused(const unsigned long value)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->isValueUnused(value) : 0;
    }

  // --- output: return pointer to output data if successful

    /** get number of bytes required for the rendered output of a single frame.
     *  This function determines the size of a rendered frame as created by getOutputData().
     *  Therefore, it can be used to allocate a sufficiently large memory buffer and pass
     *  its size to the second variant of getOutputData().
     *
     ** @param  bits  number of bits per sample used to render the pixel data
     *                (image depth, 1..MAX_BITS, 0 means 'bits stored' in the image)
     *                (MI_PastelColor = -1 for true color pastel mode, EXPERIMENTAL)
     *
     ** @return number of bytes if successful, 0 otherwise
     */
    inline unsigned long getOutputDataSize(const int bits = 0) const
    {
        return (Image != NULL) ?
            Image->getOutputDataSize(Image->getBits(bits)) : 0;
    }

    /** render pixel data and return pointer to internal memory buffer.
     *  apply VOI/PLUT transformation and (visible) overlay planes.
     *  internal memory buffer will be delete for the next getBitmap/Output operation.
     *  output data is always padded to 8, 16, 32, ... bits (bits allocated).
     *  Supported output color models: Monochrome 2 for monochrome images and RGB
     *  (or YCbCr_Full if flag CIF_KeepYCbCrColorModel is set) for color images.
     *  The rendered pixel data is always unsigned.
     *
     ** @param  bits    number of bits per sample used to render the pixel data
     *                  (image depth, 1..MAX_BITS, 0 means 'bits stored' in the image)
     *                  (MI_PastelColor = -1 for true color pastel mode, EXPERIMENTAL)
     *  @param  frame   number of frame to be rendered (0..n-1)
     *  @param  planar  0 = color-by-pixel (R1G1B1...R2G2B2...R3G3B3...),
     *                  1 = color-by-plane (R1R2R3...G1G2G3...B1B2B3...)
     *                  (only applicable to multi-planar/color images, otherwise ignored)
     *
     ** @return pointer to internal memory buffer containing rendered pixel data
     *          (if successful, NULL otherwise)
     */
    inline const void *getOutputData(const int bits = 0,
                                     const unsigned long frame = 0,
                                     const int planar = 0)
    {
        return (Image != NULL) ?
            Image->getOutputData(frame, Image->getBits(bits), planar) : NULL;
    }

    /** render pixel data and output to given memory buffer.
     *  apply VOI/PLUT transformation and (visible) overlay planes.
     *  output data is always padded to 8, 16, 32, ... bits (bits allocated).
     *  Supported output color models: Monochrome 2 for monochrome images and RGB
     *  (or YCbCr_Full if flag CIF_KeepYCbCrColorModel is set) for color images.
     *  The rendered pixel data is always unsigned.
     *
     ** @param  buffer  pointer to memory buffer (must already be allocated)
     *  @param  size    size of memory buffer (will be checked whether it is sufficient)
     *  @param  bits    number of bits per sample used to render the pixel data
     *                  (image depth, 1..MAX_BITS, 0 means 'bits stored' in the image)
     *                  (MI_PastelColor = -1 for true color pastel mode, EXPERIMENTAL)
     *  @param  frame   number of frame to be rendered (0..n-1)
     *  @param  planar  0 = color-by-pixel (R1G1B1...R2G2B2...R3G3B3...),
     *                  1 = color-by-plane (R1R2R3...G1G2G3...B1B2B3...)
     *                  (only applicable to multi-planar/color images, otherwise ignored)
     *
     ** @return status code (true if successful)
     */
    inline int getOutputData(void *buffer,
                             const unsigned long size,
                             const int bits = 0,
                             const unsigned long frame = 0,
                             const int planar = 0)
    {
        return (Image != NULL) ?
            Image->getOutputData(buffer, size, frame, Image->getBits(bits), planar) : 0;
    }

    /** render pixel data and return pointer to given plane (internal memory buffer).
     *  apply VOI/PLUT transformation and (visible) overlay planes.
     *  internal memory buffer will be delete for the next getBitmap/Output operation.
     *  Supported output color models: Monochrome 2 for monochrome images and RGB
     *  (or YCbCr_Full if flag CIF_KeepYCbCrColorModel is set) for color images.
     *  The rendered pixel data is always unsigned.
     *
     ** @param  plane  number of plane to be rendered
     *
     ** @return pointer to internal memory buffer containing rendered pixel data
     *          (if successful, NULL otherwise)
     */
    inline const void *getOutputPlane(const int plane) const
    {
        return (Image != NULL) ?
            Image->getOutputPlane(plane) : NULL;
    }

    /** delete internal memory buffer used for rendered images.
     *  Save memory if data is no longer needed.
     */
    inline void deleteOutputData() const
    {
        if (Image != NULL)
            Image->deleteOutputData();
    }

  // --- misc

    /** check whether image is monochrome or not.
     *
     ** @return true if image is monochrome, false otherwise (i.e. color image)
     */
    inline int isMonochrome() const
    {
        return (PhotometricInterpretation == EPI_Monochrome1) || (PhotometricInterpretation == EPI_Monochrome2);
    }

    /** get code for photometric interpretation (color model).
     *
     ** @return code for photometric interpretation of the image
     */
    inline EP_Interpretation getPhotometricInterpretation() const
    {
        return PhotometricInterpretation;
    }

    /** check whether image has given SOP class UID.
     *
     ** @param  uid  SOP class UID to be checked
     *
     ** @return true if image has given SOP class UID, false otherwise
     */
    int hasSOPclassUID(const char *uid) const;

    /** get intermediate pixel data representation (read-only).
     *  This function allows to access the pixel data after they have been extracted
     *  from the DICOM data element and the modality transformation has been applied
     *  (if present and not disabled).  Please note that for monochrome images the
     *  internal representation might be signed whereas color images are automatically
     *  converted to unsigned RGB format.  Pixels are aligned to 8, 16 or 32 bits.
     *  Always use DiPixel::getRepresentation() in order to determine the integer
     *  representation of the internally stored pixel data.
     *
     ** @return pointer to intermediate pixel data representation
     */
    inline const DiPixel *getInterData() const
    {
        return (Image != NULL) ?
            Image->getInterData() : NULL;
    }

 // --- display function for output device characteristic (calibration):
 //     only applicable to grayscale images

    /** get display function
     *
     ** @return pointer to current display function, NULL if absent
     */
    inline DiDisplayFunction *getDisplayFunction() const
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->getDisplayFunction() : OFstatic_cast(DiDisplayFunction *, NULL);
    }

    /** set display function
     *
     ** @param  display  object describing the output device characteristic (only referenced!)
     *
     ** @return true if successful, false otherwise
     */
    inline int setDisplayFunction(DiDisplayFunction *display)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->setDisplayFunction(display) : 0;
    }

    /** set no display function.
     *  disables display function transformation, object is not deleted!
     *
     ** @return true if successful (1 = disabled current function,
     *                              2 = there was no function to disable),
     *          false otherwise
     */
    inline int setNoDisplayFunction()
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->setNoDisplayFunction() : 0;
    }

    /** delete specified display LUT(s)
     *
     ** @param  bits  parameter of LUT to be deleted (0 = all)
     *
     ** @return true if successful, false otherwise
     */
    inline int deleteDisplayLUT(const int bits = 0)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->deleteDisplayLUT(bits) : 0;
    }

    /** convert P-value to DDL.
     *  conversion uses display LUT if present, linear scaling otherwise.
     *
     ** @param  pvalue  P-value to be converted (0..65535)
     *  @param  ddl     reference to resulting DDL
     *  @param  bits    number of bits for output
     *
     ** @return true if successful (1 = display function transformation,
     *                              2 = linear scaling),
     *          false otherwise
     */
    inline int convertPValueToDDL(const Uint16 pvalue,
                                  Uint16 &ddl,
                                  const int bits = 8)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->convertPValueToDDL(pvalue, ddl, bits) : 0;
    }

 // --- windowing (voi): only applicable to grayscale images
 //                      return true if successful (see also 'dimoimg.cc')

    /** unset all VOI transformations (windows and LUTs).
     *  only applicable to monochrome images
     *
     ** @return true if successful (1 = previous window/LUT has been valid,
     *                              2 = otherwise),
     *          false otherwise (image is invalid or not monochrome)
     */
    inline int setNoVoiTransformation()
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->setNoVoiTransformation() : 0;
    }

    /** set automatically calculated minimum/maximum window.
     *  possibly active VOI LUT is implicitly disabled.
     *  Please note that the min/max values refer to the full pixel data (i.e. including
     *  all possible present frames as specified in the constructor of this class).
     *
     ** @param  idx  ignore global min/max values if true (1)
     *
     ** @return true if successful (1 = window has changed,
     *                              2 = new window is the same as previous one),
     *          false otherwise
     */
    inline int setMinMaxWindow(const int idx = 0)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->setMinMaxWindow(idx) : 0;
    }

    /** set automatically calculated histogram window.
     *  possibly active VOI LUT is implicitly disabled.
     *
     ** @param  thresh  threshold value specifying percentage of histogram border which
     *                  shall be ignored (default: 5%).
     *
     ** @return true if successful, false otherwise
     */
    inline int setHistogramWindow(const double thresh = 0.05)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->setHistogramWindow(thresh) : 0;
    }

    /** set automatically calculated VOI window for the specified Region of Interest (ROI).
     *  The ROI is specified by means of a rectangle (left, top, width, height).  Only the part
     *  of the ROI that overlaps with the image is regarded - if the overlapping area is empty
     *  this method returns false (0).
     *  Possibly active VOI LUT is implicitly disabled.
     *
     ** @param  left_pos  x-coordinate of the top left-hand corner of the ROI (starting from 0)
     *  @param  top_pos   y-coordinate of the top left-hand corner of the ROI (starting from 0)
     *  @param  width     width in pixels of the rectangular ROI (minimum: 1)
     *  @param  height    height in pixels of the rectangular ROI (minimum: 1)
     *  @param  frame     index of the frame to be used for calculation (default: 0 = first)
     *
     ** @return true if successful (1 = window has changed,
     *                              2 = new window is the same as previous one),
     *          false otherwise
     */
    inline int setRoiWindow(const unsigned long left_pos,
                            const unsigned long top_pos,
                            const unsigned long width,
                            const unsigned long height,
                            const unsigned long frame = 0)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->setRoiWindow(left_pos, top_pos, width, height, frame) : 0;
    }

    /** set specified VOI window (given by index to window width/center sequence stored in image
     *  file).
     *  possibly active VOI LUT is implicitly disabled.
     *  NB: This function does nothing if the flag CIF_UsePresentationState is set.
     *
     ** @param  window  index to window width/center sequence (0..n-1)
     *
     ** @return true if successful, false otherwise (none monochrome or invalid index)
     */
    inline int setWindow(const unsigned long window)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->setWindow(window) : 0;
    }

    /** set specified VOI window (given by window width and center).
     *  possibly active VOI LUT is implicitly disabled.
     *
     ** @param  center  center of specified window
     *  @param  width   width of specified window (>= 1.0)
     *
     ** @return true if successful (1 = window has changed,
     *                              2 = new window is the same as previous one),
     *          false otherwise
     */
    inline int setWindow(const double center,
                         const double width)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->setWindow(center, width) : 0;
    }

    /** get current VOI window as window center and width values
     *
     ** @param  center  return current window center value
     *  @param  width   return current window width value
     *
     ** @return true if successful, false otherwise
     */
    inline int getWindow(double &center,
                         double &width)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->getWindow(center, width) : 0;
    }

    /** get number of VOI windows (stored in image file).
     *  NB: This function does nothing if the flag CIF_UsePresentationState is set.
     *
     ** @return number of VOI windows
     */
    inline unsigned long getWindowCount() const
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->getWindowCount() : 0;
    }

    /** set VOI LUT function
     *
     ** @param  function  type of VOI LUT function (default, linear or sigmoid).
     *                    'default' basically means the same as 'linear'.
     *
     ** @return true if successful (1 = function has changed,
     *                              2 = function has not changed),
     *          false otherwise
     */
    inline int setVoiLutFunction(const EF_VoiLutFunction function)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->setVoiLutFunction(function) : 0;
    }

    /** get VOI LUT function.
     *  possible values are: EFV_Default, EFV_Linear, EFV_Sigmoid.
     *
     ** @return currently active VOI LUT function or EFV_Default if not set
     */
    inline EF_VoiLutFunction getVoiLutFunction() const
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->getVoiLutFunction() : EFV_Default;
    }

    /** set VOI LUT (given by dcmdata elements).
     *  possibly active window/center is implicitly disabled.
     *  Given data is only referenced and not copied! Make sure that the corresponding DcmXXX
     *  objects exist as long as the VOI LUT is set.
     *
     ** @param  data         contains LUT data
     *  @param  descriptor   describes LUT structure
     *  @param  explanation  free form description of VOI LUT (optional)
     *  @param  descripMode  mode specifying the use of the bits per table entry value
     *
     ** @return true if successful, false otherwise
     */
    inline int setVoiLut(const DcmUnsignedShort &data,
                         const DcmUnsignedShort &descriptor,
                         const DcmLongString *explanation = NULL,
                         const EL_BitsPerTableEntry descripMode = ELM_UseValue)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->setVoiLut(data, descriptor, explanation, descripMode) : 0;
    }

    /** set VOI LUT (given by index to VOI LUT sequence stored in image file).
     *  possibly active window/center is implicitly disabled.
     *  NB: This function does nothing if the flag CIF_UsePresentationState is set.
     *
     ** @param  table  index to VOI LUT sequence (0..n-1)
     *  @param  descripMode  mode specifying the use of the bits per table entry value
     *
     ** @return true if successful, false otherwise (none monochrome or invalid index)
     */
    inline int setVoiLut(const unsigned long table,
                         const EL_BitsPerTableEntry descripMode = ELM_UseValue)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->setVoiLut(table, descripMode) : 0;
    }

    /** get number of VOI LUTs (stored in image file)
     *
     ** @return number of VOI LUTs
     */
    inline unsigned long getVoiLutCount() const
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->getVoiLutCount() : 0;
    }

    /** get description of active VOI transformation
     *
     ** @return pointer to description text (NULL if absent)
     */
    inline const char *getVoiTransformationExplanation() const
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->getVoiTransformationExplanation() : OFstatic_cast(const char *, NULL);
    }

    /** get description of specified VOI window (stored in the image file)
     *
     ** @param  window       index of the stored VOI window (0..n-1)
     *  @param  explanation  variable in which the explanation string is stored
     *
     ** @return pointer to description text (NULL if absent or index invalid)
     */
    inline const char *getVoiWindowExplanation(const unsigned long window,
                                               OFString &explanation) const
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->getVoiWindowExplanation(window, explanation) : OFstatic_cast(const char *, NULL);
    }

    /** get description of specified VOI LUT (stored in the image file)
     *
     ** @param  table        index of the stored VOI LUT (0..n-1)
     *  @param  explanation  variable in which the explanation string is stored
     *
     ** @return pointer to description text (NULL if absent or index invalid)
     */
    inline const char *getVoiLutExplanation(const unsigned long table,
                                            OFString &explanation) const
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->getVoiLutExplanation(table, explanation) : OFstatic_cast(const char *, NULL);
    }

    /** get description of performed modality LUT transformation
     *
     ** @return pointer to description text (NULL if absent)
     */
    inline const char *getModalityLutExplanation() const
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->getModalityLutExplanation() : OFstatic_cast(const char *, NULL);
    }

 // --- hardcopy parameters

    /** get polarity. applicable to monochrome and color images.
     *  possible values are EPP_Normal and EPP_Reverse
     *
     ** @return currently active polarity mode or EPP_Normal if not applicable
     */
    inline EP_Polarity getPolarity() const
    {
        return (Image != NULL) ?
            Image->getPolarity() : EPP_Normal;
    }

    /** set polarity. applicable to monochrome and color images.
     *
     ** @param  polarity  polarity (normal or reverse)
     *
     ** @return true if successful (1 = polarity has changed,
     *                              2 = polarity has not changed),
     *          false otherwise
     */
    inline int setPolarity(const EP_Polarity polarity)
    {
        return (Image != NULL) ?
            Image->setPolarity(polarity) : 0;
    }

    /** set hardcopy parameters. only applicable to monochrome images.
     *  used to display LinOD images
     *
     ** @param  min      minimum density of the print-out (in hundreds of Optical Density,
     *                   e.g. 150 means 1.5 OD)
     *  @param  max      maximum density of the print-out (ditto)
     *  @param  reflect  reflected ambient light (in candela per square meter - cd/m^2)
     *  @param  illumin  illumination (ditto)
     *
     ** @return true if successful (1 = at least one of the parameters has changed,
     *                              2 = no parameter has changed),
     *          false otherwise
     */
    inline int setHardcopyParameters(const unsigned int min,
                                     const unsigned int max,
                                     const unsigned int reflect,
                                     const unsigned int illumin)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->setHardcopyParameters(min, max, reflect, illumin) : 0;
    }

 // --- presentation LUT: only applicable to grayscale images

    /** get shape for presentation transformation.
     *  possible values are: ESP_Default, ESP_Identity, ESP_Inverse, ESP_LinOD.
     *  If a presentation LUT is currently active ESP_Default is always returned.
     *
     ** @return currently active presentation LUT shape or ESP_Default if not set
     */
    inline ES_PresentationLut getPresentationLutShape() const
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->getPresentationLutShape() : ESP_Default;
    }

    /** set shape for presentation transformation.
     *  possibly active presentation LUT is implicitly disabled.
     *
     ** @param  shape  presentation LUT shape (default, identity, inverse or lin OD).
     *                 'default' means that the output data is always created with 0 for black
     *                 and maxvalue for white (i.e. monochrome2 data is created for output).
     *
     ** @return true if successful (1 = shape has changed,
     *                              2 = shape has not changed),
     *          false otherwise
     */
    inline int setPresentationLutShape(const ES_PresentationLut shape)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->setPresentationLutShape(shape) : 0;
    }

    /** set LUT for presentation transformation.
     *  possibly active presentation LUT is implicitly disabled.
     *  Given data is only referenced and not copied! Make sure that the corresponding DcmXXX
     *  objects exist as long as the presentation LUT is set.
     *
     ** @param  data         contains LUT data
     *  @param  descriptor   describes LUT structure
     *  @param  explanation  free form description of presentation LUT (optional)
     *  @param  descripMode  mode specifying the use of the bits per table entry value
     *
     ** @return true if successful, false otherwise
     */
    inline int setPresentationLut(const DcmUnsignedShort &data,
                                  const DcmUnsignedShort &descriptor,
                                  const DcmLongString *explanation = NULL,
                                  const EL_BitsPerTableEntry descripMode = ELM_UseValue)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->setPresentationLut(data, descriptor, explanation, descripMode) : 0;
    }

    /** get description of active presentation LUT
     *
     ** @return pointer to description text (NULL if absent)
     */
    inline const char *getPresentationLutExplanation() const
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->getPresentationLutExplanation() : OFstatic_cast(const char *, NULL);
    }

    /** set inverse LUT for presentation transformation.
     *  this LUT transform is e.g. used for DICOM print (12->8, 8->12 bit)
     *  possibly active presentation LUT will not be considered!
     *
     ** @param  data         contains LUT data
     *  @param  descriptor   describes LUT structure
     *  @param  descripMode  mode specifying the use of the bits per table entry value
     *
     ** @return true if successful, false otherwise
     */
    inline int setInversePresentationLut(const DcmUnsignedShort &data,
                                         const DcmUnsignedShort &descriptor,
                                         const EL_BitsPerTableEntry descripMode = ELM_UseValue)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->setInversePresentationLut(data, descriptor, descripMode) : 0;
    }

 // --- overlays: return true (!0) if successful (see also 'diovlay.cc')
 //               only applicable to grayscale images

    /** add specified plane to group of additional overlay planes.
     *  replaces old overlay plane if group number already exists.
     *
     ** @param  group        group number (0x60nn) of overlay plane
     *  @param  width        width of overlay plane (in pixels)
     *  @param  height       height of overlay plane (in pixels)
     *  @param  left_pos     x coordinate of plane origin (referring to image origin)
     *  @param  top_pos      y coordinate of plane origin
     *  @param  data         overlay plane data (dcmdata element)
     *  @param  label        overlay plane label
     *  @param  description  overlay plane description
     *  @param  mode         display mode (see 'diutils.h')
     *
     ** @return false (0) if an error occurred, true otherwise (1 = added new plane,
     *                                                          2 = replaced existing plane)
     */
    inline int addOverlay(const unsigned int group,
                          const signed int left_pos,
                          const signed int top_pos,
                          const unsigned int width,
                          const unsigned int height,
                          const DcmOverlayData &data,
                          const DcmLongString &label,
                          const DcmLongString &description,
                          const EM_Overlay mode = EMO_Default)
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->addOverlay(group, left_pos, top_pos, width, height, data, label, description, mode) : 0;
    }

    /** remove specified (additional) overlay plane
     *
     ** @param  group  group number (0x60nn) of overlay plane
     *
     ** @return false (0) if an error occurred (e.g. plane doesn't exist), true otherwise
     */
    inline int removeOverlay(const unsigned int group)
    {
        return ((Image != NULL) && (Image->getOverlayPtr(1) != NULL)) ?
            Image->getOverlayPtr(1)->removePlane(group) : 0;
    }

    /** remove all additional overlay planes
     *
     ** @return false (0) if an error occurred, true otherwise (1 = all planes deleted,
     *                                                          2 = no planes to be deleted)
     */
    inline int removeAllOverlays()
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->removeAllOverlays() : 0;
    }

    /** check whether specified overlay plane is visible/activated.
     *  see show/hideOverlay() to modify the visibility status.
     *
     ** @param  plane  number (0..15) or group number (0x60nn) of overlay plane
     *  @param  idx    index of overlay group (0 = dataset, 1 = additional), default: 0
     *
     ** @return true (1) if overlay plane is visible, false (0) otherwise
     */
    inline int isOverlayVisible(const unsigned int plane,
                                const unsigned int idx = 0)
    {
        return ((Image != NULL) && (Image->getOverlayPtr(idx) != NULL)) ?
            Image->getOverlayPtr(idx)->isPlaneVisible(plane) : 0;
    }

    /** activate specified overlay plane
     *
     ** @param  plane  number (0..15) or group number (0x60nn) of overlay plane
     *  @param  idx    index of overlay group (0 = dataset, 1 = additional), default: 0
     *
     ** @return false (0) if an error occurred, true otherwise (1 = plane successfully activated,
     *                                                          2 = plane has already been visible)
     */
    inline int showOverlay(const unsigned int plane,
                           const unsigned int idx = 0)
    {
        return ((Image != NULL) && (Image->getOverlayPtr(idx) != NULL)) ?
            Image->getOverlayPtr(idx)->showPlane(plane) : 0;
    }

    /** activate specified overlay plane and change some parameters
     *
     ** @param  plane   number (0..15) or group number (0x60nn) of overlay plane
     *  @param  mode    display mode (see 'diutils.h')
     *  @param  fore    plane's foreground color (in percent, default: 1.0)
     *  @param  thresh  threshold value (in percent, default: 0.5), only for EMO_ThresholdReplace
     *  @param  idx     index of overlay group (0 = dataset, 1 = additional), default: 0
     *
     ** @return false (0) if an error occurred, true otherwise
     */
    inline int showOverlay(const unsigned int plane,
                           const EM_Overlay mode,
                           const double fore = 1.0,
                           const double thresh = 0.5,
                           const unsigned int idx = 0)
    {
        return ((Image != NULL) && (Image->getOverlayPtr(idx) != NULL)) ?
            Image->getOverlayPtr(idx)->showPlane(plane, fore, thresh, mode) : 0;
    }

    /** activate specified overlay plane and change 'pvalue' (only for bitmap shutters)
     *
     ** @param  plane   number (0..15) or group number (0x60nn) of overlay plane
     *  @param  pvalue  P-value used to display overlay plane
     *
     ** @return false (0) if an error occurred, true otherwise
     */
    inline int showOverlay(const unsigned int plane,
                           const Uint16 pvalue)
    {
        return ((Image != NULL) && (Image->getOverlayPtr(1) != NULL)) ?
            Image->getOverlayPtr(1)->showPlane(plane, pvalue) : 0;
    }

    /** activate all overlay planes (make them visible)
     *
     ** @param  idx  index of overlay group (0 = dataset, 1 = additional), default: 0
     *
     ** @return false (0) if an error occurred, true otherwise (1 = planes have been successfully activated,
     *                                                          2 = no planes to be activated)
     */
    inline int showAllOverlays(const unsigned int idx = 0)
    {
        return ((Image != NULL) && (Image->getOverlayPtr(idx) != NULL)) ?
            Image->getOverlayPtr(idx)->showAllPlanes() : 0;
    }

    /** activate all overlay planes and set specified parameters
     *
     ** @param  mode    display mode (see 'diutils.h')
     *  @param  fore    plane's foreground color (in percent, default: 1.0)
     *  @param  thresh  threshold value (in percent, default: 0.5), only for EMO_ThresholdReplace
     *  @param  idx     index of overlay group (0 = dataset, 1 = additional), default: 0
     *
     ** @return false (0) if an error occurred, true otherwise (1 = planes have been successfully activated,
     *                                                          2 = no planes to be activated)
     */
    inline int showAllOverlays(const EM_Overlay mode,
                               const double fore = 1,
                               const double thresh = 0.5,
                               const unsigned int idx = 0)
    {
        return ((Image != NULL) && (Image->getOverlayPtr(idx) != NULL)) ?
            Image->getOverlayPtr(idx)->showAllPlanes(fore, thresh, mode) : 0;
    }

    /** deactivate specified overlay plane
     *
     ** @param  plane  number (0..15) or group number (0x60nn) of overlay plane
     *  @param  idx    index of overlay group (0 = dataset, 1 = additional), default: 0
     *
     ** @return false (0) if an error occurred, true otherwise (1 = plane successfully deactivated,
     *                                                          2 = plane has already been invisible)
     */
    inline int hideOverlay(const unsigned int plane,
                           const unsigned int idx = 0)
    {
        return ((Image != NULL) && (Image->getOverlayPtr(idx) != NULL)) ?
            Image->getOverlayPtr(idx)->hidePlane(plane) : 0;
    }

    /** deactivate all overlay planes (make them invisible)
     *
     ** @param  idx  index of overlay group (0 = dataset, 1 = additional), default: 0
     *
     ** @return false (0) if an error occurred, true otherwise (1 = planes have been successfully deactivated,
     *                                                          2 = no planes to be deactivated)
     */
    inline int hideAllOverlays(const unsigned int idx = 0)
    {
        return ((Image != NULL) && (Image->getOverlayPtr(idx) != NULL)) ?
            Image->getOverlayPtr(idx)->hideAllPlanes() : 0;
    }

    /** move origin of specified overlay plane to given position
     *
     ** @param  plane     number (0..15) or group number (0x60nn) of overlay plane
     *  @param  left_pos  x coordinate of new plane origin (origin = 0)
     *  @param  top_pos   y coordinate of new plane origin (origin = 0)
     *  @param  idx       index of overlay group (0 = dataset, 1 = additional), default: 0
     *
     ** @return false (0) if an error occurred, true otherwise (1 = plane has been successfully moved,
     *                                                          2 = old and new position are equal, nothing to do)
     */
    inline int placeOverlay(const unsigned int plane,
                            const signed int left_pos,
                            const signed int top_pos,
                            const unsigned int idx = 0)
    {
        return ((Image != NULL) && (Image->getOverlayPtr(idx) != NULL)) ?
            Image->getOverlayPtr(idx)->placePlane(plane, left_pos, top_pos) : 0;
    }

    /** get number of overlay planes
     *
     ** @param  idx  index of overlay group (0 = dataset, 1 = additional), default: 0
     *
     ** @return number of overlay planes stored in the image
     */
    inline unsigned int getOverlayCount(const unsigned int idx = 0) const
    {
        return ((Image != NULL) && (Image->getOverlayPtr(idx) != NULL)) ?
            Image->getOverlayPtr(idx)->getCount() : 0;
    }

    /** get group number of specified overlay plane
     *
     ** @param  plane  number (0..15) or group number (0x60nn) of overlay plane
     *  @param  idx    index of overlay group (0 = dataset, 1 = additional), default: 0
     *
     ** @return group number of given overlay plane if successful, false (0) otherwise
     */
    inline unsigned int getOverlayGroupNumber(const unsigned int plane,
                                              const unsigned int idx = 0) const
    {
        return ((Image != NULL) && (Image->getOverlayPtr(idx) != NULL)) ?
            Image->getOverlayPtr(idx)->getPlaneGroupNumber(plane) : 0;
    }

    /** get label of specified overlay plane
     *
     ** @param  plane  number (0..15) or group number (0x60nn) of overlay plane
     *  @param  idx    index of overlay group (0 = dataset, 1 = additional), default: 0
     *
     ** @return pointer to overlay plane label if successful, false (NULL) otherwise
     */
    inline const char *getOverlayLabel(const unsigned int plane,
                                       const unsigned int idx = 0) const
    {
        return ((Image != NULL) && (Image->getOverlayPtr(idx) != NULL)) ?
            Image->getOverlayPtr(idx)->getPlaneLabel(plane) : OFstatic_cast(const char *, NULL);
    }

    /** get description of specified overlay plane
     *
     ** @param  plane  number (0..15) or group number (0x60nn) of overlay plane
     *  @param  idx    index of overlay group (0 = dataset, 1 = additional), default: 0
     *
     ** @return pointer to overlay plane description if successful, false (NULL) otherwise
     */
    inline const char *getOverlayDescription(const unsigned int plane,
                                             const unsigned int idx = 0) const
    {
        return ((Image != NULL) && (Image->getOverlayPtr(idx) != NULL)) ?
            Image->getOverlayPtr(idx)->getPlaneDescription(plane) : OFstatic_cast(const char *, NULL);
    }

    /** get mode of specified overlay plane
     *
     ** @param  plane  number (0..15) or group number (0x60nn) of overlay plane
     *  @param  idx    index of overlay group (0 = dataset, 1 = additional), default: 0
     *
     ** @return mode of overlay plane if successful, EMO_Default otherwise
     */
    inline EM_Overlay getOverlayMode(const unsigned int plane,
                                     const unsigned int idx = 0) const
    {
        return ((Image != NULL) && (Image->getOverlayPtr(idx) != NULL)) ?
            Image->getOverlayPtr(idx)->getPlaneMode(plane) : EMO_Default;
    }

    /** create bitmap for specified overlay plane.
     *  (up to 16 bits per pixel with two values: 'fore' and 'back')
     *  Please note that the current origin of the overlay plane is used.  Furthermore, the size
     *  of the overlay plane is restricted to the size of the surrounding image.  Use the method
     *  getFullOverlayData() if the complete bitmap data is required regardless of its position.
     *
     ** @param  plane     number (0..15) or group number (0x60nn) of overlay plane
     *  @param  width     returns width of overlay plane (in pixels)
     *  @param  height    returns height of overlay plane (in pixels)
     *  @param  left_pos  returns x coordinate of plane's origin
     *  @param  top_pos   returns y coordinate of plane's origin
     *  @param  mode      returns display mode (see 'diutils.h')
     *  @param  frame     index of frame used for output (default: 0 = first)
     *  @param  bits      number of bits (stored) in the resulting array, default: 8, range: 1..16
     *                    Used to mask the values for foreground and background color.  The resulting
     *                    array is always padded to 8 or 16 bits with 1, 8 or 16 bits allocated
     *                    depending on the value of 'bits'.
     *  @param  fore      foreground color to be set in bitmap, default: 255, range: 0..2^bits-1
     *  @param  back      background color to be set in bitmap (transparent), default: 0, range: 0..2^bits-1
     *  @param  idx       index of overlay group (0 = dataset, planes stored in the image dataset;
     *                                            1 = additional, planes added by addOverlay();
     *                                            2 = 'additional' overlay planes hide 'dataset' planes
     *                                                when the overlay group number exists in both),
     *                    default: 2
     *
     ** @return pointer to overlay plane data (internal memory buffer)
     */
    const void *getOverlayData(const unsigned int plane,
                               unsigned int &left_pos,
                               unsigned int &top_pos,
                               unsigned int &width,
                               unsigned int &height,
                               EM_Overlay &mode,
                               const unsigned long frame = 0,
                               const int bits = 8,
                               const Uint16 fore = 0xff,
                               const Uint16 back = 0x0,
                               const unsigned int idx = 2) const
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->getOverlayData(frame, plane, left_pos, top_pos, width, height, mode, idx, bits, fore, back) : NULL;
    }

    /** create bitmap for specified overlay plane.
     *  (up to 16 bits per pixel with two values: 'fore' and 'back')
     *  In contrast to the previous method the full bitmap data is always returned.
     *
     ** @param  plane   number (0..15) or group number (0x60nn) of overlay plane
     *  @param  width   returns width of overlay plane (in pixels)
     *  @param  height  returns height of overlay plane (in pixels)
     *  @param  frame   index of frame used for output (default: 0 = first)
     *  @param  bits    number of bits (stored) in the resulting array, default: 8, range: 1..16
     *                  Used to mask the values for foreground and background color.  The resulting
     *                  array is always padded to 8 or 16 bits with 1, 8 or 16 bits allocated
     *                  depending on the value of 'bits'.
     *  @param  fore    foreground color to be set in bitmap, default: 255, range: 0..2^bits-1
     *  @param  back    background color to be set in bitmap (transparent), default: 0, range: 0..2^bits-1
     *  @param  idx     index of overlay group (0 = dataset, planes stored in the image dataset;
     *                                          1 = additional, planes added by addOverlay()),
     *                  default: 0
     *
     ** @return pointer to overlay plane data (internal memory buffer)
     */
    const void *getFullOverlayData(const unsigned int plane,
                                   unsigned int &width,
                                   unsigned int &height,
                                   const unsigned long frame = 0,
                                   const int bits = 8,
                                   const Uint16 fore = 0xff,
                                   const Uint16 back = 0x0,
                                   const unsigned int idx = 0) const
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->getFullOverlayData(frame, plane, width, height, idx, bits, fore, back) : NULL;
    }

    /** delete buffer for overlay plane data.
     *  Save memory if data is no longer needed.
     */
    inline void deleteOverlayData() const
    {
        if ((Image != NULL) && (Image->getMonoImagePtr() != NULL))
            Image->getMonoImagePtr()->deleteOverlayData();
    }

    /** create bitmap for specified overlay plane and store it in (6xxx,3000) format.
     *  (1 bit allocated and stored, foreground color is 1, background color is 0,
     *   data is 16 bit padded - even length)
     *  memory is allocated but not handled internally - must be deleted from calling program.
     *
     ** @param  buffer  stores pointer to overlay data (memory is allocated internally)
     *  @param  plane   number (0..15) or group number (0x60nn) of overlay plane
     *  @param  width   returns width of overlay plane (in pixels)
     *  @param  height  returns height of overlay plane (in pixels)
     *  @param  frames  returns number of frames
     *  @param  idx     index of overlay group (0 = dataset, planes stored in the image dataset;
     *                                          1 = additional, planes added by addOverlay()),
     *                  default: 0
     *
     ** @return number of bytes allocated for the 'buffer' if successful, 0 otherwise
     */
    unsigned long create6xxx3000OverlayData(Uint8 *&buffer,
                                            const unsigned int plane,
                                            unsigned int &width,
                                            unsigned int &height,
                                            unsigned long &frames,
                                            const unsigned int idx = 0) const
    {
        return ((Image != NULL) && (Image->getMonoImagePtr() != NULL)) ?
            Image->getMonoImagePtr()->create6xxx3000OverlayData(buffer, plane, width, height, frames, idx) : 0;
    }


 // --- create...Image: return pointer to new 'DicomImage' object, memory isn't handled internally !

    /** create copy of current image object.
     *  memory is not handled internally - must be deleted from calling program.
     *
     ** @param  fstart  first frame to be processed (0 = 1st frame)
     *  @param  fcount  number of frames (0 = all frames)
     *
     ** @return pointer to new DicomImage object (NULL if an error occurred)
     */
    DicomImage *createDicomImage(unsigned long fstart = 0,
                                 unsigned long fcount = 0) const;

    /** create scaled copy of current image object (given by exact size).
     *  memory is not handled internally - must be deleted from calling program.
     *
     ** @param  width        width of new image (in pixels)
     *  @param  height       height of new image (in pixels)
     *  @param  interpolate  specifies whether scaling algorithm should use interpolation (if necessary).
     *                       default: no interpolation (0), preferred interpolation algorithm (if applicable):
     *                         1 = pbmplus algorithm, 2 = c't algorithm, 3 = bilinear magnification,
     *                         4 = bicubic magnification
     *  @param  aspect       specifies whether pixel aspect ratio should be taken into consideration
     *                       (if true, width OR height should be 0, i.e. this component will be calculated
     *                        automatically)
     *
     ** @return pointer to new DicomImage object (NULL if an error occurred)
     */
    DicomImage *createScaledImage(const unsigned long width,
                                  const unsigned long height = 0,
                                  const int interpolate = 0,
                                  int aspect = 0) const;

    /** create scaled copy of current image object (given by scaling factors).
     *  memory is not handled internally - must be deleted from calling program.
     *
     ** @param  xfactor      width of new image is multiplied with this factor (> 0)
     *  @param  yfactor      height of new image is multiplied with this factor (> 0)
     *  @param  interpolate  specifies whether scaling algorithm should use interpolation (if necessary).
     *                       default: no interpolation (0), preferred interpolation algorithm (if applicable):
     *                         1 = pbmplus algorithm, 2 = c't algorithm, 3 = bilinear magnification,
     *                         4 = bicubic magnification
     *  @param  aspect       specifies whether pixel aspect ratio should be taken into consideration
     *                       (if true, width OR height should be 0, i.e. this component will be calculated
     *                        automatically)
     *
     ** @return pointer to new DicomImage object (NULL if an error occurred)
     */
    DicomImage *createScaledImage(const double xfactor,
                                  const double yfactor = 0,
                                  const int interpolate = 0,
                                  const int aspect = 0) const;

    /** create scaled copy of specified (clipping) area of the current image object.
     *  memory is not handled internally - must be deleted from calling program.
     *  NB: Clipping and interpolated scaling at the same moment is not yet fully implemented!
     *
     ** @param  left_pos      x coordinate of top left corner of area to be scaled
     *                        (referring to image origin, negative values create a border around the image)
     *  @param  top_pos       y coordinate of top left corner of area to be scaled
     *  @param  clip_width    width of area to be scaled
     *  @param  clip_height   height of area to be scaled
     *  @param  scale_width   width of scaled image (in pixels)
     *  @param  scale_height  height of scaled image (in pixels)
     *  @param  interpolate   specifies whether scaling algorithm should use interpolation (if necessary).
     *                        default: no interpolation (0), preferred interpolation algorithm (if applicable):
     *                          1 = pbmplus algorithm, 2 = c't algorithm, 3 = bilinear magnification,
     *                          4 = bicubic magnification
     *  @param  aspect        specifies whether pixel aspect ratio should be taken into consideration
     *                        (if true, width OR height should be 0, i.e. this component will be calculated
     *                         automatically)
     *  @param  pvalue        P-value used for the border outside the image (0..65535)
     *
     ** @return pointer to new DicomImage object (NULL if an error occurred)
     */
    DicomImage *createScaledImage(const signed long left_pos,
                                  const signed long top_pos,
                                  unsigned long clip_width,
                                  unsigned long clip_height,
                                  unsigned long scale_width = 0,
                                  unsigned long scale_height = 0,
                                  const int interpolate = 0,
                                  int aspect = 0,
                                  const Uint16 pvalue = 0) const;

    /** create scaled copy of specified (clipping) area of the current image object.
     *  memory is not handled internally - must be deleted from calling program.
     *  NB: Clipping and interpolated scaling at the same moment is not yet fully implemented!
     *
     ** @param  left_pos     x coordinate of top left corner of area to be scaled
     *                       (referring to image origin, negative values create a border around the image)
     *  @param  top_pos      y coordinate of top left corner of area to be scaled
     *  @param  width        width of area to be scaled
     *  @param  height       height of area to be scaled
     *  @param  xfactor      width of new image is multiplied with this factor (> 0)
     *  @param  yfactor      height of new image is multiplied with this factor (> 0)
     *  @param  interpolate  specifies whether scaling algorithm should use interpolation (if necessary).
     *                       default: no interpolation (0), preferred interpolation algorithm (if applicable):
     *                         1 = pbmplus algorithm, 2 = c't algorithm, 3 = bilinear magnification,
     *                         4 = bicubic magnification
     *  @param  aspect       specifies whether pixel aspect ratio should be taken into consideration
     *                       (if true, width OR height should be 0, i.e. this component will be calculated
     *                        automatically)
     *  @param  pvalue       P-value used for the border outside the image (0..65535)
     *
     ** @return pointer to new DicomImage object (NULL if an error occurred)
     */
    DicomImage *createScaledImage(const signed long left_pos,
                                  const signed long top_pos,
                                  unsigned long width,
                                  unsigned long height,
                                  const double xfactor,
                                  const double yfactor = 0,
                                  const int interpolate = 0,
                                  const int aspect = 0,
                                  const Uint16 pvalue = 0) const;

    /** create copy of specified area of the current image object (clipping).
     *  memory is not handled internally - must be deleted from calling program.
     *
     ** @param  left_pos  x coordinate of top left corner of area to be copied
     *                    (referring to image origin, negative values create a border around the image)
     *  @param  top_pos   y coordinate of top left corner of area to be copied
     *  @param  width     width of area to be copied/clipped
     *  @param  height    height of area to be copied/clipped
     *  @param  pvalue    P-value used for the border outside the image (0..65535)
     *
     ** @return pointer to new DicomImage object (NULL if an error occurred)
     */
    DicomImage *createClippedImage(const signed long left_pos,
                                   const signed long top_pos,
                                   unsigned long width = 0,
                                   unsigned long height = 0,
                                   const Uint16 pvalue = 0) const;

    /** flip current image (horizontally and/or vertically)
     *
     ** @param  horz  flip horizontally if true
     *  @param  vert  flip vertically if true
     *
     ** @return true if successful (1 = flipped at least direction,
     *                              2 = not flipped, because of image resolution - width and/or height equal to 1),
     *          false otherwise
     */
    int flipImage(int horz = 1,
                  int vert = 0) const;

    /** create a flipped copy of the current image.
     *  memory is not handled internally - must be deleted from calling program.
     *
     ** @param  horz  flip horizontally if true
     *  @param  vert  flip vertically if true
     *
     ** @return pointer to new DicomImage object (NULL if an error occurred)
     */
    DicomImage *createFlippedImage(int horz = 1,
                                   int vert = 0) const;

    /** rotate current image (by steps of 90 degrees)
     *
     ** @param  degree  angle by which the image shall be rotated (-360, -270, -180, -90, 0, 90, 180, 270, 360)
     *
     ** @return true if successful (1 = rotated by at least 90 degrees,
     *                              2 = not rotated, because of image resolution or angle),
     *          false otherwise
     */
    int rotateImage(signed int degree) const;

    /** create a rotated copy of the current image.
     *  memory is not handled internally - must be deleted from calling program.
     *
     ** @param  degree  angle by which the image shall be rotated (-360, -270, -180, -90, 0, 90, 180, 270, 360)
     *
     ** @return pointer to new DicomImage object (NULL if an error occurred)
     */
    DicomImage *createRotatedImage(signed int degree) const;

    /** create monochrome copy of the current image.
     *  equal to createDicomImage() for monochrome images.
     *  memory is not handled internally - must be deleted from calling program.
     *  This method does not work if original YCbCr color model is retained (see CIF_KeepYCbCrColorModel).
     *
     ** @param  red    coefficient by which the red component is weighted (default: NTSC value)
     *  @param  green  coefficient by which the green component is weighted (default: NTSC value)
     *  @param  blue   coefficient by which the blue component is weighted (default: NTSC value)
     *
     ** @return pointer to new DicomImage object (NULL if an error occurred)
     */
    DicomImage *createMonochromeImage(const double red = 0.299,
                                      const double green = 0.587,
                                      const double blue = 0.114) const;

    /** create true color (24/32 bit) or palette (8 bit) bitmap for MS Windows.
     *  8 bit images require an appropriate color palette (256 entries, values: 0 to 255) and are only
     *  applicable to monochrome images, the beginning of a each line starts on a 32-bit address (if
     *  'padding' is true); 24 bit images store 24 bits per pixel (BGR) and do align each line to a
     *  32-bit address (if 'padding' is true); 32 bit images store 32 bits per pixel (ARGB), but only
     *  use the lower 24 bits (-RGB).
     *  The memory buffer can be allocated both externally (from the calling program) and internally
     *  (inside this class/module).  If the 'data' parameter is not NULL and the 'size' parameter, which
     *  describes the size (in bytes) of the allocated buffer, is sufficiently large, the bitmap is stored
     *  in this buffer.  Otherwise (i.e. 'data' is NULL) the memory is allocated internally.  Please note
     *  that in both cases the memory is not handled internally after this method has finished and,
     *  therefore, must be deleted from the calling program.
     *  This method does not work if original YCbCr color model is retained (see CIF_KeepYCbCrColorModel).
     *
     ** @param  data        untyped pointer memory buffer (set to NULL if not allocated externally)
     *  @param  size        size of the memory buffer in bytes (if 0 'data' is set to NULL)
     *  @param  frame       index of frame to be converted (default: 0 = first frame)
     *  @param  bits        number of bits per pixel used for the output bitmap (8, 24 or 32, default: 24)
     *  @param  upsideDown  flag indicating whether the first line stored is the top-most (default: 0) or
     *                      the bottom-most of the source image (as required by the BMP file format)
     *  @param  padding     align each line to a 32-bit address if true (default)
     *
     ** @return number of bytes allocated by the bitmap, or 0 if an error occurred
     */
    unsigned long createWindowsDIB(void *&data,
                                   const unsigned long size,
                                   const unsigned long frame = 0,
                                   const int bits = 24,
                                   const int upsideDown = 0,
                                   const int padding = 1)
    {
        return (Image != NULL) ?
            Image->createDIB(data, size, frame, bits, upsideDown, padding) : 0;
    }

    /** create true color (32 bit) or palette (8 bit) bitmap for Java (AWT default format).
     *  32 bit images allocate 32 bits per pixel (RGB), but only use the upper 24 bits.  The sample
     *  order for color images is: Red, Green, Blue.
     *  Memory is not handled internally - must be deleted from calling program.
     *  This method does not work if original YCbCr color model is retained (see CIF_KeepYCbCrColorModel).
     *
     ** @param  data   resulting pointer to bitmap data (set to NULL if an error occurred)
     *  @param  frame  index of frame to be converted (default: 0 = first frame)
     *  @param  bits   number of bits per pixel used for the output bitmap (8 or 32, default: 32)
     *
     ** @return number of bytes allocated by the bitmap, or 0 if an error occurred
     */
    unsigned long createJavaAWTBitmap(void *&data,
                                      const unsigned long frame = 0,
                                      const int bits = 32)
    {
        return (Image != NULL) ?
            Image->createAWTBitmap(data, frame, bits) : 0;
    }

    /** create 12 bit packed (monochrome) bitmap for DICOM printers.
     *  Memory is not handled internally - must be deleted from calling program.
     *
     ** @param  buffer  pointer to input memory buffer (16 bits allocated, 12 bits stored)
     *  @param  size    size of memory buffer (will be checked whether it is sufficient)
     *  @param  count   number of entries (pixels) in input buffer
     *
     ** @return pointer to memory buffer containing the packed output bitmap data (NULL if an error occurred)
     */
    static void *create12BitPackedBitmap(const void *buffer,
                                         const unsigned long size,
                                         const unsigned long count)
    {
        return DiMonoImage::createPackedBitmap(buffer, size, count, 16, 12);
    }

    /** create new single frame DicomImage with applied grayscale transformations.
     *  The method getOutputData() is used internally for the new bitmap.
     *  Limited to monochrome images.
     *
     ** @param  frame  index of frame to be converted
     *  @param  bits   number of bits per pixel used for the output bitmap
     *
     ** @return pointer to new DicomImage object (NULL if an error occurred)
     */
    DicomImage *createMonoOutputImage(const unsigned long frame,
                                      const int bits);

 // --- output image file: return true ('1') if successful

    /** render pixel data of the given frame and write image related attributes to DICOM dataset.
     *  Applies VOI/PLUT transformation and (visible) overlay planes, output data is
     *  always padded to 8, 16, 32, ... bits (bits allocated).  Replaces any modality
     *  transformation in the dataset by a linear rescale/slope since the modality
     *  transformation is rendered into the pixel data.  Replaces the VOI transformations
     *  in the dataset by a "max range" VOI window.  Removes all Overlay Plane Module
     *  attributes for embedded overlay planes from the dataset.
     *  Writes the following DICOM attributes (from Image Pixel Module):
     *    - Photometric Interpretation, Samples per Pixel
     *    - Columns, Rows, Number of Frames
     *    - Bits Allocated, Bits Stored, High Bit
     *    - Planar Configuration (only if "Samples per Pixel" is greater than 1)
     *    - Pixel Representation, Pixel Data
     *  Updates the following DICOM attributes (if present in the original image dataset):
     *    - Pixel Spacing and/or Pixel Aspect Ratio
     *  Supported output color models: Monochrome 2 for monochrome images and RGB
     *  (or YCbCr_Full if flag CIF_KeepYCbCrColorModel is set) for color images.
     *
     ** @param  dataset  reference to DICOM dataset where the image attributes are stored
     *  @param  bits     number of bits per sample (image depth, 1..MAX_BITS)
     *  @param  frame    number of frame to be rendered (0..n-1)
     *  @param  planar   0 = color-by-pixel (R1G1B1...R2G2B2...R3G3B3...),
     *                   1 = color-by-plane (R1R2R3...G1G2G3...B1B2B3...)
     *                   (only applicable to multi-planar/color images, otherwise ignored)
     *
     ** @return true if successful, false otherwise
     */
    inline int writeFrameToDataset(DcmItem &dataset,
                                   const int bits = 0,
                                   const unsigned long frame = 0,
                                   const int planar = 0)
    {
        return (Image != NULL) ?
            Image->writeFrameToDataset(dataset, frame, bits, planar) : 0;
    }

    /** write current image and related attributes to DICOM dataset.
     *  Uses the internal representation of the pixel data, therefore the output data is
     *  always padded to 8, 16, 32, ... bits (bits allocated).  Replaces any modality
     *  transformation in the dataset by a linear rescale/slope since the modality
     *  transformation is rendered into the pixel data.  Removes all Overlay Plane Module
     *  attributes for embedded overlay planes from the dataset.
     *  Writes the following DICOM attributes (from Image Pixel Module):
     *    - Photometric Interpretation, Samples per Pixel
     *    - Columns, Rows, Number of Frames
     *    - Bits Allocated, Bits Stored, High Bit
     *    - Planar Configuration (only if "Samples per Pixel" is greater than 1)
     *    - Pixel Representation, Pixel Data
     *  Updates the following DICOM attributes (if present in the original image dataset):
     *    - Pixel Spacing and/or Pixel Aspect Ratio
     *  Supported output color models: Monochrome 1 or 2 for monochrome images and RGB
     *  (or YCbCr_Full if flag CIF_KeepYCbCrColorModel is set) for color images.
     *
     ** @param  dataset  reference to DICOM dataset where the image attributes are stored
     *  @param  mode     0 = determine value of BitsStored from 'used' pixel values,
     *                   1 = determine value of BitsStored from 'possible' pixel values
     *                   (used for monochrome images only)
     *  @param  planar   0 = color-by-pixel (R1G1B1...R2G2B2...R3G3B3...),
     *                   1 = color-by-plane (R1R2R3...G1G2G3...B1B2B3...),
     *                   2 = same as original DICOM image (i.e. color-by-pixel or color-by-plane)
     *                   (only applicable to multi-planar/color images, otherwise ignored)
     *
     ** @return true if successful, false otherwise
     */
    inline int writeImageToDataset(DcmItem &dataset,
                                   const int mode = 0,
                                   const int planar = 2)
    {
        return (Image != NULL) ?
            Image->writeImageToDataset(dataset, mode, planar) : 0;
    }

    /** write pixel data to PPM file (specified by filename).
     *  pixel data is written in ASCII format.
     *  This method does not work if original YCbCr color model is retained
     *  (see CIF_KeepYCbCrColorModel).
     *
     ** @param  filename  name of output file (%d is replaced by frame number if present)
     *  @param  bits      number of bits used for output of pixel data
     *                    (default: full resolution, max: 32;
     *                     MI_PastelColor = -1 for true color pastel mode, EXPERIMENTAL)
     *  @param  frame     index of frame used for output (default: first frame = 0)
     *
     ** @return true if successful, false otherwise
     */
    int writePPM(const char *filename,
                 const int bits = 0,
                 const unsigned long frame = 0);

    /** write pixel data to PPM file (specified by open C++ stream).
     *  pixel data is written in ASCII format.
     *  This method does not work if original YCbCr color model is retained
     *  (see CIF_KeepYCbCrColorModel).
     *
     ** @param  stream  open C++ output stream
     *  @param  bits    number of bits used for output of pixel data
     *                  (default: full resolution, max: 32;
     *                   MI_PastelColor = -1 for true color pastel mode, EXPERIMENTAL)
     *  @param  frame   index of frame used for output (default: first frame = 0)
     *
     ** @return true if successful, false otherwise
     */
    int writePPM(STD_NAMESPACE ostream& stream,
                 const int bits = 0,
                 const unsigned long frame = 0);

    /** write pixel data to PPM file (specified by open C stream).
     *  pixel data is written in ASCII format.
     *  This method does not work if original YCbCr color model is retained
     *  (see CIF_KeepYCbCrColorModel).
     *
     ** @param  stream  open C output stream
     *  @param  bits    number of bits used for output of pixel data
     *                  (default: full resolution, max: 32;
     *                   MI_PastelColor = -1 for true color pastel mode, EXPERIMENTAL)
     *  @param  frame   index of frame used for output (default: first frame = 0)
     *
     ** @return true if successful, false otherwise
     */
    int writePPM(FILE *stream,
                 const int bits = 0,
                 const unsigned long frame = 0);

    /** write pixel data to raw PPM file (specified by filename).
     *  pixel data is written in binary format.
     *  This method does not work if original YCbCr color model is retained
     *  (see CIF_KeepYCbCrColorModel).
     *
     ** @param  filename  name of output file (%d is replaced by frame number if present)
     *  @param  bits      number of bits used for output of pixel data
     *                    (default: full resolution, max: 8;
     *                     MI_PastelColor = -1 for true color pastel mode, EXPERIMENTAL)
     *  @param  frame     index of frame used for output (default: first frame = 0)
     *
     ** @return true if successful, false otherwise
     */
    int writeRawPPM(const char *filename,
                    const int bits = 0,
                    const unsigned long frame= 0);

    /** write pixel data to raw PPM file (specified by open C stream).
     *  pixel data is written in binary format.
     *  This method does not work if original YCbCr color model is retained
     *  (see CIF_KeepYCbCrColorModel).
     *
     ** @param  stream  open C output stream (binary mode required!)
     *  @param  bits    number of bits used for output of pixel data
     *                  (default: full resolution, max: 8;
     *                   MI_PastelColor = -1 for true color pastel mode, EXPERIMENTAL)
     *  @param  frame   index of frame used for output (default: first frame = 0)
     *
     ** @return true if successful, false otherwise
     */
    int writeRawPPM(FILE *stream,
                    const int bits = 0,
                    const unsigned long frame = 0);

    /** write pixel data to BMP file (specified by open C stream).
     *  pixel data is written in palette or truecolor mode.
     *  This method does not work if original YCbCr color model is retained
     *  (see CIF_KeepYCbCrColorModel).
     *
     ** @param  stream  open C output stream (binary mode required!)
     *  @param  bits    number of bits used for output of pixel data
     *                  (8, 24 or 32, default (0): 8 for monochrome and 24 for color images)
     *  @param  frame   index of frame used for output (default: first frame = 0)
     *
     ** @return true if successful, false otherwise
     */
    int writeBMP(FILE *stream,
                 const int bits = 0,
                 const unsigned long frame = 0);

    /** write pixel data to BMP file (specified by filename).
     *  pixel data is written in palette or truecolor mode.
     *  This method does not work if original YCbCr color model is retained
     *  (see CIF_KeepYCbCrColorModel).
     *
     ** @param  filename  name of output file (%d is replaced by frame number if present)
     *  @param  bits      number of bits used for output of pixel data
     *                    (8, 24 or 32, default (0): 8 for monochrome and 24 for color images)
     *  @param  frame     index of frame used for output (default: first frame = 0)
     *
     ** @return true if successful, false otherwise
     */
    int writeBMP(const char *filename,
                 const int bits = 0,
                 const unsigned long frame = 0);

    /** write pixel data to pluggable image format file (specified by open C stream).
     *  Format specific parameters may be set directly in the instantiated 'plugin' class.
     *
     ** @param  plugin  pointer to image format plugin (derived from abstract class DiPluginFormat)
     *  @param  stream  open C output stream (binary mode required!)
     *  @param  frame   index of frame used for output (default: first frame = 0)
     *
     ** @return true if successful, false otherwise
     */
    int writePluginFormat(const DiPluginFormat *plugin,
                          FILE *stream,
                          const unsigned long frame = 0);

    /** write pixel data to pluggable image format file (specified by filename).
     *  Format specific parameters may be set directly in the instantiated 'plugin' class.
     *
     ** @param  plugin    pointer to image format plugin (derived from abstract class DiPluginFormat)
     *  @param  filename  name of output file (%d is replaced by frame number if present)
     *  @param  frame     index of frame used for output (default: first frame = 0)
     *
     ** @return true if successful, false otherwise
     */
    int writePluginFormat(const DiPluginFormat *plugin,
                          const char *filename,
                          const unsigned long frame = 0);


 protected:

    /** constructor, create copy of given image object with different image data and photometric interpretation
     *
     ** @param  dicom      source object to be copied
     *  @param  image      new image data
     *  @param  interpret  new photometric interpretation
     */
    DicomImage(const DicomImage *dicom,
               DiImage *image,
               const EP_Interpretation interpret = EPI_Unknown);

    /** initialize object.
     *  create internal image object depending on color model. is used for all 'real' constructors.
     */
    void Init();

    /** check whether data dictionary is present
     *
     ** @return true if dictionary is present, false otherwise
     */
    int checkDataDictionary();

    /** get SOP class UID of current image object
     *
     ** @return SOP class UID (or NULL if an error occurred)
     */
    const char *getSOPclassUID() const;

    /** normalize given degree value (for internal use).
     *  negative value are mapped to positive range (-360 -> 0, -270 -> 90, -180 -> 180, -90 -> 270),
     *  360 is set to 0, all other values are rejected
     *
     ** @param  degree  value to be normalized, valid values are: 0, 90, 180, 270
     *
     ** @return true if successful, false otherwise (invalid value)
     */
    int normalizeDegreeValue(signed int &degree) const;


 private:

    /// current state of converting progress (error level)
    EI_Status ImageStatus;
    /// DICOM color model (enumeration)
    EP_Interpretation PhotometricInterpretation;

    /// points to document object
    DiDocument *Document;
    /// points to image object
    DiImage    *Image;

 // --- declarations to avoid compiler warnings

    DicomImage(const DicomImage &);
    DicomImage &operator=(const DicomImage &);
};


#endif
