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