Logo Search packages:      
Sourcecode: dcmtk version File versions

dvpstat.cc

/*
 *
 *  Copyright (C) 1998-2004, OFFIS
 *
 *  This software and supporting documentation were developed by
 *
 *    Kuratorium OFFIS e.V.
 *    Healthcare Information and Communication Systems
 *    Escherweg 2
 *    D-26121 Oldenburg, Germany
 *
 *  THIS SOFTWARE IS MADE AVAILABLE,  AS IS,  AND OFFIS MAKES NO  WARRANTY
 *  REGARDING  THE  SOFTWARE,  ITS  PERFORMANCE,  ITS  MERCHANTABILITY  OR
 *  FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES  OR
 *  ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND
 *  PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
 *
 *  Module: dcmpstat
 *
 *  Author: Marco Eichelberg
 *
 *  Purpose:
 *    classes: DVPresentationState
 *
 *  Last Update:      $Author: joergr $
 *  Update Date:      $Date: 2004/02/04 15:57:49 $
 *  CVS/RCS Revision: $Revision: 1.79 $
 *  Status:           $State: Exp $
 *
 *  CVS/RCS Log at end of file
 *
 */

#include "osconfig.h"    /* make sure OS specific configuration is included first */

#include "ofstream.h"
#include "dvpstat.h"
#include "dvpsdef.h"     /* for constants and macros */
#include "ofstring.h"
#include "dcmimage.h"    /* for DicomImage */
#include "dvpscu.h"      /* for DVPSCurve */
#include "dvpsvl.h"      /* for DVPSVOILUT */
#include "dvpsvw.h"      /* for DVPSVOIWindow */
#include "dvpsov.h"      /* for DVPSOverlay */
#include "dvpsda.h"      /* for DVPSDisplayedArea */
#include "dvpssv.h"      /* for DVPSSoftcopyVOI */
#include "dvpshlp.h"     /* for class DVPSHelper */
#include "ofstd.h"       /* for class OFStandard */

#include "dvpsgl.h"      /* for DVPSGraphicLayer, needed by MSVC5 with STL */
#include "dvpsrs.h"      /* for DVPSReferencedSeries, needed by MSVC5 with STL */
#include "dvpsal.h"      /* for DVPSOverlayCurveActivationLayer, needed by MSVC5 with STL */
#include "dvpsga.h"      /* for DVPSGraphicAnnotation, needed by MSVC5 with STL */
#include "dvpsri.h"      /* for DVPSReferencedImage, needed by MSVC5 with STL */
#include "dvpstx.h"      /* for DVPSTextObject, needed by MSVC5 with STL */
#include "dvpsgr.h"      /* for DVPSGraphicObject, needed by MSVC5 with STL */

#define INCLUDE_CSTDLIB
#define INCLUDE_CSTDIO
#define INCLUDE_CSTRING
#define INCLUDE_CMATH
#define INCLUDE_CTIME
#include "ofstdinc.h"

BEGIN_EXTERN_C
#ifdef HAVE_LIBC_H
#include <libc.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
END_EXTERN_C

/* --------------- class DVPresentationState --------------- */

00076 DVPresentationState::DVPresentationState(
    DiDisplayFunction **dispFunction,
    unsigned long minPrintBitmapX,
    unsigned long minPrintBitmapY,
    unsigned long maxPrintBitmapX,
    unsigned long maxPrintBitmapY,
    unsigned long maxPreviewImageX,
    unsigned long maxPreviewImageY)
: DcmPresentationState()
, currentImageDataset(NULL)
, currentImageFileformat(NULL)
, currentImage(NULL)
, previewImage(NULL)
, currentImageWidth(0)
, currentImageHeight(0)
, renderedImageWidth(0)
, renderedImageHeight(0)
, renderedImageTop(0)
, renderedImageLeft(0)
, renderedImageBottom(0)
, renderedImageRight(0)
, currentImageSOPClassUID(NULL)
, currentImageSOPInstanceUID(NULL)
, currentImageSelectedFrame(0)
, currentImageOwned(OFFalse)
, currentImageVOIValid(OFFalse)
, currentImagePLUTValid(OFFalse)
, currentImageFlip(OFFalse)
, currentImageRotation(DVPSR_0_deg)
, currentImageOverlaysValid(0)
, currentImageCurveList()
, currentImageVOILUTList()
, currentImageVOIWindowList()
, currentImageModality(DCM_Modality)
, currentImageMonochrome1(OFFalse)
, displayTransform(DVPSD_GSDF)
, imageInverse(OFFalse)
, displayFunction(dispFunction)
, minimumPrintBitmapWidth(minPrintBitmapX)
, minimumPrintBitmapHeight(minPrintBitmapY)
, maximumPrintBitmapWidth(maxPrintBitmapX)
, maximumPrintBitmapHeight(maxPrintBitmapY)
, maximumPreviewImageWidth(maxPreviewImageX)
, maximumPreviewImageHeight(maxPreviewImageY)
{
  createInstanceUID();
}


00125 DVPresentationState::~DVPresentationState()
{
  detachImage();
}

00130 void DVPresentationState::detachImage()
{
  if (currentImage) delete currentImage;
  deletePreviewImage();
  if (currentImageOwned)
  {
    if (currentImageFileformat) delete currentImageFileformat;
    else if (currentImageDataset) delete currentImageDataset;
  }
  currentImage = NULL;
  currentImageFileformat = NULL;
  currentImageDataset = NULL;
  currentImageCurveList.clear();
  currentImageVOILUTList.clear();
  currentImageVOIWindowList.clear();
  currentImageModality.clear();
  currentImageMonochrome1 = OFFalse;

  // reset flags
  currentImageWidth = 0;
  currentImageHeight = 0;
  renderedImageWidth = 0;
  renderedImageHeight = 0;
  renderedImageTop = 0;
  renderedImageLeft = 0;
  renderedImageBottom = 0;
  renderedImageRight = 0;
  currentImageOwned = OFFalse;
  currentImageVOIValid = OFFalse;
  currentImagePLUTValid = OFFalse;
  currentImageFlip = OFFalse;
  currentImageRotation = DVPSR_0_deg;
  currentImageOverlaysValid = 0;
  currentImageSOPClassUID=NULL;
  currentImageSOPInstanceUID=NULL;
  currentImageSelectedFrame=0;
}


00169 void DVPresentationState::clear()
{
  DcmPresentationState::clear();
  detachImage(); // clears all currentImageXX attributes
  // we do not change the display function
  displayTransform = DVPSD_GSDF;
  imageInverse = OFFalse;
  return;
}


00180 OFCondition DVPresentationState::writeHardcopyImageAttributes(DcmItem &dset)
{
  OFCondition result = EC_Normal;
  DcmElement *delem=NULL;
  DcmSequenceOfItems *dseq=NULL;
  DcmItem *ditem=NULL;

  DVPSHelper::setDefault(result, patientName, DEFAULT_patientName);
  ADD_TO_DATASET(DcmPersonName, patientName)
  ADD_TO_DATASET(DcmLongString, patientID)
  ADD_TO_DATASET(DcmDate, patientBirthDate)
  ADD_TO_DATASET(DcmCodeString, patientSex)

  // write source image sequence
  if (result == EC_Normal)
  {
    dseq = new DcmSequenceOfItems(DCM_SourceImageSequence);
    if (dseq)
    {
      // first item references source image
      if (currentImageSOPClassUID && currentImageSOPInstanceUID)
      {
        ditem = new DcmItem();
        if (ditem)
        {
          delem = new DcmUniqueIdentifier(DCM_SOPClassUID);
          if (delem)
          {
            result = delem->putString(currentImageSOPClassUID);
            ditem->insert(delem, OFTrue /*replaceOld*/);
          } else result=EC_MemoryExhausted;
          delem = new DcmUniqueIdentifier(DCM_SOPInstanceUID);
          if (delem)
          {
            result = delem->putString(currentImageSOPInstanceUID);
            ditem->insert(delem, OFTrue /*replaceOld*/);
          } else result=EC_MemoryExhausted;
          if (EC_Normal == result) dseq->insert(ditem);  else delete ditem;
        } else result = EC_MemoryExhausted;
      }
      // second item references presentation state
      ditem = new DcmItem();
      if (ditem)
      {
        delem = new DcmUniqueIdentifier(sOPInstanceUID);
        if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
        delem = new DcmUniqueIdentifier(DCM_SOPClassUID);
        if (delem)
        {
          result = delem->putString(UID_GrayscaleSoftcopyPresentationStateStorage);
          ditem->insert(delem, OFTrue /*replaceOld*/);
        } else result=EC_MemoryExhausted;
        if (EC_Normal == result) dseq->insert(ditem);  else delete ditem;
       }
    } else result = EC_MemoryExhausted;
    if (EC_Normal == result) dset.insert(dseq, OFTrue /*replaceOld*/); else delete dseq;
  }

  return result;
}

00241 unsigned long DVPresentationState::getPrintBitmapSize()
{
  unsigned long result = 0;
  unsigned long width;
  unsigned long height;
  if (getPrintBitmapWidthHeight(width, height) == EC_Normal)
    result = width * height * 2;       // print bitmap: 12 bit stored, 16 bit allocated (2 bytes per pixel)
  return result;
}


00252 OFCondition DVPresentationState::setMinimumPrintBitmapWidthHeight(unsigned long width,
                                                                  unsigned long height)
{
  OFCondition result = EC_IllegalCall;
  const unsigned long max = (width > height) ? width : height;
  if (((maximumPrintBitmapWidth == 0) || (maximumPrintBitmapWidth >= 2 * max)) &&
      ((maximumPrintBitmapHeight == 0) || (maximumPrintBitmapHeight >= 2 * max)))
  {
    minimumPrintBitmapWidth = width;
    minimumPrintBitmapHeight = height;
    result = EC_Normal;
  }
  return result;
}


00268 OFCondition DVPresentationState::setMaximumPrintBitmapWidthHeight(unsigned long width,
                                                                  unsigned long height)
{
  OFCondition result = EC_IllegalCall;
  const unsigned long min = (width < height) ? width : height;
  if (((minimumPrintBitmapWidth == 0) || (min >= 2 * minimumPrintBitmapWidth)) &&
      ((minimumPrintBitmapHeight == 0) || (min >= 2 * minimumPrintBitmapHeight)))
  {
    maximumPrintBitmapWidth = width;
    maximumPrintBitmapHeight = height;
    result = EC_Normal;
  }
  return result;
}


00284 OFCondition DVPresentationState::getPrintBitmapWidthHeight(unsigned long &width,
                                                           unsigned long &height)
{
  OFCondition result = EC_Normal;
  if (currentImage)
  {
    renderPixelData(OFFalse);                                 // switch off display function
    width = renderedImageWidth;
    height = renderedImageHeight;
    if ((width > 0) && (height > 0))
    {
      width = (unsigned long)(renderedImageRight - renderedImageLeft + 1);
      height = (unsigned long)(renderedImageBottom - renderedImageTop + 1);

      if ((minimumPrintBitmapWidth > 0) && (width < minimumPrintBitmapWidth))
      {
        if ((minimumPrintBitmapHeight > 0) && (height < minimumPrintBitmapHeight))
        {
          const unsigned long xfactor = (unsigned long)((double)(minimumPrintBitmapWidth - 1) / (double)width) + 1;
          const unsigned long yfactor = (unsigned long)((double)(minimumPrintBitmapHeight - 1) / (double)height) + 1;
          if (xfactor > yfactor)
          {
            width *= xfactor;
            height *= xfactor;
          } else {
            width *= yfactor;
            height *= yfactor;
          }
        } else {
          const unsigned long factor = (unsigned long)((double)(minimumPrintBitmapWidth - 1) / (double)width) + 1;
          width *= factor;
          height *= factor;
        }
      }
      else if ((minimumPrintBitmapHeight > 0) && (height < minimumPrintBitmapHeight))
      {
        const unsigned long factor = (unsigned long)((double)(minimumPrintBitmapHeight - 1) / (double)height) + 1;
        width *= factor;
        height *= factor;
      }

      if ((maximumPrintBitmapWidth > 0) && (width > maximumPrintBitmapWidth))
      {
        if ((maximumPrintBitmapHeight > 0) && (height > maximumPrintBitmapHeight))
        {
          const unsigned long xdivisor = (unsigned long)((double)(width - 1) / (double)maximumPrintBitmapWidth) + 1;
          const unsigned long ydivisor = (unsigned long)((double)(height - 1) / (double)maximumPrintBitmapHeight) + 1;
          if (xdivisor > ydivisor)
          {
            width /= xdivisor;
            height /= xdivisor;
          } else {
            width /= ydivisor;
            height /= ydivisor;
          }
        } else {
          const unsigned long divisor = (unsigned long)((double)(width - 1) / (double)maximumPrintBitmapWidth) + 1;
          width /= divisor;
          height /= divisor;
        }
      }
      else if ((maximumPrintBitmapHeight > 0) && (height > maximumPrintBitmapHeight))
      {
        const unsigned long divisor = (unsigned long)((double)(height - 1) / (double)maximumPrintBitmapHeight) + 1;
        width /= divisor;
        height /= divisor;
      }
    }
  } else {
    width = 0;
    height = 0;
    result = EC_IllegalCall;
  }
  return result;
}


00361 OFCondition DVPresentationState::getPrintBitmapWidth(unsigned long &width)
{
  unsigned long dummy;
  return getPrintBitmapWidthHeight(width, dummy);
}


00368 OFCondition DVPresentationState::getPrintBitmapHeight(unsigned long &height)
{
  unsigned long dummy;
  return getPrintBitmapWidthHeight(dummy, height);
}


00375 double DVPresentationState::getPrintBitmapPixelAspectRatio()
{
  double result = getDisplayedAreaPresentationPixelAspectRatio();
  if (result == 1.0) return result; // handle most frequent case quickly
  if (result == 0.0) result = 1.0; // should never happen

  DVPSRotationType rotation = getRotation();
  if ((rotation==DVPSR_90_deg)||(rotation==DVPSR_270_deg)) result = 1.0/result;
  return result;
}


00387 OFCondition DVPresentationState::getPrintBitmap(void *bitmap,
                                                unsigned long size,
                                                OFBool inversePLUT)
{
  OFCondition result = EC_IllegalCall;
  if ((bitmap != NULL) && (size == getPrintBitmapSize()))       // check given buffer
  {
    if (currentImage)
    {
      renderPixelData(OFFalse);                                 // don't use current display function
      unsigned long width;
      unsigned long height;
      if (getPrintBitmapWidthHeight(width, height) == EC_Normal)
      {
        DicomImage *image = currentImage;

        /* we deactivate any presentation LUT at this point because
         * getPrintBitmapWidthHeight() calls renderPixelData().
         */
        if (presentationLUT.getType() == DVPSP_table)
        {
          if (inversePLUT)
          {
            if (currentImageMonochrome1) currentImage->setPolarity(EPP_Reverse);
            presentationLUT.activateInverseLUT(currentImage);
          } else {
            // we never render a presentation LUT into the print bitmap at this stage.
            if (currentImageMonochrome1) currentImage->setPresentationLutShape(ESP_Inverse);
            else currentImage->setPresentationLutShape(ESP_Identity);
          }
          // make sure the presentation LUT is re-activated for on-screen display
          currentImagePLUTValid = OFFalse;
        }

        /* clip to displayed area if necessary */
        if ((renderedImageLeft != 1) || (renderedImageRight != (signed long)renderedImageWidth) ||
            (renderedImageTop != 1) || (renderedImageBottom != (signed long)renderedImageHeight))
        {
          DicomImage *img = currentImage->createMonoOutputImage(currentImageSelectedFrame-1, 12 /*bits*/);
          if (img == NULL)
            img = currentImage;                                 // fall-back solution
          image = img->createClippedImage(renderedImageLeft - 1, renderedImageTop - 1, renderedImageRight - renderedImageLeft + 1,
            renderedImageBottom - renderedImageTop + 1, getShutterPresentationValue());
          if (img != currentImage)
            delete img;
        }
        /* scale up to minimum size or down to maximum size if necessary */
        if (((signed long)width != renderedImageRight - renderedImageLeft + 1) ||
           ((signed long)height != renderedImageBottom - renderedImageTop + 1))
        {
          DicomImage *img = image;
          image = img->createScaledImage(width, height, 0 /*no interpolation*/, 0 /*ignore aspect ratio*/);
          if (img != currentImage)
            delete img;
        }
        if (image != NULL)
        {
          if (image->getOutputData(bitmap, size, 12 /*bits*/, currentImageSelectedFrame-1)) result = EC_Normal;
        }
        if (image != currentImage) delete image;
      }
    }
  }
  return result;
}


00454 OFCondition DVPresentationState::createPreviewImage(unsigned long maxWidth,
                                                    unsigned long maxHeight,
                                                    OFBool clipMode)
{
  OFCondition result = EC_IllegalCall;
  if ((currentImage != NULL) && (maxWidth > 0) && (maxHeight > 0))
  {
    deletePreviewImage();
    renderPixelData();
    unsigned long width = maxWidth;
    unsigned long height = maxHeight;
    double ratio = getPrintBitmapPixelAspectRatio();    // never 0 !
    if ((double)renderedImageWidth / (double)maxWidth * ratio < (double)renderedImageHeight / (double)maxHeight)
      width = 0;
    else
      height = 0;
    if (clipMode)
    {
      /* not yet implemented: clip preview image to current displayed area */
    }
    double oldRatio = currentImage->getWidthHeightRatio();
    currentImage->setWidthHeightRatio(ratio);
    previewImage = currentImage->createScaledImage(width, height, 1 /*interpolate*/, 1 /*aspect ratio*/);
    currentImage->setWidthHeightRatio(oldRatio);
    if (previewImage != NULL)
    {
      if (previewImage->getStatus() == EIS_Normal)
      {
        previewImage->removeAllOverlays();
        result = EC_Normal;
      } else {
        deletePreviewImage();
      }
    }
  }
  return result;
}


00493 void DVPresentationState::deletePreviewImage()
{
  delete previewImage;
  previewImage = NULL;
}


00500 unsigned long DVPresentationState::getPreviewImageSize()
{
  unsigned long result = 0;
  unsigned long width;
  unsigned long height;
  if (getPreviewImageWidthHeight(width, height) == EC_Normal)
      result = width * height;
  return result;
}


00511 OFCondition DVPresentationState::getPreviewImageWidthHeight(unsigned long &width,
                                                            unsigned long &height)
{
  OFCondition result = EC_IllegalCall;
  if (previewImage != NULL)
  {
    width = previewImage->getWidth();
    height = previewImage->getHeight();
    if ((width > 0) && (height > 0))
      result = EC_Normal;
  } else {
    width = 0;
    height = 0;
  }
  return result;
}


00529 OFCondition DVPresentationState::getPreviewImageWidth(unsigned long &width)
{
  unsigned long dummy;
  return getPreviewImageWidthHeight(width, dummy);
}


00536 OFCondition DVPresentationState::getPreviewImageHeight(unsigned long &height)
{
  unsigned long dummy;
  return getPreviewImageWidthHeight(dummy, height);
}


00543 OFCondition DVPresentationState::getPreviewImageBitmap(void *bitmap,
                                                       unsigned long size)
{
  OFCondition result = EC_IllegalCall;
  if ((previewImage != NULL) && (bitmap != NULL) && (size > 0))
  {
    renderPixelData();
    if (previewImage->getOutputData(bitmap, size, 8 /*bits*/, currentImageSelectedFrame-1))
      result = EC_Normal;
  }
  return result;
}


00557 OFCondition DVPresentationState::attachImage(DcmDataset *dataset, OFBool transferOwnership)
{
  if (!dataset) return EC_IllegalCall;

  // select the right DicomImage constructor depending on the Modality LUT
  DicomImage *image = NULL;
  if (useModalityRescale)
  {
    Float64 slope = 1.0;
    Float64 intercept = 0.0;

    if (EC_Normal != rescaleSlope.getFloat64(slope, 0))
    {
      if (verboseMode)
      {
        logstream->lockCerr() << "warning: unable to evaluate Modality Rescale Slope, ignoring." << endl;
        logstream->unlockCerr();
      }
      slope = 1.0;
    }
    if (EC_Normal != rescaleIntercept.getFloat64(intercept, 0))
    {
      if (verboseMode)
      {
        logstream->lockCerr() << "warning: unable to evaluate Modality Rescale Slope, ignoring." << endl;
        logstream->unlockCerr();
      }
      intercept = 0.0;
    }
    image = new DicomImage(dataset, dataset->getOriginalXfer(),
      slope, intercept, CIF_UsePresentationState);
  }
  else if (useModalityLUT)
  {
    image = new DicomImage(dataset, dataset->getOriginalXfer(),
      modalityLUTData, modalityLUTDescriptor, &modalityLUTExplanation, CIF_UsePresentationState);
  }
  else
  {
    image = new DicomImage(dataset, dataset->getOriginalXfer(), CIF_UsePresentationState);
  }

  OFCondition result = EC_Normal;
  if (image)
  {
    if (EIS_Normal == image->getStatus())
    {
      OFString aString;
      DcmStack stack;
      detachImage();
      currentImage = image;
      currentImageWidth = image->getWidth();
      currentImageHeight = image->getHeight();
      currentImageDataset = dataset;
      currentImageOwned = transferOwnership;
      currentImageSelectedFrame = 1; // default: first frame

      // get Modality
      if (EC_Normal == dataset->search(DCM_Modality, stack, ESM_fromHere, OFFalse))
      {
        currentImageModality = *((DcmCodeString *)(stack.top()));
      }
      stack.clear();

      // determine default Presentation LUT Shape
      if (EC_Normal == dataset->search(DCM_PhotometricInterpretation, stack, ESM_fromHere, OFFalse))
      {
         DcmCodeString *photometricInterpretation = (DcmCodeString *)(stack.top());
         if (photometricInterpretation->getVM() == 1)
         {
           aString.clear();
           photometricInterpretation->getOFString(aString,0);
           if ((aString == "MONOCHROME1")||(aString == "MONOCHROME 1")) currentImageMonochrome1 = OFTrue;
         }
      }
      stack.clear();

      // get SOP class UID and SOP instance UID.
      if ((EC_Normal == result)&&(EC_Normal == dataset->search(DCM_SOPClassUID, stack, ESM_fromHere, OFFalse)))
      {
        result = ((DcmUniqueIdentifier *)(stack.top()))->getString(currentImageSOPClassUID);
      }
      stack.clear();
      if ((EC_Normal == result)&&(EC_Normal == dataset->search(DCM_SOPInstanceUID, stack, ESM_fromHere, OFFalse)))
      {
        result = ((DcmUniqueIdentifier *)(stack.top()))->getString(currentImageSOPInstanceUID);
      }
      if (EC_Normal==result) result = currentImageCurveList.read(*dataset);
      if (EC_Normal==result) result = currentImageVOILUTList.read(*dataset);
      if (EC_Normal==result) result = currentImageVOIWindowList.read(*dataset);

      createPreviewImage(maximumPreviewImageWidth, maximumPreviewImageHeight);
    } else {
      delete image;
      result = EC_IllegalCall;
    }
  } else result = EC_MemoryExhausted;
  return result;
}

00657 OFCondition DVPresentationState::getImageWidth(unsigned long &width)
{
  OFCondition result=EC_Normal;
  if (currentImage) width = currentImageWidth;
  else
  {
    width = 0;
    result = EC_IllegalCall;
  }
  return result;
}

00669 OFCondition DVPresentationState::getImageHeight(unsigned long &height)
{
  OFCondition result=EC_Normal;
  if (currentImage) height = currentImageHeight;
  else
  {
    height = 0;
    result = EC_IllegalCall;
  }
  return result;
}


00682 OFCondition DVPresentationState::attachImage(DcmFileFormat *fileformat, OFBool transferOwnership)
{
  if (fileformat == NULL) return EC_IllegalCall;
  OFCondition result = attachImage(fileformat->getDataset(), transferOwnership);
  if (EC_Normal == result) currentImageFileformat = fileformat;
  return result;
}


00691 OFCondition DVPresentationState::addImageReferenceAttached(
    const char *aetitle,
    const char *filesetID,
    const char *filesetUID)
{
  if (currentImageDataset) return addImageReference(*currentImageDataset, aetitle, filesetID, filesetUID);
  else return EC_IllegalCall;
}


00701 OFCondition DVPresentationState::removeImageReferenceAttached()
{
  if (currentImageDataset) return removeImageReference(*currentImageDataset);
  else return EC_IllegalCall;
}



00709 OFCondition DVPresentationState::setCurrentPresentationLUT(DVPSPresentationLUTType newType)
{
  OFCondition result = presentationLUT.setType(newType);
  currentImagePLUTValid = OFFalse; // PLUT has changed
  imageInverse = presentationLUT.isInverse();
  return result;
}

00717 OFCondition DVPresentationState::setDefaultPresentationLUTShape()
{
  OFCondition result = EC_Normal;
  if (currentImageMonochrome1) result=presentationLUT.setType(DVPSP_inverse); else result=presentationLUT.setType(DVPSP_identity);
  currentImagePLUTValid = OFFalse; // PLUT has changed
  imageInverse = presentationLUT.isInverse();
  return result;
}

00726 OFCondition DVPresentationState::setPresentationLookupTable(
    DcmUnsignedShort& lutDescriptor,
    DcmUnsignedShort& lutData,
    DcmLongString& lutExplanation)
{
  OFCondition result = presentationLUT.setLUT(lutDescriptor, lutData, lutExplanation);
  currentImagePLUTValid = OFFalse; // PLUT has changed
  OFBool wasInverse = imageInverse;
  imageInverse = presentationLUT.isInverse();

  // keep inverse/normal status as before
  if ((wasInverse && (! imageInverse))||(imageInverse && (! wasInverse))) result = invertImage();
  return result;
}

00741 OFCondition DVPresentationState::setPresentationLookupTable(DcmItem &dset)
{
  OFCondition result = presentationLUT.read(dset, OFFalse);
  if (EC_Normal != result) presentationLUT.setType(DVPSP_identity); // set to well-defined default in case of error
  currentImagePLUTValid = OFFalse; // PLUT has changed
  OFBool wasInverse = imageInverse;
  imageInverse = presentationLUT.isInverse();

  // keep inverse/normal status as before
  if ((wasInverse && (! imageInverse))||(imageInverse && (! wasInverse))) result = invertImage();
  return result;
}


00755 void DVPresentationState::removeShutter(DVPSShutterType type)
{
  switch (type)
  {
    case DVPSU_rectangular:
      useShutterRectangular = OFFalse;
      break;
    case DVPSU_circular:
      useShutterCircular = OFFalse;
      break;
    case DVPSU_polygonal:
      useShutterPolygonal = OFFalse;
      break;
    case DVPSU_bitmap:
      if (useShutterBitmap) currentImageOverlaysValid = 1; // invalid but nothing added
      useShutterBitmap = OFFalse;
      break;
  }
  return;
}


00777 OFCondition DVPresentationState::setRectShutter(Sint32 lv, Sint32 rv, Sint32 uh, Sint32 lh)
{
  OFCondition result=EC_Normal;
  char buf[80];

  sprintf(buf, "%ld", (long)lv);
  result = shutterLeftVerticalEdge.putString(buf);
  sprintf(buf, "%ld", (long)rv);
  if (EC_Normal==result) result = shutterRightVerticalEdge.putString(buf);
  sprintf(buf, "%ld", (long)uh);
  if (EC_Normal==result) result = shutterUpperHorizontalEdge.putString(buf);
  sprintf(buf, "%ld", (long)lh);
  if (EC_Normal==result) result = shutterLowerHorizontalEdge.putString(buf);
  if ((EC_Normal==result)&&(shutterPresentationValue.getLength()==0))
      result = shutterPresentationValue.putUint16(0,0);
  if (EC_Normal==result)
  {
    useShutterRectangular = OFTrue;
    if (useShutterBitmap) currentImageOverlaysValid = 1; // invalid but nothing added
    useShutterBitmap = OFFalse;
  }
  return result;
}


00802 OFCondition DVPresentationState::setCircularShutter(Sint32 centerX, Sint32 centerY, Sint32 radius)
{
  OFCondition result=EC_Normal;
  char buf[80];

  sprintf(buf, "%ld\\%ld", (long)centerY, (long)centerX);
  result = centerOfCircularShutter.putString(buf);
  sprintf(buf, "%ld", (long)radius);
  if (EC_Normal==result) result = radiusOfCircularShutter.putString(buf);
  if ((EC_Normal==result)&&(shutterPresentationValue.getLength()==0))
      result = shutterPresentationValue.putUint16(0,0);
  if (EC_Normal==result)
  {
    useShutterCircular = OFTrue;
    if (useShutterBitmap) currentImageOverlaysValid = 1; // invalid but nothing added
    useShutterBitmap = OFFalse;
  }
  return result;
}


00823 OFCondition DVPresentationState::addPolyShutterVertex(Sint32 x, Sint32 y)
{
  if (verticesOfThePolygonalShutter.getLength()==0) return EC_IllegalCall;
  OFString aString;
  OFCondition result = verticesOfThePolygonalShutter.getOFStringArray(aString,OFTrue);
  if (result==EC_Normal)
  {
    char buf[80];
    sprintf(buf, "\\%ld\\%ld", (long)y, (long)x);
    aString += buf;
    result = verticesOfThePolygonalShutter.putOFStringArray(aString);
  }

  if (result==EC_Normal)
  {
    Sint32 xp0 = 0;
    Sint32 yp0 = 0;
    result = getPolyShutterVertex(0, xp0, yp0);
    if (result==EC_Normal)
    {
      if ((xp0==x)&&(yp0==y)) // polygon is closed now, activate.
      {
        if (shutterPresentationValue.getLength()==0)
           result = shutterPresentationValue.putUint16(0,0);
        if (EC_Normal==result)
        {
          useShutterPolygonal = OFTrue;
          if (useShutterBitmap) currentImageOverlaysValid = 1; // invalid but nothing added
          useShutterBitmap = OFFalse;
        }
      }
    }
  }
  return result;
}

00859 OFCondition DVPresentationState::removeGraphicLayer(size_t idx)
{
  const char *name = graphicLayerList.getGraphicLayerName(idx);
  if (name==NULL) return EC_IllegalCall;
  activationLayerList.removeLayer(name);
  currentImageOverlaysValid = 1; // invalid but nothing added
  graphicAnnotationList.removeLayer(name);
  return graphicLayerList.removeGraphicLayer(idx);
}

00869 size_t DVPresentationState::getNumberOfTextObjects(size_t layer)
{
  if (!currentImage) return 0;
  return graphicAnnotationList.getNumberOfTextObjects(graphicLayerList.getGraphicLayerName(layer), currentImageSOPInstanceUID, currentImageSelectedFrame);
}

00875 DVPSTextObject *DVPresentationState::getTextObject(size_t layer, size_t idx)
{
  if (!currentImage) return NULL;
  return graphicAnnotationList.getTextObject(graphicLayerList.getGraphicLayerName(layer), currentImageSOPInstanceUID, currentImageSelectedFrame, idx);
}

00881 DVPSTextObject *DVPresentationState::addTextObject(size_t layer, DVPSObjectApplicability applicability)
{
  if (!currentImage) return NULL;
  return graphicAnnotationList.addTextObject(graphicLayerList.getGraphicLayerName(layer), currentImageSOPClassUID,
    currentImageSOPInstanceUID, currentImageSelectedFrame, applicability);
}

00888 OFCondition DVPresentationState::removeTextObject(size_t layer, size_t idx)
{
  if (!currentImage) return EC_IllegalCall;
  return graphicAnnotationList.removeTextObject(graphicLayerList.getGraphicLayerName(layer), currentImageSOPInstanceUID, currentImageSelectedFrame, idx);
}

00894 OFCondition DVPresentationState::moveTextObject(size_t old_layer, size_t idx, size_t new_layer, DVPSObjectApplicability applicability)
{
  if (!currentImage) return EC_IllegalCall;
  if (old_layer==new_layer) return EC_Normal;
  return graphicAnnotationList.moveTextObject(
    graphicLayerList.getGraphicLayerName(old_layer),
    currentImageSOPClassUID,
    currentImageSOPInstanceUID,
    currentImageSelectedFrame,
    idx,
    applicability,
    graphicLayerList.getGraphicLayerName(new_layer));
}

00908 size_t DVPresentationState::getNumberOfGraphicObjects(size_t layer)
{
  if (!currentImage) return 0;
  return graphicAnnotationList.getNumberOfGraphicObjects(graphicLayerList.getGraphicLayerName(layer), currentImageSOPInstanceUID, currentImageSelectedFrame);
}

00914 DVPSGraphicObject *DVPresentationState::getGraphicObject(size_t layer, size_t idx)
{
  if (!currentImage) return NULL;
  return graphicAnnotationList.getGraphicObject(graphicLayerList.getGraphicLayerName(layer), currentImageSOPInstanceUID, currentImageSelectedFrame, idx);
}

00920 DVPSGraphicObject *DVPresentationState::addGraphicObject(size_t layer, DVPSObjectApplicability applicability)
{
  if (!currentImage) return NULL;
  return graphicAnnotationList.addGraphicObject(graphicLayerList.getGraphicLayerName(layer), currentImageSOPClassUID,
    currentImageSOPInstanceUID, currentImageSelectedFrame, applicability);
}

00927 OFCondition DVPresentationState::removeGraphicObject(size_t layer, size_t idx)
{
  if (!currentImage) return EC_IllegalCall;
  return graphicAnnotationList.removeGraphicObject(graphicLayerList.getGraphicLayerName(layer), currentImageSOPInstanceUID, currentImageSelectedFrame, idx);
}

00933 OFCondition DVPresentationState::moveGraphicObject(size_t old_layer, size_t idx, size_t new_layer, DVPSObjectApplicability applicability)
{
  if (!currentImage) return EC_IllegalCall;
  if (old_layer==new_layer) return EC_Normal;
  return graphicAnnotationList.moveGraphicObject(
    graphicLayerList.getGraphicLayerName(old_layer),
    currentImageSOPClassUID,
    currentImageSOPInstanceUID,
    currentImageSelectedFrame,
    idx,
    applicability,
    graphicLayerList.getGraphicLayerName(new_layer));
}


00948 DVPSCurve *DVPresentationState::getCurve(size_t layer, size_t idx)
{
  Uint16 rgroup = activationLayerList.getActivationGroup(
    graphicLayerList.getGraphicLayerName(layer), idx, OFTrue);
  if (rgroup==0) return NULL;
  else return currentImageCurveList.getCurveGroup(rgroup);
}

00956 size_t DVPresentationState::getNumberOfCurvesInImage()
{
  return currentImageCurveList.size();
}

00961 DVPSCurve *DVPresentationState::getCurveInImage(size_t idx)
{
  return currentImageCurveList.getCurve(idx);
}

00966 OFCondition DVPresentationState::addCurve(size_t layer, size_t curveidxinimage)
{
  const char *lname = graphicLayerList.getGraphicLayerName(layer);
  DVPSCurve *curve = currentImageCurveList.getCurve(curveidxinimage);
  if ((curve==NULL)||(lname==NULL)) return EC_IllegalCall;
  return activationLayerList.setActivation(0x5000 + curve->getCurveGroup(), lname);
}

00974 OFBool DVPresentationState::haveActiveVOIWindow()
{
  DVPSSoftcopyVOI *voi = getCurrentSoftcopyVOI();
  if (voi)
  {
    if (voi->haveLUT()) return OFFalse; else return OFTrue;
  }
  return OFFalse;
}

00984 OFBool DVPresentationState::haveActiveVOILUT()
{
  DVPSSoftcopyVOI *voi = getCurrentSoftcopyVOI();
  if (voi) return voi->haveLUT();
  return OFFalse;
}

00991 const char *DVPresentationState::getCurrentVOIDescription()
{
  DVPSSoftcopyVOI *voi = getCurrentSoftcopyVOI();
  if (voi) return voi->getCurrentVOIDescription();
  return NULL;
}

00998 OFCondition DVPresentationState::getCurrentWindowWidth(double &w)
{
  DVPSSoftcopyVOI *voi = getCurrentSoftcopyVOI();
  if (voi) return voi->getCurrentWindowWidth(w);
  return EC_IllegalCall;
}

01005 OFCondition DVPresentationState::getCurrentWindowCenter(double &c)
{
  DVPSSoftcopyVOI *voi = getCurrentSoftcopyVOI();
  if (voi) return voi->getCurrentWindowCenter(c);
  return EC_IllegalCall;
}

01012 size_t DVPresentationState::getNumberOfVOILUTsInImage()
{
  return currentImageVOILUTList.size();
}

01017 size_t DVPresentationState::getNumberOfVOIWindowsInImage()
{
  return currentImageVOIWindowList.size();
}

01022 const char *DVPresentationState::getDescriptionOfVOILUTsInImage(size_t idx)
{
  DVPSVOILUT *lut = currentImageVOILUTList.getVOILUT(idx);
  if (lut==NULL) return NULL;
  return lut->getExplanation();
}

01029 const char *DVPresentationState::getDescriptionOfVOIWindowsInImage(size_t idx)
{
  DVPSVOIWindow *window = currentImageVOIWindowList.getVOIWindow(idx);
  if (window==NULL) return NULL;
  return window->getExplanation();
}

01036 OFCondition DVPresentationState::setVOILUTFromImage(size_t idx,
    DVPSObjectApplicability applicability)
{
  if (currentImage == NULL) return EC_IllegalCall;

  DVPSVOILUT *lut = currentImageVOILUTList.getVOILUT(idx);
  if (lut)
  {
    currentImageVOIValid = OFFalse; // VOI has changed

    DVPSSoftcopyVOI *voi = softcopyVOIList.createSoftcopyVOI(
      referencedSeriesList, currentImageSOPClassUID, currentImageSOPInstanceUID,
      currentImageSelectedFrame, currentImage->getFrameCount(), applicability);
    if (voi) return lut->assign(*voi);
  }
  return EC_IllegalCall;
}

01054 OFCondition DVPresentationState::setVOIWindowFromImage(size_t idx,
    DVPSObjectApplicability applicability)
{
  currentImageVOIValid = OFFalse; // VOI has changed
  DVPSVOIWindow *window = currentImageVOIWindowList.getVOIWindow(idx);
  if (window)
  {
    return setVOIWindow(window->getWindowCenter(),
      window->getWindowWidth(), window->getExplanation(), applicability);
  }
  return EC_IllegalCall;
}

01067 OFCondition DVPresentationState::setVOIWindow(double wCenter, double wWidth, const char *description,
    DVPSObjectApplicability applicability)
{
  if (currentImage == NULL) return EC_IllegalCall;
  currentImageVOIValid = OFFalse; // VOI has changed
  DVPSSoftcopyVOI *voi = softcopyVOIList.createSoftcopyVOI(
      referencedSeriesList, currentImageSOPClassUID, currentImageSOPInstanceUID,
      currentImageSelectedFrame, currentImage->getFrameCount(), applicability);
  if (voi) return voi->setVOIWindow(wCenter, wWidth, description);
  return EC_IllegalCall;
}

01079 OFCondition DVPresentationState::setVOILUT(
    DcmUnsignedShort& lutDescriptor,
    DcmUnsignedShort& lutData,
    DcmLongString& lutExplanation,
    DVPSObjectApplicability applicability)
{
  if (lutData.getLength() == 0) return EC_IllegalCall;
  if (lutDescriptor.getVM() != 3) return EC_IllegalCall;
  if (currentImage == NULL) return EC_IllegalCall;

  currentImageVOIValid = OFFalse; // VOI has changed
  DVPSSoftcopyVOI *voi = softcopyVOIList.createSoftcopyVOI(
      referencedSeriesList, currentImageSOPClassUID, currentImageSOPInstanceUID,
      currentImageSelectedFrame, currentImage->getFrameCount(), applicability);
  if (voi) return voi->setVOILUT(lutDescriptor, lutData, lutExplanation);
  return EC_IllegalCall;
}

01097 void DVPresentationState::deactivateVOI(DVPSObjectApplicability applicability)
{
  if (currentImage == NULL) return;
  currentImageVOIValid = OFFalse; // VOI has changed
  softcopyVOIList.removeSoftcopyVOI(
      referencedSeriesList, currentImageSOPInstanceUID,
      currentImageSelectedFrame, currentImage->getFrameCount(), applicability);
  return;
}

01107 OFCondition DVPresentationState::setGammaVOILUT(double gammaValue, DVPSObjectApplicability applicability)
{
  if (currentImage == NULL) return EC_IllegalCall;

  OFCondition status = EC_IllegalCall;
  const unsigned int numberOfBits = 16;
  unsigned long numberOfEntries = 0;
  signed long firstMapped = 0;
  if (haveActiveVOIWindow())    // use active VOI window to specify the LUT descriptor
  {
    double ww, wc;
    if ((getCurrentWindowWidth(ww) == EC_Normal) && (getCurrentWindowCenter(wc) == EC_Normal))
    {
      if (ww <= 65536)
      {
        numberOfEntries = (unsigned long)ww;
        firstMapped = (signed long)(wc - ww / 2);
      }
    }
  }
  if (numberOfEntries == 0)     // no valid VOI window, use whole pixel range
  {
    double min, max;
    if (getImageMinMaxPixelRange(min, max) == EC_Normal)
    {
      if (max - min < 65536.0)
      {
        numberOfEntries = (unsigned long)(max - min + 1.0);
        firstMapped = (signed long)min;
      }
    }
  }

  if ((numberOfEntries > 0) && (numberOfEntries <= 65536) &&
     ((firstMapped >= -32768) && (firstMapped <= 32767)) || (firstMapped >= 0) && (firstMapped <= 65535))
  {
    Uint16 *data = new Uint16[numberOfEntries];
    if (data != NULL)
    {
      /* calculate gamma curve */
      const Uint16 maxValue = 0xFFFF >> (16 - numberOfBits);
      double step = (double)maxValue / ((double)numberOfEntries - 1.0);
      double gammaExp = 1.0 / gammaValue;
      double factor = (double)maxValue / pow((double)maxValue, gammaExp);
      unsigned long i;
      for (i = 0; i < numberOfEntries; i++)
        data[i]= (Uint16)(factor * pow(i * step, gammaExp));

      Uint16 numEntries16 = 0;
      if (numberOfEntries < 65536)
        numEntries16 = (Uint16)numberOfEntries;

      /* LUT Descriptor */
      DcmElement *lutDescriptor = NULL;
      if (firstMapped < 0)
      {
        // LUT Descriptor is SS
        lutDescriptor = new DcmSignedShort(DcmTag(DCM_LUTDescriptor, EVR_SS));
        if (lutDescriptor != NULL)
        {
            status = lutDescriptor->putSint16((Sint16)numEntries16, 0);
            if (EC_Normal == status)
              status = lutDescriptor->putSint16((Sint16)firstMapped, 1);
            if (EC_Normal == status)
              status = lutDescriptor->putSint16((Sint16)numberOfBits, 2);
        } else
          status = EC_MemoryExhausted;
      } else {
        // LUT Descriptor is US
        lutDescriptor = new DcmUnsignedShort(DcmTag(DCM_LUTDescriptor, EVR_US));
        if (lutDescriptor != NULL)
        {
            status = lutDescriptor->putUint16(numEntries16, 0);
            if (EC_Normal == status)
              status = lutDescriptor->putUint16((Uint16)firstMapped, 1);
            if (EC_Normal == status)
              status = lutDescriptor->putUint16((Uint16)numberOfBits, 2);
        } else
            status = EC_MemoryExhausted;
      }

      /* LUT Data */
      DcmElement *lutData = NULL;
      if (status == EC_Normal)
      {
        // LUT Data as OW, because of max size = 64K
        lutData = new DcmOtherByteOtherWord(DcmTag(DCM_LUTData, EVR_OW));
        if (lutData != NULL)
          status = lutData->putUint16Array(data, numberOfEntries);
        else
          status = EC_MemoryExhausted;
      }

      /* LUT Explanation */
      DcmLongString *lutExplanation = NULL;
      if (status == EC_Normal)
      {
        char explanation[100];
        char gammabuf[16];
        OFStandard::ftoa(gammabuf, sizeof(gammabuf), gammaValue, OFStandard::ftoa_format_f, 3, 1);

        sprintf(explanation, "LUT with gamma %s, descriptor %u/%ld/%u", gammabuf,
               (numberOfEntries < 65536) ? (Uint16)numberOfEntries : 0, firstMapped, numberOfBits);

        lutExplanation = new DcmLongString(DCM_LUTExplanation);
        if (lutExplanation != NULL)
          status = lutExplanation->putString(explanation);
        else
          status = EC_MemoryExhausted;
      }

      /* set VOI LUT */
      if (status == EC_Normal)
      {
        if ((lutDescriptor != NULL) && (lutData != NULL) && (lutExplanation !=  NULL))
          status = setVOILUT(*(DcmUnsignedShort *)lutDescriptor, *(DcmUnsignedShort *)lutData, *lutExplanation, applicability);
      }

      /* delete temporary dcmtk structures */
      delete lutDescriptor;
      delete lutData;
      delete lutExplanation;
    } else
      status = EC_MemoryExhausted;
    delete[] data;
  }
  return status;
}


01237 const char *DVPresentationState::getActiveOverlayLabel(size_t layer, size_t idx)
{
  Uint16 group = getActiveOverlayGroup(layer, idx);
  if (group==0) return NULL;
  DVPSOverlay *internalOverlay = overlayList.getOverlayGroup(group);
  if (internalOverlay) return internalOverlay->getOverlayLabel();
  if (currentImage) return currentImage->getOverlayLabel(group);
  return NULL;
}

01247 const char *DVPresentationState::getActiveOverlayDescription(size_t layer, size_t idx)
{
  Uint16 group = getActiveOverlayGroup(layer, idx);
  if (group==0) return NULL;
  DVPSOverlay *internalOverlay = overlayList.getOverlayGroup(group);
  if (internalOverlay) return internalOverlay->getOverlayDescription();
  if (currentImage) return currentImage->getOverlayDescription(group);
  return NULL;
}

01257 OFBool DVPresentationState::activeOverlayIsROI(size_t layer, size_t idx)
{
  Uint16 group = getActiveOverlayGroup(layer, idx);
  if (group==0) return OFFalse;
  DVPSOverlay *internalOverlay = overlayList.getOverlayGroup(group);
  if (internalOverlay) return internalOverlay->isROI();
  if ((currentImage)&&(EMO_RegionOfInterest == currentImage->getOverlayMode(group))) return OFTrue;
  return OFFalse;
}

01267 size_t DVPresentationState::getNumberOfOverlaysInImage()
{
  if (currentImage == NULL) return 0;

  unsigned int numOverlays=currentImage->getOverlayCount();
  size_t result = (size_t) numOverlays;
  Uint16 group;
  for (unsigned int i=0; i<numOverlays; i++)
  {
    // ignore all overlays which are shadowed by the presentation state
    group = (Uint16)(currentImage->getOverlayGroupNumber(i));
    if ((group==0)||(overlayList.haveOverlayGroup(group))) result--;
  }
  return result;
}


01284 Uint16 DVPresentationState::getOverlayInImageGroup(size_t idx)
{
  if (currentImage == NULL) return 0;

  size_t currentIndex = 0;
  Uint16 group;
  do
  {
    group = (Uint16) (currentImage->getOverlayGroupNumber(currentIndex++));
    if (!overlayList.haveOverlayGroup(group))
    {
      // group is not shadowed by the presentation state
      if (idx==0) return group; else idx--;
    }
  } while (group != 0);
  return 0;
}


01303 const char *DVPresentationState::getOverlayInImageLabel(size_t idx)
{
  Uint16 group = getOverlayInImageGroup(idx); // returns 0 if currentImage==NULL
  if (group==0) return NULL; else return currentImage->getOverlayLabel(group);
}


01310 const char *DVPresentationState::getOverlayInImageDescription(size_t idx)
{
  Uint16 group = getOverlayInImageGroup(idx); // returns 0 if currentImage==NULL
  if (group==0) return NULL; else return currentImage->getOverlayDescription(group);
}


01317 size_t DVPresentationState::getOverlayInImageActivationLayer(size_t idx)
{
  Uint16 group = getOverlayInImageGroup(idx); // returns 0 if currentImage==NULL
  if (group==0) return DVPS_IDX_NONE;
  const char *layerName = activationLayerList.getActivationLayer(group);
  if (layerName) return graphicLayerList.getGraphicLayerIndex(layerName);
  else return DVPS_IDX_NONE;
}


01327 OFBool DVPresentationState::overlayInImageIsROI(size_t idx)
{
  Uint16 group = getOverlayInImageGroup(idx); // returns 0 if currentImage==NULL
  if (group==0) return OFFalse;
  if (EMO_RegionOfInterest == currentImage->getOverlayMode(group)) return OFTrue;
  else return OFFalse;
}

01335 OFCondition DVPresentationState::removeOverlayFromPresentationState(size_t idx)
{
  Uint16 group = getOverlayInPresentationStateGroup(idx);
  if (group != 0)
  {
    activationLayerList.removeActivation(group);
    currentImageOverlaysValid = 1; // invalid but nothing added
    return overlayList.removeOverlay(idx);
  }
  return EC_IllegalCall; // overlay does not exist
}


01348 Uint16 DVPresentationState::findOverlayGroup(Uint16 currentGroup)
{
  int allocated[16];
  size_t i, max;
  Uint16 group = 0;

  for (i=0; i<16; i++) allocated[i]=0;
  max = overlayList.size();
  for (i=0; i<max; i++)
  { // mark all group numbers used in presentation state
    group = getOverlayInPresentationStateGroup(i);
    if ((group >= 0x6000)&&(group <= 0x601F)) allocated[(Uint16)(group - 0x6000) >> 1] = 2;
  }
  max = getNumberOfOverlaysInImage();
  for (i=0; i<max; i++)
  { // mark all group numbers used in image
    group = getOverlayInImageGroup(i);
    if ((group >= 0x6000)&&(group <= 0x601F)) allocated[(Uint16)(group - 0x6000) >> 1] += 1;
  }
  // now we have 0=unused, 1=used in image, 2=used in pstate, 3=used in both.

  // check if the current group can be left unchanged
  if ((currentGroup >= 0x6000)&&(currentGroup <= 0x601F))
  {
    if (allocated[(Uint16)(group - 0x6000) >> 1] == 2) return currentGroup;
  }
  // find a free group
  for (i=0; i<16; i++) if (allocated[i]==0) return 0x6000+(i<<1);
  // find a group not used in the presentation state
  for (i=0; i<16; i++) if (allocated[i]<2) return 0x6000+(i<<1);
  // not found.
  return 0;
}

01382 OFCondition DVPresentationState::changeOverlayGroupInPresentationState(size_t idx, Uint16 newGroup)
{
  Uint16 group = getOverlayInPresentationStateGroup(idx);
  if (group != 0)
  {
    if (newGroup==0) newGroup = findOverlayGroup(group);
    if (newGroup==group) return EC_Normal; // shortcut - no change needed
    OFCondition result = overlayList.changeOverlayGroup(idx, newGroup);
    if (EC_Normal == result)
    {
      const char *layerName = activationLayerList.getActivationLayer(group);
      if (layerName)
      {
        activationLayerList.removeActivation(group);
        result = activationLayerList.setActivation(newGroup, layerName);
        currentImageOverlaysValid = 0; // invalid
      }
    }
    return result;
  }
  return EC_IllegalCall;
}

01405 OFCondition DVPresentationState::addOverlayToPresentationState(DcmItem& overlayIOD, Uint16 groupInItem, Uint16 newGroup)
{
  if (newGroup==0) newGroup = findOverlayGroup();
  if (newGroup==0) return EC_IllegalCall; // no group number available
  return overlayList.addOverlay(overlayIOD, groupInItem, newGroup);
}

01412 OFBool DVPresentationState::overlayIsSuitableAsBitmapShutter(size_t idx)
{
  if (currentImage)
  {
    DVPSOverlay *overlay = overlayList.getOverlay(idx);
    if (overlay)
    {
      return overlay->isSuitableAsShutter(currentImage->getWidth(), currentImage->getHeight());
    }
  }
  return OFFalse;
}

01425 OFCondition DVPresentationState::activateOverlayInImage(size_t layer, size_t idx)
{
  Uint16 group = getOverlayInImageGroup(idx);
  if (group==0) return EC_IllegalCall;
  if (activationLayerList.getActivationLayer(group) != NULL) return EC_IllegalCall; //already activated

  const char *layerName = getGraphicLayerName(layer);
  if (layerName==NULL) return EC_IllegalCall;
  currentImageOverlaysValid = 1; // invalid but nothing (external) added
  return activationLayerList.setActivation(group, layerName);
}

01437 OFCondition DVPresentationState::activateOverlayInPresentationState(size_t layer, size_t idx)
{
  Uint16 group = getOverlayInPresentationStateGroup(idx);
  if (group==0) return EC_IllegalCall;
  if (activationLayerList.getActivationLayer(group) != NULL) return EC_IllegalCall; //already activated
  if (haveShutter(DVPSU_bitmap))
  { // check if the overlay is used as the bitmap shutter
    Uint16 shutterGroup=0;
    shutterOverlayGroup.getUint16(shutterGroup,0);
    if (shutterGroup == group) return EC_IllegalCall; // used as bitmap shutter
  }
  const char *layerName = getGraphicLayerName(layer);
  if (layerName==NULL) return EC_IllegalCall;
  currentImageOverlaysValid = 0; // invalid
  return activationLayerList.setActivation(group, layerName);
}

01454 OFCondition DVPresentationState::activateOverlayAsBitmapShutter(size_t idx)
{
  Uint16 group = getOverlayInPresentationStateGroup(idx);
  if (group==0) return EC_IllegalCall;
  if (activationLayerList.getActivationLayer(group) != NULL) return EC_IllegalCall; // activated as overlay
  if (overlayIsSuitableAsBitmapShutter(idx))
  {
    shutterOverlayGroup.clear();
    OFCondition result = shutterOverlayGroup.putUint16(group,0);
    if ((EC_Normal==result)&&(shutterPresentationValue.getLength()==0))
        result = shutterPresentationValue.putUint16(0,0);
    if (EC_Normal==result)
    {
      useShutterRectangular = OFFalse;
      useShutterCircular = OFFalse;
      useShutterPolygonal = OFFalse;
      useShutterBitmap = OFTrue;
      currentImageOverlaysValid = 0; // invalid
    }
    return result;
  }
  return EC_IllegalCall;
}

01478 OFCondition DVPresentationState::deactivateOverlay(size_t layer, size_t idx)
{
  Uint16 group = activationLayerList.getActivationGroup(
    graphicLayerList.getGraphicLayerName(layer), idx, OFFalse);
  if (group == 0) return EC_IllegalCall;
  activationLayerList.removeActivation(group);
  currentImageOverlaysValid = 1; // invalid but nothing added
  return EC_Normal;
}

01488 Uint16 DVPresentationState::convertPValueToDDL(Uint16 pvalue, unsigned int bits)
{
  Uint16 result = 0;
  if ((bits == 8) || (bits == 12))
  {
    if (currentImage && (bits == 8))
    {
      /* activate display transform */
      if (displayFunction && (displayTransform != DVPSD_none))
        currentImage->setDisplayFunction(displayFunction[displayTransform]);
      else
        currentImage->setNoDisplayFunction();
      currentImage->convertPValueToDDL(pvalue, result, bits /* 8 */);
    } else
      result = (pvalue >> (16 - bits));
  }
  return result;
}


01508 void DVPresentationState::renderPixelData(OFBool display)
{
  if (currentImage == NULL) return;
  int result=0;

  /* activate Barten transform */
  if (displayFunction && (displayTransform != DVPSD_none) && display)
  {
    currentImage->setDisplayFunction(displayFunction[displayTransform]);
    if (previewImage != NULL)
      previewImage->setDisplayFunction(displayFunction[displayTransform]);
  } else {
    currentImage->setNoDisplayFunction();
    if (previewImage != NULL)
      previewImage->setNoDisplayFunction();
  }

  if (! currentImageVOIValid)
  {
     currentImageVOIValid = OFTrue;

     /* set VOI transformation */
     DVPSSoftcopyVOI *voi = getCurrentSoftcopyVOI();
     if (voi)
     {
       if (voi->haveLUT())
       {
         result = currentImage->setVoiLut(voi->getLUTData(), voi->getLUTDescriptor());
         if (previewImage != NULL)
           previewImage->setVoiLut(voi->getLUTData(), voi->getLUTDescriptor());
       } else {
         double wc=0.0, ww=0.0;
         if ((EC_Normal == voi->getCurrentWindowCenter(wc)) &&
             (EC_Normal == voi->getCurrentWindowWidth(ww)))
         {
           result = currentImage->setWindow(wc, ww);
           if (previewImage != NULL)
             previewImage->setWindow(wc, ww);
         } else {
           result = currentImage->setNoVoiTransformation();
           if (previewImage != NULL)
             previewImage->setNoVoiTransformation();
         }
       }
     } else {
       result = currentImage->setNoVoiTransformation();
       if (previewImage != NULL)
         previewImage->setNoVoiTransformation();
     }
     if ((!result) && verboseMode)
     {
       logstream->lockCerr() << "warning: unable to set VOI transformation, ignoring." << endl;
       logstream->unlockCerr();
     }
  } /* VOI transform */

  if (! currentImagePLUTValid)
  {
     presentationLUT.activate(currentImage);
     if (previewImage != NULL)
       presentationLUT.activate(previewImage);
     currentImagePLUTValid = OFTrue;
  } /* Presentation LUT */

  Uint16 bitmapShutterGroup = 0;
  Uint16 bitmapShutterPValue = 0;
  if (useShutterBitmap)
  {
    if (EC_Normal != shutterOverlayGroup.getUint16(bitmapShutterGroup, 0)) bitmapShutterGroup=0;
    if (EC_Normal != shutterPresentationValue.getUint16(bitmapShutterPValue, 0)) bitmapShutterPValue=0;
  }

  if (currentImageOverlaysValid==1)
  {
    /* overlays are invalid but no external overlays have been added */
    /* remove all external overlays that are not active as overlay or bitmap shutter */
    for (unsigned int remgroup=0x6000; remgroup <= 0x601F; remgroup += 2)
    {
      if ((remgroup != bitmapShutterGroup)&&((! overlayList.haveOverlayGroup(remgroup))||
          (NULL == activationLayerList.getActivationLayer(remgroup))))
      {
         currentImage->removeOverlay(remgroup); // ignore return value.
      }
    }
    currentImageOverlaysValid = 2; // valid
  }
  else if (currentImageOverlaysValid==0)
  {
    /* overlays are invalid */

    /* since we might be required to add external overlays, we first
     * need to flip the image back to its original rotation and flip state
     */
    if (currentImageFlip)
    {
      result = currentImage->flipImage();
      if (previewImage != NULL) previewImage->flipImage();
      if ((!result) && verboseMode)
      {
        logstream->lockCerr() << "warning: unable to flip image horizontally, ignoring." << endl;
        logstream->unlockCerr();
      }
      currentImageFlip = OFFalse;
    }
    signed int srot=0;
    switch(currentImageRotation)
    {
      case DVPSR_0_deg:   break;
      case DVPSR_90_deg:  srot=270; break;
      case DVPSR_180_deg: srot=180; break;
      case DVPSR_270_deg: srot=90; break;
    }
    if (srot != 0)
    {
      result = currentImage->rotateImage(srot);
      if (previewImage != NULL)
        previewImage->rotateImage(srot);
      if ((!result) && verboseMode)
      {
        logstream->lockCerr() << "warning: unable to rotate image by " << srot << " degrees, ignoring." << endl;
        logstream->unlockCerr();
      }
    }
    currentImageRotation = DVPSR_0_deg;

    // deactivate all overlays first
    result = currentImage->removeAllOverlays();
    if ((!result) && verboseMode)
    {
      logstream->lockCerr() << "warning: unable to disable external overlays, ignoring." << endl;
      logstream->unlockCerr();
    }

    size_t numOverlays = overlayList.size();
    DVPSOverlay *overlay = NULL;
    Uint16 ovgroup;
    for (size_t ovidx=0; ovidx<numOverlays; ovidx++)
    {
      overlay = overlayList.getOverlay(ovidx);
      if (overlay)
      {
        ovgroup = overlay->getOverlayGroup()+ 0x6000;
        if (NULL != activationLayerList.getActivationLayer(ovgroup))
        {
          if (activateOverlayHelper(*overlay, *currentImage).bad())
          {
            if ((!result) && verboseMode)
            {
              logstream->lockCerr() << "warning: unable to set external overlay group 0x"
                << hex << ovgroup << dec << ", ignoring." << endl;
              logstream->unlockCerr();
            }
          }
        }
        else if ((useShutterBitmap)&&(ovgroup == bitmapShutterGroup))
        {
          //activate bitmap overlay
          if (activateOverlayHelper(*overlay, *currentImage, OFTrue, bitmapShutterPValue).bad())
          {
            if ((!result) && verboseMode)
            {
              logstream->lockCerr() << "warning: unable to activate bitmap shutter 0x"
                << hex << ovgroup << dec << ", ignoring." << endl;
              logstream->unlockCerr();
            }
          }
        }
      }
    }
    currentImageOverlaysValid = 2; // valid
  }

  OFBool pstateFlip = getFlip();
  DVPSRotationType pstateRotation = getRotation();

  // store image width and height after application of rotation
  if ((pstateRotation == DVPSR_90_deg) || (pstateRotation == DVPSR_270_deg))
  {
    renderedImageWidth = currentImageHeight;
    renderedImageHeight = currentImageWidth;
  } else {
    renderedImageWidth = currentImageWidth;
    renderedImageHeight = currentImageHeight;
  }

  // get coordinates of current displayed area and store values after the
  // 'virtual' anti-rotation has been applied
  Sint32 tlhcX = 1;
  Sint32 tlhcY = 1;
  Sint32 brhcX = currentImageWidth;
  Sint32 brhcY = currentImageHeight;
  getImageRelativeDisplayedArea(tlhcX, tlhcY, brhcX, brhcY);
  if (tlhcX > brhcX)
  {                                     // swap 'left' and 'right' if necessary
    Sint32 tmp = tlhcX;
    tlhcX = brhcX;
    brhcX = tmp;
  }
  if (tlhcY > brhcY)
  {                                     // swap 'top' and 'bottom' if necessary
    Sint32 tmp = tlhcY;
    tlhcY = brhcY;
    brhcY = tmp;
  }
  switch (pstateRotation)
  {
    case DVPSR_0_deg:
      renderedImageTop = tlhcY;
      renderedImageLeft = tlhcX;
      renderedImageBottom = brhcY;
      renderedImageRight = brhcX;
      break;
    case DVPSR_90_deg:
      renderedImageTop = tlhcX;
      renderedImageLeft = (signed long)currentImageHeight - brhcY + 1;
      renderedImageBottom = brhcX;
      renderedImageRight = (signed long)currentImageHeight - tlhcY + 1;
      break;
    case DVPSR_180_deg:
      renderedImageTop = (signed long)currentImageHeight - brhcY + 1;
      renderedImageLeft = (signed long)currentImageWidth - brhcX + 1;
      renderedImageBottom = (signed long)currentImageHeight - tlhcY + 1;
      renderedImageRight = (signed long)currentImageWidth - tlhcX + 1;
      break;
    case DVPSR_270_deg:
      renderedImageTop = (signed long)currentImageWidth - brhcX + 1;
      renderedImageLeft = tlhcY;
      renderedImageBottom = (signed long)currentImageWidth - tlhcX + 1;
      renderedImageRight = brhcY;
      break;
  }
  if (pstateFlip)
  {
    signed long tmp = renderedImageLeft;
    renderedImageLeft = (signed long)renderedImageWidth - renderedImageRight + 1;
    renderedImageRight = (signed long)renderedImageWidth - tmp + 1;
  }

  // we can always reach the final rotation/flip status with
  // at most one rotation and one flip. The following formula
  // derives the operations to perform.
  OFBool flp=OFFalse;
  if ((pstateFlip && !currentImageFlip)||(!pstateFlip && currentImageFlip)) flp=OFTrue; else flp=OFFalse;

  signed int rot=0;
  switch (pstateRotation)
  {
    case DVPSR_0_deg:
      switch(currentImageRotation)
      {
        case DVPSR_0_deg:   rot=0; break;
        case DVPSR_90_deg:  if (currentImageFlip) rot=90; else rot=270; break;
        case DVPSR_180_deg: rot=180; break;
        case DVPSR_270_deg: if (currentImageFlip) rot=270; else rot=90; break;
      }
      break;
    case DVPSR_90_deg:
      switch(currentImageRotation)
      {
        case DVPSR_0_deg:   if (currentImageFlip) rot=270; else rot=90; break;
        case DVPSR_90_deg:  rot=0; break;
        case DVPSR_180_deg: if (currentImageFlip) rot=90; else rot=270; break;
        case DVPSR_270_deg: rot=180; break;
      }
      break;
    case DVPSR_180_deg:
      switch(currentImageRotation)
      {
        case DVPSR_0_deg:   rot=180; break;
        case DVPSR_90_deg:  if (currentImageFlip) rot=270; else rot=90; break;
        case DVPSR_180_deg: rot=0; break;
        case DVPSR_270_deg: if (currentImageFlip) rot=90; else rot=270; break;
      }
      break;
    case DVPSR_270_deg:
      switch(currentImageRotation)
      {
        case DVPSR_0_deg:   if (currentImageFlip) rot=90; else rot=270; break;
        case DVPSR_90_deg:  rot=180; break;
        case DVPSR_180_deg: if (currentImageFlip) rot=270; else rot=90; break;
        case DVPSR_270_deg: rot=0; break;
      }
      break;
  }

  if (rot != 0)
  {
    result = currentImage->rotateImage(rot);
    if (previewImage != NULL) previewImage->rotateImage(rot);
    if ((!result) && verboseMode)
    {
      logstream->lockCerr() << "warning: unable to rotate image by " << rot << " degrees, ignoring." << endl;
      logstream->unlockCerr();
    }
  }

  if (flp)
  {
    result = currentImage->flipImage();
    if (previewImage != NULL) previewImage->flipImage();
    if ((!result) && verboseMode)
    {
      logstream->lockCerr() << "warning: unable to flip image horizontally, ignoring." << endl;
      logstream->unlockCerr();
    }
  }

  currentImageRotation = pstateRotation;
  currentImageFlip = pstateFlip;

  return;
}


01822 OFCondition DVPresentationState::getOverlayData(
     size_t layer,
     size_t idx,
     const void *&overlayData,
     unsigned int &width,
     unsigned int &height,
     unsigned int &left_pos,
     unsigned int &top_pos,
     OFBool &isROI,
     Uint16 &fore,
     unsigned int bits)
{
   EM_Overlay mode = EMO_Default;
   if (currentImage && ((bits == 8) || (bits == 12)))
   {
     renderPixelData();
     Uint16 group = activationLayerList.getActivationGroup(graphicLayerList.getGraphicLayerName(layer), idx, OFFalse);
     if (group==0) return EC_IllegalCall;
     Uint16 back = 0;
     fore = (Uint16)DicomImageClass::maxval(bits);   /* 255 or 4095 */
     Uint16 pvalue = 65535;
     if (graphicLayerList.getGraphicLayerRecommendedDisplayValueGray(layer, pvalue) == EC_Normal)
         currentImage->convertPValueToDDL(pvalue, fore, bits);
     if (fore == 0)
         back = (Uint16)DicomImageClass::maxval(bits);
     const void *data = currentImage->getOverlayData((unsigned int)group, left_pos, top_pos, width, height, mode,
       currentImageSelectedFrame-1, bits, fore, back);
     if (EMO_RegionOfInterest == mode) isROI=OFTrue; else isROI=OFFalse;
     if (data) overlayData = data;
     else
     {
       overlayData = NULL;
       return EC_IllegalCall;
     }
   } else {
     overlayData = NULL;
     width = 0;
     height = 0;
     left_pos = 0;
     top_pos = 0;
     isROI = OFFalse;
     fore = 0;
     return EC_IllegalCall;
   }
   return EC_Normal;
}

01869 OFBool DVPresentationState::isInverse()
{
    return imageInverse;
}

01874 OFCondition DVPresentationState::invertImage()
{
  OFCondition status = presentationLUT.invert();
  currentImagePLUTValid = OFFalse; // PLUT has changed
  imageInverse = (imageInverse ? OFFalse : OFTrue);
  return status;
}


01883 OFCondition DVPresentationState::getPixelData(
     const void *&pixelData,
     unsigned long &width,
     unsigned long &height)
{
   if (currentImage)
   {
     renderPixelData();
     width = currentImage->getWidth();
     height = currentImage->getHeight();
     pixelData = currentImage->getOutputData(8, currentImageSelectedFrame-1);
   } else {
     pixelData = NULL;
     width = 0;
     height = 0;
     return EC_IllegalCall;
   }
   return EC_Normal;
}

01903 OFCondition DVPresentationState::getPixelData(
     void *pixelData,
     unsigned long size)
{
   if (currentImage)
   {
     renderPixelData();
     if (currentImage->getOutputData(pixelData, size, 8, currentImageSelectedFrame-1))
         return EC_Normal;
   }
   return EC_IllegalCall;
}

01916 OFCondition DVPresentationState::getImageMinMaxPixelRange(double &minValue, double& maxValue)
{
  OFCondition result = EC_IllegalCall;
  if (currentImage)
  {
    if (currentImage->getMinMaxValues(minValue, maxValue, 1)) result = EC_Normal;
  }
  return result;
}

01926 OFCondition DVPresentationState::getImageMinMaxPixelValue(double &minValue, double& maxValue)
{
  OFCondition result = EC_IllegalCall;
  if (currentImage)
  {
    if (currentImage->getMinMaxValues(minValue, maxValue, 0)) result = EC_Normal;
  }
  return result;
}

01936 OFCondition DVPresentationState::getImageNumberOfFrames(unsigned long &frames)
{
  if (currentImage)
  {
    frames = (unsigned long)(currentImage->getFrameCount());
    return EC_Normal;
  }
  return EC_IllegalCall;
}

01946 OFCondition DVPresentationState::selectImageFrameNumber(unsigned long frame)
{
  if ((frame > 0) && currentImage && (frame <= currentImage->getFrameCount()))
  {
    if (currentImageSelectedFrame != frame)
      currentImageVOIValid = OFFalse; // VOI might has changed
    currentImageSelectedFrame=frame;
    return EC_Normal;
  }
  return EC_IllegalCall;
}

01958 unsigned long DVPresentationState::getSelectedImageFrameNumber()
{
  if (currentImage)
  {
    if (currentImageSelectedFrame <= currentImage->getFrameCount())
      return currentImageSelectedFrame;
  }
  return 0;
}

01968 DVPSDisplayedArea *DVPresentationState::getDisplayedAreaSelection()
{
  if (currentImage==NULL) return NULL;
  DVPSDisplayedArea * area = displayedAreaSelectionList.findDisplayedArea(currentImageSOPInstanceUID, currentImageSelectedFrame);
  if (area==NULL)
  {
      if (verboseMode)
      {
        logstream->lockCerr() << "Warning: no displayed area selection item for current image found, creating default." << endl;
        logstream->unlockCerr();
      }
      if ((currentImageDataset)&&(EC_Normal == createDefaultDisplayedArea(*currentImageDataset)))
      {
        area = displayedAreaSelectionList.findDisplayedArea(currentImageSOPInstanceUID, currentImageSelectedFrame);
      }
  }
  return area;
}

01987 DVPSPresentationSizeMode DVPresentationState::getDisplayedAreaPresentationSizeMode()
{
  DVPSDisplayedArea * area = getDisplayedAreaSelection();
  if (area) return area->getPresentationSizeMode(); else return DVPSD_scaleToFit;
}

01993 double DVPresentationState::getDisplayedAreaPresentationPixelAspectRatio()
{
  DVPSDisplayedArea * area = getDisplayedAreaSelection();
  if (area) return area->getPresentationPixelAspectRatio(); else return 1.0;
}

01999 OFCondition DVPresentationState::getStandardDisplayedArea(Sint32& tlhcX, Sint32& tlhcY, Sint32& brhcX, Sint32& brhcY)
{
  DVPSDisplayedArea * area = getDisplayedAreaSelection();
  if (area)
  {
    area->getDisplayedArea(tlhcX, tlhcY, brhcX, brhcY);
    return EC_Normal;
  }
  return EC_IllegalCall;
}

02010 OFCondition DVPresentationState::getImageRelativeDisplayedArea(Sint32& tlhcX, Sint32& tlhcY, Sint32& brhcX, Sint32& brhcY)
{
  DVPSDisplayedArea * area = getDisplayedAreaSelection();
  if (area)
  {
    DVPSRotationType rotation = getRotation();
    OFBool flip = getFlip();
    area = area->clone(); // create temporary copy
    area->rotateAndFlip(rotation, flip, DVPSR_0_deg, OFFalse);
    area->getDisplayedArea(tlhcX, tlhcY, brhcX, brhcY);
    delete area;
    return EC_Normal;
  }
  return EC_IllegalCall;
}

02026 OFCondition DVPresentationState::getDisplayedAreaPresentationPixelSpacing(double& x, double& y)
{
  DVPSDisplayedArea * area = getDisplayedAreaSelection();
  if (area) return area->getPresentationPixelSpacing(x, y); else return EC_IllegalCall;
}

02032 OFCondition DVPresentationState::getDisplayedAreaPresentationPixelMagnificationRatio(double& magnification)
{
  DVPSDisplayedArea * area = getDisplayedAreaSelection();
  if (area) return area->getPresentationPixelMagnificationRatio(magnification); else return EC_IllegalCall;
}

02038 OFBool DVPresentationState::canUseDisplayedAreaTrueSize()
{
  DVPSDisplayedArea * area = getDisplayedAreaSelection();
  if (area) return area->canUseTrueSize(); else return OFFalse;
}

02044 OFCondition DVPresentationState::setStandardDisplayedArea(
     DVPSPresentationSizeMode sizeMode,
     Sint32 tlhcX, Sint32 tlhcY,
     Sint32 brhcX, Sint32 brhcY,
     double magnification,
     DVPSObjectApplicability applicability)
{
  if (currentImage == NULL) return EC_IllegalCall;

  // make sure that we have an old displayed area item that "knows" about pixel spacing/aspect ratio,
  // because we will only copy this data into the new item.
  DVPSDisplayedArea *area = getDisplayedAreaSelection();

  // find appropriate item, create new if necessary.
  area = displayedAreaSelectionList.createDisplayedArea(
      referencedSeriesList, currentImageSOPClassUID, currentImageSOPInstanceUID,
      currentImageSelectedFrame, currentImage->getFrameCount(), applicability);

  if (area) return area->setDisplayedArea(sizeMode, tlhcX, tlhcY, brhcX, brhcY, magnification);
  return EC_IllegalCall;
}

02066 OFCondition DVPresentationState::setImageRelativeDisplayedArea(
     DVPSPresentationSizeMode sizeMode,
     Sint32 tlhcX, Sint32 tlhcY,
     Sint32 brhcX, Sint32 brhcY,
     double magnification,
     DVPSObjectApplicability applicability)
{
  if (currentImage == NULL) return EC_IllegalCall;

  // make sure that we have an old displayed area item that "knows" about pixel spacing/aspect ratio,
  // because we will only copy this data into the new item.
  DVPSDisplayedArea *area = getDisplayedAreaSelection();

  // find appropriate item, create new if necessary.
  area = displayedAreaSelectionList.createDisplayedArea(
      referencedSeriesList, currentImageSOPClassUID, currentImageSOPInstanceUID,
      currentImageSelectedFrame, currentImage->getFrameCount(), applicability);

  if (area)
  {
     // get current rotation and flip status
     DVPSRotationType rotation = getRotation();
     OFBool flip = getFlip();

     // force rotation and flip status back to unrotated/unflipped
     // because in this case standard displayed area and image relative displayed area are the same
     area->rotateAndFlip(rotation, flip, DVPSR_0_deg, OFFalse);

     // set displayed area
     OFCondition result = area->setDisplayedArea(sizeMode, tlhcX, tlhcY, brhcX, brhcY, magnification);

     // restore rotation and flip status
     area->rotateAndFlip(DVPSR_0_deg, OFFalse, rotation, flip);

     return result;
  }
  return EC_IllegalCall;
}


02106 DVPSSoftcopyVOI *DVPresentationState::getCurrentSoftcopyVOI()
{
  if (currentImage==NULL) return NULL;
  return softcopyVOIList.findSoftcopyVOI(currentImageSOPInstanceUID, currentImageSelectedFrame);
}

02112 OFCondition DVPresentationState::getPrintBitmapRequestedImageSize(OFString& requestedImageSize)
{
  requestedImageSize.clear();
  if ((currentImage)&&(getDisplayedAreaPresentationSizeMode()==DVPSD_trueSize))
  {
    double x=0.0, y=0.0;
    if (EC_Normal == getDisplayedAreaPresentationPixelSpacing(x, y))
    {
      char c[80];
      DVPSRotationType rotation = getRotation();
      if ((rotation==DVPSR_90_deg)||(rotation==DVPSR_270_deg))
      {
        x = y * currentImageHeight; // physical height of unrotated image in mm
      } else {
        x *= currentImageWidth;  // physical width of unrotated image in mm
      }
      OFStandard::ftoa(c, sizeof(c), x, OFStandard::ftoa_format_f);

      requestedImageSize = c;
      return EC_Normal;
    }
  }
  return EC_IllegalCall;
}

02137 OFCondition DVPresentationState::writePresentationLUTforPrint(DcmItem &dset)
{
  OFCondition result = EC_Normal;
  if (currentImageMonochrome1)
  {
    // write inverted LUT because image is also converted to MONOCHROME2
    presentationLUT.invert();
    if (EC_Normal==result) result = presentationLUT.write(dset, OFFalse);
    presentationLUT.invert();
  } else result = presentationLUT.write(dset, OFFalse);
  return result;
}

02150 const char *DVPresentationState::getCurrentImageModality()
{
  char *c = NULL;
  if (EC_Normal == currentImageModality.getString(c)) return c; else return NULL;
}

02156 void DVPresentationState::setLog(OFConsole *stream, OFBool verbMode, OFBool dbgMode)
{
  DcmPresentationState::setLog(stream, verbMode, dbgMode);
  currentImageCurveList.setLog(logstream, verbMode, dbgMode);
  currentImageVOILUTList.setLog(logstream, verbMode, dbgMode);
  currentImageVOIWindowList.setLog(logstream, verbMode, dbgMode);
}


02165 const char *DVPresentationState::getAttachedImageSOPClassUID()
{
  return currentImageSOPClassUID;
}


02171 const char *DVPresentationState::getAttachedImageSOPInstanceUID()
{
  return currentImageSOPInstanceUID;
}


02177 OFCondition DVPresentationState::activateOverlayHelper(DVPSOverlay& ovl, DicomImage &image, OFBool asShutter, Uint16 pvalue)
{
  Sint16 originX=0;
  Sint16 originY=0;
  Uint16 sizeX=0;
  Uint16 sizeY=0;
  unsigned int group = ovl.getOverlayGroup() + 0x6000;
  EM_Overlay mode=EMO_Graphic;
  if (asShutter) mode=EMO_BitmapShutter; else if (ovl.isROI()) mode=EMO_RegionOfInterest;

  OFCondition result = ovl.getValues(originX, originY, sizeX, sizeY);
  if (result.good())
  {
    signed int left_pos = (signed int) originX;
    signed int top_pos = (signed int) originY;
    unsigned int columns = (unsigned int)sizeX;
    unsigned int rows = (unsigned int)sizeY;
    if (0 == image.addOverlay(group, left_pos, top_pos, columns, rows,
      ovl.getData(), ovl.getLabel(), ovl.getDescription(), mode))
        result = EC_IllegalCall;
    if ((asShutter)&&(EC_Normal==result))
    {
      if (0 == image.showOverlay(group, pvalue)) result = EC_IllegalCall;
    }
  }
  return result;
}

02205 OFCondition DVPresentationState::read(DcmItem &dset)
{
  OFCondition result = DcmPresentationState::read(dset);
  imageInverse = presentationLUT.isInverse();
  return result;
}

02212 OFCondition DVPresentationState::createFromImage(
  DcmItem &dset,
  DVPSoverlayActivation overlayActivation,
  DVPSVOIActivation voiActivation,
  OFBool curveActivation,
  OFBool shutterActivation,
  OFBool presentationActivation,
  DVPSGraphicLayering layering,
  const char *aetitle,
  const char *filesetID,
  const char *filesetUID)
{
  OFCondition result = DcmPresentationState::createFromImage(
    dset, overlayActivation, voiActivation, curveActivation, shutterActivation,
    presentationActivation, layering, aetitle, filesetID, filesetUID);
  imageInverse = presentationLUT.isInverse();
  return result;
}


/*
 *  $Log: dvpstat.cc,v $
 *  Revision 1.79  2004/02/04 15:57:49  joergr
 *  Removed acknowledgements with e-mail addresses from CVS log.
 *
 *  Revision 1.78  2003/09/05 14:30:08  meichel
 *  Introduced new API methods that allow Displayed Areas to be queried
 *    and set either relative to the image (ignoring rotation and flip) or
 *    in absolute values as defined in the standard.  Rotate and flip methods
 *    now adjust displayed areas in the presentation state.
 *
 *  Revision 1.77  2003/08/27 14:57:20  meichel
 *  Splitted class DVPresentationState into a base class DcmPresentationState
 *    that does not depend on module dcmimgle and current derived class with
 *    public API identical to the previous version.
 *
 *  Revision 1.76  2003/06/04 12:30:29  meichel
 *  Added various includes needed by MSVC5 with STL
 *
 *  Revision 1.75  2003/04/14 14:28:05  meichel
 *  Added explicit typecasts in calls to pow(). Needed by Visual C++ .NET 2003.
 *
 *  Revision 1.74  2002/12/09 13:28:16  joergr
 *  Renamed parameter/local variable to avoid name clashes with global
 *  declaration left and/or right (used for as iostream manipulators).
 *
 *  Revision 1.73  2002/12/04 10:41:38  meichel
 *  Changed toolkit to use OFStandard::ftoa instead of sprintf for all
 *    double to string conversions that are supposed to be locale independent
 *
 *  Revision 1.72  2002/11/27 15:48:15  meichel
 *  Adapted module dcmpstat to use of new header file ofstdinc.h
 *
 *  Revision 1.71  2002/04/16 14:02:22  joergr
 *  Added configurable support for C++ ANSI standard includes (e.g. streams).
 *
 *  Revision 1.70  2002/01/08 10:40:58  joergr
 *  Corrected spelling of function dcmGenerateUniqueIdentifier().
 *  Changed prefix of UIDs created for series and studies (now using constants
 *  SITE_SERIES_UID_ROOT and SITE_STUDY_UID_ROOT which are supposed to be used
 *  in these cases).
 *
 *  Revision 1.69  2001/11/28 13:57:05  joergr
 *  Check return value of DcmItem::insert() statements where appropriate to
 *  avoid memory leaks when insert procedure fails.
 *
 *  Revision 1.68  2001/09/28 13:50:14  joergr
 *  Added "#include <iomanip.h>" to keep gcc 3.0 quiet.
 *
 *  Revision 1.67  2001/09/26 15:36:34  meichel
 *  Adapted dcmpstat to class OFCondition
 *
 *  Revision 1.66  2001/06/01 15:50:39  meichel
 *  Updated copyright header
 *
 *  Revision 1.65  2000/11/13 15:50:46  meichel
 *  Added dcmpstat support methods for creating image references
 *    in SR documents.
 *
 *  Revision 1.64  2000/07/12 12:49:05  joergr
 *  Added comment.
 *
 *  Revision 1.63  2000/07/03 14:04:01  joergr
 *  Fixed bug: VOI LUT transform defined per frame was not supported by the
 *  method renderPixelData().
 *
 *  Revision 1.62  2000/06/09 10:15:37  joergr
 *  Added support for rendering inverse presentation LUT into print bitmaps.
 *
 *  Revision 1.61  2000/06/08 17:39:07  joergr
 *  Corrected bug in addImageReferenceToPState().
 *
 *  Revision 1.60  2000/06/08 10:44:38  meichel
 *  Implemented Referenced Presentation LUT Sequence on Basic Film Session level.
 *    Empty film boxes (pages) are not written to file anymore.
 *
 *  Revision 1.59  2000/06/02 16:01:08  meichel
 *  Adapted all dcmpstat classes to use OFConsole for log and error output
 *
 *  Revision 1.58  2000/06/02 12:48:04  joergr
 *  Reject invalid frame numbers in method selectImageFrameNumber().
 *
 *  Revision 1.57  2000/05/31 13:02:40  meichel
 *  Moved dcmpstat macros and constants into a common header file
 *
 *  Revision 1.56  2000/05/30 14:22:14  joergr
 *  Renamed some variables to avoid compiler warnings (reported by gcc 2.9x with
 *  additional compiler flags).
 *
 *  Revision 1.55  2000/05/30 13:59:16  joergr
 *  Removed methods which were already marked as "retired".
 *  Added new function allowing to set a VOILUT created from a given gamma
 *  value.
 *
 *  Revision 1.54  2000/03/08 16:29:11  meichel
 *  Updated copyright header.
 *
 *  Revision 1.53  2000/03/03 14:14:06  meichel
 *  Implemented library support for redirecting error messages into memory
 *    instead of printing them to stdout/stderr for GUI applications.
 *
 *  Revision 1.52  2000/02/23 15:12:57  meichel
 *  Corrected macro for Borland C++ Builder 4 workaround.
 *
 *  Revision 1.51  2000/02/01 11:54:45  meichel
 *  Avoiding to include <stdlib.h> as extern "C" on Borland C++ Builder 4,
 *    workaround for bug in compiler header files.
 *
 *  Revision 1.50  1999/11/15 19:03:13  joergr
 *  Changed behaviour of method getOverlayData(): parameter 'transp' replaced by
 *  'fore' to specify the foreground color used for the overlay plane.
 *  Fixed bug concerning the setting of window center and width for the preview
 *  image.
 *
 *  Revision 1.49  1999/11/12 16:51:54  meichel
 *  Corrected creation of circular shutters, X/Y coordinates were swapped.
 *
 *  Revision 1.48  1999/10/25 18:46:07  joergr
 *  Fixed bug caused by the incorrect order of x/y coordinates for circular
 *  and polygonal shutters (the DICOM standard is somehow inconsistent in this
 *  respect).
 *
 *  Revision 1.47  1999/10/22 09:08:23  joergr
 *  Added validity check to methods setting pixel aspect ratio and pixel
 *  spacing (>0). Fixed problems with incorrect pixel spacing (0\0) stored in
 *  sample images.
 *
 *  Revision 1.46  1999/10/20 18:41:20  joergr
 *  Added explicit type cast to make MSVC happy.
 *
 *  Revision 1.45  1999/10/20 11:01:16  joergr
 *  Enhanced method getOverlayData to support 12 bit data for print.
 *  Enhanced method convertPValueToDDL to support 12 bit data for print.
 *  Added support for a down-scaled preview image of the current DICOM image
 *  (e.g. useful for online-windowing or print preview).
 *  Always use the variable 'currentImageSelectedFrame' as the frame number,
 *  not 1.
 *
 *  Revision 1.44  1999/10/19 16:24:58  meichel
 *  Corrected handling of MONOCHROME1 images when used with P-LUTs
 *
 *  Revision 1.43  1999/10/18 10:18:52  joergr
 *  Use the current display shutter P-value for the border area of print
 *  bitmaps.
 *  Switch off time consuming interpolation for implicite scaling of print
 *  bitmaps.
 *
 *  Revision 1.42  1999/10/13 14:12:02  meichel
 *  Added config file entries and access methods
 *    for user-defined VOI presets, log directory, verbatim logging
 *    and an explicit list of image display formats for each printer.
 *
 *  Revision 1.41  1999/10/07 17:22:03  meichel
 *  Reworked management of Presentation LUTs in order to create tighter
 *    coupling between Softcopy and Print.
 *
 *  Revision 1.40  1999/10/06 13:24:50  joergr
 *  Fixed bug in renderPixelData: images haven't been flipped correctly for
 *  PrintBitmap.
 *  Corrected creation of PrintBitmap pixel data: VOI windows should be applied
 *  before clipping to avoid that the region outside the image (border) is also
 *  windowed (this requires a new method in dcmimgle to create a DicomImage
 *  with the grayscale transformations already applied).
 *
 *  Revision 1.39  1999/09/30 12:04:04  joergr
 *  Corrected typos and formatting; modified comments.
 *
 *  Revision 1.38  1999/09/20 13:22:23  joergr
 *  Corrected bug with clipping of rotated print bitmaps (removed inconsistency
 *  with 90 and 270 degree rotation).
 *
 *  Revision 1.37  1999/09/17 14:29:46  meichel
 *  Moved static helper functions to new class DVPSHelper, removed some unused code.
 *
 *  Revision 1.36  1999/09/13 14:01:23  thiel
 *  correction of DEBUG code for LIN_OD
 *
 *  Revision 1.35  1999/09/10 13:07:38  thiel
 *  correction of LIN OD in createFromImage
 *
 *  Revision 1.34  1999/09/10 12:46:58  meichel
 *  Added implementations for a number of print API methods.
 *
 *  Revision 1.33  1999/09/10 09:16:44  joergr
 *  Added support for CIELAB display function. New methods to handle display
 *  functions. Old methods are marked as retired and should be removed asap.
 *
 *  Revision 1.32  1999/09/10 07:32:44  thiel
 *  Added Presentation LUT Shape LIN OD
 *
 *  Revision 1.31  1999/09/07 09:05:13  joergr
 *  Completed support for getting a print bitmap out of a pstate object.
 *
 *  Revision 1.30  1999/09/01 16:15:11  meichel
 *  Added support for requested image size to print routines
 *
 *  Revision 1.29  1999/08/31 14:01:38  meichel
 *  Fixed print image crop boundary computation problem
 *
 *  Revision 1.28  1999/08/27 15:57:51  meichel
 *  Added methods for saving hardcopy images and stored print objects
 *    either in file or in the local database.
 *
 *  Revision 1.27  1999/08/25 16:51:17  joergr
 *  Added minimal support to get a print bitmap out of a pstate object.
 *
 *  Revision 1.26  1999/07/30 13:35:01  meichel
 *  Added new classes managing Stored Print objects
 *
 *  Revision 1.25  1999/07/28 07:57:26  meichel
 *  Minor correction for VC++ 5.
 *
 *  Revision 1.24  1999/07/22 16:40:04  meichel
 *  Adapted dcmpstat data structures and API to supplement 33 letter ballot text.
 *
 *  Revision 1.23  1999/07/14 12:03:44  meichel
 *  Updated data dictionary for supplement 29, 39, 33_lb, CP packet 4 and 5.
 *    Corrected dcmtk applications for changes in attribute name constants.
 *
 *  Revision 1.22  1999/05/04 15:27:27  meichel
 *  Minor code purifications to keep gcc on OSF1 quiet.
 *
 *  Revision 1.21  1999/05/03 11:01:38  joergr
 *  Minor code purifications to keep Sun CC 2.0.1 quiet.
 *
 *  Revision 1.20  1999/04/28 11:34:29  meichel
 *  When creating a presentation state for an image, modality rescale/slope
 *    without rescale type is handled now in a more lenient way.
 *
 *  Revision 1.19  1999/04/27 11:26:01  joergr
 *  Added method to check whether current image is inverse or not.
 *
 *  Revision 1.18  1999/03/22 09:52:42  meichel
 *  Reworked data dictionary based on the 1998 DICOM edition and the latest
 *    supplement versions. Corrected dcmtk applications for minor changes
 *    in attribute name constants.
 *
 *  Revision 1.17  1999/03/22 09:06:48  joergr
 *  Added parameter to get value of (transparent) background color for method
 *  getOverlayData.
 *
 *  Revision 1.16  1999/03/03 17:58:07  joergr
 *  Changed implementation of invertImage(): set modify flag for all plut types.
 *
 *  Revision 1.15  1999/03/03 14:02:03  joergr
 *  Changed implementation of invertImage() to avoid compiler errors on MSVC5
 *  ('return' has to be last statement).
 *
 *  Revision 1.14  1999/03/03 13:32:34  joergr
 *  Added method to invert an image by changing the presentation state LUT or
 *  shape.
 *  Changed implementation of method 'getOverlayData()': now conversion from
 *  P-value to DDL is implictly performed and the correct P-value for the related
 *  layer is used.
 *
 *  Revision 1.13  1999/02/25 18:41:42  joergr
 *  Added method to fill pixel data into an externally handled storage area.
 *  Added initialization of local variable to avoid compiler warnings (reported
 *  by gcc 2.7.2.1 on Linux).
 *
 *  Revision 1.12  1999/02/23 11:49:05  joergr
 *  Corrected bug: shutters were not saved correctly (sometimes even ignored).
 *
 *  Revision 1.11  1999/02/18 11:36:40  meichel
 *  Added new method convertPValueToDDL() to DVPresentationState
 *    that maps P-Values to DDLs.
 *
 *  Revision 1.10  1999/02/17 10:05:35  meichel
 *  Moved creation of Display Function object from DVPresentationState to
 *    DVInterface to avoid unnecessary re-reads.
 *
 *  Revision 1.9  1999/02/09 15:59:09  meichel
 *  Implemented bitmap shutter activation amd method for
 *    exchanging graphic layers.
 *
 *  Revision 1.8  1999/02/05 17:45:39  meichel
 *  Added config file entry for monitor characteristics file.  Monitor charac-
 *    teristics are passed to dcmimage if present to activate Barten transform.
 *
 *  Revision 1.7  1999/01/18 17:30:36  meichel
 *  Now preventing VOI Windows with a width <= 0.0.  Presentation label and
 *    creator's name are now correctly set.
 *
 *  Revision 1.6  1999/01/15 17:32:59  meichel
 *  added methods to DVPresentationState allowing to access the image
 *    references in the presentation state.  Also added methods allowing to
 *    get the width and height of the attached image.
 *
 *  Revision 1.5  1999/01/11 13:35:51  meichel
 *  added new methods getImageAspectRatio, getImageMinMaxPixelRange and
 *    getImageMinMaxPixelValue to class DVPresentationState.
 *
 *  Revision 1.4  1998/12/23 14:02:27  meichel
 *  Updated for changed interfaces in dcmimage overlays.
 *    Fixed bug affecting overlay origin delivered to dcmimage.
 *
 *  Revision 1.3  1998/12/22 17:57:18  meichel
 *  Implemented Presentation State interface for overlays,
 *    VOI LUTs, VOI windows, curves. Added test program that
 *    allows to add curve data to DICOM images.
 *
 *  Revision 1.2  1998/12/14 16:10:48  meichel
 *  Implemented Presentation State interface for graphic layers,
 *    text and graphic annotations, presentation LUTs.
 *
 *  Revision 1.1  1998/11/27 14:50:47  meichel
 *  Initial Release.
 *
 */

Generated by  Doxygen 1.6.0   Back to index