1 /*
2  *
3  *  Copyright (C) 1998-2017, OFFIS e.V.
4  *  All rights reserved.  See COPYRIGHT file for details.
5  *
6  *  This software and supporting documentation were developed by
7  *
8  *    OFFIS e.V.
9  *    R&D Division Health
10  *    Escherweg 2
11  *    D-26121 Oldenburg, Germany
12  *
13  *
14  *  Module: dcmpstat
15  *
16  *  Author: Marco Eichelberg
17  *
18  *  Purpose:
19  *    classes: DVPresentationState
20  *
21  */
22 
23 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
24 
25 #include "dcmtk/ofstd/ofstream.h"
26 #include "dcmtk/dcmpstat/dvpstat.h"
27 #include "dcmtk/dcmpstat/dvpsdef.h"     /* for constants and macros */
28 #include "dcmtk/ofstd/ofstring.h"
29 #include "dcmtk/dcmimgle/dcmimage.h"    /* for DicomImage */
30 #include "dcmtk/dcmpstat/dvpscu.h"      /* for DVPSCurve */
31 #include "dcmtk/dcmpstat/dvpsvl.h"      /* for DVPSVOILUT */
32 #include "dcmtk/dcmpstat/dvpsvw.h"      /* for DVPSVOIWindow */
33 #include "dcmtk/dcmpstat/dvpsov.h"      /* for DVPSOverlay */
34 #include "dcmtk/dcmpstat/dvpsda.h"      /* for DVPSDisplayedArea */
35 #include "dcmtk/dcmpstat/dvpssv.h"      /* for DVPSSoftcopyVOI */
36 #include "dcmtk/dcmpstat/dvpshlp.h"     /* for class DVPSHelper */
37 #include "dcmtk/ofstd/ofstd.h"       /* for class OFStandard */
38 
39 #include "dcmtk/dcmpstat/dvpsgl.h"      /* for DVPSGraphicLayer, needed by MSVC5 with STL */
40 #include "dcmtk/dcmpstat/dvpsrs.h"      /* for DVPSReferencedSeries, needed by MSVC5 with STL */
41 #include "dcmtk/dcmpstat/dvpsal.h"      /* for DVPSOverlayCurveActivationLayer, needed by MSVC5 with STL */
42 #include "dcmtk/dcmpstat/dvpsga.h"      /* for DVPSGraphicAnnotation, needed by MSVC5 with STL */
43 #include "dcmtk/dcmpstat/dvpsri.h"      /* for DVPSReferencedImage, needed by MSVC5 with STL */
44 #include "dcmtk/dcmpstat/dvpstx.h"      /* for DVPSTextObject, needed by MSVC5 with STL */
45 #include "dcmtk/dcmpstat/dvpsgr.h"      /* for DVPSGraphicObject, needed by MSVC5 with STL */
46 
47 #define INCLUDE_CSTDLIB
48 #define INCLUDE_CSTDIO
49 #define INCLUDE_CSTRING
50 #define INCLUDE_CMATH
51 #define INCLUDE_CTIME
52 #define INCLUDE_LIBC
53 #define INCLUDE_UNISTD
54 #include "dcmtk/ofstd/ofstdinc.h"
55 
56 /* --------------- class DVPresentationState --------------- */
57 
DVPresentationState(DiDisplayFunction ** dispFunction,unsigned long minPrintBitmapX,unsigned long minPrintBitmapY,unsigned long maxPrintBitmapX,unsigned long maxPrintBitmapY,unsigned long maxPreviewImageX,unsigned long maxPreviewImageY)58 DVPresentationState::DVPresentationState(
59     DiDisplayFunction **dispFunction,
60     unsigned long minPrintBitmapX,
61     unsigned long minPrintBitmapY,
62     unsigned long maxPrintBitmapX,
63     unsigned long maxPrintBitmapY,
64     unsigned long maxPreviewImageX,
65     unsigned long maxPreviewImageY)
66 : DcmPresentationState()
67 , currentImageDataset(NULL)
68 , currentImageFileformat(NULL)
69 , currentImage(NULL)
70 , previewImage(NULL)
71 , currentImageWidth(0)
72 , currentImageHeight(0)
73 , renderedImageWidth(0)
74 , renderedImageHeight(0)
75 , renderedImageTop(0)
76 , renderedImageLeft(0)
77 , renderedImageBottom(0)
78 , renderedImageRight(0)
79 , currentImageSOPClassUID(NULL)
80 , currentImageSOPInstanceUID(NULL)
81 , currentImageSelectedFrame(0)
82 , currentImageOwned(OFFalse)
83 , currentImageVOIValid(OFFalse)
84 , currentImagePLUTValid(OFFalse)
85 , currentImageFlip(OFFalse)
86 , currentImageRotation(DVPSR_0_deg)
87 , currentImageOverlaysValid(0)
88 , currentImageCurveList()
89 , currentImageVOILUTList()
90 , currentImageVOIWindowList()
91 , currentImageModality(DCM_Modality)
92 , currentImageMonochrome1(OFFalse)
93 , displayTransform(DVPSD_GSDF)
94 , imageInverse(OFFalse)
95 , displayFunction(dispFunction)
96 , minimumPrintBitmapWidth(minPrintBitmapX)
97 , minimumPrintBitmapHeight(minPrintBitmapY)
98 , maximumPrintBitmapWidth(maxPrintBitmapX)
99 , maximumPrintBitmapHeight(maxPrintBitmapY)
100 , maximumPreviewImageWidth(maxPreviewImageX)
101 , maximumPreviewImageHeight(maxPreviewImageY)
102 {
103   createInstanceUID();
104 }
105 
106 
~DVPresentationState()107 DVPresentationState::~DVPresentationState()
108 {
109   detachImage();
110 }
111 
detachImage()112 void DVPresentationState::detachImage()
113 {
114   if (currentImage) delete currentImage;
115   deletePreviewImage();
116   if (currentImageOwned)
117   {
118     if (currentImageFileformat) delete currentImageFileformat;
119     else if (currentImageDataset) delete currentImageDataset;
120   }
121   currentImage = NULL;
122   currentImageFileformat = NULL;
123   currentImageDataset = NULL;
124   currentImageCurveList.clear();
125   currentImageVOILUTList.clear();
126   currentImageVOIWindowList.clear();
127   currentImageModality.clear();
128   currentImageMonochrome1 = OFFalse;
129 
130   // reset flags
131   currentImageWidth = 0;
132   currentImageHeight = 0;
133   renderedImageWidth = 0;
134   renderedImageHeight = 0;
135   renderedImageTop = 0;
136   renderedImageLeft = 0;
137   renderedImageBottom = 0;
138   renderedImageRight = 0;
139   currentImageOwned = OFFalse;
140   currentImageVOIValid = OFFalse;
141   currentImagePLUTValid = OFFalse;
142   currentImageFlip = OFFalse;
143   currentImageRotation = DVPSR_0_deg;
144   currentImageOverlaysValid = 0;
145   currentImageSOPClassUID=NULL;
146   currentImageSOPInstanceUID=NULL;
147   currentImageSelectedFrame=0;
148 }
149 
150 
clear()151 void DVPresentationState::clear()
152 {
153   DcmPresentationState::clear();
154   detachImage(); // clears all currentImageXX attributes
155   // we do not change the display function
156   displayTransform = DVPSD_GSDF;
157   imageInverse = OFFalse;
158   return;
159 }
160 
161 
writeHardcopyImageAttributes(DcmItem & dset)162 OFCondition DVPresentationState::writeHardcopyImageAttributes(DcmItem &dset)
163 {
164   OFCondition result = EC_Normal;
165   DcmElement *delem=NULL;
166   DcmSequenceOfItems *dseq=NULL;
167   DcmItem *ditem=NULL;
168 
169   DVPSHelper::setDefault(result, patientName, DEFAULT_patientName);
170   ADD_TO_DATASET(DcmPersonName, patientName)
171   ADD_TO_DATASET(DcmLongString, patientID)
172   ADD_TO_DATASET(DcmDate, patientBirthDate)
173   ADD_TO_DATASET(DcmCodeString, patientSex)
174 
175   // write source image sequence
176   if (result == EC_Normal)
177   {
178     dseq = new DcmSequenceOfItems(DCM_SourceImageSequence);
179     if (dseq)
180     {
181       // first item references source image
182       if (currentImageSOPClassUID && currentImageSOPInstanceUID)
183       {
184         ditem = new DcmItem();
185         if (ditem)
186         {
187           delem = new DcmUniqueIdentifier(DCM_SOPClassUID);
188           if (delem)
189           {
190             result = delem->putString(currentImageSOPClassUID);
191             ditem->insert(delem, OFTrue /*replaceOld*/);
192           } else result=EC_MemoryExhausted;
193           delem = new DcmUniqueIdentifier(DCM_SOPInstanceUID);
194           if (delem)
195           {
196             result = delem->putString(currentImageSOPInstanceUID);
197             ditem->insert(delem, OFTrue /*replaceOld*/);
198           } else result=EC_MemoryExhausted;
199           if (EC_Normal == result) dseq->insert(ditem);  else delete ditem;
200         } else result = EC_MemoryExhausted;
201       }
202       // second item references presentation state
203       ditem = new DcmItem();
204       if (ditem)
205       {
206         delem = new DcmUniqueIdentifier(sOPInstanceUID);
207         if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
208         delem = new DcmUniqueIdentifier(DCM_SOPClassUID);
209         if (delem)
210         {
211           result = delem->putString(UID_GrayscaleSoftcopyPresentationStateStorage);
212           ditem->insert(delem, OFTrue /*replaceOld*/);
213         } else result=EC_MemoryExhausted;
214         if (EC_Normal == result) dseq->insert(ditem);  else delete ditem;
215        }
216     } else result = EC_MemoryExhausted;
217     if (EC_Normal == result) dset.insert(dseq, OFTrue /*replaceOld*/); else delete dseq;
218   }
219 
220   return result;
221 }
222 
getPrintBitmapSize()223 unsigned long DVPresentationState::getPrintBitmapSize()
224 {
225   unsigned long result = 0;
226   unsigned long width;
227   unsigned long height;
228   if (getPrintBitmapWidthHeight(width, height) == EC_Normal)
229     result = width * height * 2;       // print bitmap: 12 bit stored, 16 bit allocated (2 bytes per pixel)
230   return result;
231 }
232 
233 
setMinimumPrintBitmapWidthHeight(unsigned long width,unsigned long height)234 OFCondition DVPresentationState::setMinimumPrintBitmapWidthHeight(unsigned long width,
235                                                                   unsigned long height)
236 {
237   OFCondition result = EC_IllegalCall;
238   const unsigned long max = (width > height) ? width : height;
239   if (((maximumPrintBitmapWidth == 0) || (maximumPrintBitmapWidth >= 2 * max)) &&
240       ((maximumPrintBitmapHeight == 0) || (maximumPrintBitmapHeight >= 2 * max)))
241   {
242     minimumPrintBitmapWidth = width;
243     minimumPrintBitmapHeight = height;
244     result = EC_Normal;
245   }
246   return result;
247 }
248 
249 
setMaximumPrintBitmapWidthHeight(unsigned long width,unsigned long height)250 OFCondition DVPresentationState::setMaximumPrintBitmapWidthHeight(unsigned long width,
251                                                                   unsigned long height)
252 {
253   OFCondition result = EC_IllegalCall;
254   const unsigned long min = (width < height) ? width : height;
255   if (((minimumPrintBitmapWidth == 0) || (min >= 2 * minimumPrintBitmapWidth)) &&
256       ((minimumPrintBitmapHeight == 0) || (min >= 2 * minimumPrintBitmapHeight)))
257   {
258     maximumPrintBitmapWidth = width;
259     maximumPrintBitmapHeight = height;
260     result = EC_Normal;
261   }
262   return result;
263 }
264 
265 
getPrintBitmapWidthHeight(unsigned long & width,unsigned long & height)266 OFCondition DVPresentationState::getPrintBitmapWidthHeight(unsigned long &width,
267                                                            unsigned long &height)
268 {
269   OFCondition result = EC_Normal;
270   if (currentImage)
271   {
272     renderPixelData(OFFalse);                                 // switch off display function
273     width = renderedImageWidth;
274     height = renderedImageHeight;
275     if ((width > 0) && (height > 0))
276     {
277       width = (unsigned long)(renderedImageRight - renderedImageLeft + 1);
278       height = (unsigned long)(renderedImageBottom - renderedImageTop + 1);
279 
280       if ((minimumPrintBitmapWidth > 0) && (width < minimumPrintBitmapWidth))
281       {
282         if ((minimumPrintBitmapHeight > 0) && (height < minimumPrintBitmapHeight))
283         {
284           const unsigned long xfactor = (unsigned long)((double)(minimumPrintBitmapWidth - 1) / (double)width) + 1;
285           const unsigned long yfactor = (unsigned long)((double)(minimumPrintBitmapHeight - 1) / (double)height) + 1;
286           if (xfactor > yfactor)
287           {
288             width *= xfactor;
289             height *= xfactor;
290           } else {
291             width *= yfactor;
292             height *= yfactor;
293           }
294         } else {
295           const unsigned long factor = (unsigned long)((double)(minimumPrintBitmapWidth - 1) / (double)width) + 1;
296           width *= factor;
297           height *= factor;
298         }
299       }
300       else if ((minimumPrintBitmapHeight > 0) && (height < minimumPrintBitmapHeight))
301       {
302         const unsigned long factor = (unsigned long)((double)(minimumPrintBitmapHeight - 1) / (double)height) + 1;
303         width *= factor;
304         height *= factor;
305       }
306 
307       if ((maximumPrintBitmapWidth > 0) && (width > maximumPrintBitmapWidth))
308       {
309         if ((maximumPrintBitmapHeight > 0) && (height > maximumPrintBitmapHeight))
310         {
311           const unsigned long xdivisor = (unsigned long)((double)(width - 1) / (double)maximumPrintBitmapWidth) + 1;
312           const unsigned long ydivisor = (unsigned long)((double)(height - 1) / (double)maximumPrintBitmapHeight) + 1;
313           if (xdivisor > ydivisor)
314           {
315             width /= xdivisor;
316             height /= xdivisor;
317           } else {
318             width /= ydivisor;
319             height /= ydivisor;
320           }
321         } else {
322           const unsigned long divisor = (unsigned long)((double)(width - 1) / (double)maximumPrintBitmapWidth) + 1;
323           width /= divisor;
324           height /= divisor;
325         }
326       }
327       else if ((maximumPrintBitmapHeight > 0) && (height > maximumPrintBitmapHeight))
328       {
329         const unsigned long divisor = (unsigned long)((double)(height - 1) / (double)maximumPrintBitmapHeight) + 1;
330         width /= divisor;
331         height /= divisor;
332       }
333     }
334   } else {
335     width = 0;
336     height = 0;
337     result = EC_IllegalCall;
338   }
339   return result;
340 }
341 
342 
getPrintBitmapWidth(unsigned long & width)343 OFCondition DVPresentationState::getPrintBitmapWidth(unsigned long &width)
344 {
345   unsigned long dummy;
346   return getPrintBitmapWidthHeight(width, dummy);
347 }
348 
349 
getPrintBitmapHeight(unsigned long & height)350 OFCondition DVPresentationState::getPrintBitmapHeight(unsigned long &height)
351 {
352   unsigned long dummy;
353   return getPrintBitmapWidthHeight(dummy, height);
354 }
355 
356 
getPrintBitmapPixelAspectRatio()357 double DVPresentationState::getPrintBitmapPixelAspectRatio()
358 {
359   double result = getDisplayedAreaPresentationPixelAspectRatio();
360   if (result == 1.0) return result; // handle most frequent case quickly
361   if (result == 0.0) result = 1.0; // should never happen
362 
363   DVPSRotationType rotation = getRotation();
364   if ((rotation==DVPSR_90_deg)||(rotation==DVPSR_270_deg)) result = 1.0/result;
365   return result;
366 }
367 
368 
getPrintBitmap(void * bitmap,unsigned long size,OFBool inversePLUT)369 OFCondition DVPresentationState::getPrintBitmap(void *bitmap,
370                                                 unsigned long size,
371                                                 OFBool inversePLUT)
372 {
373   OFCondition result = EC_IllegalCall;
374   if ((bitmap != NULL) && (size == getPrintBitmapSize()))       // check given buffer
375   {
376     if (currentImage)
377     {
378       renderPixelData(OFFalse);                                 // don't use current display function
379       unsigned long width;
380       unsigned long height;
381       if (getPrintBitmapWidthHeight(width, height) == EC_Normal)
382       {
383         DicomImage *image = currentImage;
384 
385         /* we deactivate any presentation LUT at this point because
386          * getPrintBitmapWidthHeight() calls renderPixelData().
387          */
388         if (presentationLUT.getType() == DVPSP_table)
389         {
390           if (inversePLUT)
391           {
392             if (currentImageMonochrome1) currentImage->setPolarity(EPP_Reverse);
393             presentationLUT.activateInverseLUT(currentImage);
394           } else {
395             // we never render a presentation LUT into the print bitmap at this stage.
396             if (currentImageMonochrome1) currentImage->setPresentationLutShape(ESP_Inverse);
397             else currentImage->setPresentationLutShape(ESP_Identity);
398           }
399           // make sure the presentation LUT is re-activated for on-screen display
400           currentImagePLUTValid = OFFalse;
401         }
402 
403         /* clip to displayed area if necessary */
404         if ((renderedImageLeft != 1) || (renderedImageRight != (signed long)renderedImageWidth) ||
405             (renderedImageTop != 1) || (renderedImageBottom != (signed long)renderedImageHeight))
406         {
407           DicomImage *img = currentImage->createMonoOutputImage(currentImageSelectedFrame-1, 12 /*bits*/);
408           if (img == NULL)
409             img = currentImage;                                 // fall-back solution
410           image = img->createClippedImage(renderedImageLeft - 1, renderedImageTop - 1, renderedImageRight - renderedImageLeft + 1,
411             renderedImageBottom - renderedImageTop + 1, getShutterPresentationValue());
412           if (img != currentImage)
413             delete img;
414         }
415         /* scale up to minimum size or down to maximum size if necessary */
416         if (((signed long)width != renderedImageRight - renderedImageLeft + 1) ||
417            ((signed long)height != renderedImageBottom - renderedImageTop + 1))
418         {
419           DicomImage *img = image;
420           image = img->createScaledImage(width, height, 0 /*no interpolation*/, 0 /*ignore aspect ratio*/);
421           if (img != currentImage)
422             delete img;
423         }
424         if (image != NULL)
425         {
426           if (image->getOutputData(bitmap, size, 12 /*bits*/, currentImageSelectedFrame-1)) result = EC_Normal;
427         }
428         if (image != currentImage) delete image;
429       }
430     }
431   }
432   return result;
433 }
434 
435 
createPreviewImage(unsigned long maxWidth,unsigned long maxHeight,OFBool clipMode)436 OFCondition DVPresentationState::createPreviewImage(unsigned long maxWidth,
437                                                     unsigned long maxHeight,
438                                                     OFBool clipMode)
439 {
440   OFCondition result = EC_IllegalCall;
441   if ((currentImage != NULL) && (maxWidth > 0) && (maxHeight > 0))
442   {
443     deletePreviewImage();
444     renderPixelData();
445     unsigned long width = maxWidth;
446     unsigned long height = maxHeight;
447     double ratio = getPrintBitmapPixelAspectRatio();    // never 0 !
448     if ((double)renderedImageWidth / (double)maxWidth * ratio < (double)renderedImageHeight / (double)maxHeight)
449       width = 0;
450     else
451       height = 0;
452     if (clipMode)
453     {
454       /* not yet implemented: clip preview image to current displayed area */
455     }
456     double oldRatio = currentImage->getWidthHeightRatio();
457     currentImage->setWidthHeightRatio(ratio);
458     previewImage = currentImage->createScaledImage(width, height, 1 /*interpolate*/, 1 /*aspect ratio*/);
459     currentImage->setWidthHeightRatio(oldRatio);
460     if (previewImage != NULL)
461     {
462       if (previewImage->getStatus() == EIS_Normal)
463       {
464         previewImage->removeAllOverlays();
465         result = EC_Normal;
466       } else {
467         deletePreviewImage();
468       }
469     }
470   }
471   return result;
472 }
473 
474 
deletePreviewImage()475 void DVPresentationState::deletePreviewImage()
476 {
477   delete previewImage;
478   previewImage = NULL;
479 }
480 
481 
getPreviewImageSize()482 unsigned long DVPresentationState::getPreviewImageSize()
483 {
484   unsigned long result = 0;
485   unsigned long width;
486   unsigned long height;
487   if (getPreviewImageWidthHeight(width, height) == EC_Normal)
488       result = width * height;
489   return result;
490 }
491 
492 
getPreviewImageWidthHeight(unsigned long & width,unsigned long & height)493 OFCondition DVPresentationState::getPreviewImageWidthHeight(unsigned long &width,
494                                                             unsigned long &height)
495 {
496   OFCondition result = EC_IllegalCall;
497   if (previewImage != NULL)
498   {
499     width = previewImage->getWidth();
500     height = previewImage->getHeight();
501     if ((width > 0) && (height > 0))
502       result = EC_Normal;
503   } else {
504     width = 0;
505     height = 0;
506   }
507   return result;
508 }
509 
510 
getPreviewImageWidth(unsigned long & width)511 OFCondition DVPresentationState::getPreviewImageWidth(unsigned long &width)
512 {
513   unsigned long dummy;
514   return getPreviewImageWidthHeight(width, dummy);
515 }
516 
517 
getPreviewImageHeight(unsigned long & height)518 OFCondition DVPresentationState::getPreviewImageHeight(unsigned long &height)
519 {
520   unsigned long dummy;
521   return getPreviewImageWidthHeight(dummy, height);
522 }
523 
524 
getPreviewImageBitmap(void * bitmap,unsigned long size)525 OFCondition DVPresentationState::getPreviewImageBitmap(void *bitmap,
526                                                        unsigned long size)
527 {
528   OFCondition result = EC_IllegalCall;
529   if ((previewImage != NULL) && (bitmap != NULL) && (size > 0))
530   {
531     renderPixelData();
532     if (previewImage->getOutputData(bitmap, size, 8 /*bits*/, currentImageSelectedFrame-1))
533       result = EC_Normal;
534   }
535   return result;
536 }
537 
538 
attachImage(DcmDataset * dataset,OFBool transferOwnership)539 OFCondition DVPresentationState::attachImage(DcmDataset *dataset, OFBool transferOwnership)
540 {
541   if (!dataset) return EC_IllegalCall;
542 
543   // select the right DicomImage constructor depending on the Modality LUT
544   DicomImage *image = NULL;
545   if (useModalityRescale)
546   {
547     Float64 slope = 1.0;
548     Float64 intercept = 0.0;
549 
550     if (EC_Normal != rescaleSlope.getFloat64(slope, 0))
551     {
552       DCMPSTAT_WARN("unable to evaluate Modality Rescale Slope, ignoring.");
553       slope = 1.0;
554     }
555     if (EC_Normal != rescaleIntercept.getFloat64(intercept, 0))
556     {
557       DCMPSTAT_WARN("unable to evaluate Modality Rescale Slope, ignoring.");
558       intercept = 0.0;
559     }
560     image = new DicomImage(dataset, dataset->getOriginalXfer(),
561       slope, intercept, CIF_UsePresentationState);
562   }
563   else if (useModalityLUT)
564   {
565     image = new DicomImage(dataset, dataset->getOriginalXfer(),
566       modalityLUTData, modalityLUTDescriptor, &modalityLUTExplanation, CIF_UsePresentationState);
567   }
568   else
569   {
570     image = new DicomImage(dataset, dataset->getOriginalXfer(), CIF_UsePresentationState);
571   }
572 
573   OFCondition result = EC_Normal;
574   if (image)
575   {
576     if (EIS_Normal == image->getStatus())
577     {
578       OFString aString;
579       DcmStack stack;
580       detachImage();
581       currentImage = image;
582       currentImageWidth = image->getWidth();
583       currentImageHeight = image->getHeight();
584       currentImageDataset = dataset;
585       currentImageOwned = transferOwnership;
586       currentImageSelectedFrame = 1; // default: first frame
587 
588       // get Modality
589       if (EC_Normal == dataset->search(DCM_Modality, stack, ESM_fromHere, OFFalse))
590       {
591         currentImageModality = *((DcmCodeString *)(stack.top()));
592       }
593       stack.clear();
594 
595       // determine default Presentation LUT Shape
596       if (EC_Normal == dataset->search(DCM_PhotometricInterpretation, stack, ESM_fromHere, OFFalse))
597       {
598          DcmCodeString *photometricInterpretation = (DcmCodeString *)(stack.top());
599          if (photometricInterpretation->getVM() == 1)
600          {
601            aString.clear();
602            photometricInterpretation->getOFString(aString,0);
603            if ((aString == "MONOCHROME1")||(aString == "MONOCHROME 1")) currentImageMonochrome1 = OFTrue;
604          }
605       }
606       stack.clear();
607 
608       // get SOP class UID and SOP instance UID.
609       if ((EC_Normal == result)&&(EC_Normal == dataset->search(DCM_SOPClassUID, stack, ESM_fromHere, OFFalse)))
610       {
611         result = ((DcmUniqueIdentifier *)(stack.top()))->getString(currentImageSOPClassUID);
612       }
613       stack.clear();
614       if ((EC_Normal == result)&&(EC_Normal == dataset->search(DCM_SOPInstanceUID, stack, ESM_fromHere, OFFalse)))
615       {
616         result = ((DcmUniqueIdentifier *)(stack.top()))->getString(currentImageSOPInstanceUID);
617       }
618       if (EC_Normal==result) result = currentImageCurveList.read(*dataset);
619       if (EC_Normal==result) result = currentImageVOILUTList.read(*dataset);
620       if (EC_Normal==result) result = currentImageVOIWindowList.read(*dataset);
621 
622       createPreviewImage(maximumPreviewImageWidth, maximumPreviewImageHeight);
623     } else {
624       delete image;
625       result = EC_IllegalCall;
626     }
627   } else result = EC_MemoryExhausted;
628   return result;
629 }
630 
getImageWidth(unsigned long & width)631 OFCondition DVPresentationState::getImageWidth(unsigned long &width)
632 {
633   OFCondition result=EC_Normal;
634   if (currentImage) width = currentImageWidth;
635   else
636   {
637     width = 0;
638     result = EC_IllegalCall;
639   }
640   return result;
641 }
642 
getImageHeight(unsigned long & height)643 OFCondition DVPresentationState::getImageHeight(unsigned long &height)
644 {
645   OFCondition result=EC_Normal;
646   if (currentImage) height = currentImageHeight;
647   else
648   {
649     height = 0;
650     result = EC_IllegalCall;
651   }
652   return result;
653 }
654 
655 
attachImage(DcmFileFormat * fileformat,OFBool transferOwnership)656 OFCondition DVPresentationState::attachImage(DcmFileFormat *fileformat, OFBool transferOwnership)
657 {
658   if (fileformat == NULL) return EC_IllegalCall;
659   OFCondition result = attachImage(fileformat->getDataset(), transferOwnership);
660   if (EC_Normal == result) currentImageFileformat = fileformat;
661   return result;
662 }
663 
664 
addImageReferenceAttached(const char * aetitle,const char * filesetID,const char * filesetUID)665 OFCondition DVPresentationState::addImageReferenceAttached(
666     const char *aetitle,
667     const char *filesetID,
668     const char *filesetUID)
669 {
670   if (currentImageDataset) return addImageReference(*currentImageDataset, aetitle, filesetID, filesetUID);
671   else return EC_IllegalCall;
672 }
673 
674 
removeImageReferenceAttached()675 OFCondition DVPresentationState::removeImageReferenceAttached()
676 {
677   if (currentImageDataset) return removeImageReference(*currentImageDataset);
678   else return EC_IllegalCall;
679 }
680 
681 
682 
setCurrentPresentationLUT(DVPSPresentationLUTType newType)683 OFCondition DVPresentationState::setCurrentPresentationLUT(DVPSPresentationLUTType newType)
684 {
685   OFCondition result = presentationLUT.setType(newType);
686   currentImagePLUTValid = OFFalse; // PLUT has changed
687   imageInverse = presentationLUT.isInverse();
688   return result;
689 }
690 
setDefaultPresentationLUTShape()691 OFCondition DVPresentationState::setDefaultPresentationLUTShape()
692 {
693   OFCondition result = EC_Normal;
694   if (currentImageMonochrome1) result=presentationLUT.setType(DVPSP_inverse); else result=presentationLUT.setType(DVPSP_identity);
695   currentImagePLUTValid = OFFalse; // PLUT has changed
696   imageInverse = presentationLUT.isInverse();
697   return result;
698 }
699 
setPresentationLookupTable(DcmUnsignedShort & lutDescriptor,DcmUnsignedShort & lutData,DcmLongString & lutExplanation)700 OFCondition DVPresentationState::setPresentationLookupTable(
701     DcmUnsignedShort& lutDescriptor,
702     DcmUnsignedShort& lutData,
703     DcmLongString& lutExplanation)
704 {
705   OFCondition result = presentationLUT.setLUT(lutDescriptor, lutData, lutExplanation);
706   currentImagePLUTValid = OFFalse; // PLUT has changed
707   OFBool wasInverse = imageInverse;
708   imageInverse = presentationLUT.isInverse();
709 
710   // keep inverse/normal status as before
711   if ((wasInverse && (! imageInverse))||(imageInverse && (! wasInverse))) result = invertImage();
712   return result;
713 }
714 
setPresentationLookupTable(DcmItem & dset)715 OFCondition DVPresentationState::setPresentationLookupTable(DcmItem &dset)
716 {
717   OFCondition result = presentationLUT.read(dset, OFFalse);
718   if (EC_Normal != result) presentationLUT.setType(DVPSP_identity); // set to well-defined default in case of error
719   currentImagePLUTValid = OFFalse; // PLUT has changed
720   OFBool wasInverse = imageInverse;
721   imageInverse = presentationLUT.isInverse();
722 
723   // keep inverse/normal status as before
724   if ((wasInverse && (! imageInverse))||(imageInverse && (! wasInverse))) result = invertImage();
725   return result;
726 }
727 
728 
removeShutter(DVPSShutterType type)729 void DVPresentationState::removeShutter(DVPSShutterType type)
730 {
731   switch (type)
732   {
733     case DVPSU_rectangular:
734       useShutterRectangular = OFFalse;
735       break;
736     case DVPSU_circular:
737       useShutterCircular = OFFalse;
738       break;
739     case DVPSU_polygonal:
740       useShutterPolygonal = OFFalse;
741       break;
742     case DVPSU_bitmap:
743       if (useShutterBitmap) currentImageOverlaysValid = 1; // invalid but nothing added
744       useShutterBitmap = OFFalse;
745       break;
746   }
747   return;
748 }
749 
750 
setRectShutter(Sint32 lv,Sint32 rv,Sint32 uh,Sint32 lh)751 OFCondition DVPresentationState::setRectShutter(Sint32 lv, Sint32 rv, Sint32 uh, Sint32 lh)
752 {
753   OFCondition result=EC_Normal;
754   char buf[80];
755 
756   sprintf(buf, "%ld", (long)lv);
757   result = shutterLeftVerticalEdge.putString(buf);
758   sprintf(buf, "%ld", (long)rv);
759   if (EC_Normal==result) result = shutterRightVerticalEdge.putString(buf);
760   sprintf(buf, "%ld", (long)uh);
761   if (EC_Normal==result) result = shutterUpperHorizontalEdge.putString(buf);
762   sprintf(buf, "%ld", (long)lh);
763   if (EC_Normal==result) result = shutterLowerHorizontalEdge.putString(buf);
764   if ((EC_Normal==result)&&(shutterPresentationValue.getLength()==0))
765       result = shutterPresentationValue.putUint16(0,0);
766   if (EC_Normal==result)
767   {
768     useShutterRectangular = OFTrue;
769     if (useShutterBitmap) currentImageOverlaysValid = 1; // invalid but nothing added
770     useShutterBitmap = OFFalse;
771   }
772   return result;
773 }
774 
775 
setCircularShutter(Sint32 centerX,Sint32 centerY,Sint32 radius)776 OFCondition DVPresentationState::setCircularShutter(Sint32 centerX, Sint32 centerY, Sint32 radius)
777 {
778   OFCondition result=EC_Normal;
779   char buf[80];
780 
781   sprintf(buf, "%ld\\%ld", (long)centerY, (long)centerX);
782   result = centerOfCircularShutter.putString(buf);
783   sprintf(buf, "%ld", (long)radius);
784   if (EC_Normal==result) result = radiusOfCircularShutter.putString(buf);
785   if ((EC_Normal==result)&&(shutterPresentationValue.getLength()==0))
786       result = shutterPresentationValue.putUint16(0,0);
787   if (EC_Normal==result)
788   {
789     useShutterCircular = OFTrue;
790     if (useShutterBitmap) currentImageOverlaysValid = 1; // invalid but nothing added
791     useShutterBitmap = OFFalse;
792   }
793   return result;
794 }
795 
796 
addPolyShutterVertex(Sint32 x,Sint32 y)797 OFCondition DVPresentationState::addPolyShutterVertex(Sint32 x, Sint32 y)
798 {
799   if (verticesOfThePolygonalShutter.getLength()==0) return EC_IllegalCall;
800   OFString aString;
801   OFCondition result = verticesOfThePolygonalShutter.getOFStringArray(aString,OFTrue);
802   if (result==EC_Normal)
803   {
804     char buf[80];
805     sprintf(buf, "\\%ld\\%ld", (long)y, (long)x);
806     aString += buf;
807     result = verticesOfThePolygonalShutter.putOFStringArray(aString);
808   }
809 
810   if (result==EC_Normal)
811   {
812     Sint32 xp0 = 0;
813     Sint32 yp0 = 0;
814     result = getPolyShutterVertex(0, xp0, yp0);
815     if (result==EC_Normal)
816     {
817       if ((xp0==x)&&(yp0==y)) // polygon is closed now, activate.
818       {
819         if (shutterPresentationValue.getLength()==0)
820            result = shutterPresentationValue.putUint16(0,0);
821         if (EC_Normal==result)
822         {
823           useShutterPolygonal = OFTrue;
824           if (useShutterBitmap) currentImageOverlaysValid = 1; // invalid but nothing added
825           useShutterBitmap = OFFalse;
826         }
827       }
828     }
829   }
830   return result;
831 }
832 
removeGraphicLayer(size_t idx)833 OFCondition DVPresentationState::removeGraphicLayer(size_t idx)
834 {
835   const char *name = graphicLayerList.getGraphicLayerName(idx);
836   if (name==NULL) return EC_IllegalCall;
837   activationLayerList.removeLayer(name);
838   currentImageOverlaysValid = 1; // invalid but nothing added
839   graphicAnnotationList.removeLayer(name);
840   return graphicLayerList.removeGraphicLayer(idx);
841 }
842 
getNumberOfTextObjects(size_t layer)843 size_t DVPresentationState::getNumberOfTextObjects(size_t layer)
844 {
845   if (!currentImage) return 0;
846   return graphicAnnotationList.getNumberOfTextObjects(graphicLayerList.getGraphicLayerName(layer), currentImageSOPInstanceUID, currentImageSelectedFrame);
847 }
848 
getTextObject(size_t layer,size_t idx)849 DVPSTextObject *DVPresentationState::getTextObject(size_t layer, size_t idx)
850 {
851   if (!currentImage) return NULL;
852   return graphicAnnotationList.getTextObject(graphicLayerList.getGraphicLayerName(layer), currentImageSOPInstanceUID, currentImageSelectedFrame, idx);
853 }
854 
addTextObject(size_t layer,DVPSObjectApplicability applicability)855 DVPSTextObject *DVPresentationState::addTextObject(size_t layer, DVPSObjectApplicability applicability)
856 {
857   if (!currentImage) return NULL;
858   return graphicAnnotationList.addTextObject(graphicLayerList.getGraphicLayerName(layer), currentImageSOPClassUID,
859     currentImageSOPInstanceUID, currentImageSelectedFrame, applicability);
860 }
861 
removeTextObject(size_t layer,size_t idx)862 OFCondition DVPresentationState::removeTextObject(size_t layer, size_t idx)
863 {
864   if (!currentImage) return EC_IllegalCall;
865   return graphicAnnotationList.removeTextObject(graphicLayerList.getGraphicLayerName(layer), currentImageSOPInstanceUID, currentImageSelectedFrame, idx);
866 }
867 
moveTextObject(size_t old_layer,size_t idx,size_t new_layer,DVPSObjectApplicability applicability)868 OFCondition DVPresentationState::moveTextObject(size_t old_layer, size_t idx, size_t new_layer, DVPSObjectApplicability applicability)
869 {
870   if (!currentImage) return EC_IllegalCall;
871   if (old_layer==new_layer) return EC_Normal;
872   return graphicAnnotationList.moveTextObject(
873     graphicLayerList.getGraphicLayerName(old_layer),
874     currentImageSOPClassUID,
875     currentImageSOPInstanceUID,
876     currentImageSelectedFrame,
877     idx,
878     applicability,
879     graphicLayerList.getGraphicLayerName(new_layer));
880 }
881 
getNumberOfGraphicObjects(size_t layer)882 size_t DVPresentationState::getNumberOfGraphicObjects(size_t layer)
883 {
884   if (!currentImage) return 0;
885   return graphicAnnotationList.getNumberOfGraphicObjects(graphicLayerList.getGraphicLayerName(layer), currentImageSOPInstanceUID, currentImageSelectedFrame);
886 }
887 
getGraphicObject(size_t layer,size_t idx)888 DVPSGraphicObject *DVPresentationState::getGraphicObject(size_t layer, size_t idx)
889 {
890   if (!currentImage) return NULL;
891   return graphicAnnotationList.getGraphicObject(graphicLayerList.getGraphicLayerName(layer), currentImageSOPInstanceUID, currentImageSelectedFrame, idx);
892 }
893 
addGraphicObject(size_t layer,DVPSObjectApplicability applicability)894 DVPSGraphicObject *DVPresentationState::addGraphicObject(size_t layer, DVPSObjectApplicability applicability)
895 {
896   if (!currentImage) return NULL;
897   return graphicAnnotationList.addGraphicObject(graphicLayerList.getGraphicLayerName(layer), currentImageSOPClassUID,
898     currentImageSOPInstanceUID, currentImageSelectedFrame, applicability);
899 }
900 
removeGraphicObject(size_t layer,size_t idx)901 OFCondition DVPresentationState::removeGraphicObject(size_t layer, size_t idx)
902 {
903   if (!currentImage) return EC_IllegalCall;
904   return graphicAnnotationList.removeGraphicObject(graphicLayerList.getGraphicLayerName(layer), currentImageSOPInstanceUID, currentImageSelectedFrame, idx);
905 }
906 
moveGraphicObject(size_t old_layer,size_t idx,size_t new_layer,DVPSObjectApplicability applicability)907 OFCondition DVPresentationState::moveGraphicObject(size_t old_layer, size_t idx, size_t new_layer, DVPSObjectApplicability applicability)
908 {
909   if (!currentImage) return EC_IllegalCall;
910   if (old_layer==new_layer) return EC_Normal;
911   return graphicAnnotationList.moveGraphicObject(
912     graphicLayerList.getGraphicLayerName(old_layer),
913     currentImageSOPClassUID,
914     currentImageSOPInstanceUID,
915     currentImageSelectedFrame,
916     idx,
917     applicability,
918     graphicLayerList.getGraphicLayerName(new_layer));
919 }
920 
921 
getCurve(size_t layer,size_t idx)922 DVPSCurve *DVPresentationState::getCurve(size_t layer, size_t idx)
923 {
924   Uint16 rgroup = activationLayerList.getActivationGroup(
925     graphicLayerList.getGraphicLayerName(layer), idx, OFTrue);
926   if (rgroup==0) return NULL;
927   else return currentImageCurveList.getCurveGroup(rgroup);
928 }
929 
getNumberOfCurvesInImage()930 size_t DVPresentationState::getNumberOfCurvesInImage()
931 {
932   return currentImageCurveList.size();
933 }
934 
getCurveInImage(size_t idx)935 DVPSCurve *DVPresentationState::getCurveInImage(size_t idx)
936 {
937   return currentImageCurveList.getCurve(idx);
938 }
939 
addCurve(size_t layer,size_t curveidxinimage)940 OFCondition DVPresentationState::addCurve(size_t layer, size_t curveidxinimage)
941 {
942   const char *lname = graphicLayerList.getGraphicLayerName(layer);
943   DVPSCurve *curve = currentImageCurveList.getCurve(curveidxinimage);
944   if ((curve==NULL)||(lname==NULL)) return EC_IllegalCall;
945   return activationLayerList.setActivation(0x5000 + curve->getCurveGroup(), lname);
946 }
947 
haveActiveVOIWindow()948 OFBool DVPresentationState::haveActiveVOIWindow()
949 {
950   DVPSSoftcopyVOI *voi = getCurrentSoftcopyVOI();
951   if (voi)
952   {
953     if (voi->haveLUT()) return OFFalse; else return OFTrue;
954   }
955   return OFFalse;
956 }
957 
haveActiveVOILUT()958 OFBool DVPresentationState::haveActiveVOILUT()
959 {
960   DVPSSoftcopyVOI *voi = getCurrentSoftcopyVOI();
961   if (voi) return voi->haveLUT();
962   return OFFalse;
963 }
964 
getCurrentVOIDescription()965 const char *DVPresentationState::getCurrentVOIDescription()
966 {
967   DVPSSoftcopyVOI *voi = getCurrentSoftcopyVOI();
968   if (voi) return voi->getCurrentVOIDescription();
969   return NULL;
970 }
971 
getCurrentWindowWidth(double & w)972 OFCondition DVPresentationState::getCurrentWindowWidth(double &w)
973 {
974   DVPSSoftcopyVOI *voi = getCurrentSoftcopyVOI();
975   if (voi) return voi->getCurrentWindowWidth(w);
976   return EC_IllegalCall;
977 }
978 
getCurrentWindowCenter(double & c)979 OFCondition DVPresentationState::getCurrentWindowCenter(double &c)
980 {
981   DVPSSoftcopyVOI *voi = getCurrentSoftcopyVOI();
982   if (voi) return voi->getCurrentWindowCenter(c);
983   return EC_IllegalCall;
984 }
985 
getNumberOfVOILUTsInImage()986 size_t DVPresentationState::getNumberOfVOILUTsInImage()
987 {
988   return currentImageVOILUTList.size();
989 }
990 
getNumberOfVOIWindowsInImage()991 size_t DVPresentationState::getNumberOfVOIWindowsInImage()
992 {
993   return currentImageVOIWindowList.size();
994 }
995 
getDescriptionOfVOILUTsInImage(size_t idx)996 const char *DVPresentationState::getDescriptionOfVOILUTsInImage(size_t idx)
997 {
998   DVPSVOILUT *lut = currentImageVOILUTList.getVOILUT(idx);
999   if (lut==NULL) return NULL;
1000   return lut->getExplanation();
1001 }
1002 
getDescriptionOfVOIWindowsInImage(size_t idx)1003 const char *DVPresentationState::getDescriptionOfVOIWindowsInImage(size_t idx)
1004 {
1005   DVPSVOIWindow *window = currentImageVOIWindowList.getVOIWindow(idx);
1006   if (window==NULL) return NULL;
1007   return window->getExplanation();
1008 }
1009 
setVOILUTFromImage(size_t idx,DVPSObjectApplicability applicability)1010 OFCondition DVPresentationState::setVOILUTFromImage(size_t idx,
1011     DVPSObjectApplicability applicability)
1012 {
1013   if (currentImage == NULL) return EC_IllegalCall;
1014 
1015   DVPSVOILUT *lut = currentImageVOILUTList.getVOILUT(idx);
1016   if (lut)
1017   {
1018     currentImageVOIValid = OFFalse; // VOI has changed
1019 
1020     DVPSSoftcopyVOI *voi = softcopyVOIList.createSoftcopyVOI(
1021       referencedSeriesList, currentImageSOPClassUID, currentImageSOPInstanceUID,
1022       currentImageSelectedFrame, currentImage->getFrameCount(), applicability);
1023     if (voi) return lut->assign(*voi);
1024   }
1025   return EC_IllegalCall;
1026 }
1027 
setVOIWindowFromImage(size_t idx,DVPSObjectApplicability applicability)1028 OFCondition DVPresentationState::setVOIWindowFromImage(size_t idx,
1029     DVPSObjectApplicability applicability)
1030 {
1031   currentImageVOIValid = OFFalse; // VOI has changed
1032   DVPSVOIWindow *window = currentImageVOIWindowList.getVOIWindow(idx);
1033   if (window)
1034   {
1035     return setVOIWindow(window->getWindowCenter(),
1036       window->getWindowWidth(), window->getExplanation(), applicability);
1037   }
1038   return EC_IllegalCall;
1039 }
1040 
setVOIWindow(double wCenter,double wWidth,const char * description,DVPSObjectApplicability applicability)1041 OFCondition DVPresentationState::setVOIWindow(double wCenter, double wWidth, const char *description,
1042     DVPSObjectApplicability applicability)
1043 {
1044   if (currentImage == NULL) return EC_IllegalCall;
1045   currentImageVOIValid = OFFalse; // VOI has changed
1046   DVPSSoftcopyVOI *voi = softcopyVOIList.createSoftcopyVOI(
1047       referencedSeriesList, currentImageSOPClassUID, currentImageSOPInstanceUID,
1048       currentImageSelectedFrame, currentImage->getFrameCount(), applicability);
1049   if (voi) return voi->setVOIWindow(wCenter, wWidth, description);
1050   return EC_IllegalCall;
1051 }
1052 
setVOILUT(DcmUnsignedShort & lutDescriptor,DcmUnsignedShort & lutData,DcmLongString & lutExplanation,DVPSObjectApplicability applicability)1053 OFCondition DVPresentationState::setVOILUT(
1054     DcmUnsignedShort& lutDescriptor,
1055     DcmUnsignedShort& lutData,
1056     DcmLongString& lutExplanation,
1057     DVPSObjectApplicability applicability)
1058 {
1059   if (lutData.getLength() == 0) return EC_IllegalCall;
1060   if (lutDescriptor.getVM() != 3) return EC_IllegalCall;
1061   if (currentImage == NULL) return EC_IllegalCall;
1062 
1063   currentImageVOIValid = OFFalse; // VOI has changed
1064   DVPSSoftcopyVOI *voi = softcopyVOIList.createSoftcopyVOI(
1065       referencedSeriesList, currentImageSOPClassUID, currentImageSOPInstanceUID,
1066       currentImageSelectedFrame, currentImage->getFrameCount(), applicability);
1067   if (voi) return voi->setVOILUT(lutDescriptor, lutData, lutExplanation);
1068   return EC_IllegalCall;
1069 }
1070 
deactivateVOI(DVPSObjectApplicability applicability)1071 void DVPresentationState::deactivateVOI(DVPSObjectApplicability applicability)
1072 {
1073   if (currentImage == NULL) return;
1074   currentImageVOIValid = OFFalse; // VOI has changed
1075   softcopyVOIList.removeSoftcopyVOI(
1076       referencedSeriesList, currentImageSOPInstanceUID,
1077       currentImageSelectedFrame, currentImage->getFrameCount(), applicability);
1078   return;
1079 }
1080 
setGammaVOILUT(double gammaValue,DVPSObjectApplicability applicability)1081 OFCondition DVPresentationState::setGammaVOILUT(double gammaValue, DVPSObjectApplicability applicability)
1082 {
1083   if (currentImage == NULL) return EC_IllegalCall;
1084 
1085   OFCondition status = EC_IllegalCall;
1086   const unsigned int numberOfBits = 16;
1087   unsigned long numberOfEntries = 0;
1088   signed long firstMapped = 0;
1089   if (haveActiveVOIWindow())    // use active VOI window to specify the LUT descriptor
1090   {
1091     double ww, wc;
1092     if ((getCurrentWindowWidth(ww) == EC_Normal) && (getCurrentWindowCenter(wc) == EC_Normal))
1093     {
1094       if (ww <= 65536)
1095       {
1096         numberOfEntries = (unsigned long)ww;
1097         firstMapped = (signed long)(wc - ww / 2);
1098       }
1099     }
1100   }
1101   if (numberOfEntries == 0)     // no valid VOI window, use whole pixel range
1102   {
1103     double min, max;
1104     if (getImageMinMaxPixelRange(min, max) == EC_Normal)
1105     {
1106       if (max - min < 65536.0)
1107       {
1108         numberOfEntries = (unsigned long)(max - min + 1.0);
1109         firstMapped = (signed long)min;
1110       }
1111     }
1112   }
1113 
1114   if ((numberOfEntries > 0) && (numberOfEntries <= 65536) &&
1115      (((firstMapped >= -32768) && (firstMapped <= 32767)) || ((firstMapped >= 0) && (firstMapped <= 65535))))
1116   {
1117     Uint16 *data = new Uint16[numberOfEntries];
1118     if (data != NULL)
1119     {
1120       /* calculate gamma curve */
1121       const Uint16 maxValue = 0xFFFF >> (16 - numberOfBits);
1122       double step = (double)maxValue / ((double)numberOfEntries - 1.0);
1123       double gammaExp = 1.0 / gammaValue;
1124       double factor = (double)maxValue / pow((double)maxValue, gammaExp);
1125       unsigned long i;
1126       for (i = 0; i < numberOfEntries; i++)
1127         data[i]= (Uint16)(factor * pow(i * step, gammaExp));
1128 
1129       Uint16 numEntries16 = 0;
1130       if (numberOfEntries < 65536)
1131         numEntries16 = (Uint16)numberOfEntries;
1132 
1133       /* LUT Descriptor */
1134       DcmElement *lutDescriptor = NULL;
1135       if (firstMapped < 0)
1136       {
1137         // LUT Descriptor is SS
1138         lutDescriptor = new DcmSignedShort(DcmTag(DCM_LUTDescriptor, EVR_SS));
1139         if (lutDescriptor != NULL)
1140         {
1141             status = lutDescriptor->putSint16((Sint16)numEntries16, 0);
1142             if (EC_Normal == status)
1143               status = lutDescriptor->putSint16((Sint16)firstMapped, 1);
1144             if (EC_Normal == status)
1145               status = lutDescriptor->putSint16((Sint16)numberOfBits, 2);
1146         } else
1147           status = EC_MemoryExhausted;
1148       } else {
1149         // LUT Descriptor is US
1150         lutDescriptor = new DcmUnsignedShort(DcmTag(DCM_LUTDescriptor, EVR_US));
1151         if (lutDescriptor != NULL)
1152         {
1153             status = lutDescriptor->putUint16(numEntries16, 0);
1154             if (EC_Normal == status)
1155               status = lutDescriptor->putUint16((Uint16)firstMapped, 1);
1156             if (EC_Normal == status)
1157               status = lutDescriptor->putUint16((Uint16)numberOfBits, 2);
1158         } else
1159             status = EC_MemoryExhausted;
1160       }
1161 
1162       /* LUT Data */
1163       DcmElement *lutData = NULL;
1164       if (status == EC_Normal)
1165       {
1166         // LUT Data as OW, because of max size = 64K
1167         lutData = new DcmOtherByteOtherWord(DcmTag(DCM_LUTData, EVR_OW));
1168         if (lutData != NULL)
1169           status = lutData->putUint16Array(data, numberOfEntries);
1170         else
1171           status = EC_MemoryExhausted;
1172       }
1173 
1174       /* LUT Explanation */
1175       DcmLongString *lutExplanation = NULL;
1176       if (status == EC_Normal)
1177       {
1178         char explanation[100];
1179         char gammabuf[16];
1180         OFStandard::ftoa(gammabuf, sizeof(gammabuf), gammaValue, OFStandard::ftoa_format_f, 3, 1);
1181 
1182         sprintf(explanation, "LUT with gamma %s, descriptor %u/%ld/%u", gammabuf,
1183                (numberOfEntries < 65536) ? (Uint16)numberOfEntries : 0, firstMapped, numberOfBits);
1184 
1185         lutExplanation = new DcmLongString(DCM_LUTExplanation);
1186         if (lutExplanation != NULL)
1187           status = lutExplanation->putString(explanation);
1188         else
1189           status = EC_MemoryExhausted;
1190       }
1191 
1192       /* set VOI LUT */
1193       if (status == EC_Normal)
1194       {
1195         if ((lutDescriptor != NULL) && (lutData != NULL) && (lutExplanation !=  NULL))
1196           status = setVOILUT(*(DcmUnsignedShort *)lutDescriptor, *(DcmUnsignedShort *)lutData, *lutExplanation, applicability);
1197       }
1198 
1199       /* delete temporary dcmtk structures */
1200       delete lutDescriptor;
1201       delete lutData;
1202       delete lutExplanation;
1203     } else
1204       status = EC_MemoryExhausted;
1205     delete[] data;
1206   }
1207   return status;
1208 }
1209 
1210 
getActiveOverlayLabel(size_t layer,size_t idx)1211 const char *DVPresentationState::getActiveOverlayLabel(size_t layer, size_t idx)
1212 {
1213   Uint16 group = getActiveOverlayGroup(layer, idx);
1214   if (group==0) return NULL;
1215   DVPSOverlay *internalOverlay = overlayList.getOverlayGroup(group);
1216   if (internalOverlay) return internalOverlay->getOverlayLabel();
1217   if (currentImage) return currentImage->getOverlayLabel(group);
1218   return NULL;
1219 }
1220 
getActiveOverlayDescription(size_t layer,size_t idx)1221 const char *DVPresentationState::getActiveOverlayDescription(size_t layer, size_t idx)
1222 {
1223   Uint16 group = getActiveOverlayGroup(layer, idx);
1224   if (group==0) return NULL;
1225   DVPSOverlay *internalOverlay = overlayList.getOverlayGroup(group);
1226   if (internalOverlay) return internalOverlay->getOverlayDescription();
1227   if (currentImage) return currentImage->getOverlayDescription(group);
1228   return NULL;
1229 }
1230 
activeOverlayIsROI(size_t layer,size_t idx)1231 OFBool DVPresentationState::activeOverlayIsROI(size_t layer, size_t idx)
1232 {
1233   Uint16 group = getActiveOverlayGroup(layer, idx);
1234   if (group==0) return OFFalse;
1235   DVPSOverlay *internalOverlay = overlayList.getOverlayGroup(group);
1236   if (internalOverlay) return internalOverlay->isROI();
1237   if ((currentImage)&&(EMO_RegionOfInterest == currentImage->getOverlayMode(group))) return OFTrue;
1238   return OFFalse;
1239 }
1240 
getNumberOfOverlaysInImage()1241 size_t DVPresentationState::getNumberOfOverlaysInImage()
1242 {
1243   if (currentImage == NULL) return 0;
1244 
1245   unsigned int numOverlays=currentImage->getOverlayCount();
1246   size_t result = (size_t) numOverlays;
1247   Uint16 group;
1248   for (unsigned int i=0; i<numOverlays; i++)
1249   {
1250     // ignore all overlays which are shadowed by the presentation state
1251     group = (Uint16)(currentImage->getOverlayGroupNumber(i));
1252     if ((group==0)||(overlayList.haveOverlayGroup(group))) result--;
1253   }
1254   return result;
1255 }
1256 
1257 
getOverlayInImageGroup(size_t idx)1258 Uint16 DVPresentationState::getOverlayInImageGroup(size_t idx)
1259 {
1260   if (currentImage == NULL) return 0;
1261 
1262   size_t currentIndex = 0;
1263   Uint16 group;
1264   do
1265   {
1266     group = (Uint16) (currentImage->getOverlayGroupNumber(OFstatic_cast(Uint32, currentIndex++)));
1267     if (!overlayList.haveOverlayGroup(group))
1268     {
1269       // group is not shadowed by the presentation state
1270       if (idx==0) return group; else idx--;
1271     }
1272   } while (group != 0);
1273   return 0;
1274 }
1275 
1276 
getOverlayInImageLabel(size_t idx)1277 const char *DVPresentationState::getOverlayInImageLabel(size_t idx)
1278 {
1279   Uint16 group = getOverlayInImageGroup(idx); // returns 0 if currentImage==NULL
1280   if (group==0) return NULL; else return currentImage->getOverlayLabel(group);
1281 }
1282 
1283 
getOverlayInImageDescription(size_t idx)1284 const char *DVPresentationState::getOverlayInImageDescription(size_t idx)
1285 {
1286   Uint16 group = getOverlayInImageGroup(idx); // returns 0 if currentImage==NULL
1287   if (group==0) return NULL; else return currentImage->getOverlayDescription(group);
1288 }
1289 
1290 
getOverlayInImageActivationLayer(size_t idx)1291 size_t DVPresentationState::getOverlayInImageActivationLayer(size_t idx)
1292 {
1293   Uint16 group = getOverlayInImageGroup(idx); // returns 0 if currentImage==NULL
1294   if (group==0) return DVPS_IDX_NONE;
1295   const char *layerName = activationLayerList.getActivationLayer(group);
1296   if (layerName) return graphicLayerList.getGraphicLayerIndex(layerName);
1297   else return DVPS_IDX_NONE;
1298 }
1299 
1300 
overlayInImageIsROI(size_t idx)1301 OFBool DVPresentationState::overlayInImageIsROI(size_t idx)
1302 {
1303   Uint16 group = getOverlayInImageGroup(idx); // returns 0 if currentImage==NULL
1304   if (group==0) return OFFalse;
1305   if (EMO_RegionOfInterest == currentImage->getOverlayMode(group)) return OFTrue;
1306   else return OFFalse;
1307 }
1308 
removeOverlayFromPresentationState(size_t idx)1309 OFCondition DVPresentationState::removeOverlayFromPresentationState(size_t idx)
1310 {
1311   Uint16 group = getOverlayInPresentationStateGroup(idx);
1312   if (group != 0)
1313   {
1314     activationLayerList.removeActivation(group);
1315     currentImageOverlaysValid = 1; // invalid but nothing added
1316     return overlayList.removeOverlay(idx);
1317   }
1318   return EC_IllegalCall; // overlay does not exist
1319 }
1320 
1321 
findOverlayGroup(Uint16 currentGroup)1322 Uint16 DVPresentationState::findOverlayGroup(Uint16 currentGroup)
1323 {
1324   int allocated[16];
1325   size_t i, max;
1326   Uint16 group = 0;
1327 
1328   for (i=0; i<16; i++) allocated[i]=0;
1329   max = overlayList.size();
1330   for (i=0; i<max; i++)
1331   { // mark all group numbers used in presentation state
1332     group = getOverlayInPresentationStateGroup(i);
1333     if ((group >= 0x6000)&&(group <= 0x601F)) allocated[(Uint16)(group - 0x6000) >> 1] = 2;
1334   }
1335   max = getNumberOfOverlaysInImage();
1336   for (i=0; i<max; i++)
1337   { // mark all group numbers used in image
1338     group = getOverlayInImageGroup(i);
1339     if ((group >= 0x6000)&&(group <= 0x601F)) allocated[(Uint16)(group - 0x6000) >> 1] += 1;
1340   }
1341   // now we have 0=unused, 1=used in image, 2=used in pstate, 3=used in both.
1342 
1343   // check if the current group can be left unchanged
1344   if ((currentGroup >= 0x6000)&&(currentGroup <= 0x601F))
1345   {
1346     if (allocated[(Uint16)(group - 0x6000) >> 1] == 2) return currentGroup;
1347   }
1348   // find a free group
1349   for (i=0; i<16; i++) if (allocated[i]==0) return OFstatic_cast(Uint16, 0x6000+(i<<1));
1350   // find a group not used in the presentation state
1351   for (i=0; i<16; i++) if (allocated[i]<2) return OFstatic_cast(Uint16, 0x6000+(i<<1));
1352   // not found.
1353   return 0;
1354 }
1355 
changeOverlayGroupInPresentationState(size_t idx,Uint16 newGroup)1356 OFCondition DVPresentationState::changeOverlayGroupInPresentationState(size_t idx, Uint16 newGroup)
1357 {
1358   Uint16 group = getOverlayInPresentationStateGroup(idx);
1359   if (group != 0)
1360   {
1361     if (newGroup==0) newGroup = findOverlayGroup(group);
1362     if (newGroup==group) return EC_Normal; // shortcut - no change needed
1363     OFCondition result = overlayList.changeOverlayGroup(idx, newGroup);
1364     if (EC_Normal == result)
1365     {
1366       const char *layerName = activationLayerList.getActivationLayer(group);
1367       if (layerName)
1368       {
1369         activationLayerList.removeActivation(group);
1370         result = activationLayerList.setActivation(newGroup, layerName);
1371         currentImageOverlaysValid = 0; // invalid
1372       }
1373     }
1374     return result;
1375   }
1376   return EC_IllegalCall;
1377 }
1378 
addOverlayToPresentationState(DcmItem & overlayIOD,Uint16 groupInItem,Uint16 newGroup)1379 OFCondition DVPresentationState::addOverlayToPresentationState(DcmItem& overlayIOD, Uint16 groupInItem, Uint16 newGroup)
1380 {
1381   if (newGroup==0) newGroup = findOverlayGroup();
1382   if (newGroup==0) return EC_IllegalCall; // no group number available
1383   return overlayList.addOverlay(overlayIOD, groupInItem, newGroup);
1384 }
1385 
overlayIsSuitableAsBitmapShutter(size_t idx)1386 OFBool DVPresentationState::overlayIsSuitableAsBitmapShutter(size_t idx)
1387 {
1388   if (currentImage)
1389   {
1390     DVPSOverlay *overlay = overlayList.getOverlay(idx);
1391     if (overlay)
1392     {
1393       return overlay->isSuitableAsShutter(currentImage->getWidth(), currentImage->getHeight());
1394     }
1395   }
1396   return OFFalse;
1397 }
1398 
activateOverlayInImage(size_t layer,size_t idx)1399 OFCondition DVPresentationState::activateOverlayInImage(size_t layer, size_t idx)
1400 {
1401   Uint16 group = getOverlayInImageGroup(idx);
1402   if (group==0) return EC_IllegalCall;
1403   if (activationLayerList.getActivationLayer(group) != NULL) return EC_IllegalCall; //already activated
1404 
1405   const char *layerName = getGraphicLayerName(layer);
1406   if (layerName==NULL) return EC_IllegalCall;
1407   currentImageOverlaysValid = 1; // invalid but nothing (external) added
1408   return activationLayerList.setActivation(group, layerName);
1409 }
1410 
activateOverlayInPresentationState(size_t layer,size_t idx)1411 OFCondition DVPresentationState::activateOverlayInPresentationState(size_t layer, size_t idx)
1412 {
1413   Uint16 group = getOverlayInPresentationStateGroup(idx);
1414   if (group==0) return EC_IllegalCall;
1415   if (activationLayerList.getActivationLayer(group) != NULL) return EC_IllegalCall; //already activated
1416   if (haveShutter(DVPSU_bitmap))
1417   { // check if the overlay is used as the bitmap shutter
1418     Uint16 shutterGroup=0;
1419     shutterOverlayGroup.getUint16(shutterGroup,0);
1420     if (shutterGroup == group) return EC_IllegalCall; // used as bitmap shutter
1421   }
1422   const char *layerName = getGraphicLayerName(layer);
1423   if (layerName==NULL) return EC_IllegalCall;
1424   currentImageOverlaysValid = 0; // invalid
1425   return activationLayerList.setActivation(group, layerName);
1426 }
1427 
activateOverlayAsBitmapShutter(size_t idx)1428 OFCondition DVPresentationState::activateOverlayAsBitmapShutter(size_t idx)
1429 {
1430   Uint16 group = getOverlayInPresentationStateGroup(idx);
1431   if (group==0) return EC_IllegalCall;
1432   if (activationLayerList.getActivationLayer(group) != NULL) return EC_IllegalCall; // activated as overlay
1433   if (overlayIsSuitableAsBitmapShutter(idx))
1434   {
1435     shutterOverlayGroup.clear();
1436     OFCondition result = shutterOverlayGroup.putUint16(group,0);
1437     if ((EC_Normal==result)&&(shutterPresentationValue.getLength()==0))
1438         result = shutterPresentationValue.putUint16(0,0);
1439     if (EC_Normal==result)
1440     {
1441       useShutterRectangular = OFFalse;
1442       useShutterCircular = OFFalse;
1443       useShutterPolygonal = OFFalse;
1444       useShutterBitmap = OFTrue;
1445       currentImageOverlaysValid = 0; // invalid
1446     }
1447     return result;
1448   }
1449   return EC_IllegalCall;
1450 }
1451 
deactivateOverlay(size_t layer,size_t idx)1452 OFCondition DVPresentationState::deactivateOverlay(size_t layer, size_t idx)
1453 {
1454   Uint16 group = activationLayerList.getActivationGroup(
1455     graphicLayerList.getGraphicLayerName(layer), idx, OFFalse);
1456   if (group == 0) return EC_IllegalCall;
1457   activationLayerList.removeActivation(group);
1458   currentImageOverlaysValid = 1; // invalid but nothing added
1459   return EC_Normal;
1460 }
1461 
convertPValueToDDL(Uint16 pvalue,unsigned int bits)1462 Uint16 DVPresentationState::convertPValueToDDL(Uint16 pvalue, unsigned int bits)
1463 {
1464   Uint16 result = 0;
1465   if ((bits == 8) || (bits == 12))
1466   {
1467     if (currentImage && (bits == 8))
1468     {
1469       /* activate display transform */
1470       if (displayFunction && (displayTransform != DVPSD_none))
1471         currentImage->setDisplayFunction(displayFunction[displayTransform]);
1472       else
1473         currentImage->setNoDisplayFunction();
1474       currentImage->convertPValueToDDL(pvalue, result, bits /* 8 */);
1475     } else
1476       result = (pvalue >> (16 - bits));
1477   }
1478   return result;
1479 }
1480 
1481 
renderPixelData(OFBool display)1482 void DVPresentationState::renderPixelData(OFBool display)
1483 {
1484   if (currentImage == NULL) return;
1485   int result=0;
1486 
1487   /* activate Barten transform */
1488   if (displayFunction && (displayTransform != DVPSD_none) && display)
1489   {
1490     currentImage->setDisplayFunction(displayFunction[displayTransform]);
1491     if (previewImage != NULL)
1492       previewImage->setDisplayFunction(displayFunction[displayTransform]);
1493   } else {
1494     currentImage->setNoDisplayFunction();
1495     if (previewImage != NULL)
1496       previewImage->setNoDisplayFunction();
1497   }
1498 
1499   if (! currentImageVOIValid)
1500   {
1501      currentImageVOIValid = OFTrue;
1502 
1503      /* set VOI transformation */
1504      DVPSSoftcopyVOI *voi = getCurrentSoftcopyVOI();
1505      if (voi)
1506      {
1507        if (voi->haveLUT())
1508        {
1509          result = currentImage->setVoiLut(voi->getLUTData(), voi->getLUTDescriptor());
1510          if (previewImage != NULL)
1511            previewImage->setVoiLut(voi->getLUTData(), voi->getLUTDescriptor());
1512        } else {
1513          double wc=0.0, ww=0.0;
1514          if ((EC_Normal == voi->getCurrentWindowCenter(wc)) &&
1515              (EC_Normal == voi->getCurrentWindowWidth(ww)))
1516          {
1517            result = currentImage->setWindow(wc, ww);
1518            if (previewImage != NULL)
1519              previewImage->setWindow(wc, ww);
1520          } else {
1521            result = currentImage->setNoVoiTransformation();
1522            if (previewImage != NULL)
1523              previewImage->setNoVoiTransformation();
1524          }
1525        }
1526      } else {
1527        result = currentImage->setNoVoiTransformation();
1528        if (previewImage != NULL)
1529          previewImage->setNoVoiTransformation();
1530      }
1531      if (!result)
1532        DCMPSTAT_WARN("unable to set VOI transformation, ignoring.");
1533   } /* VOI transform */
1534 
1535   if (! currentImagePLUTValid)
1536   {
1537      presentationLUT.activate(currentImage);
1538      if (previewImage != NULL)
1539        presentationLUT.activate(previewImage);
1540      currentImagePLUTValid = OFTrue;
1541   } /* Presentation LUT */
1542 
1543   Uint16 bitmapShutterGroup = 0;
1544   Uint16 bitmapShutterPValue = 0;
1545   if (useShutterBitmap)
1546   {
1547     if (EC_Normal != shutterOverlayGroup.getUint16(bitmapShutterGroup, 0)) bitmapShutterGroup=0;
1548     if (EC_Normal != shutterPresentationValue.getUint16(bitmapShutterPValue, 0)) bitmapShutterPValue=0;
1549   }
1550 
1551   if (currentImageOverlaysValid==1)
1552   {
1553     /* overlays are invalid but no external overlays have been added */
1554     /* remove all external overlays that are not active as overlay or bitmap shutter */
1555     for (unsigned int remgroup=0x6000; remgroup <= 0x601F; remgroup += 2)
1556     {
1557       if ((remgroup != bitmapShutterGroup)&&((! overlayList.haveOverlayGroup(remgroup))||
1558           (NULL == activationLayerList.getActivationLayer(remgroup))))
1559       {
1560          currentImage->removeOverlay(remgroup); // ignore return value.
1561       }
1562     }
1563     currentImageOverlaysValid = 2; // valid
1564   }
1565   else if (currentImageOverlaysValid==0)
1566   {
1567     /* overlays are invalid */
1568 
1569     /* since we might be required to add external overlays, we first
1570      * need to flip the image back to its original rotation and flip state
1571      */
1572     if (currentImageFlip)
1573     {
1574       result = currentImage->flipImage();
1575       if (previewImage != NULL) previewImage->flipImage();
1576       if (!result)
1577         DCMPSTAT_WARN("unable to flip image horizontally, ignoring.");
1578       currentImageFlip = OFFalse;
1579     }
1580     signed int srot=0;
1581     switch(currentImageRotation)
1582     {
1583       case DVPSR_0_deg:   break;
1584       case DVPSR_90_deg:  srot=270; break;
1585       case DVPSR_180_deg: srot=180; break;
1586       case DVPSR_270_deg: srot=90; break;
1587     }
1588     if (srot != 0)
1589     {
1590       result = currentImage->rotateImage(srot);
1591       if (previewImage != NULL)
1592         previewImage->rotateImage(srot);
1593       if (!result)
1594         DCMPSTAT_WARN("unable to rotate image by " << srot << " degrees, ignoring.");
1595     }
1596     currentImageRotation = DVPSR_0_deg;
1597 
1598     // deactivate all overlays first
1599     result = currentImage->removeAllOverlays();
1600     if (!result)
1601       DCMPSTAT_WARN("unable to disable external overlays, ignoring.");
1602 
1603     size_t numOverlays = overlayList.size();
1604     DVPSOverlay *overlay = NULL;
1605     Uint16 ovgroup;
1606     for (size_t ovidx=0; ovidx<numOverlays; ovidx++)
1607     {
1608       overlay = overlayList.getOverlay(ovidx);
1609       if (overlay)
1610       {
1611         ovgroup = overlay->getOverlayGroup()+ 0x6000;
1612         if (NULL != activationLayerList.getActivationLayer(ovgroup))
1613         {
1614           if (activateOverlayHelper(*overlay, *currentImage).bad())
1615           {
1616             if (!result)
1617               DCMPSTAT_WARN("unable to set external overlay group 0x"
1618                 << STD_NAMESPACE hex << ovgroup << STD_NAMESPACE dec << ", ignoring.");
1619           }
1620         }
1621         else if ((useShutterBitmap)&&(ovgroup == bitmapShutterGroup))
1622         {
1623           //activate bitmap overlay
1624           if (activateOverlayHelper(*overlay, *currentImage, OFTrue, bitmapShutterPValue).bad())
1625           {
1626             if (!result)
1627               DCMPSTAT_WARN("unable to activate bitmap shutter 0x"
1628                 << STD_NAMESPACE hex << ovgroup << STD_NAMESPACE dec << ", ignoring.");
1629           }
1630         }
1631       }
1632     }
1633     currentImageOverlaysValid = 2; // valid
1634   }
1635 
1636   OFBool pstateFlip = getFlip();
1637   DVPSRotationType pstateRotation = getRotation();
1638 
1639   // store image width and height after application of rotation
1640   if ((pstateRotation == DVPSR_90_deg) || (pstateRotation == DVPSR_270_deg))
1641   {
1642     renderedImageWidth = currentImageHeight;
1643     renderedImageHeight = currentImageWidth;
1644   } else {
1645     renderedImageWidth = currentImageWidth;
1646     renderedImageHeight = currentImageHeight;
1647   }
1648 
1649   // get coordinates of current displayed area and store values after the
1650   // 'virtual' anti-rotation has been applied
1651   Sint32 tlhcX = 1;
1652   Sint32 tlhcY = 1;
1653   Sint32 brhcX = currentImageWidth;
1654   Sint32 brhcY = currentImageHeight;
1655   getImageRelativeDisplayedArea(tlhcX, tlhcY, brhcX, brhcY);
1656   if (tlhcX > brhcX)
1657   {                                     // swap 'left' and 'right' if necessary
1658     Sint32 tmp = tlhcX;
1659     tlhcX = brhcX;
1660     brhcX = tmp;
1661   }
1662   if (tlhcY > brhcY)
1663   {                                     // swap 'top' and 'bottom' if necessary
1664     Sint32 tmp = tlhcY;
1665     tlhcY = brhcY;
1666     brhcY = tmp;
1667   }
1668   switch (pstateRotation)
1669   {
1670     case DVPSR_0_deg:
1671       renderedImageTop = tlhcY;
1672       renderedImageLeft = tlhcX;
1673       renderedImageBottom = brhcY;
1674       renderedImageRight = brhcX;
1675       break;
1676     case DVPSR_90_deg:
1677       renderedImageTop = tlhcX;
1678       renderedImageLeft = (signed long)currentImageHeight - brhcY + 1;
1679       renderedImageBottom = brhcX;
1680       renderedImageRight = (signed long)currentImageHeight - tlhcY + 1;
1681       break;
1682     case DVPSR_180_deg:
1683       renderedImageTop = (signed long)currentImageHeight - brhcY + 1;
1684       renderedImageLeft = (signed long)currentImageWidth - brhcX + 1;
1685       renderedImageBottom = (signed long)currentImageHeight - tlhcY + 1;
1686       renderedImageRight = (signed long)currentImageWidth - tlhcX + 1;
1687       break;
1688     case DVPSR_270_deg:
1689       renderedImageTop = (signed long)currentImageWidth - brhcX + 1;
1690       renderedImageLeft = tlhcY;
1691       renderedImageBottom = (signed long)currentImageWidth - tlhcX + 1;
1692       renderedImageRight = brhcY;
1693       break;
1694   }
1695   if (pstateFlip)
1696   {
1697     signed long tmp = renderedImageLeft;
1698     renderedImageLeft = (signed long)renderedImageWidth - renderedImageRight + 1;
1699     renderedImageRight = (signed long)renderedImageWidth - tmp + 1;
1700   }
1701 
1702   // we can always reach the final rotation/flip status with
1703   // at most one rotation and one flip. The following formula
1704   // derives the operations to perform.
1705   OFBool flp=OFFalse;
1706   if ((pstateFlip && !currentImageFlip)||(!pstateFlip && currentImageFlip)) flp=OFTrue; else flp=OFFalse;
1707 
1708   signed int rot=0;
1709   switch (pstateRotation)
1710   {
1711     case DVPSR_0_deg:
1712       switch(currentImageRotation)
1713       {
1714         case DVPSR_0_deg:   rot=0; break;
1715         case DVPSR_90_deg:  if (currentImageFlip) rot=90; else rot=270; break;
1716         case DVPSR_180_deg: rot=180; break;
1717         case DVPSR_270_deg: if (currentImageFlip) rot=270; else rot=90; break;
1718       }
1719       break;
1720     case DVPSR_90_deg:
1721       switch(currentImageRotation)
1722       {
1723         case DVPSR_0_deg:   if (currentImageFlip) rot=270; else rot=90; break;
1724         case DVPSR_90_deg:  rot=0; break;
1725         case DVPSR_180_deg: if (currentImageFlip) rot=90; else rot=270; break;
1726         case DVPSR_270_deg: rot=180; break;
1727       }
1728       break;
1729     case DVPSR_180_deg:
1730       switch(currentImageRotation)
1731       {
1732         case DVPSR_0_deg:   rot=180; break;
1733         case DVPSR_90_deg:  if (currentImageFlip) rot=270; else rot=90; break;
1734         case DVPSR_180_deg: rot=0; break;
1735         case DVPSR_270_deg: if (currentImageFlip) rot=90; else rot=270; break;
1736       }
1737       break;
1738     case DVPSR_270_deg:
1739       switch(currentImageRotation)
1740       {
1741         case DVPSR_0_deg:   if (currentImageFlip) rot=90; else rot=270; break;
1742         case DVPSR_90_deg:  rot=180; break;
1743         case DVPSR_180_deg: if (currentImageFlip) rot=270; else rot=90; break;
1744         case DVPSR_270_deg: rot=0; break;
1745       }
1746       break;
1747   }
1748 
1749   if (rot != 0)
1750   {
1751     result = currentImage->rotateImage(rot);
1752     if (previewImage != NULL) previewImage->rotateImage(rot);
1753     if (!result)
1754       DCMPSTAT_WARN("unable to rotate image by " << rot << " degrees, ignoring.");
1755   }
1756 
1757   if (flp)
1758   {
1759     result = currentImage->flipImage();
1760     if (previewImage != NULL) previewImage->flipImage();
1761     if (!result)
1762       DCMPSTAT_WARN("unable to flip image horizontally, ignoring.");
1763   }
1764 
1765   currentImageRotation = pstateRotation;
1766   currentImageFlip = pstateFlip;
1767 
1768   return;
1769 }
1770 
1771 
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)1772 OFCondition DVPresentationState::getOverlayData(
1773      size_t layer,
1774      size_t idx,
1775      const void *&overlayData,
1776      unsigned int &width,
1777      unsigned int &height,
1778      unsigned int &left_pos,
1779      unsigned int &top_pos,
1780      OFBool &isROI,
1781      Uint16 &fore,
1782      unsigned int bits)
1783 {
1784    EM_Overlay mode = EMO_Default;
1785    if (currentImage && ((bits == 8) || (bits == 12)))
1786    {
1787      renderPixelData();
1788      Uint16 group = activationLayerList.getActivationGroup(graphicLayerList.getGraphicLayerName(layer), idx, OFFalse);
1789      if (group==0) return EC_IllegalCall;
1790      Uint16 back = 0;
1791      fore = (Uint16)DicomImageClass::maxval(bits);   /* 255 or 4095 */
1792      Uint16 pvalue = 65535;
1793      if (graphicLayerList.getGraphicLayerRecommendedDisplayValueGray(layer, pvalue) == EC_Normal)
1794          currentImage->convertPValueToDDL(pvalue, fore, bits);
1795      if (fore == 0)
1796          back = (Uint16)DicomImageClass::maxval(bits);
1797      const void *data = currentImage->getOverlayData((unsigned int)group, left_pos, top_pos, width, height, mode,
1798        currentImageSelectedFrame-1, bits, fore, back);
1799      if (EMO_RegionOfInterest == mode) isROI=OFTrue; else isROI=OFFalse;
1800      if (data) overlayData = data;
1801      else
1802      {
1803        overlayData = NULL;
1804        return EC_IllegalCall;
1805      }
1806    } else {
1807      overlayData = NULL;
1808      width = 0;
1809      height = 0;
1810      left_pos = 0;
1811      top_pos = 0;
1812      isROI = OFFalse;
1813      fore = 0;
1814      return EC_IllegalCall;
1815    }
1816    return EC_Normal;
1817 }
1818 
isInverse()1819 OFBool DVPresentationState::isInverse()
1820 {
1821     return imageInverse;
1822 }
1823 
invertImage()1824 OFCondition DVPresentationState::invertImage()
1825 {
1826   OFCondition status = presentationLUT.invert();
1827   currentImagePLUTValid = OFFalse; // PLUT has changed
1828   imageInverse = (imageInverse ? OFFalse : OFTrue);
1829   return status;
1830 }
1831 
1832 
getPixelData(const void * & pixelData,unsigned long & width,unsigned long & height)1833 OFCondition DVPresentationState::getPixelData(
1834      const void *&pixelData,
1835      unsigned long &width,
1836      unsigned long &height)
1837 {
1838    if (currentImage)
1839    {
1840      renderPixelData();
1841      width = currentImage->getWidth();
1842      height = currentImage->getHeight();
1843      pixelData = currentImage->getOutputData(8, currentImageSelectedFrame-1);
1844    } else {
1845      pixelData = NULL;
1846      width = 0;
1847      height = 0;
1848      return EC_IllegalCall;
1849    }
1850    return EC_Normal;
1851 }
1852 
getPixelData(void * pixelData,unsigned long size)1853 OFCondition DVPresentationState::getPixelData(
1854      void *pixelData,
1855      unsigned long size)
1856 {
1857    if (currentImage)
1858    {
1859      renderPixelData();
1860      if (currentImage->getOutputData(pixelData, size, 8, currentImageSelectedFrame-1))
1861          return EC_Normal;
1862    }
1863    return EC_IllegalCall;
1864 }
1865 
getImageMinMaxPixelRange(double & minValue,double & maxValue)1866 OFCondition DVPresentationState::getImageMinMaxPixelRange(double &minValue, double& maxValue)
1867 {
1868   OFCondition result = EC_IllegalCall;
1869   if (currentImage)
1870   {
1871     if (currentImage->getMinMaxValues(minValue, maxValue, 1)) result = EC_Normal;
1872   }
1873   return result;
1874 }
1875 
getImageMinMaxPixelValue(double & minValue,double & maxValue)1876 OFCondition DVPresentationState::getImageMinMaxPixelValue(double &minValue, double& maxValue)
1877 {
1878   OFCondition result = EC_IllegalCall;
1879   if (currentImage)
1880   {
1881     if (currentImage->getMinMaxValues(minValue, maxValue, 0)) result = EC_Normal;
1882   }
1883   return result;
1884 }
1885 
getImageNumberOfFrames(unsigned long & frames)1886 OFCondition DVPresentationState::getImageNumberOfFrames(unsigned long &frames)
1887 {
1888   if (currentImage)
1889   {
1890     frames = (unsigned long)(currentImage->getFrameCount());
1891     return EC_Normal;
1892   }
1893   return EC_IllegalCall;
1894 }
1895 
selectImageFrameNumber(unsigned long frame)1896 OFCondition DVPresentationState::selectImageFrameNumber(unsigned long frame)
1897 {
1898   if ((frame > 0) && currentImage && (frame <= currentImage->getFrameCount()))
1899   {
1900     if (currentImageSelectedFrame != frame)
1901       currentImageVOIValid = OFFalse; // VOI might has changed
1902     currentImageSelectedFrame=frame;
1903     return EC_Normal;
1904   }
1905   return EC_IllegalCall;
1906 }
1907 
getSelectedImageFrameNumber()1908 unsigned long DVPresentationState::getSelectedImageFrameNumber()
1909 {
1910   if (currentImage)
1911   {
1912     if (currentImageSelectedFrame <= currentImage->getFrameCount())
1913       return currentImageSelectedFrame;
1914   }
1915   return 0;
1916 }
1917 
getDisplayedAreaSelection()1918 DVPSDisplayedArea *DVPresentationState::getDisplayedAreaSelection()
1919 {
1920   if (currentImage==NULL) return NULL;
1921   DVPSDisplayedArea * area = displayedAreaSelectionList.findDisplayedArea(currentImageSOPInstanceUID, currentImageSelectedFrame);
1922   if (area==NULL)
1923   {
1924       DCMPSTAT_WARN("no displayed area selection item for current image found, creating default.");
1925       if ((currentImageDataset)&&(EC_Normal == createDefaultDisplayedArea(*currentImageDataset)))
1926       {
1927         area = displayedAreaSelectionList.findDisplayedArea(currentImageSOPInstanceUID, currentImageSelectedFrame);
1928       }
1929   }
1930   return area;
1931 }
1932 
getDisplayedAreaPresentationSizeMode()1933 DVPSPresentationSizeMode DVPresentationState::getDisplayedAreaPresentationSizeMode()
1934 {
1935   DVPSDisplayedArea * area = getDisplayedAreaSelection();
1936   if (area) return area->getPresentationSizeMode(); else return DVPSD_scaleToFit;
1937 }
1938 
getDisplayedAreaPresentationPixelAspectRatio()1939 double DVPresentationState::getDisplayedAreaPresentationPixelAspectRatio()
1940 {
1941   DVPSDisplayedArea * area = getDisplayedAreaSelection();
1942   if (area) return area->getPresentationPixelAspectRatio(); else return 1.0;
1943 }
1944 
getStandardDisplayedArea(Sint32 & tlhcX,Sint32 & tlhcY,Sint32 & brhcX,Sint32 & brhcY)1945 OFCondition DVPresentationState::getStandardDisplayedArea(Sint32& tlhcX, Sint32& tlhcY, Sint32& brhcX, Sint32& brhcY)
1946 {
1947   DVPSDisplayedArea * area = getDisplayedAreaSelection();
1948   if (area)
1949   {
1950     area->getDisplayedArea(tlhcX, tlhcY, brhcX, brhcY);
1951     return EC_Normal;
1952   }
1953   return EC_IllegalCall;
1954 }
1955 
getImageRelativeDisplayedArea(Sint32 & tlhcX,Sint32 & tlhcY,Sint32 & brhcX,Sint32 & brhcY)1956 OFCondition DVPresentationState::getImageRelativeDisplayedArea(Sint32& tlhcX, Sint32& tlhcY, Sint32& brhcX, Sint32& brhcY)
1957 {
1958   DVPSDisplayedArea * area = getDisplayedAreaSelection();
1959   if (area)
1960   {
1961     DVPSRotationType rotation = getRotation();
1962     OFBool flip = getFlip();
1963     area = area->clone(); // create temporary copy
1964     area->rotateAndFlip(rotation, flip, DVPSR_0_deg, OFFalse);
1965     area->getDisplayedArea(tlhcX, tlhcY, brhcX, brhcY);
1966     delete area;
1967     return EC_Normal;
1968   }
1969   return EC_IllegalCall;
1970 }
1971 
getDisplayedAreaPresentationPixelSpacing(double & x,double & y)1972 OFCondition DVPresentationState::getDisplayedAreaPresentationPixelSpacing(double& x, double& y)
1973 {
1974   DVPSDisplayedArea * area = getDisplayedAreaSelection();
1975   if (area) return area->getPresentationPixelSpacing(x, y); else return EC_IllegalCall;
1976 }
1977 
getDisplayedAreaPresentationPixelMagnificationRatio(double & magnification)1978 OFCondition DVPresentationState::getDisplayedAreaPresentationPixelMagnificationRatio(double& magnification)
1979 {
1980   DVPSDisplayedArea * area = getDisplayedAreaSelection();
1981   if (area) return area->getPresentationPixelMagnificationRatio(magnification); else return EC_IllegalCall;
1982 }
1983 
canUseDisplayedAreaTrueSize()1984 OFBool DVPresentationState::canUseDisplayedAreaTrueSize()
1985 {
1986   DVPSDisplayedArea * area = getDisplayedAreaSelection();
1987   if (area) return area->canUseTrueSize(); else return OFFalse;
1988 }
1989 
setStandardDisplayedArea(DVPSPresentationSizeMode sizeMode,Sint32 tlhcX,Sint32 tlhcY,Sint32 brhcX,Sint32 brhcY,double magnification,DVPSObjectApplicability applicability)1990 OFCondition DVPresentationState::setStandardDisplayedArea(
1991      DVPSPresentationSizeMode sizeMode,
1992      Sint32 tlhcX, Sint32 tlhcY,
1993      Sint32 brhcX, Sint32 brhcY,
1994      double magnification,
1995      DVPSObjectApplicability applicability)
1996 {
1997   if (currentImage == NULL) return EC_IllegalCall;
1998 
1999   // make sure that we have an old displayed area item that "knows" about pixel spacing/aspect ratio,
2000   // because we will only copy this data into the new item.
2001   DVPSDisplayedArea *area = getDisplayedAreaSelection();
2002 
2003   // find appropriate item, create new if necessary.
2004   area = displayedAreaSelectionList.createDisplayedArea(
2005       referencedSeriesList, currentImageSOPClassUID, currentImageSOPInstanceUID,
2006       currentImageSelectedFrame, currentImage->getFrameCount(), applicability);
2007 
2008   if (area) return area->setDisplayedArea(sizeMode, tlhcX, tlhcY, brhcX, brhcY, magnification);
2009   return EC_IllegalCall;
2010 }
2011 
setImageRelativeDisplayedArea(DVPSPresentationSizeMode sizeMode,Sint32 tlhcX,Sint32 tlhcY,Sint32 brhcX,Sint32 brhcY,double magnification,DVPSObjectApplicability applicability)2012 OFCondition DVPresentationState::setImageRelativeDisplayedArea(
2013      DVPSPresentationSizeMode sizeMode,
2014      Sint32 tlhcX, Sint32 tlhcY,
2015      Sint32 brhcX, Sint32 brhcY,
2016      double magnification,
2017      DVPSObjectApplicability applicability)
2018 {
2019   if (currentImage == NULL) return EC_IllegalCall;
2020 
2021   // make sure that we have an old displayed area item that "knows" about pixel spacing/aspect ratio,
2022   // because we will only copy this data into the new item.
2023   DVPSDisplayedArea *area = getDisplayedAreaSelection();
2024 
2025   // find appropriate item, create new if necessary.
2026   area = displayedAreaSelectionList.createDisplayedArea(
2027       referencedSeriesList, currentImageSOPClassUID, currentImageSOPInstanceUID,
2028       currentImageSelectedFrame, currentImage->getFrameCount(), applicability);
2029 
2030   if (area)
2031   {
2032      // get current rotation and flip status
2033      DVPSRotationType rotation = getRotation();
2034      OFBool flip = getFlip();
2035 
2036      // force rotation and flip status back to unrotated/unflipped
2037      // because in this case standard displayed area and image relative displayed area are the same
2038      area->rotateAndFlip(rotation, flip, DVPSR_0_deg, OFFalse);
2039 
2040      // set displayed area
2041      OFCondition result = area->setDisplayedArea(sizeMode, tlhcX, tlhcY, brhcX, brhcY, magnification);
2042 
2043      // restore rotation and flip status
2044      area->rotateAndFlip(DVPSR_0_deg, OFFalse, rotation, flip);
2045 
2046      return result;
2047   }
2048   return EC_IllegalCall;
2049 }
2050 
2051 
getCurrentSoftcopyVOI()2052 DVPSSoftcopyVOI *DVPresentationState::getCurrentSoftcopyVOI()
2053 {
2054   if (currentImage==NULL) return NULL;
2055   return softcopyVOIList.findSoftcopyVOI(currentImageSOPInstanceUID, currentImageSelectedFrame);
2056 }
2057 
getPrintBitmapRequestedImageSize(OFString & requestedImageSize)2058 OFCondition DVPresentationState::getPrintBitmapRequestedImageSize(OFString& requestedImageSize)
2059 {
2060   requestedImageSize.clear();
2061   if ((currentImage)&&(getDisplayedAreaPresentationSizeMode()==DVPSD_trueSize))
2062   {
2063     double x=0.0, y=0.0;
2064     if (EC_Normal == getDisplayedAreaPresentationPixelSpacing(x, y))
2065     {
2066       char c[80];
2067       DVPSRotationType rotation = getRotation();
2068       if ((rotation==DVPSR_90_deg)||(rotation==DVPSR_270_deg))
2069       {
2070         x = y * currentImageHeight; // physical height of unrotated image in mm
2071       } else {
2072         x *= currentImageWidth;  // physical width of unrotated image in mm
2073       }
2074       OFStandard::ftoa(c, sizeof(c), x, OFStandard::ftoa_format_f);
2075 
2076       requestedImageSize = c;
2077       return EC_Normal;
2078     }
2079   }
2080   return EC_IllegalCall;
2081 }
2082 
writePresentationLUTforPrint(DcmItem & dset)2083 OFCondition DVPresentationState::writePresentationLUTforPrint(DcmItem &dset)
2084 {
2085   OFCondition result = EC_Normal;
2086   if (currentImageMonochrome1)
2087   {
2088     // write inverted LUT because image is also converted to MONOCHROME2
2089     presentationLUT.invert();
2090     if (EC_Normal==result) result = presentationLUT.write(dset, OFFalse);
2091     presentationLUT.invert();
2092   } else result = presentationLUT.write(dset, OFFalse);
2093   return result;
2094 }
2095 
getCurrentImageModality()2096 const char *DVPresentationState::getCurrentImageModality()
2097 {
2098   char *c = NULL;
2099   if (EC_Normal == currentImageModality.getString(c)) return c; else return NULL;
2100 }
2101 
getAttachedImageSOPClassUID()2102 const char *DVPresentationState::getAttachedImageSOPClassUID()
2103 {
2104   return currentImageSOPClassUID;
2105 }
2106 
2107 
getAttachedImageSOPInstanceUID()2108 const char *DVPresentationState::getAttachedImageSOPInstanceUID()
2109 {
2110   return currentImageSOPInstanceUID;
2111 }
2112 
2113 
activateOverlayHelper(DVPSOverlay & ovl,DicomImage & image,OFBool asShutter,Uint16 pvalue)2114 OFCondition DVPresentationState::activateOverlayHelper(DVPSOverlay& ovl, DicomImage &image, OFBool asShutter, Uint16 pvalue)
2115 {
2116   Sint16 originX=0;
2117   Sint16 originY=0;
2118   Uint16 sizeX=0;
2119   Uint16 sizeY=0;
2120   unsigned int group = ovl.getOverlayGroup() + 0x6000;
2121   EM_Overlay mode=EMO_Graphic;
2122   if (asShutter) mode=EMO_BitmapShutter; else if (ovl.isROI()) mode=EMO_RegionOfInterest;
2123 
2124   OFCondition result = ovl.getValues(originX, originY, sizeX, sizeY);
2125   if (result.good())
2126   {
2127     signed int left_pos = (signed int) originX;
2128     signed int top_pos = (signed int) originY;
2129     unsigned int columns = (unsigned int)sizeX;
2130     unsigned int rows = (unsigned int)sizeY;
2131     if (0 == image.addOverlay(group, left_pos, top_pos, columns, rows,
2132       ovl.getData(), ovl.getLabel(), ovl.getDescription(), mode))
2133         result = EC_IllegalCall;
2134     if ((asShutter)&&(EC_Normal==result))
2135     {
2136       if (0 == image.showOverlay(group, pvalue)) result = EC_IllegalCall;
2137     }
2138   }
2139   return result;
2140 }
2141 
read(DcmItem & dset)2142 OFCondition DVPresentationState::read(DcmItem &dset)
2143 {
2144   OFCondition result = DcmPresentationState::read(dset);
2145   imageInverse = presentationLUT.isInverse();
2146   return result;
2147 }
2148 
createFromImage(DcmItem & dset,DVPSoverlayActivation overlayActivation,DVPSVOIActivation voiActivation,OFBool curveActivation,OFBool shutterActivation,OFBool presentationActivation,DVPSGraphicLayering layering,const char * aetitle,const char * filesetID,const char * filesetUID)2149 OFCondition DVPresentationState::createFromImage(
2150   DcmItem &dset,
2151   DVPSoverlayActivation overlayActivation,
2152   DVPSVOIActivation voiActivation,
2153   OFBool curveActivation,
2154   OFBool shutterActivation,
2155   OFBool presentationActivation,
2156   DVPSGraphicLayering layering,
2157   const char *aetitle,
2158   const char *filesetID,
2159   const char *filesetUID)
2160 {
2161   OFCondition result = DcmPresentationState::createFromImage(
2162     dset, overlayActivation, voiActivation, curveActivation, shutterActivation,
2163     presentationActivation, layering, aetitle, filesetID, filesetUID);
2164   imageInverse = presentationLUT.isInverse();
2165   return result;
2166 }
2167