1 /*
2  *
3  *  Copyright (C) 1998-2019, 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: DVPSStoredPrint
20  *
21  */
22 
23 #include "dcmtk/config/osconfig.h"      /* make sure OS specific configuration is included first */
24 #include "dcmtk/dcmpstat/dvpssp.h"
25 #include "dcmtk/dcmpstat/dvpsdef.h"     /* for constants and macros */
26 #include "dcmtk/ofstd/ofstring.h"
27 #include "dcmtk/dcmdata/dcuid.h"
28 #include "dcmtk/dcmpstat/dvpsib.h"
29 #include "dcmtk/dcmpstat/dvpshlp.h"
30 #include "dcmtk/dcmimgle/dcmimage.h"
31 #include "dcmtk/dcmimgle/digsdfn.h"
32 #include "dcmtk/dcmpstat/dvpscf.h"
33 #include "dcmtk/dcmnet/dimse.h"         /* for DICOM_WARNING_STATUS */
34 #include "dcmtk/dcmpstat/dvpsov.h"      /* for DVPSOverlay, needed by MSVC5 with STL */
35 #include "dcmtk/dcmpstat/dvpsgl.h"      /* for DVPSGraphicLayer, needed by MSVC5 with STL */
36 #include "dcmtk/dcmpstat/dvpsrs.h"      /* for DVPSReferencedSeries, needed by MSVC5 with STL */
37 #include "dcmtk/dcmpstat/dvpsal.h"      /* for DVPSOverlayCurveActivationLayer, needed by MSVC5 with STL */
38 #include "dcmtk/dcmpstat/dvpsga.h"      /* for DVPSGraphicAnnotation, needed by MSVC5 with STL */
39 #include "dcmtk/dcmpstat/dvpscu.h"      /* for DVPSCurve, needed by MSVC5 with STL */
40 #include "dcmtk/dcmpstat/dvpsvl.h"      /* for DVPSVOILUT, needed by MSVC5 with STL */
41 #include "dcmtk/dcmpstat/dvpsvw.h"      /* for DVPSVOIWindow, needed by MSVC5 with STL */
42 #include "dcmtk/dcmpstat/dvpsda.h"      /* for DVPSDisplayedArea, needed by MSVC5 with STL */
43 #include "dcmtk/dcmpstat/dvpssv.h"      /* for DVPSSoftcopyVOI, needed by MSVC5 with STL */
44 #include "dcmtk/dcmpstat/dvpsab.h"      /* for DVPSAnnotationContent, needed by MSVC5 with STL */
45 #include "dcmtk/dcmpstat/dvpstx.h"      /* for DVPSTextObject, needed by MSVC5 with STL */
46 #include "dcmtk/dcmpstat/dvpsgr.h"      /* for DVPSGraphicObject, needed by MSVC5 with STL */
47 #include "dcmtk/dcmpstat/dvpsri.h"      /* for DVPSReferencedImage, needed by MSVC5 with STL */
48 
49 #define INCLUDE_CMATH
50 #define INCLUDE_CTIME
51 #include "dcmtk/ofstd/ofstdinc.h"
52 
53 #define DIMSE_STATUS_OK(status) (((status) == 0) || DICOM_WARNING_STATUS(status))
54 #define DIMSE_STATUS_BAD(status) (((status) != 0) && !(DICOM_WARNING_STATUS(status)))
55 
56 
57 /* --------------- class DVPSStoredPrint --------------- */
58 
DVPSStoredPrint(Uint16 illumin,Uint16 reflection,const char * aetitle)59 DVPSStoredPrint::DVPSStoredPrint(Uint16 illumin, Uint16 reflection, const char *aetitle)
60 : patientName(DCM_PatientName)
61 , patientID(DCM_PatientID)
62 , patientBirthDate(DCM_PatientBirthDate)
63 , patientSex(DCM_PatientSex)
64 , studyInstanceUID(DCM_StudyInstanceUID)
65 , studyDate(DCM_StudyDate)
66 , studyTime(DCM_StudyTime)
67 , referringPhysicianName(DCM_ReferringPhysicianName)
68 , studyID(DCM_StudyID)
69 , accessionNumber(DCM_AccessionNumber)
70 , seriesInstanceUID(DCM_SeriesInstanceUID)
71 , seriesNumber(DCM_SeriesNumber)
72 , manufacturer(DCM_Manufacturer)
73 , originator(DCM_Originator)
74 , destination(DCM_DestinationAE)
75 , printerName(DCM_PrinterName)
76 , instanceNumber(DCM_InstanceNumber)
77 , imageDisplayFormat(DCM_ImageDisplayFormat)
78 , annotationDisplayFormatID(DCM_AnnotationDisplayFormatID)
79 , filmOrientation(DCM_FilmOrientation)
80 , filmSizeID(DCM_FilmSizeID)
81 , magnificationType(DCM_MagnificationType)
82 , smoothingType(DCM_SmoothingType)
83 , borderDensity(DCM_BorderDensity)
84 , emptyImageDensity(DCM_EmptyImageDensity)
85 , minDensity(DCM_MinDensity)
86 , maxDensity(DCM_MaxDensity)
87 , trim(DCM_Trim)
88 , configurationInformation(DCM_ConfigurationInformation)
89 , illumination(DCM_Illumination)
90 , reflectedAmbientLight(DCM_ReflectedAmbientLight)
91 , requestedResolutionID(DCM_RequestedResolutionID)
92 , referencedPresentationLUTInstanceUID(DCM_ReferencedSOPInstanceUID)
93 , referencedPresentationLUTAlignment(DVPSK_other)
94 , imageBoxContentList()
95 , annotationContentList()
96 , presentationLUTList()
97 , sOPInstanceUID(DCM_SOPInstanceUID)
98 , specificCharacterSet(DCM_SpecificCharacterSet)
99 , instanceCreationDate(DCM_InstanceCreationDate)
100 , instanceCreationTime(DCM_InstanceCreationTime)
101 , imageSeriesInstanceUID(DCM_SeriesInstanceUID)
102 , currentValuesValid(OFFalse)
103 , currentNumCols(0)
104 , currentNumRows(0)
105 , decimateCropBehaviour(DVPSI_default)
106 , filmSessionInstanceUID()
107 , filmBoxInstanceUID()
108 , presentationLUTInstanceUID()
109 , globalPresentationLUT()
110 , globalPresentationLUTValid(OFFalse)
111 , transmitImagesIn12Bit(OFTrue)
112 , renderPresentationLUTinSCP(OFFalse)
113 , tempDensity()
114 {
115   illumination.putUint16(illumin, 0);
116   reflectedAmbientLight.putUint16(reflection, 0);
117   if (aetitle != NULL)
118     originator.putString(aetitle);
119 }
120 
DVPSStoredPrint(const DVPSStoredPrint & copy)121 DVPSStoredPrint::DVPSStoredPrint(const DVPSStoredPrint& copy)
122 : patientName(copy.patientName)
123 , patientID(copy.patientID)
124 , patientBirthDate(copy.patientBirthDate)
125 , patientSex(copy.patientSex)
126 , studyInstanceUID(copy.studyInstanceUID)
127 , studyDate(copy.studyDate)
128 , studyTime(copy.studyTime)
129 , referringPhysicianName(copy.referringPhysicianName)
130 , studyID(copy.studyID)
131 , accessionNumber(copy.accessionNumber)
132 , seriesInstanceUID(copy.seriesInstanceUID)
133 , seriesNumber(copy.seriesNumber)
134 , manufacturer(copy.manufacturer)
135 , originator(copy.originator)
136 , destination(copy.destination)
137 , printerName(copy.printerName)
138 , instanceNumber(copy.instanceNumber)
139 , imageDisplayFormat(copy.imageDisplayFormat)
140 , annotationDisplayFormatID(copy.annotationDisplayFormatID)
141 , filmOrientation(copy.filmOrientation)
142 , filmSizeID(copy.filmSizeID)
143 , magnificationType(copy.magnificationType)
144 , smoothingType(copy.smoothingType)
145 , borderDensity(copy.borderDensity)
146 , emptyImageDensity(copy.emptyImageDensity)
147 , minDensity(copy.minDensity)
148 , maxDensity(copy.maxDensity)
149 , trim(copy.trim)
150 , configurationInformation(copy.configurationInformation)
151 , illumination(copy.illumination)
152 , reflectedAmbientLight(copy.reflectedAmbientLight)
153 , requestedResolutionID(copy.requestedResolutionID)
154 , referencedPresentationLUTInstanceUID(copy.referencedPresentationLUTInstanceUID)
155 , referencedPresentationLUTAlignment(copy.referencedPresentationLUTAlignment)
156 , imageBoxContentList(copy.imageBoxContentList)
157 , annotationContentList(copy.annotationContentList)
158 , presentationLUTList(copy.presentationLUTList)
159 , sOPInstanceUID(copy.sOPInstanceUID)
160 , specificCharacterSet(copy.specificCharacterSet)
161 , instanceCreationDate(copy.instanceCreationDate)
162 , instanceCreationTime(copy.instanceCreationTime)
163 , imageSeriesInstanceUID(copy.imageSeriesInstanceUID)
164 , currentValuesValid(copy.currentValuesValid)
165 , currentNumCols(copy.currentNumCols)
166 , currentNumRows(copy.currentNumRows)
167 , decimateCropBehaviour(copy.decimateCropBehaviour)
168 , filmSessionInstanceUID(copy.filmSessionInstanceUID)
169 , filmBoxInstanceUID(copy.filmBoxInstanceUID)
170 , presentationLUTInstanceUID(copy.presentationLUTInstanceUID)
171 , globalPresentationLUT(copy.globalPresentationLUT)
172 , globalPresentationLUTValid(copy.globalPresentationLUTValid)
173 , transmitImagesIn12Bit(copy.transmitImagesIn12Bit)
174 , renderPresentationLUTinSCP(copy.renderPresentationLUTinSCP)
175 , tempDensity(copy.tempDensity)
176 {
177 }
178 
~DVPSStoredPrint()179 DVPSStoredPrint::~DVPSStoredPrint()
180 {
181 }
182 
clear()183 void DVPSStoredPrint::clear()
184 {
185   patientName.clear();
186   patientID.clear();
187   patientBirthDate.clear();
188   patientSex.clear();
189   studyInstanceUID.clear();
190   studyDate.clear();
191   studyTime.clear();
192   referringPhysicianName.clear();
193   studyID.clear();
194   accessionNumber.clear();
195   seriesInstanceUID.clear();
196   seriesNumber.clear();
197   manufacturer.clear();
198   originator.clear();
199   destination.clear();
200   printerName.clear();
201   instanceNumber.clear();
202   imageDisplayFormat.clear();
203   annotationDisplayFormatID.clear();
204   filmOrientation.clear();
205   filmSizeID.clear();
206   magnificationType.clear();
207   smoothingType.clear();
208   borderDensity.clear();
209   emptyImageDensity.clear();
210   minDensity.clear();
211   maxDensity.clear();
212   trim.clear();
213   configurationInformation.clear();
214   illumination.clear();
215   reflectedAmbientLight.clear();
216   requestedResolutionID.clear();
217   referencedPresentationLUTInstanceUID.clear();
218   referencedPresentationLUTAlignment = DVPSK_other;
219   imageBoxContentList.clear();
220   annotationContentList.clear();
221   presentationLUTList.clear();
222   sOPInstanceUID.clear();
223   specificCharacterSet.clear();
224   instanceCreationDate.clear();
225   instanceCreationTime.clear();
226   imageSeriesInstanceUID.clear();
227   invalidateCache();
228   decimateCropBehaviour = DVPSI_default;
229   filmSessionInstanceUID.clear();
230   filmBoxInstanceUID.clear();
231   presentationLUTInstanceUID.clear();
232   globalPresentationLUT.clear();
233   globalPresentationLUTValid = OFFalse;
234   transmitImagesIn12Bit = OFTrue;
235   renderPresentationLUTinSCP = OFFalse;
236   tempDensity.clear();
237 }
238 
invalidateCache()239 void DVPSStoredPrint::invalidateCache()
240 {
241   currentValuesValid = OFFalse;
242   currentNumCols=0;
243   currentNumRows=0;
244 }
245 
updateCache()246 void DVPSStoredPrint::updateCache()
247 {
248   if (currentValuesValid) return;
249   OFString aString;
250   imageDisplayFormat.getOFStringArray(aString,OFTrue);
251   if (aString.substr(0,9) == "STANDARD\\")
252   {
253     unsigned long columns=0;
254     unsigned long rows=0;
255     const char *format = aString.c_str() + 9;
256 
257     if (2==sscanf(format, "%lu,%lu", &columns, &rows))
258     {
259       currentNumCols = columns;
260       currentNumRows = rows;
261       if ((columns > 0)&&(rows > 0)) currentValuesValid = OFTrue;
262     } else {
263       DCMPSTAT_WARN("cannot parse image display format '" << aString.c_str() << "'");
264     }
265   } else {
266     DCMPSTAT_WARN("unknown image display format '" << aString.c_str() << "'");
267   }
268   return;
269 }
270 
isImageStorageSOPClass(OFString & sopclassuid)271 OFBool DVPSStoredPrint::isImageStorageSOPClass(OFString& sopclassuid)
272 {
273   for (int i=0; i<numberOfDcmImageSOPClassUIDs; i++)
274   {
275     if (dcmImageSOPClassUIDs[i] && (sopclassuid == dcmImageSOPClassUIDs[i])) return OFTrue;
276   }
277   return OFFalse;
278 }
279 
280 
read(DcmItem & dset)281 OFCondition DVPSStoredPrint::read(DcmItem &dset)
282 {
283   DcmSequenceOfItems *seq;
284   DcmItem *item;
285   OFCondition result = EC_Normal;
286   DcmStack stack;
287   OFString aString;
288 
289   clear(); // re-initialize Stored Print object
290 
291   DcmUniqueIdentifier sopclassuid(DCM_SOPClassUID);
292   DcmUniqueIdentifier refsopclassuid(DCM_ReferencedSOPClassUID);
293   READ_FROM_DATASET(DcmUniqueIdentifier, EVR_UI, sopclassuid)
294   sopclassuid.getOFString(aString,0);
295   if (aString != UID_RETIRED_StoredPrintStorage)
296   {
297     result=EC_IllegalCall;
298     DCMPSTAT_WARN("SOP Class UID does not match StoredPrintStorage");
299   }
300 
301   DcmCodeString modality(DCM_Modality);
302   READ_FROM_DATASET(DcmCodeString, EVR_CS, modality)
303   if (modality.getLength() == 0)
304   {
305     result=EC_IllegalCall;
306     DCMPSTAT_WARN("Modality missing or empty in Stored Print");
307   }
308 
309   READ_FROM_DATASET(DcmPersonName, EVR_PN, patientName)
310   READ_FROM_DATASET(DcmLongString, EVR_LO, patientID)
311   READ_FROM_DATASET(DcmDate, EVR_DA, patientBirthDate)
312   READ_FROM_DATASET(DcmCodeString, EVR_CS, patientSex)
313   READ_FROM_DATASET(DcmUniqueIdentifier, EVR_UI, studyInstanceUID)
314   READ_FROM_DATASET(DcmDate, EVR_DA, studyDate)
315   READ_FROM_DATASET(DcmTime, EVR_TM, studyTime)
316   READ_FROM_DATASET(DcmPersonName, EVR_PN, referringPhysicianName)
317   READ_FROM_DATASET(DcmShortString, EVR_SH, studyID)
318   READ_FROM_DATASET(DcmShortString, EVR_SH, accessionNumber)
319   READ_FROM_DATASET(DcmUniqueIdentifier, EVR_UI, seriesInstanceUID)
320   READ_FROM_DATASET(DcmIntegerString, EVR_IS, seriesNumber)
321   READ_FROM_DATASET(DcmLongString, EVR_LO, manufacturer)
322   READ_FROM_DATASET(DcmIntegerString, EVR_IS, instanceNumber)
323   READ_FROM_DATASET(DcmUniqueIdentifier, EVR_UI, sOPInstanceUID)
324   READ_FROM_DATASET(DcmCodeString, EVR_CS, specificCharacterSet)
325   READ_FROM_DATASET(DcmDate, EVR_DA, instanceCreationDate)
326   READ_FROM_DATASET(DcmTime, EVR_TM, instanceCreationTime)
327 
328   if (EC_Normal==result) result = presentationLUTList.read(dset);
329 
330   if (result==EC_Normal)
331   {
332     stack.clear();
333     if (EC_Normal == dset.search(DCM_RETIRED_FilmBoxContentSequence, stack, ESM_fromHere, OFFalse))
334     {
335       seq=(DcmSequenceOfItems *)stack.top();
336       if (seq->card() ==1)
337       {
338          item = seq->getItem(0);
339          stack.clear();
340 
341          READ_FROM_DATASET2(DcmShortText, EVR_ST, imageDisplayFormat)
342          READ_FROM_DATASET2(DcmCodeString, EVR_CS, annotationDisplayFormatID)
343          if (result==EC_TagNotFound) result = EC_Normal;
344          READ_FROM_DATASET2(DcmCodeString, EVR_CS, filmOrientation)
345          READ_FROM_DATASET2(DcmCodeString, EVR_CS, filmSizeID)
346          READ_FROM_DATASET2(DcmCodeString, EVR_CS, magnificationType)
347          READ_FROM_DATASET2(DcmCodeString, EVR_CS, smoothingType)
348          if (result==EC_TagNotFound) result = EC_Normal;
349          READ_FROM_DATASET2(DcmCodeString, EVR_CS, borderDensity)
350          if (result==EC_TagNotFound) result = EC_Normal;
351          READ_FROM_DATASET2(DcmCodeString, EVR_CS, emptyImageDensity)
352          if (result==EC_TagNotFound) result = EC_Normal;
353          READ_FROM_DATASET2(DcmUnsignedShort, EVR_US, minDensity)
354          if (result==EC_TagNotFound) result = EC_Normal;
355          READ_FROM_DATASET2(DcmUnsignedShort, EVR_US, maxDensity)
356          READ_FROM_DATASET2(DcmCodeString, EVR_CS, trim)
357          READ_FROM_DATASET2(DcmShortText, EVR_ST, configurationInformation)
358          READ_FROM_DATASET2(DcmUnsignedShort, EVR_US, illumination)
359          if (result==EC_TagNotFound) result = EC_Normal;
360          READ_FROM_DATASET2(DcmUnsignedShort, EVR_US, reflectedAmbientLight)
361          if (result==EC_TagNotFound) result = EC_Normal;
362          READ_FROM_DATASET2(DcmCodeString, EVR_CS, requestedResolutionID)
363          if (result==EC_TagNotFound) result = EC_Normal;
364          // check referenced presentation LUT sequence
365          // if there is any reference, it must refer to one of the presentation LUTs we are managing.
366          stack.clear();
367          if (EC_Normal == item->search(DCM_ReferencedPresentationLUTSequence, stack, ESM_fromHere, OFFalse))
368          {
369            seq=(DcmSequenceOfItems *)stack.top();
370            if (seq->card() ==1)
371            {
372               item = seq->getItem(0);
373               stack.clear();
374               READ_FROM_DATASET2(DcmUniqueIdentifier, EVR_UI, referencedPresentationLUTInstanceUID)
375               if (referencedPresentationLUTInstanceUID.getLength() > 0)
376               {
377                 referencedPresentationLUTInstanceUID.getOFString(aString,0);
378                 if (NULL == presentationLUTList.findPresentationLUT(aString.c_str()))
379                 {
380                   result=EC_IllegalCall;
381                   DCMPSTAT_WARN("FilmBoxContentSequence presentation LUT reference cannot be resolved");
382                 }
383               }
384            } else {
385              result=EC_TagNotFound;
386              DCMPSTAT_WARN("found FilmBoxContentSequence in Stored Print with ReferencedPresentationLUTSequence number of items != 1");
387            }
388          }
389       } else {
390         result=EC_TagNotFound;
391         DCMPSTAT_WARN("found FilmBoxContentSequence in Stored Print with number of items != 1");
392       }
393     }
394   }
395 
396   if (EC_Normal==result) result = imageBoxContentList.read(dset, presentationLUTList);
397 
398   if (EC_Normal==result) result = annotationContentList.read(dset);
399 
400   /* Now perform basic sanity checks */
401 
402   if (result==EC_Normal)
403   {
404     if ((studyInstanceUID.getLength() == 0)||(studyInstanceUID.getVM() != 1))
405     {
406         result=EC_TagNotFound;
407         DCMPSTAT_WARN("StudyInstanceUID missing or incorrect in Stored Print");
408     }
409     if ((seriesInstanceUID.getLength() == 0)||(seriesInstanceUID.getVM() != 1))
410     {
411         result=EC_TagNotFound;
412         DCMPSTAT_WARN("SeriesInstanceUID missing or incorrect in Stored Print");
413     }
414     if ((sOPInstanceUID.getLength() == 0)||(sOPInstanceUID.getVM() != 1))
415     {
416         result=EC_TagNotFound;
417         DCMPSTAT_WARN("SOPInstanceUID missing or incorrect in Stored Print");
418     }
419     if ((patientName.getLength() == 0)||(patientName.getVM() != 1))
420     {
421        // result=EC_TagNotFound;
422       DCMPSTAT_WARN("PatientName missing or incorrect in Stored Print");
423     }
424     if ((imageDisplayFormat.getLength() == 0)||(imageDisplayFormat.getVM() != 1))
425     {
426         result=EC_TagNotFound;
427         DCMPSTAT_WARN("ImageDisplayFormat missing or incorrect in Stored Print");
428     }
429     if (imageBoxContentList.size() == 0)
430     {
431         result=EC_TagNotFound;
432         DCMPSTAT_WARN("ImageBoxContentSequence missing or empty in Stored Print");
433     }
434   }
435 
436   /* Finally check the Print Management Capabilities Sequence
437    * we require the following SOP classes to be referenced here:
438    *   - Basic Film Box
439    *   - Basic Grayscale Image Box
440    *   - at least one Image Storage SOP Class
441    * we also allow the following SOP classes to be referenced:
442    *   - Printer (is part of Basic Grayscale Meta SOP Class)
443    *   - Basic Film Session (ditto)
444    *   - Presentation LUT
445    *   - Basic Annotation Box
446    */
447   if (result==EC_Normal)
448   {
449     stack.clear();
450     if (EC_Normal == dset.search(DCM_RETIRED_PrintManagementCapabilitiesSequence, stack, ESM_fromHere, OFFalse))
451     {
452       OFBool haveFilmBox = OFFalse;
453       OFBool haveGrayscaleImageBox = OFFalse;
454       OFBool haveImageStorage = OFFalse;
455 
456       seq=(DcmSequenceOfItems *)stack.top();
457       unsigned long numItems = seq->card();
458       for (unsigned long i=0; i<numItems; i++)
459       {
460          item = seq->getItem(i);
461          stack.clear();
462          refsopclassuid.clear();
463          READ_FROM_DATASET2(DcmUniqueIdentifier, EVR_UI, refsopclassuid)
464          refsopclassuid.getOFString(aString,0);
465          if (aString == UID_BasicFilmBoxSOPClass)
466            haveFilmBox=OFTrue;
467          else
468            if (aString==UID_BasicGrayscaleImageBoxSOPClass)
469              haveGrayscaleImageBox = OFTrue;
470            else
471              if ((aString == UID_PrinterSOPClass)
472                ||(aString == UID_BasicFilmSessionSOPClass)
473                ||(aString == UID_PresentationLUTSOPClass)
474                ||(aString == UID_BasicAnnotationBoxSOPClass)) { }
475              else
476                if (isImageStorageSOPClass(aString))
477                  haveImageStorage=OFTrue;
478                else
479                  {
480                    result=EC_IllegalCall;
481                    DCMPSTAT_WARN("Unsupported SOP Class UID in PrintManagementCapabilitiesSequence");
482                  }
483 
484       }
485       if (EC_Normal==result)
486       {
487         if (! haveFilmBox)
488         {
489            result=EC_IllegalCall;
490            DCMPSTAT_WARN("Film Box SOP Class not referenced in PrintManagementCapabilitiesSequence");
491         }
492         if (! haveGrayscaleImageBox)
493         {
494            result=EC_IllegalCall;
495            DCMPSTAT_WARN("Basic Grayscale Image Box SOP Class not referenced in PrintManagementCapabilitiesSequence");
496         }
497         if (! haveImageStorage)
498         {
499            result=EC_IllegalCall;
500            DCMPSTAT_WARN("No Image Storage SOP Class referenced in PrintManagementCapabilitiesSequence");
501         }
502       }
503     } else {
504       result=EC_TagNotFound;
505       DCMPSTAT_WARN("PrintManagementCapabilitiesSequence not found");
506     }
507   }
508 
509   /* read PrinterName from PrinterCharacteristicsSequence if available */
510   if (result == EC_Normal)
511   {
512     originator.clear();
513     destination.clear();
514     printerName.clear();
515     stack.clear();
516     if (EC_Normal == dset.search(DCM_RETIRED_PrinterCharacteristicsSequence, stack, ESM_fromHere, OFFalse))
517     {
518       seq = (DcmSequenceOfItems *)stack.top();
519       if (seq->card() > 0)
520       {
521          item = seq->getItem(0);
522          stack.clear();
523          READ_FROM_DATASET2(DcmApplicationEntity, EVR_AE, originator)
524          READ_FROM_DATASET2(DcmApplicationEntity, EVR_AE, destination)
525          READ_FROM_DATASET2(DcmLongString, EVR_LO, printerName)
526       }
527     }
528     if (printerName.getLength() == 0)
529       DCMPSTAT_WARN("PrinterName missing or incorrect in PrinterCharacteristicsSequence");
530   }
531 
532   return result;
533 }
534 
535 
createDefaultValues()536 OFCondition DVPSStoredPrint::createDefaultValues()
537 {
538   OFCondition result = EC_Normal;
539   char uid[100];
540   OFString aString;
541 
542   SET_UID(seriesInstanceUID)
543   SET_UID(imageSeriesInstanceUID)
544 
545   if ((result==EC_Normal)&&(patientName.getLength()==0))
546   {
547         result = patientName.putString(DEFAULT_patientName);
548   }
549 
550   if ((result==EC_Normal)&&(sOPInstanceUID.getLength()==0))
551   {
552     result = sOPInstanceUID.putString(dcmGenerateUniqueIdentifier(uid));
553     DVPSHelper::currentDate(aString);
554     if (result==EC_Normal) result = instanceCreationDate.putString(aString.c_str());
555     DVPSHelper::currentTime(aString);
556     if (result==EC_Normal) result = instanceCreationTime.putString(aString.c_str());
557   }
558 
559   if ((result==EC_Normal)&&(studyInstanceUID.getLength()==0))
560   {
561     result = studyInstanceUID.putString(dcmGenerateUniqueIdentifier(uid, SITE_STUDY_UID_ROOT));
562     DVPSHelper::currentDate(aString);
563     if (result==EC_Normal) result = studyDate.putString(aString.c_str());
564     DVPSHelper::currentTime(aString);
565     if (result==EC_Normal) result = studyTime.putString(aString.c_str());
566   }
567 
568   if ((result==EC_Normal)&&(imageDisplayFormat.getLength()==0)) result = imageDisplayFormat.putString(DEFAULT_imageDisplayFormat);
569   return result;
570 }
571 
write(DcmItem & dset,OFBool writeRequestedImageSize,OFBool limitImages,OFBool updateDecimateCrop,OFBool ignoreEmptyImages)572 OFCondition DVPSStoredPrint::write(
573   DcmItem &dset,
574   OFBool writeRequestedImageSize,
575   OFBool limitImages,
576   OFBool updateDecimateCrop,
577   OFBool ignoreEmptyImages)
578 {
579   DcmElement *delem=NULL;
580   DcmSequenceOfItems *dseq=NULL;
581   DcmItem *ditem=NULL;
582 
583   OFCondition result = createDefaultValues();
584   if ((EC_Normal==result)&& updateDecimateCrop) result = imageBoxContentList.setRequestedDecimateCropBehaviour(decimateCropBehaviour); // set in all image boxes
585   if (EC_Normal==result) result = imageBoxContentList.createDefaultValues(limitImages, ignoreEmptyImages); // renumber if limitImages is true
586 
587   ADD_TO_DATASET(DcmPersonName, patientName)
588   ADD_TO_DATASET(DcmLongString, patientID)
589   ADD_TO_DATASET(DcmDate, patientBirthDate)
590   ADD_TO_DATASET(DcmCodeString, patientSex)
591   ADD_TO_DATASET(DcmUniqueIdentifier, studyInstanceUID)
592   ADD_TO_DATASET(DcmDate, studyDate)
593   ADD_TO_DATASET(DcmTime, studyTime)
594   ADD_TO_DATASET(DcmPersonName, referringPhysicianName)
595   ADD_TO_DATASET(DcmShortString, studyID)
596   ADD_TO_DATASET(DcmShortString, accessionNumber)
597   ADD_TO_DATASET(DcmUniqueIdentifier, seriesInstanceUID)
598   ADD_TO_DATASET(DcmIntegerString, seriesNumber)
599   ADD_TO_DATASET(DcmLongString, manufacturer)
600   ADD_TO_DATASET(DcmIntegerString, instanceNumber)
601   ADD_TO_DATASET(DcmUniqueIdentifier, sOPInstanceUID)
602 
603   if (specificCharacterSet.getLength() > 0) { ADD_TO_DATASET(DcmCodeString, specificCharacterSet) }
604   if (instanceCreationDate.getLength() > 0) { ADD_TO_DATASET(DcmDate, instanceCreationDate) }
605   if (instanceCreationTime.getLength() > 0) { ADD_TO_DATASET(DcmTime, instanceCreationTime) }
606 
607   /* create the Film Box Content SQ */
608   if (result == EC_Normal)
609   {
610     ditem = new DcmItem();
611     if (ditem)
612     {
613       dseq = new DcmSequenceOfItems(DCM_RETIRED_FilmBoxContentSequence);
614       if (dseq)
615       {
616         ADD_TO_DATASET2(DcmShortText, imageDisplayFormat)
617         ADD_TO_DATASET2(DcmCodeString, filmOrientation)
618         ADD_TO_DATASET2(DcmCodeString, filmSizeID)
619         ADD_TO_DATASET2(DcmCodeString, magnificationType)
620         ADD_TO_DATASET2(DcmUnsignedShort, maxDensity)
621         ADD_TO_DATASET2(DcmShortText, configurationInformation)
622         if (annotationDisplayFormatID.getLength() > 0) { ADD_TO_DATASET2(DcmCodeString, annotationDisplayFormatID) }
623         if (smoothingType.getLength() > 0) { ADD_TO_DATASET2(DcmCodeString, smoothingType) }
624         if (borderDensity.getLength() > 0) { ADD_TO_DATASET2(DcmCodeString, borderDensity) }
625         if (emptyImageDensity.getLength() > 0) { ADD_TO_DATASET2(DcmCodeString, emptyImageDensity) }
626         if (minDensity.getLength() > 0) { ADD_TO_DATASET2(DcmUnsignedShort, minDensity) }
627         if (trim.getLength() > 0) { ADD_TO_DATASET2(DcmCodeString, trim) }
628         if (requestedResolutionID.getLength() > 0) { ADD_TO_DATASET2(DcmCodeString, requestedResolutionID) }
629         if ((presentationLUTList.size() > 0) || globalPresentationLUTValid)
630         {
631           ADD_TO_DATASET2(DcmUnsignedShort, illumination)
632           ADD_TO_DATASET2(DcmUnsignedShort, reflectedAmbientLight)
633           if ((result == EC_Normal) && globalPresentationLUTValid)
634           {
635               // generate a new UID for the "global" presentation LUT
636               char uid[100];
637               dcmGenerateUniqueIdentifier(uid);
638               globalPresentationLUT.setSOPInstanceUID(uid);
639               result = referencedPresentationLUTInstanceUID.putString(uid);
640           }
641           if (EC_Normal == result) result = addReferencedPLUTSQ(*ditem);
642         }
643         if (result==EC_Normal)
644         {
645           dseq->insert(ditem);
646           dset.insert(dseq, OFTrue /*replaceOld*/);
647         } else {
648           // out of memory during creation of sequence contents.
649           delete dseq;
650           delete ditem;
651           result = EC_MemoryExhausted;
652         }
653       } else {
654         // could allocate item but not sequence. Bail out.
655         delete ditem;
656         result = EC_MemoryExhausted;
657       }
658     }
659     else result = EC_MemoryExhausted;
660   }
661 
662   /* add SOP Class UID */
663   DcmUniqueIdentifier sopclassuid(DCM_SOPClassUID);
664   if (result==EC_Normal)
665   {
666      result = sopclassuid.putString(UID_RETIRED_StoredPrintStorage);
667   }
668   ADD_TO_DATASET(DcmUniqueIdentifier, sopclassuid)
669 
670   /* add Modality */
671 
672   DcmCodeString modality(DCM_Modality);
673   if (result==EC_Normal)
674   {
675      result = modality.putString("STORED_PRINT");  // defined term
676   }
677   ADD_TO_DATASET(DcmCodeString, modality)
678 
679   // compute number of image boxes to write
680   updateCache();
681   unsigned long writeImageBoxes=0; // default: write all
682   if (limitImages && currentValuesValid) writeImageBoxes = currentNumCols * currentNumRows;
683 
684   // write PresentationLUTContentSequence
685   if (EC_Normal == result)
686   {
687     // write general presentation LUT only
688     if (globalPresentationLUTValid)
689     {
690         dseq = new DcmSequenceOfItems(DCM_RETIRED_PresentationLUTContentSequence);
691         if (dseq)
692         {
693             ditem = new DcmItem();
694             if (ditem)
695             {
696                 result = globalPresentationLUT.write(*ditem, OFTrue);
697                 if (result == EC_Normal) dseq->insert(ditem); else delete ditem;
698             } else result = EC_MemoryExhausted;
699         } else result = EC_MemoryExhausted;
700         if (result == EC_Normal) dset.insert(dseq, OFTrue /*replaceOld*/); else delete dseq;
701     } else {
702         // write presentation LUT list
703         result = presentationLUTList.write(dset);
704     }
705   }
706 
707   // write imageBoxContentList
708   if (EC_Normal == result)
709     result = imageBoxContentList.write(dset, writeRequestedImageSize, (size_t)writeImageBoxes, ignoreEmptyImages, !globalPresentationLUTValid);
710 
711   // write annotationContentList
712   if (EC_Normal == result) result = annotationContentList.write(dset);
713 
714   // write PrintManagementCapabilitiesSequence
715   dseq = new DcmSequenceOfItems(DCM_RETIRED_PrintManagementCapabilitiesSequence);
716   if (dseq)
717   {
718     if (EC_Normal == result) result = DVPSHelper::addReferencedUIDItem(*dseq, UID_BasicFilmSessionSOPClass);
719     if (EC_Normal == result) result = DVPSHelper::addReferencedUIDItem(*dseq, UID_BasicFilmBoxSOPClass);
720     if (EC_Normal == result) result = DVPSHelper::addReferencedUIDItem(*dseq, UID_BasicGrayscaleImageBoxSOPClass);
721     if (EC_Normal == result) result = imageBoxContentList.addImageSOPClasses(*dseq, (size_t)writeImageBoxes);
722     if ((result == EC_Normal)&&(presentationLUTList.size() > 0))
723     {
724       result = DVPSHelper::addReferencedUIDItem(*dseq, UID_PresentationLUTSOPClass);
725     }
726     if ((result == EC_Normal)&&(annotationContentList.size() > 0))
727     {
728       result = DVPSHelper::addReferencedUIDItem(*dseq, UID_BasicAnnotationBoxSOPClass);
729     }
730 
731     if (result==EC_Normal) dset.insert(dseq, OFTrue /*replaceOld*/); else delete dseq;
732   } else result = EC_MemoryExhausted;
733 
734   // write PrinterCharacteristicsSequence (Type 2)
735   if (EC_Normal == result)
736   {
737     dseq = new DcmSequenceOfItems(DCM_RETIRED_PrinterCharacteristicsSequence);
738     if (dseq)
739     {
740      if (printerName.getLength() > 0)
741      {
742        ditem = new DcmItem();
743        if (ditem)
744        {
745          ADD_TO_DATASET2(DcmApplicationEntity, originator);
746          ADD_TO_DATASET2(DcmApplicationEntity, destination);
747          ADD_TO_DATASET2(DcmLongString, printerName);
748          if (result == EC_Normal) result = dseq->insert(ditem); else delete ditem;
749        } else result = EC_MemoryExhausted;
750      }
751      if (result == EC_Normal) dset.insert(dseq, OFTrue /*replaceOld*/); else delete dseq;
752     } else result = EC_MemoryExhausted;
753   }
754 
755   return result;
756 }
757 
writeHardcopyImageAttributes(DcmItem & dset)758 OFCondition DVPSStoredPrint::writeHardcopyImageAttributes(DcmItem &dset)
759 {
760   DcmElement *delem=NULL;
761   OFCondition result = createDefaultValues();
762 
763   // add general study module
764   ADD_TO_DATASET(DcmUniqueIdentifier, studyInstanceUID)
765   ADD_TO_DATASET(DcmDate, studyDate)
766   ADD_TO_DATASET(DcmTime, studyTime)
767   ADD_TO_DATASET(DcmPersonName, referringPhysicianName)
768   ADD_TO_DATASET(DcmShortString, studyID)
769   ADD_TO_DATASET(DcmShortString, accessionNumber)
770 
771   // add general series module for hardcopy images
772   DcmIntegerString imageSeriesNumber(DCM_SeriesNumber); // always empty
773   DcmCodeString modality(DCM_Modality);
774   if (result==EC_Normal)
775   {
776      result = modality.putString("HC");
777   }
778   ADD_TO_DATASET(DcmUniqueIdentifier, imageSeriesInstanceUID)
779   ADD_TO_DATASET(DcmIntegerString, imageSeriesNumber)
780   ADD_TO_DATASET(DcmCodeString, modality)
781 
782   return result;
783 }
784 
getImagePresentationLUT(size_t idx)785 DVPSPresentationLUT *DVPSStoredPrint::getImagePresentationLUT(size_t idx)
786 {
787     /* look for referenced Presentation LUT in image box */
788     const char *plutuid = imageBoxContentList.getReferencedPresentationLUTInstanceUID(idx);
789     /* if absent, look for referenced Presentation LUT in film box */
790     if ((plutuid == NULL) || (strlen(plutuid) == 0))
791     {
792         char *uid = NULL;
793         if (referencedPresentationLUTInstanceUID.getString(uid) == EC_Normal)
794             plutuid = uid;
795     }
796     DVPSPresentationLUT *plut = NULL;
797     if ((plutuid != NULL) && (strlen(plutuid) > 0))
798         plut = presentationLUTList.findPresentationLUT(plutuid);
799     return plut;
800 }
801 
getPresentationLUT()802 DVPSPresentationLUT *DVPSStoredPrint::getPresentationLUT()
803 {
804     if (globalPresentationLUTValid)
805         return &globalPresentationLUT;
806     return NULL;
807 }
808 
setDefaultPresentationLUT()809 OFCondition DVPSStoredPrint::setDefaultPresentationLUT()
810 {
811     globalPresentationLUTValid = OFFalse;
812     globalPresentationLUT.clear();
813     return EC_Normal;
814 }
815 
setPresentationLUTShape(DVPSPresentationLUTType shape)816 OFCondition DVPSStoredPrint::setPresentationLUTShape(DVPSPresentationLUTType shape)
817 {
818     OFCondition result = EC_IllegalCall;
819     if ((shape == DVPSP_identity) || (shape == DVPSP_lin_od))
820     {
821         result = globalPresentationLUT.setType(shape);
822         globalPresentationLUTValid = (result == EC_Normal);
823     }
824     return result;
825 }
826 
setPresentationLookupTable(DcmItem & dset)827 OFCondition DVPSStoredPrint::setPresentationLookupTable(DcmItem &dset)
828 {
829   OFCondition result = globalPresentationLUT.read(dset, OFFalse);
830   globalPresentationLUTValid = (result == EC_Normal);
831   return result;
832 }
833 
convertODtoPValue(Uint16 density,unsigned int bits)834 Sint32 DVPSStoredPrint::convertODtoPValue(Uint16 density, unsigned int bits)
835 {
836   const Uint16 min = getMinDensityValue();
837   const Uint16 max = getMaxDensityValue();
838   if ((min < max) && ((bits == 8) || (bits == 12) || (bits == 16)))
839   {
840     if (density >= max)
841       return 0;
842     else if (density <= min)
843       return (Sint32)DicomImageClass::maxval(bits);
844     else
845     {
846       const double l0 = (double)getPrintIllumination();
847       const double la = (double)getPrintReflectedAmbientLight();
848       const double d0 = (double)density / 100;
849       const double dmin = (double)min / 100;
850       const double dmax = (double)max / 100;
851       const double lmin = la + l0 * pow((double)10, -dmax);
852       const double lmax = la + l0 * pow((double)10, -dmin);
853       const double jmin = DiGSDFunction::getJNDIndex(lmin);
854       const double jmax = DiGSDFunction::getJNDIndex(lmax);
855       const double factor = (double)DicomImageClass::maxval(bits) / (jmax - jmin);
856       return (Sint32)((DiGSDFunction::getJNDIndex(la + l0 * pow((double)10, -d0)) - jmin) * factor);
857     }
858   }
859   return -1;
860 }
861 
addImageBox(const char * retrieveaetitle,const char * refstudyuid,const char * refseriesuid,const char * refsopclassuid,const char * refsopinstanceuid,const char * requestedimagesize,const char * patientid,DVPSPresentationLUT * presentationlut,OFBool inversePLUT)862 OFCondition DVPSStoredPrint::addImageBox(
863   const char *retrieveaetitle,
864   const char *refstudyuid,
865   const char *refseriesuid,
866   const char *refsopclassuid,
867   const char *refsopinstanceuid,
868   const char *requestedimagesize,
869   const char *patientid,
870   DVPSPresentationLUT *presentationlut,
871   OFBool inversePLUT)
872 {
873   char instanceuid[100];
874   const char *lutUID = presentationLUTList.addPresentationLUT(presentationlut, inversePLUT);
875   return imageBoxContentList.addImageBox(dcmGenerateUniqueIdentifier(instanceuid),
876      retrieveaetitle, refstudyuid, refseriesuid, refsopclassuid,
877      refsopinstanceuid, requestedimagesize, patientid, lutUID);
878 }
879 
addImageBox(const char * retrieveaetitle,const char * refsopinstanceuid,const char * requestedimagesize,const char * patientid,DVPSPresentationLUT * presentationlut,OFBool inversePLUT)880 OFCondition DVPSStoredPrint::addImageBox(
881   const char *retrieveaetitle,
882   const char *refsopinstanceuid,
883   const char *requestedimagesize,
884   const char *patientid,
885   DVPSPresentationLUT *presentationlut,
886   OFBool inversePLUT)
887 {
888   char *refstudyuid=NULL;
889   char *refseriesuid=NULL;
890 
891   createDefaultValues(); // make sure that all UIDs are defined
892   studyInstanceUID.getString(refstudyuid); // same study UID for stored print and hardcopy image
893   imageSeriesInstanceUID.getString(refseriesuid); // but separate series for the hardcopy images
894 
895   return addImageBox(retrieveaetitle, refstudyuid, refseriesuid, UID_RETIRED_HardcopyGrayscaleImageStorage,
896      refsopinstanceuid, requestedimagesize, patientid, presentationlut, inversePLUT);
897 }
898 
setOriginator(const char * aetitle)899 OFCondition DVPSStoredPrint::setOriginator(const char *aetitle)
900 {
901   if ((aetitle == NULL) || (strlen(aetitle) == 0))
902     return originator.clear();
903   else
904     return originator.putString(aetitle);
905 }
906 
setDestination(const char * aetitle)907 OFCondition DVPSStoredPrint::setDestination(const char *aetitle)
908 {
909   if ((aetitle == NULL) || (strlen(aetitle) == 0))
910     return destination.clear();
911   else
912     return destination.putString(aetitle);
913 }
914 
setPrinterName(const char * name)915 OFCondition DVPSStoredPrint::setPrinterName(const char *name)
916 {
917   if ((name == NULL) || (strlen(name) == 0))
918     return printerName.clear();
919   else
920     return printerName.putString(name);
921 }
922 
setInstanceUID(const char * uid)923 OFCondition DVPSStoredPrint::setInstanceUID(const char *uid)
924 {
925   if ((uid==NULL)||(strlen(uid)==0)) return EC_IllegalCall;
926   return sOPInstanceUID.putString(uid);
927 }
928 
setImageDisplayFormat(unsigned long columns,unsigned long rows)929 OFCondition DVPSStoredPrint::setImageDisplayFormat(unsigned long columns, unsigned long rows)
930 {
931   if ((columns==0)||(rows==0)) return EC_IllegalCall;
932   char newFormat[80];
933   sprintf(newFormat, "STANDARD\\%lu,%lu", columns, rows);
934 
935   OFCondition result = imageDisplayFormat.putString(newFormat);
936   if (EC_Normal == result)
937   {
938     currentNumCols = columns;
939     currentNumRows = rows;
940     currentValuesValid = OFTrue;
941   } else invalidateCache();
942   return result;
943 }
944 
setFilmSizeID(const char * value)945 OFCondition DVPSStoredPrint::setFilmSizeID(const char *value)
946 {
947   if ((value==NULL)||(strlen(value)==0))
948   {
949     filmSizeID.clear();
950     return EC_Normal;
951   }
952   return filmSizeID.putString(value);
953 }
954 
setMagnificationType(const char * value)955 OFCondition DVPSStoredPrint::setMagnificationType(const char *value)
956 {
957   if ((value==NULL)||(strlen(value)==0))
958   {
959     magnificationType.clear();
960     return EC_Normal;
961   }
962   return magnificationType.putString(value);
963 }
964 
setSmoothingType(const char * value)965 OFCondition DVPSStoredPrint::setSmoothingType(const char *value)
966 {
967   if ((value==NULL)||(strlen(value)==0))
968   {
969     smoothingType.clear();
970     return EC_Normal;
971   }
972   return smoothingType.putString(value);
973 }
974 
setConfigurationInformation(const char * value)975 OFCondition DVPSStoredPrint::setConfigurationInformation(const char *value)
976 {
977   if ((value==NULL)||(strlen(value)==0))
978   {
979     configurationInformation.clear();
980     return EC_Normal;
981   }
982   return configurationInformation.putString(value);
983 }
984 
setResolutionID(const char * value)985 OFCondition DVPSStoredPrint::setResolutionID(const char *value)
986 {
987   if ((value==NULL)||(strlen(value)==0))
988   {
989     requestedResolutionID.clear();
990     return EC_Normal;
991   }
992   return requestedResolutionID.putString(value);
993 }
994 
setFilmOrientation(DVPSFilmOrientation value)995 OFCondition DVPSStoredPrint::setFilmOrientation(DVPSFilmOrientation value)
996 {
997   switch (value)
998   {
999     case DVPSF_portrait:
1000       return filmOrientation.putString("PORTRAIT");
1001       /* break; */
1002     case DVPSF_landscape:
1003       return filmOrientation.putString("LANDSCAPE");
1004       /* break; */
1005     case DVPSF_default:
1006       filmOrientation.clear();
1007       break;
1008   }
1009   return EC_Normal;
1010 }
1011 
setTrim(DVPSTrimMode value)1012 OFCondition DVPSStoredPrint::setTrim(DVPSTrimMode value)
1013 {
1014   switch (value)
1015   {
1016     case DVPSH_trim_on:
1017       return trim.putString("YES");
1018       /* break; */
1019     case DVPSH_trim_off:
1020       return trim.putString("NO");
1021       /* break; */
1022     case DVPSH_default:
1023       trim.clear();
1024       break;
1025   }
1026   return EC_Normal;
1027 }
1028 
setRequestedDecimateCropBehaviour(DVPSDecimateCropBehaviour value)1029 OFCondition DVPSStoredPrint::setRequestedDecimateCropBehaviour(DVPSDecimateCropBehaviour value)
1030 {
1031   decimateCropBehaviour = value;
1032   return EC_Normal;
1033 }
1034 
1035 
newPrinter(const char * name,const char * destinationAE)1036 OFCondition DVPSStoredPrint::newPrinter(const char *name, const char *destinationAE)
1037 {
1038   filmSizeID.clear();
1039   magnificationType.clear();
1040   smoothingType.clear();
1041   configurationInformation.clear();
1042   requestedResolutionID.clear();
1043   trim.clear();
1044   borderDensity.clear();
1045   emptyImageDensity.clear();
1046   minDensity.clear();
1047   maxDensity.clear();
1048 
1049   if (name != NULL)
1050     setPrinterName(name);
1051   if (destinationAE != NULL)
1052     setDestination(destinationAE);
1053 
1054   OFCondition result = setRequestedDecimateCropBehaviour(DVPSI_default);
1055   if (EC_Normal == result) result = imageBoxContentList.setAllImagesToDefault();
1056   return result;
1057 }
1058 
getOriginator()1059 const char *DVPSStoredPrint::getOriginator()
1060 {
1061   char *c = NULL;
1062   if (EC_Normal == originator.getString(c)) return c; else return NULL;
1063 }
1064 
getDestination()1065 const char *DVPSStoredPrint::getDestination()
1066 {
1067   char *c = NULL;
1068   if (EC_Normal == destination.getString(c)) return c; else return NULL;
1069 }
1070 
getPrinterName()1071 const char *DVPSStoredPrint::getPrinterName()
1072 {
1073   char *c = NULL;
1074   if (EC_Normal == printerName.getString(c)) return c; else return NULL;
1075 }
1076 
getImageDisplayFormatColumns()1077 unsigned long DVPSStoredPrint::getImageDisplayFormatColumns()
1078 {
1079   updateCache();
1080   return currentNumCols;
1081 }
1082 
getImageDisplayFormatRows()1083 unsigned long DVPSStoredPrint::getImageDisplayFormatRows()
1084 {
1085   updateCache();
1086   return currentNumRows;
1087 }
1088 
getFilmOrientation()1089 DVPSFilmOrientation DVPSStoredPrint::getFilmOrientation()
1090 {
1091   DVPSFilmOrientation result = DVPSF_default;
1092   char *c = NULL;
1093   if ((EC_Normal == filmOrientation.getString(c))&& c)
1094   {
1095     OFString aString(c);
1096     if (aString == "PORTRAIT") result = DVPSF_portrait;
1097     else if (aString == "LANDSCAPE") result = DVPSF_landscape;
1098   }
1099   return result;
1100 }
1101 
getTrim()1102 DVPSTrimMode DVPSStoredPrint::getTrim()
1103 {
1104   DVPSTrimMode result = DVPSH_default;
1105   char *c = NULL;
1106   if ((EC_Normal == trim.getString(c))&& c)
1107   {
1108     OFString aString(c);
1109     if (aString == "YES") result = DVPSH_trim_on;
1110     else if (aString == "NO") result = DVPSH_trim_off;
1111   }
1112   return result;
1113 }
1114 
getStudyInstanceUID()1115 const char *DVPSStoredPrint::getStudyInstanceUID()
1116 {
1117   char *c = NULL;
1118   if (EC_Normal == studyInstanceUID.getString(c)) return c; else return NULL;
1119 }
1120 
getSeriesInstanceUID()1121 const char *DVPSStoredPrint::getSeriesInstanceUID()
1122 {
1123   char *c = NULL;
1124   if (EC_Normal == seriesInstanceUID.getString(c)) return c; else return NULL;
1125 }
1126 
getSOPInstanceUID()1127 const char *DVPSStoredPrint::getSOPInstanceUID()
1128 {
1129   char *c = NULL;
1130   if (EC_Normal == sOPInstanceUID.getString(c)) return c; else return NULL;
1131 }
1132 
getFilmSizeID()1133 const char *DVPSStoredPrint::getFilmSizeID()
1134 {
1135   char *c = NULL;
1136   if (EC_Normal == filmSizeID.getString(c)) return c; else return NULL;
1137 }
1138 
getMagnificationType()1139 const char *DVPSStoredPrint::getMagnificationType()
1140 {
1141   char *c = NULL;
1142   if (EC_Normal == magnificationType.getString(c)) return c; else return NULL;
1143 }
1144 
getSmoothingType()1145 const char *DVPSStoredPrint::getSmoothingType()
1146 {
1147   char *c = NULL;
1148   if (EC_Normal == smoothingType.getString(c)) return c; else return NULL;
1149 }
1150 
getConfigurationInformation()1151 const char *DVPSStoredPrint::getConfigurationInformation()
1152 {
1153   char *c = NULL;
1154   if (EC_Normal == configurationInformation.getString(c)) return c; else return NULL;
1155 }
1156 
getResolutionID()1157 const char *DVPSStoredPrint::getResolutionID()
1158 {
1159   char *c = NULL;
1160   if (EC_Normal == requestedResolutionID.getString(c)) return c; else return NULL;
1161 }
1162 
setBorderDensity(const char * value)1163 OFCondition DVPSStoredPrint::setBorderDensity(const char *value)
1164 {
1165   if ((value==NULL)||(strlen(value)==0))
1166   {
1167     borderDensity.clear();
1168     return EC_Normal;
1169   }
1170   return borderDensity.putString(value);
1171 }
1172 
setEmtpyImageDensity(const char * value)1173 OFCondition DVPSStoredPrint::setEmtpyImageDensity(const char *value)
1174 {
1175   if ((value==NULL)||(strlen(value)==0))
1176   {
1177     emptyImageDensity.clear();
1178     return EC_Normal;
1179   }
1180   return emptyImageDensity.putString(value);
1181 }
1182 
getBorderDensity()1183 const char *DVPSStoredPrint::getBorderDensity()
1184 {
1185   char *c = NULL;
1186   if (EC_Normal == borderDensity.getString(c)) return c; else return NULL;
1187 }
1188 
getEmtpyImageDensity()1189 const char *DVPSStoredPrint::getEmtpyImageDensity()
1190 {
1191   char *c = NULL;
1192   if (EC_Normal == emptyImageDensity.getString(c)) return c; else return NULL;
1193 }
1194 
setPrintIllumination(Uint16 value)1195 OFCondition DVPSStoredPrint::setPrintIllumination(Uint16 value)
1196 {
1197   return illumination.putUint16(value, 0);
1198 }
1199 
getPrintIllumination()1200 Uint16 DVPSStoredPrint::getPrintIllumination()
1201 {
1202   Uint16 result = 0;
1203   if (EC_Normal == illumination.getUint16(result, 0)) return result; else return 0;
1204 }
1205 
setPrintReflectedAmbientLight(Uint16 value)1206 OFCondition DVPSStoredPrint::setPrintReflectedAmbientLight(Uint16 value)
1207 {
1208   return reflectedAmbientLight.putUint16(value, 0);
1209 }
1210 
getPrintReflectedAmbientLight()1211 Uint16 DVPSStoredPrint::getPrintReflectedAmbientLight()
1212 {
1213   Uint16 result = 0;
1214   if (EC_Normal == reflectedAmbientLight.getUint16(result, 0)) return result; else return 0;
1215 }
1216 
deleteImage(size_t idx)1217 OFCondition DVPSStoredPrint::deleteImage(size_t idx)
1218 {
1219   OFCondition result = imageBoxContentList.deleteImage(idx);
1220   char *c = NULL;
1221   if (EC_Normal != configurationInformation.getString(c)) c = NULL;
1222   presentationLUTList.cleanup(c, imageBoxContentList);
1223   return result;
1224 }
1225 
deleteMultipleImages(size_t number)1226 OFCondition DVPSStoredPrint::deleteMultipleImages(size_t number)
1227 {
1228   OFCondition result = imageBoxContentList.deleteMultipleImages(number);
1229   char *c = NULL;
1230   if (EC_Normal != configurationInformation.getString(c)) c = NULL;
1231   presentationLUTList.cleanup(c, imageBoxContentList);
1232   return result;
1233 }
1234 
deleteSpooledImages()1235 OFCondition DVPSStoredPrint::deleteSpooledImages()
1236 {
1237   OFCondition result = EC_IllegalCall;
1238   char *c = NULL;
1239   size_t deleteImageBoxes=0;
1240 
1241   updateCache();
1242   if (currentValuesValid)
1243   {
1244         deleteImageBoxes = currentNumCols * currentNumRows;
1245     if (deleteImageBoxes > imageBoxContentList.size()) deleteImageBoxes = imageBoxContentList.size();
1246     result = imageBoxContentList.deleteMultipleImages(deleteImageBoxes);
1247   }
1248   if (EC_Normal != configurationInformation.getString(c)) c = NULL;
1249   presentationLUTList.cleanup(c, imageBoxContentList);
1250   return result;
1251 }
1252 
printSCUgetPrinterInstance(DVPSPrintMessageHandler & printHandler)1253 OFCondition DVPSStoredPrint::printSCUgetPrinterInstance(DVPSPrintMessageHandler& printHandler)
1254 {
1255   DcmDataset *attributeListOut=NULL;
1256   Uint16 status=0;
1257   OFCondition cond=printHandler.getRQ(UID_PrinterSOPClass, UID_PrinterSOPInstance, NULL, 0, status, attributeListOut);
1258 
1259   /* the N-GET response has been dumped somewhere else, we only need to delete it */
1260   delete attributeListOut;
1261 
1262   if (cond.bad()) return EC_IllegalCall;
1263   return EC_Normal;
1264 }
1265 
printSCUpreparePresentationLUT(DVPSPrintMessageHandler & printHandler,OFBool printerRequiresMatchingLUT,OFBool printerLUTRenderingPreferred,OFBool printerSupports12Bit)1266 OFCondition DVPSStoredPrint::printSCUpreparePresentationLUT(
1267   DVPSPrintMessageHandler& printHandler,
1268   OFBool printerRequiresMatchingLUT,
1269   OFBool printerLUTRenderingPreferred,
1270   OFBool printerSupports12Bit)
1271 {
1272   /* first of all we determine whether we can let the print SCP render Presentation LUT for us. */
1273   renderPresentationLUTinSCP = OFFalse;   // set to true if we can create a presentation LUT for all images
1274   transmitImagesIn12Bit = OFTrue;         // set to false later if images should be transmitted in 8-bit depth
1275 
1276   OFBool printerSupportsPresentationLUT = printHandler.printerSupportsPresentationLUT();
1277   DVPSPresentationLUT *plut = NULL;
1278   if (printerSupportsPresentationLUT)
1279   {
1280     char *filmBox = NULL;
1281     if (EC_Normal != referencedPresentationLUTInstanceUID.getString(filmBox)) filmBox=NULL;
1282     const char *plutuid = imageBoxContentList.haveSinglePresentationLUTUsed(filmBox);
1283     if (plutuid) plut = presentationLUTList.findPresentationLUT(plutuid);
1284     if (plut && (plut->isLegalPrintPresentationLUT()))
1285     {
1286       /* there is a single Presentation LUT that can be used for the complete film,
1287        * and it is a valid Supplement 22 Presentation LUT.
1288        */
1289       if (printerSupports12Bit)
1290       {
1291         /* 12-bit printer, we use the LUT if the printer can handle it and if the user wants it */
1292         if (printerLUTRenderingPreferred)
1293         {
1294           if (printerRequiresMatchingLUT)
1295           {
1296             if (plut->matchesImageDepth(OFTrue)) renderPresentationLUTinSCP = OFTrue;
1297             else
1298             {
1299               if (plut->matchesImageDepth(OFFalse))
1300               {
1301                 renderPresentationLUTinSCP = OFTrue;
1302                 transmitImagesIn12Bit = OFFalse;
1303               }
1304             }
1305           } else renderPresentationLUTinSCP = OFTrue;
1306         }
1307       } else {
1308         /* 8-bit printer, we use the LUT if the printer can handle it */
1309         transmitImagesIn12Bit = OFFalse;
1310         if (printerRequiresMatchingLUT)
1311         {
1312           if (plut->matchesImageDepth(OFFalse)) renderPresentationLUTinSCP = OFTrue;
1313         } else renderPresentationLUTinSCP = OFTrue;
1314       }
1315     } else transmitImagesIn12Bit = printerSupports12Bit;
1316   } else {
1317         transmitImagesIn12Bit = printerSupports12Bit;
1318         DCMPSTAT_WARN("spooler: printer does not support Presentation LUT SOP Class,"
1319              << "  presentation LUT related print job settings will be ignored.");
1320   }
1321 
1322   OFCondition result = EC_Normal;
1323   if (printerSupportsPresentationLUT)
1324   {
1325     DcmDataset dset;
1326     DcmDataset *attributeListOut=NULL;
1327     Uint16 status=0;
1328     if (renderPresentationLUTinSCP)
1329     {
1330       result = plut->write(dset, OFFalse);
1331     } else {
1332       DVPSPresentationLUT identity;
1333       result = identity.write(dset, OFFalse);
1334     }
1335 
1336     if (result==EC_Normal)
1337     {
1338       OFCondition cond = printHandler.createRQ(UID_PresentationLUTSOPClass, presentationLUTInstanceUID, &dset, status, attributeListOut);
1339       if (cond.good() && DIMSE_STATUS_OK(status))
1340       {
1341         /* nothing */
1342       } else {
1343         presentationLUTInstanceUID.clear();
1344         result = EC_IllegalCall;
1345       }
1346       delete attributeListOut;
1347     }
1348   }
1349 
1350   return result;
1351 }
1352 
addReferencedPLUTSQ(DcmItem & dset)1353 OFCondition DVPSStoredPrint::addReferencedPLUTSQ(DcmItem &dset)
1354 {
1355   if (referencedPresentationLUTInstanceUID.getLength() == 0) return EC_Normal;
1356 
1357   OFCondition result = EC_Normal;
1358   DcmElement *delem=NULL;
1359   DcmSequenceOfItems *dseq = new DcmSequenceOfItems(DCM_ReferencedPresentationLUTSequence);
1360   DcmItem *ditem = new DcmItem();
1361 
1362   if (ditem && dseq)
1363   {
1364      ADD_TO_DATASET2(DcmUniqueIdentifier, referencedPresentationLUTInstanceUID)
1365      if (result==EC_Normal)
1366      {
1367        dseq->insert(ditem);
1368        dset.insert(dseq, OFTrue /*replaceOld*/);
1369      } else {
1370       delete dseq;
1371       delete ditem;
1372      }
1373   } else {
1374     delete dseq;
1375     delete ditem;
1376     result = EC_MemoryExhausted;
1377   }
1378   return result;
1379 }
1380 
addPresentationLUTReference(DcmItem & dset)1381 OFCondition DVPSStoredPrint::addPresentationLUTReference(DcmItem& dset)
1382 {
1383   DcmElement *delem=NULL;
1384   OFCondition result = EC_Normal;
1385 
1386   ADD_TO_DATASET(DcmUnsignedShort, illumination)
1387   ADD_TO_DATASET(DcmUnsignedShort, reflectedAmbientLight)
1388 
1389   if (presentationLUTInstanceUID.size() > 0)
1390   {
1391 
1392     DcmUniqueIdentifier refsopclassuid(DCM_ReferencedSOPClassUID);
1393     DcmUniqueIdentifier refsopinstanceuid(DCM_ReferencedSOPInstanceUID);
1394     if (result==EC_Normal) result = refsopclassuid.putString(UID_PresentationLUTSOPClass);
1395     if (result==EC_Normal) result = refsopinstanceuid.putString(presentationLUTInstanceUID.c_str());
1396     DcmSequenceOfItems *dseq = new DcmSequenceOfItems(DCM_ReferencedPresentationLUTSequence);
1397     DcmItem *ditem = new DcmItem();
1398     if ((result == EC_Normal) && ditem && dseq)
1399     {
1400        ADD_TO_DATASET2(DcmUniqueIdentifier, refsopclassuid)
1401        ADD_TO_DATASET2(DcmUniqueIdentifier, refsopinstanceuid)
1402        if (result==EC_Normal)
1403        {
1404          dseq->insert(ditem);
1405          dset.insert(dseq, OFTrue /*replaceOld*/);
1406        } else {
1407         delete dseq;
1408         delete ditem;
1409        }
1410     } else {
1411       delete dseq;
1412       delete ditem;
1413       result = EC_MemoryExhausted;
1414     }
1415   }
1416   return result;
1417 }
1418 
printSCUcreateBasicFilmSession(DVPSPrintMessageHandler & printHandler,DcmDataset & dset,OFBool plutInSession)1419 OFCondition DVPSStoredPrint::printSCUcreateBasicFilmSession(
1420    DVPSPrintMessageHandler& printHandler,
1421    DcmDataset& dset,
1422    OFBool plutInSession)
1423 {
1424   if (filmSessionInstanceUID.size() > 0) return EC_IllegalCall;
1425 
1426   DcmDataset *attributeListOut=NULL;
1427   Uint16 status=0;
1428   OFCondition result = EC_Normal;
1429 
1430   // we expect 'number of copies', 'print priority', 'medium type' and 'film destination' in dset
1431   // add illumination and reflection, and presentation LUT reference if necessary.
1432   if ((printHandler.printerSupportsPresentationLUT()) && plutInSession) result = addPresentationLUTReference(dset);
1433 
1434   if (result==EC_Normal)
1435   {
1436     OFCondition cond = printHandler.createRQ(UID_BasicFilmSessionSOPClass, filmSessionInstanceUID, &dset, status, attributeListOut);
1437     if (cond.bad() || DIMSE_STATUS_BAD(status))
1438     {
1439       result = EC_IllegalCall;
1440       filmSessionInstanceUID.clear();
1441     }
1442     delete attributeListOut;
1443   }
1444   return result;
1445 }
1446 
printSCUcreateBasicFilmBox(DVPSPrintMessageHandler & printHandler,OFBool plutInSession)1447 OFCondition DVPSStoredPrint::printSCUcreateBasicFilmBox(DVPSPrintMessageHandler& printHandler, OFBool plutInSession)
1448 {
1449   if ((filmSessionInstanceUID.size() == 0)||(filmBoxInstanceUID.size() > 0)) return EC_IllegalCall;
1450 
1451   OFCondition result = EC_Normal;
1452   DcmDataset dset;
1453   DcmElement *delem=NULL;
1454   DcmSequenceOfItems *dseq=NULL;
1455   DcmSequenceOfItems *seq=NULL;
1456   DcmItem *ditem=NULL;
1457   DcmItem *item=NULL;
1458   DcmDataset *attributeListOut=NULL;
1459   char *c = NULL;
1460   Uint16 status=0;
1461   DcmStack stack;
1462   OFString grayscaleIB(UID_BasicGrayscaleImageBoxSOPClass);
1463   OFString annotationB(UID_BasicAnnotationBoxSOPClass);
1464 
1465   ADD_TO_DATASET(DcmShortText, imageDisplayFormat)
1466   if (filmOrientation.getLength() > 0)           { ADD_TO_DATASET(DcmCodeString, filmOrientation) }
1467   if (filmSizeID.getLength() > 0)                { ADD_TO_DATASET(DcmCodeString, filmSizeID) }
1468   if (magnificationType.getLength() > 0)         { ADD_TO_DATASET(DcmCodeString, magnificationType) }
1469   if (maxDensity.getLength() > 0)                { ADD_TO_DATASET(DcmUnsignedShort, maxDensity) }
1470   if (configurationInformation.getLength() > 0)  { ADD_TO_DATASET(DcmShortText, configurationInformation) }
1471   if (smoothingType.getLength() > 0)             { ADD_TO_DATASET(DcmCodeString, smoothingType) }
1472   if (borderDensity.getLength() > 0)             { ADD_TO_DATASET(DcmCodeString, borderDensity) }
1473   if (emptyImageDensity.getLength() > 0)         { ADD_TO_DATASET(DcmCodeString, emptyImageDensity) }
1474   if (minDensity.getLength() > 0)                { ADD_TO_DATASET(DcmUnsignedShort, minDensity) }
1475   if (trim.getLength() > 0)                      { ADD_TO_DATASET(DcmCodeString, trim) }
1476   if (requestedResolutionID.getLength() > 0)     { ADD_TO_DATASET(DcmCodeString, requestedResolutionID) }
1477   if ((printHandler.printerSupportsAnnotationBox())&&(annotationDisplayFormatID.getLength() > 0))
1478   {
1479         ADD_TO_DATASET(DcmCodeString, annotationDisplayFormatID)
1480   }
1481 
1482   // add Referenced Film Session SQ
1483   DcmUniqueIdentifier refsopclassuid(DCM_ReferencedSOPClassUID);
1484   DcmUniqueIdentifier refsopinstanceuid(DCM_ReferencedSOPInstanceUID);
1485   if (result==EC_Normal) result = refsopclassuid.putString(UID_BasicFilmSessionSOPClass);
1486   if (result==EC_Normal) result = refsopinstanceuid.putString(filmSessionInstanceUID.c_str());
1487   if (result==EC_Normal)
1488   {
1489     ditem = new DcmItem();
1490     if (ditem)
1491     {
1492       dseq = new DcmSequenceOfItems(DCM_ReferencedFilmSessionSequence);
1493       if (dseq)
1494       {
1495         ADD_TO_DATASET2(DcmUniqueIdentifier, refsopclassuid)
1496         ADD_TO_DATASET2(DcmUniqueIdentifier, refsopinstanceuid)
1497         if (result==EC_Normal)
1498         {
1499           dseq->insert(ditem);
1500           dset.insert(dseq, OFTrue /*replaceOld*/);
1501         } else {
1502           // out of memory during creation of sequence contents.
1503           delete dseq;
1504           delete ditem;
1505           result = EC_MemoryExhausted;
1506         }
1507       } else {
1508         // could allocate item but not sequence. Bail out.
1509         delete ditem;
1510         result = EC_MemoryExhausted;
1511       }
1512     }
1513     else result = EC_MemoryExhausted;
1514   }
1515 
1516   // add illumination and reflection, and presentation LUT reference if necessary.
1517   if ((result==EC_Normal) && (printHandler.printerSupportsPresentationLUT()) && (!plutInSession)) result = addPresentationLUTReference(dset);
1518 
1519   if (result==EC_Normal)
1520   {
1521         size_t numItems = 0;
1522         size_t i;
1523     OFCondition cond = printHandler.createRQ(UID_BasicFilmBoxSOPClass, filmBoxInstanceUID, &dset, status, attributeListOut);
1524     if (cond.good() && DIMSE_STATUS_OK(status) && attributeListOut)
1525     {
1526       // N-CREATE was successful, now evaluate Referenced Image Box SQ
1527       stack.clear();
1528       if (EC_Normal == attributeListOut->search(DCM_ReferencedImageBoxSequence, stack, ESM_fromHere, OFFalse))
1529       {
1530         seq=(DcmSequenceOfItems *)stack.top();
1531         numItems = (size_t)seq->card();
1532         if (numItems > imageBoxContentList.size()) numItems = imageBoxContentList.size();
1533         for (i=0; i<numItems; i++)
1534         {
1535            item = seq->getItem(OFstatic_cast(Uint32, i));
1536            stack.clear();
1537            READ_FROM_DATASET2(DcmUniqueIdentifier, EVR_UI, refsopclassuid)
1538            READ_FROM_DATASET2(DcmUniqueIdentifier, EVR_UI, refsopinstanceuid)
1539            if (EC_Normal==result) result = refsopclassuid.getString(c);
1540            if ((EC_Normal==result) && c && (grayscaleIB == c))
1541            {
1542              result = refsopinstanceuid.getString(c);
1543                  if (EC_Normal==result) result = imageBoxContentList.setImageSOPInstanceUID(i, c);
1544            } else result = EC_IllegalCall; /* wrong SOP class or unable to read UID */
1545         }
1546       } else result=EC_TagNotFound;
1547 
1548       // evaluate Referenced Basic Annotation Box SQ if present
1549       stack.clear();
1550       annotationContentList.clearAnnotationSOPInstanceUIDs();
1551       if (EC_Normal == attributeListOut->search(DCM_ReferencedBasicAnnotationBoxSequence, stack, ESM_fromHere, OFFalse))
1552       {
1553         seq=(DcmSequenceOfItems *)stack.top();
1554         numItems = (size_t)seq->card();
1555         if (numItems > annotationContentList.size()) numItems = annotationContentList.size();
1556         for (i=0; i<numItems; i++)
1557         {
1558            item = seq->getItem(OFstatic_cast(Uint32, i));
1559            stack.clear();
1560            READ_FROM_DATASET2(DcmUniqueIdentifier, EVR_UI, refsopclassuid)
1561            READ_FROM_DATASET2(DcmUniqueIdentifier, EVR_UI, refsopinstanceuid)
1562            if (EC_Normal==result) result = refsopclassuid.getString(c);
1563            if ((EC_Normal==result) && c && (annotationB == c))
1564            {
1565              result = refsopinstanceuid.getString(c);
1566                  if (EC_Normal==result) result = annotationContentList.setAnnotationSOPInstanceUID(i, c);
1567            } else result = EC_IllegalCall; /* wrong SOP class or unable to read UID */
1568         }
1569       }
1570     } else {
1571       filmBoxInstanceUID.clear();
1572       result = EC_IllegalCall;
1573     }
1574     delete attributeListOut;
1575   }
1576   return result;
1577 }
1578 
1579 
printSCUprintBasicFilmBox(DVPSPrintMessageHandler & printHandler)1580 OFCondition DVPSStoredPrint::printSCUprintBasicFilmBox(DVPSPrintMessageHandler& printHandler)
1581 {
1582   if (filmBoxInstanceUID.size() == 0) return EC_IllegalCall;
1583   DcmDataset *attributeListOut=NULL;
1584   Uint16 status=0;
1585 
1586   OFCondition cond = printHandler.actionRQ(UID_BasicFilmBoxSOPClass, filmBoxInstanceUID.c_str(),
1587     1 /* action type ID 1 = print */, NULL /* no action information */, status, attributeListOut);
1588   delete attributeListOut; // should be empty anyway
1589 
1590   if (cond.good() && DIMSE_STATUS_OK(status)) return EC_Normal;
1591   return EC_IllegalCall; // otherwise
1592 }
1593 
printSCUprintBasicFilmSession(DVPSPrintMessageHandler & printHandler)1594 OFCondition DVPSStoredPrint::printSCUprintBasicFilmSession(DVPSPrintMessageHandler& printHandler)
1595 {
1596   DcmDataset *attributeListOut=NULL;
1597   Uint16 status=0;
1598 
1599   OFCondition cond = printHandler.actionRQ(UID_BasicFilmSessionSOPClass, filmSessionInstanceUID.c_str(),
1600     1 /* action type ID 1 = print */, NULL /* no action information */, status, attributeListOut);
1601   delete attributeListOut; // should be empty anyway
1602 
1603   if (cond.good() && DIMSE_STATUS_OK(status)) return EC_Normal;
1604   return EC_IllegalCall; // otherwise
1605 }
1606 
printSCUdelete(DVPSPrintMessageHandler & printHandler)1607 OFCondition DVPSStoredPrint::printSCUdelete(DVPSPrintMessageHandler& printHandler)
1608 {
1609   OFCondition cond = EC_Normal;
1610   Uint16 status=0;
1611   OFCondition result = EC_Normal;
1612 
1613   // delete basic film box
1614   if (filmBoxInstanceUID.size() > 0)
1615   {
1616     cond = printHandler.deleteRQ(UID_BasicFilmBoxSOPClass, filmBoxInstanceUID.c_str(), status);
1617     if (cond.bad() || DIMSE_STATUS_BAD(status)) result = EC_IllegalCall;
1618     filmBoxInstanceUID.clear();
1619   }
1620 
1621   // delete basic film session
1622   if (filmSessionInstanceUID.size() > 0)
1623   {
1624     cond = printHandler.deleteRQ(UID_BasicFilmSessionSOPClass, filmSessionInstanceUID.c_str(), status);
1625     if (cond.bad() || DIMSE_STATUS_BAD(status)) result = EC_IllegalCall;
1626     filmSessionInstanceUID.clear();
1627   }
1628 
1629   // delete presentation LUT
1630   if ((presentationLUTInstanceUID.size() > 0)&&(printHandler.printerSupportsPresentationLUT()))
1631   {
1632     cond = printHandler.deleteRQ(UID_PresentationLUTSOPClass, presentationLUTInstanceUID.c_str(), status);
1633     if (cond.bad() || DIMSE_STATUS_BAD(status)) result = EC_IllegalCall;
1634     presentationLUTInstanceUID.clear();
1635   }
1636   return result;
1637 }
1638 
printSCUsetBasicImageBox(DVPSPrintMessageHandler & printHandler,size_t idx,DicomImage & image,OFBool useMonochrome1)1639 OFCondition DVPSStoredPrint::printSCUsetBasicImageBox(
1640     DVPSPrintMessageHandler& printHandler,
1641     size_t idx,
1642     DicomImage& image,
1643     OFBool useMonochrome1)
1644 {
1645   DcmDataset dataset;
1646   DcmItem *ditem = NULL;
1647   DcmSequenceOfItems *dseq = NULL;
1648   char str[100];
1649   DcmPolymorphOBOW *pxData = NULL;
1650   const void *pxDataVoid;
1651   unsigned long width = image.getWidth();
1652   unsigned long height = image.getHeight();
1653   DcmDataset *attributeListOut=NULL;
1654   Uint16 status=0;
1655 
1656   const char *imageSopInstanceUID = imageBoxContentList.getSOPInstanceUID(idx);
1657   if (imageSopInstanceUID==NULL) return EC_IllegalCall;
1658 
1659   /* any presentation LUT to render on SCU side? */
1660   if (! renderPresentationLUTinSCP)
1661   {
1662     /* look for referenced Presentation LUT in image box */
1663     const char *imageplutuid = imageBoxContentList.getReferencedPresentationLUTInstanceUID(idx);
1664     char *filmplutuid = NULL;
1665     if (EC_Normal != referencedPresentationLUTInstanceUID.getString(filmplutuid)) filmplutuid=NULL;
1666     /* if absent, look for referenced Presentation LUT in film box */
1667     if ((imageplutuid == NULL)||(strlen(imageplutuid)==0)) imageplutuid = filmplutuid;
1668     DVPSPresentationLUT *pLUT = NULL;
1669     if (imageplutuid && (strlen(imageplutuid)>0)) pLUT = presentationLUTList.findPresentationLUT(imageplutuid);
1670     if (pLUT)
1671     {
1672       /* found presentation LUT, activate */
1673       if (pLUT->activate(&image))
1674       {
1675         if ((pLUT->getType() == DVPSP_table)&&(! transmitImagesIn12Bit))
1676         {
1677           DCMPSTAT_WARN("rendering Presentation LUT into 8-bit bitmap, image quality loss possible.");
1678         }
1679       } else {
1680         DCMPSTAT_WARN("unable to activate Presentation LUT, using IDENTITY instead.");
1681         image.setPresentationLutShape(ESP_Identity);
1682       }
1683     } /* else image.setPresentationLutShape(ESP_Identity); -- this does not make sense for MONO1 HG images */
1684   } /* else image.setPresentationLutShape(ESP_Identity); -- this does not make sense for MONO1 HG images */
1685 
1686   OFCondition result = imageBoxContentList.prepareBasicImageBox(idx, dataset);
1687   if (EC_Normal == result)
1688   {
1689     ditem = new DcmItem();
1690     if (ditem)
1691     {
1692       dseq = new DcmSequenceOfItems(DCM_BasicGrayscaleImageSequence);
1693       if (dseq)
1694       {
1695         if (EC_Normal==result) result = DVPSHelper::putUint16Value(ditem, DCM_SamplesPerPixel, 1);
1696         if (useMonochrome1)
1697         {
1698           image.setPolarity(EPP_Reverse);
1699           if (EC_Normal==result) result = DVPSHelper::putStringValue(ditem, DCM_PhotometricInterpretation, "MONOCHROME1");
1700         } else {
1701           if (EC_Normal==result) result = DVPSHelper::putStringValue(ditem, DCM_PhotometricInterpretation, "MONOCHROME2");
1702         }
1703         if (EC_Normal==result) result = DVPSHelper::putUint16Value(ditem, DCM_PixelRepresentation, 0);
1704         if (EC_Normal==result) result = DVPSHelper::putUint16Value(ditem, DCM_Rows, (Uint16)height);
1705         if (EC_Normal==result) result = DVPSHelper::putUint16Value(ditem, DCM_Columns, (Uint16)width);
1706         double aspectRatio = image.getWidthHeightRatio();
1707         if ((aspectRatio != 1.0)&&(aspectRatio != 0))
1708         {
1709           sprintf(str, "10000\\%ld", (long)(aspectRatio*10000.0));
1710           if (EC_Normal==result) result = DVPSHelper::putStringValue(ditem, DCM_PixelAspectRatio, str);
1711         }
1712         if (transmitImagesIn12Bit)
1713         {
1714           if (EC_Normal==result) result = DVPSHelper::putUint16Value(ditem, DCM_BitsAllocated, 16);
1715           if (EC_Normal==result) result = DVPSHelper::putUint16Value(ditem, DCM_BitsStored, 12);
1716           if (EC_Normal==result) result = DVPSHelper::putUint16Value(ditem, DCM_HighBit, 11);
1717           if (EC_Normal==result)
1718           {
1719              pxDataVoid = image.getOutputData(12);
1720                  pxData = new DcmPolymorphOBOW(DCM_PixelData);
1721              if (pxData && pxDataVoid)
1722              {
1723                result = pxData->putUint16Array((Uint16 *)pxDataVoid, (width*height));
1724                if (EC_Normal==result) result = ditem->insert(pxData, OFTrue /*replaceOld*/); else delete pxData;
1725             } else result = EC_IllegalCall;
1726           }
1727         } else {
1728           if (EC_Normal==result) result = DVPSHelper::putUint16Value(ditem, DCM_BitsAllocated, 8);
1729           if (EC_Normal==result) result = DVPSHelper::putUint16Value(ditem, DCM_BitsStored, 8);
1730           if (EC_Normal==result) result = DVPSHelper::putUint16Value(ditem, DCM_HighBit, 7);
1731           if (EC_Normal==result)
1732           {
1733              pxDataVoid = image.getOutputData(8);
1734                  pxData = new DcmPolymorphOBOW(DCM_PixelData);
1735              if (pxData && pxDataVoid)
1736              {
1737                result = pxData->putUint8Array((Uint8 *)pxDataVoid, (width*height));
1738                if (EC_Normal==result) result = ditem->insert(pxData, OFTrue /*replaceOld*/); else delete pxData;
1739             } else result = EC_IllegalCall;
1740           }
1741         }
1742 
1743         if (result==EC_Normal)
1744         {
1745           dseq->insert(ditem);
1746           dataset.insert(dseq, OFTrue /*replaceOld*/);
1747         } else {
1748           // out of memory during creation of sequence contents.
1749           delete dseq;
1750           delete ditem;
1751           result = EC_MemoryExhausted;
1752         }
1753       } else {
1754         // could allocate item but not sequence. Bail out.
1755         delete ditem;
1756         result = EC_MemoryExhausted;
1757       }
1758         } else result = EC_MemoryExhausted;
1759   }
1760 
1761   if (EC_Normal == result)
1762   {
1763     OFCondition cond = printHandler.setRQ(UID_BasicGrayscaleImageBoxSOPClass, imageSopInstanceUID, &dataset, status, attributeListOut);
1764     if (cond.bad() || DIMSE_STATUS_BAD(status)) result = EC_IllegalCall;
1765   }
1766   delete attributeListOut;
1767   return result;
1768 }
1769 
printSCUsetBasicAnnotationBox(DVPSPrintMessageHandler & printHandler,size_t idx)1770 OFCondition DVPSStoredPrint::printSCUsetBasicAnnotationBox(
1771     DVPSPrintMessageHandler& printHandler,
1772     size_t idx)
1773 {
1774   DcmDataset dataset;
1775   DcmDataset *attributeListOut=NULL;
1776   Uint16 status=0;
1777   OFCondition result = EC_Normal;
1778 
1779   if (printHandler.printerSupportsAnnotationBox())
1780   {
1781     const char *annotationSopInstanceUID = annotationContentList.getSOPInstanceUID(idx);
1782     if ((annotationSopInstanceUID==NULL)||(strlen(annotationSopInstanceUID)==0))
1783     {
1784        DCMPSTAT_WARN("not enough Annotation Boxes created by printer, ignoring annotation.");
1785        return EC_Normal;
1786     }
1787 
1788     result = annotationContentList.prepareBasicAnnotationBox(idx, dataset);
1789 
1790     if (EC_Normal == result)
1791     {
1792       OFCondition cond = printHandler.setRQ(UID_BasicAnnotationBoxSOPClass, annotationSopInstanceUID, &dataset, status, attributeListOut);
1793       if (cond.bad() || DIMSE_STATUS_BAD(status)) result = EC_IllegalCall;
1794     }
1795     delete attributeListOut;
1796   } else {
1797     DCMPSTAT_WARN("printer does not support Annotation Box, ignoring annotation.");
1798   }
1799 
1800   return result;
1801 }
1802 
getMaxDensity()1803 const char *DVPSStoredPrint::getMaxDensity()
1804 {
1805   if (maxDensity.getLength() > 0)
1806   {
1807     Uint16 density=0;
1808     if (EC_Normal == maxDensity.getUint16(density,0))
1809     {
1810       char buf[20];
1811       sprintf(buf, "%hu", density);
1812       tempDensity = buf;
1813       return tempDensity.c_str();
1814     }
1815   }
1816   return NULL;
1817 }
1818 
getMinDensity()1819 const char *DVPSStoredPrint::getMinDensity()
1820 {
1821   if (minDensity.getLength() > 0)
1822   {
1823     Uint16 density=0;
1824     if (EC_Normal == minDensity.getUint16(density,0))
1825     {
1826       char buf[20];
1827       sprintf(buf, "%hu", density);
1828       tempDensity = buf;
1829       return tempDensity.c_str();
1830     }
1831   }
1832   return NULL;
1833 }
1834 
getMaxDensityValue()1835 Uint16 DVPSStoredPrint::getMaxDensityValue()
1836 {
1837   if (maxDensity.getLength() > 0)
1838   {
1839     Uint16 density = 0;
1840     if (EC_Normal == maxDensity.getUint16(density, 0))
1841       return density;
1842   }
1843   return 300;
1844 }
1845 
getMinDensityValue()1846 Uint16 DVPSStoredPrint::getMinDensityValue()
1847 {
1848   if (minDensity.getLength() > 0)
1849   {
1850     Uint16 density = 0;
1851     if (EC_Normal == minDensity.getUint16(density, 0))
1852       return density;
1853   }
1854   return 20;
1855 }
1856 
setMaxDensity(const char * value)1857 OFCondition DVPSStoredPrint::setMaxDensity(const char *value)
1858 {
1859   OFCondition result = EC_Normal;
1860   if (value && (strlen(value)>0))
1861   {
1862         Uint16 density = 0;
1863         if (1 == (sscanf(value, "%hu", &density)))
1864         {
1865           result = maxDensity.putUint16(density, 0);
1866         } else result = EC_IllegalCall;
1867   } else maxDensity.clear();
1868   return result;
1869 }
1870 
setMinDensity(const char * value)1871 OFCondition DVPSStoredPrint::setMinDensity(const char *value)
1872 {
1873   OFCondition result = EC_Normal;
1874   if (value && (strlen(value)>0))
1875   {
1876         Uint16 density = 0;
1877         if (1 == (sscanf(value, "%hu", &density)))
1878         {
1879           result = minDensity.putUint16(density, 0);
1880         } else result = EC_IllegalCall;
1881   } else minDensity.clear();
1882   return result;
1883 }
1884 
setSingleAnnotation(const char * displayformat,const char * text,Uint16 position)1885 OFCondition DVPSStoredPrint::setSingleAnnotation(
1886     const char *displayformat,
1887     const char *text,
1888     Uint16 position)
1889 {
1890   OFCondition result = EC_IllegalCall;
1891   if (displayformat && text)
1892   {
1893     char newuid[70];
1894     dcmGenerateUniqueIdentifier(newuid);
1895     deleteAnnotations();
1896     result = annotationContentList.addAnnotationBox(newuid, text, position);
1897     if (EC_Normal==result) result = annotationDisplayFormatID.putString(displayformat);
1898   }
1899   return result;
1900 }
1901 
deleteAnnotations()1902 void DVPSStoredPrint::deleteAnnotations()
1903 {
1904   annotationContentList.clear();
1905   annotationDisplayFormatID.clear();
1906   return;
1907 }
1908 
1909 
1910 
printSCPCreate(DVConfiguration & cfg,const char * cfgname,DcmDataset * rqDataset,T_DIMSE_Message & rsp,DcmDataset * & rspDataset,OFBool presentationLUTnegotiated,DVPSPresentationLUT_PList & globalPresentationLUTList,const char * filmSessionUID,DcmUniqueIdentifier & study,DcmUniqueIdentifier & psSeries,DcmUniqueIdentifier & imgSeries)1911 OFBool DVPSStoredPrint::printSCPCreate(
1912   DVConfiguration& cfg,
1913   const char *cfgname,
1914   DcmDataset *rqDataset,
1915   T_DIMSE_Message& rsp,
1916   DcmDataset *& rspDataset,
1917   OFBool presentationLUTnegotiated,
1918   DVPSPresentationLUT_PList& globalPresentationLUTList,
1919   const char *filmSessionUID,
1920   DcmUniqueIdentifier& study,
1921   DcmUniqueIdentifier& psSeries,
1922   DcmUniqueIdentifier& imgSeries)
1923 {
1924   studyInstanceUID = study;
1925   seriesInstanceUID = psSeries;
1926   imageSeriesInstanceUID = imgSeries;
1927 
1928   OFBool result = OFTrue;
1929   DcmStack stack;
1930   filmBoxInstanceUID = rsp.msg.NCreateRSP.AffectedSOPInstanceUID;
1931 
1932   // filmOrientation
1933   if (result)
1934   {
1935     READ_FROM_PDATASET(DcmCodeString, EVR_CS, filmOrientation)
1936     if (filmOrientation.getLength() == 0) filmOrientation.putString(DEFAULT_filmOrientation);
1937     else
1938     {
1939       OFString aString;
1940       filmOrientation.getOFString(aString, 0, OFTrue);
1941       if ((aString != "PORTRAIT")&&(aString != "LANDSCAPE"))
1942       {
1943         DCMPSTAT_WARN("cannot create Basic Film Box: illegal film orientation: '" << aString.c_str() << "'");
1944         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
1945         result = OFFalse;
1946       }
1947     }
1948   }
1949 
1950   // imageDisplayFormat
1951   if (result)
1952   {
1953     READ_FROM_PDATASET(DcmShortText, EVR_ST, imageDisplayFormat)
1954     if (imageDisplayFormat.getLength() == 0)
1955     {
1956         DCMPSTAT_WARN("cannot create Basic Film Box: image display format missing or empty");
1957         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_MissingAttribute;
1958         result = OFFalse;
1959     } else {
1960       currentValuesValid = OFFalse;
1961       updateCache(); // evaluates image display format and computes number of columns and rows
1962       if (currentValuesValid)
1963       {
1964         // now we check whether this is a supported layout as per the config file
1965         Uint32 numPortraitDisplayFormats = cfg.getTargetPrinterNumberOfPortraitDisplayFormats(cfgname);
1966         if (numPortraitDisplayFormats > 0)
1967         {
1968           OFBool found = OFFalse;
1969           DVPSFilmOrientation orientation = getFilmOrientation();
1970           Uint32 col=0;
1971           Uint32 row=0;
1972           for (Uint32 i=0; i<numPortraitDisplayFormats; i++)
1973           {
1974              col=cfg.getTargetPrinterPortraitDisplayFormatColumns(cfgname,i);
1975              row=cfg.getTargetPrinterPortraitDisplayFormatRows(cfgname,i);
1976              if (orientation == DVPSF_landscape)
1977              {
1978                if ((col==currentNumRows)&&(row==currentNumCols))
1979                {
1980                  found = OFTrue;
1981                  break;
1982                }
1983              } else {
1984                if ((col==currentNumCols)&&(row==currentNumRows))
1985                {
1986                  found = OFTrue;
1987                  break;
1988                }
1989              }
1990           }
1991           if (! found)
1992           {
1993             OFString aString;
1994             imageDisplayFormat.getOFStringArray(aString);
1995             DCMPSTAT_WARN("cannot create Basic Film Box: unsupported image display format: '" << aString.c_str() << "'");
1996             rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
1997             result = OFFalse;
1998           }
1999         }
2000       } else {
2001         OFString aString;
2002         imageDisplayFormat.getOFStringArray(aString);
2003         DCMPSTAT_WARN("cannot create Basic Film Box: illegal image display format: '" << aString.c_str() << "'");
2004         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2005         result = OFFalse;
2006       }
2007     }
2008   }
2009 
2010   // filmSizeID
2011   if (result)
2012   {
2013     Uint32 numFilmSizes = cfg.getTargetPrinterNumberOfFilmSizeIDs(cfgname);
2014     READ_FROM_PDATASET(DcmCodeString, EVR_CS, filmSizeID)
2015     if (filmSizeID.getLength() == 0)
2016     {
2017       if (numFilmSizes > 0)
2018       {
2019         OFString aString;
2020         cfg.getTargetPrinterFilmSizeID(cfgname, 0, aString);
2021         filmSizeID.putString(aString.c_str());
2022       } else {
2023         filmSizeID.putString(DEFAULT_filmSizeID);
2024       }
2025     } else {
2026       // check whether we can accept the proposed medium type
2027       OFString theSizeID;
2028       OFString aString;
2029       OFBool found = OFFalse;
2030       filmSizeID.getOFString(theSizeID, 0, OFTrue);
2031       for (Uint32 i=0; i<numFilmSizes; i++)
2032       {
2033         cfg.getTargetPrinterFilmSizeID(cfgname, i, aString);
2034         if (theSizeID == aString)
2035         {
2036           found = OFTrue;
2037           break;
2038         }
2039       }
2040       if (! found)
2041       {
2042         DCMPSTAT_WARN("cannot create Basic Film Box: illegal film size ID: '" << theSizeID.c_str() << "'");
2043         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2044         result = OFFalse;
2045       }
2046     }
2047   }
2048 
2049   // magnificationType
2050   if (result)
2051   {
2052     Uint32 numMagnifications = cfg.getTargetPrinterNumberOfMagnificationTypes(cfgname);
2053     READ_FROM_PDATASET(DcmCodeString, EVR_CS, magnificationType)
2054     if (magnificationType.getLength() == 0)
2055     {
2056       if (numMagnifications > 0)
2057       {
2058         OFString aString;
2059         cfg.getTargetPrinterMagnificationType(cfgname, 0, aString);
2060         magnificationType.putString(aString.c_str());
2061       } else {
2062         magnificationType.putString(DEFAULT_magnificationType);
2063       }
2064     } else {
2065       // check whether we can accept the proposed medium type
2066       OFString theMagnification;
2067       OFString aString;
2068       OFBool found = OFFalse;
2069       magnificationType.getOFString(theMagnification, 0, OFTrue);
2070       for (Uint32 i=0; i<numMagnifications; i++)
2071       {
2072         cfg.getTargetPrinterMagnificationType(cfgname, i, aString);
2073         if (theMagnification == aString)
2074         {
2075           found = OFTrue;
2076           break;
2077         }
2078       }
2079       if (! found)
2080       {
2081         DCMPSTAT_WARN("cannot create Basic Film Box: illegal magnification type: '" << theMagnification.c_str() << "'");
2082         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2083         result = OFFalse;
2084       }
2085     }
2086   }
2087 
2088   // smoothingType
2089   if (result)
2090   {
2091     Uint32 numSmoothings = cfg.getTargetPrinterNumberOfSmoothingTypes(cfgname);
2092     READ_FROM_PDATASET(DcmCodeString, EVR_CS, smoothingType)
2093     if (smoothingType.getLength() == 0)
2094     {
2095       if (numSmoothings > 0)
2096       {
2097         OFString aString;
2098         cfg.getTargetPrinterSmoothingType(cfgname, 0, aString);
2099         smoothingType.putString(aString.c_str());
2100       }
2101     } else {
2102       // check whether we can accept the proposed smoothing type
2103       OFString theSmoothing;
2104       OFString aString;
2105       OFBool found = OFFalse;
2106       smoothingType.getOFString(theSmoothing, 0, OFTrue);
2107       for (Uint32 i=0; i<numSmoothings; i++)
2108       {
2109         cfg.getTargetPrinterSmoothingType(cfgname, i, aString);
2110         if (theSmoothing == aString)
2111         {
2112           found = OFTrue;
2113           break;
2114         }
2115       }
2116       if (numSmoothings == 0)
2117       {
2118         DCMPSTAT_WARN("cannot create Basic Film Box: smoothing type requested but not supported.");
2119         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2120         result = OFFalse;
2121       }
2122       else if (! found)
2123       {
2124         DCMPSTAT_WARN("cannot create Basic Film Box: illegal smoothing type: '" << theSmoothing.c_str() << "'");
2125         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2126         result = OFFalse;
2127       }
2128     }
2129   }
2130 
2131 
2132   // borderDensity
2133   if (result)
2134   {
2135     Uint32 numBorderDensities = cfg.getTargetPrinterNumberOfBorderDensities(cfgname);
2136     READ_FROM_PDATASET(DcmCodeString, EVR_CS, borderDensity)
2137     if (borderDensity.getLength() == 0)
2138     {
2139       if (numBorderDensities > 0)
2140       {
2141         OFString aString;
2142         cfg.getTargetPrinterBorderDensity(cfgname, 0, aString);
2143         borderDensity.putString(aString.c_str());
2144       }
2145     } else {
2146       // check whether we can accept the proposed border density
2147       if (numBorderDensities == 0) // we don't support border density
2148       {
2149         DCMPSTAT_WARN("cannot create Basic Film Box: border density requested but not supported.");
2150         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2151         result = OFFalse;
2152       } else {
2153         OFString theBorderDensity;
2154         OFString aString;
2155         OFBool found = OFFalse;
2156         OFBool supportsNumericDensity = OFFalse;
2157         unsigned long l;
2158         borderDensity.getOFString(theBorderDensity, 0, OFTrue);
2159         for (Uint32 i=0; i<numBorderDensities; i++)
2160         {
2161           cfg.getTargetPrinterBorderDensity(cfgname, i, aString);
2162           if (theBorderDensity == aString)
2163           {
2164             found = OFTrue;
2165             break;
2166           } else {
2167             if (1 == sscanf(aString.c_str(), "%lu", &l)) supportsNumericDensity = OFTrue;
2168           }
2169         }
2170         if ((! found) && supportsNumericDensity)
2171         {
2172           // the density was not found in the list; check whether it is numerical
2173           if (1 == sscanf(theBorderDensity.c_str(), "%lu", &l)) found = OFTrue;
2174         }
2175 
2176         if (! found)
2177         {
2178           DCMPSTAT_WARN("cannot create Basic Film Box: illegal border density: '" << theBorderDensity.c_str() << "'");
2179           rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2180           result = OFFalse;
2181         }
2182       }
2183     }
2184   }
2185 
2186   // emptyImageDensity
2187   if (result)
2188   {
2189     Uint32 numEmptyImageDensities = cfg.getTargetPrinterNumberOfEmptyImageDensities(cfgname);
2190     READ_FROM_PDATASET(DcmCodeString, EVR_CS, emptyImageDensity)
2191     if (emptyImageDensity.getLength() == 0)
2192     {
2193       if (numEmptyImageDensities > 0)
2194       {
2195         OFString aString;
2196         cfg.getTargetPrinterEmptyImageDensity(cfgname, 0, aString);
2197         emptyImageDensity.putString(aString.c_str());
2198       }
2199     } else {
2200       // check whether we can accept the proposed empty image density
2201       if (numEmptyImageDensities == 0) // we don't support empty image density
2202       {
2203         DCMPSTAT_WARN("cannot create Basic Film Box: empty image density requested but not supported.");
2204         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2205         result = OFFalse;
2206       } else {
2207         OFString theEIDensity;
2208         OFString aString;
2209         OFBool found = OFFalse;
2210         OFBool supportsNumericDensity = OFFalse;
2211         unsigned long l;
2212         emptyImageDensity.getOFString(theEIDensity, 0, OFTrue);
2213         for (Uint32 i=0; i<numEmptyImageDensities; i++)
2214         {
2215           cfg.getTargetPrinterEmptyImageDensity(cfgname, i, aString);
2216           if (theEIDensity == aString)
2217           {
2218             found = OFTrue;
2219             break;
2220           } else {
2221             if (1 == sscanf(aString.c_str(), "%lu", &l)) supportsNumericDensity = OFTrue;
2222           }
2223         }
2224         if ((! found) && supportsNumericDensity)
2225         {
2226           // the density was not found in the list; check whether it is numerical
2227           if (1 == sscanf(theEIDensity.c_str(), "%lu", &l)) found = OFTrue;
2228         }
2229 
2230         if (! found)
2231         {
2232           DCMPSTAT_WARN("cannot create Basic Film Box: illegal empty image density: '" << theEIDensity.c_str() << "'");
2233           rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2234           result = OFFalse;
2235         }
2236       }
2237     }
2238   }
2239 
2240   // maxDensity
2241   if (result)
2242   {
2243     Uint32 numMaxDensities = cfg.getTargetPrinterNumberOfMaxDensities(cfgname);
2244     READ_FROM_PDATASET(DcmUnsignedShort, EVR_US, maxDensity)
2245     if (maxDensity.getLength() == 0)
2246     {
2247       if (numMaxDensities > 0)
2248       {
2249         OFString aString;
2250         cfg.getTargetPrinterMaxDensity(cfgname, 0, aString);
2251         if (EC_Normal != setMaxDensity(aString.c_str())) maxDensity.putUint16(DEFAULT_maxDensity, 0);
2252       }
2253     } // we don't check a max density set by the user (for now)
2254   }
2255 
2256   // minDensity
2257   if (result)
2258   {
2259     Uint32 numMinDensities = cfg.getTargetPrinterNumberOfMinDensities(cfgname);
2260     READ_FROM_PDATASET(DcmUnsignedShort, EVR_US, minDensity)
2261     if (minDensity.getLength() == 0)
2262     {
2263       if (numMinDensities > 0)
2264       {
2265         OFString aString;
2266         cfg.getTargetPrinterMinDensity(cfgname, 0, aString);
2267         if (EC_Normal != setMinDensity(aString.c_str())) minDensity.putUint16(DEFAULT_minDensity, 0);
2268       }
2269     } else {
2270       if (numMinDensities == 0) // we don't support min density
2271       {
2272         DCMPSTAT_WARN("cannot create Basic Film Box: min density requested but not supported.");
2273         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2274         result = OFFalse;
2275       }
2276       // we don't check a min density set by the user (for now)
2277     }
2278   }
2279 
2280   // trim
2281   if (result)
2282   {
2283     READ_FROM_PDATASET(DcmCodeString, EVR_CS, trim)
2284     if (trim.getLength() == 0)
2285     {
2286       if (cfg.getTargetPrinterSupportsTrim(cfgname)) trim.putString(DEFAULT_trim);
2287     }
2288     else
2289     {
2290       if (cfg.getTargetPrinterSupportsTrim(cfgname))
2291       {
2292         OFString aString;
2293         trim.getOFString(aString, 0, OFTrue);
2294         if ((aString != "YES")&&(aString != "NO"))
2295         {
2296           DCMPSTAT_WARN("cannot create Basic Film Box: illegal trim: '" << aString.c_str() << "'");
2297           rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2298           result = OFFalse;
2299         }
2300       } else {
2301         DCMPSTAT_WARN("cannot create Basic Film Box: trim requested but not supported.");
2302         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2303         result = OFFalse;
2304       }
2305     }
2306   }
2307 
2308   // configurationInformation
2309   if (result)
2310   {
2311     READ_FROM_PDATASET(DcmShortText, EVR_ST, configurationInformation)
2312     if (configurationInformation.getLength() > 0)
2313     {
2314       // check whether we can accept the proposed configuration information
2315       Uint32 numConfigurationInformation = cfg.getTargetPrinterNumberOfConfigurationSettings(cfgname);
2316       if (numConfigurationInformation == 0) // we don't support configuration information
2317       {
2318         DCMPSTAT_WARN("cannot create Basic Film Box: configuration information requested but not supported.");
2319         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2320         result = OFFalse;
2321       } else {
2322         OFString theConfiguration;
2323         OFBool found = OFFalse;
2324         configurationInformation.getOFString(theConfiguration, 0, OFTrue);
2325         for (Uint32 i=0; i<numConfigurationInformation; i++)
2326         {
2327           if (theConfiguration == cfg.getTargetPrinterConfigurationSetting(cfgname, i))
2328           {
2329             found = OFTrue;
2330             break;
2331           }
2332         }
2333         if (! found)
2334         {
2335           DCMPSTAT_WARN("cannot create Basic Film Box: illegal configuration information: '" << theConfiguration.c_str() << "'");
2336           rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2337           result = OFFalse;
2338         }
2339       }
2340     }
2341   }
2342 
2343   // requestedResolutionID
2344   if (result)
2345   {
2346     Uint32 numResolutionIDs = cfg.getTargetPrinterNumberOfPrinterResolutionIDs(cfgname);
2347     READ_FROM_PDATASET(DcmCodeString, EVR_CS, requestedResolutionID)
2348     if (requestedResolutionID.getLength() == 0)
2349     {
2350       if (numResolutionIDs > 0)
2351       {
2352         OFString aString;
2353         cfg.getTargetPrinterResolutionID(cfgname, 0, aString);
2354         requestedResolutionID.putString(aString.c_str());
2355       }
2356     } else {
2357       // check whether we can accept the requested resolution ID
2358       if (numResolutionIDs == 0) // we don't support requested resolution ID
2359       {
2360         DCMPSTAT_WARN("cannot create Basic Film Box: requested resolution ID present but not supported.");
2361         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2362         result = OFFalse;
2363       } else {
2364         OFString theResolutionID;
2365         OFString aString;
2366         OFBool found = OFFalse;
2367         requestedResolutionID.getOFString(theResolutionID, 0, OFTrue);
2368         for (Uint32 i=0; i<numResolutionIDs; i++)
2369         {
2370           cfg.getTargetPrinterResolutionID(cfgname, i, aString);
2371           if (theResolutionID == aString)
2372           {
2373             found = OFTrue;
2374             break;
2375           }
2376         }
2377         if (! found)
2378         {
2379           DCMPSTAT_WARN("cannot create Basic Film Box: illegal requested resolution ID: '" << theResolutionID.c_str() << "'");
2380           rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2381           result = OFFalse;
2382         }
2383       }
2384     }
2385   }
2386 
2387   if (presentationLUTnegotiated)
2388   {
2389 
2390     // illumination
2391     if (result)
2392     {
2393       READ_FROM_PDATASET(DcmUnsignedShort, EVR_US, illumination)
2394       if (illumination.getLength() == 0) illumination.putUint16(DEFAULT_illumination, 0);
2395       // we don't check illumination set by the user (for now)
2396     }
2397 
2398     // reflectedAmbientLight
2399     if (result)
2400     {
2401       READ_FROM_PDATASET(DcmUnsignedShort, EVR_US, reflectedAmbientLight)
2402       if (reflectedAmbientLight.getLength() == 0) illumination.putUint16(DEFAULT_reflectedAmbientLight, 0);
2403       // we don't check reflected ambient light set by the user (for now)
2404     }
2405 
2406     // referenced presentation LUT sequence
2407     if (result)
2408     {
2409       stack.clear();
2410 
2411       if (rqDataset && (EC_Normal == rqDataset->search(DCM_ReferencedPresentationLUTSequence, stack, ESM_fromHere, OFFalse)))
2412       {
2413         DcmSequenceOfItems *seq=(DcmSequenceOfItems *)stack.top();
2414         if (seq->card() ==1)
2415         {
2416            OFString aString;
2417            DcmItem *item = seq->getItem(0);
2418            stack.clear();
2419            READ_FROM_DATASET2(DcmUniqueIdentifier, EVR_UI, referencedPresentationLUTInstanceUID)
2420            if (referencedPresentationLUTInstanceUID.getLength() > 0)
2421            {
2422              referencedPresentationLUTInstanceUID.getOFString(aString,0);
2423              DVPSPresentationLUT *currentPLUT = globalPresentationLUTList.findPresentationLUT(aString.c_str());
2424              if (NULL == currentPLUT)
2425              {
2426                DCMPSTAT_WARN("cannot create Basic Film Box: presentation LUT reference cannot be resolved");
2427                rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2428                result = OFFalse;
2429              } else {
2430                // check referenced SOP class UID
2431                DcmUniqueIdentifier refClassUID(DCM_ReferencedSOPClassUID);
2432                stack.clear();
2433                READ_FROM_DATASET2(DcmUniqueIdentifier, EVR_UI, refClassUID)
2434                if (refClassUID.getLength() > 0)
2435                {
2436                   aString.clear();
2437                   refClassUID.getOFString(aString,0, OFTrue);
2438                   if (aString != UID_PresentationLUTSOPClass)
2439                   {
2440                     DCMPSTAT_WARN("cannot create Basic Film Box: referenced SOP class UID in referenced presentation LUT sequence incorrect:"
2441                         << DcmObject::PrintHelper(*stack.top(), DCMTypes::PF_shortenLongTagValues));
2442                     rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2443                     result = OFFalse;
2444                   } else {
2445                     // referenced presentation LUT sequence is OK
2446                     // synchronize presentationLUTInstanceUID and referencedPresentationLUTInstanceUID
2447                     presentationLUTInstanceUID.clear();
2448                     referencedPresentationLUTInstanceUID.getOFString(presentationLUTInstanceUID,0);
2449                     referencedPresentationLUTAlignment = currentPLUT->getAlignment();
2450                   }
2451                } else {
2452                   DCMPSTAT_WARN("cannot create Basic Film Box: no referenced SOP class UID in referenced presentation LUT sequence");
2453                   rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2454                   result = OFFalse;
2455                }
2456              }
2457            } else {
2458              DCMPSTAT_WARN("cannot create Basic Film Box: no referenced SOP instance UID in referenced presentation LUT sequence");
2459              rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2460              result = OFFalse;
2461            }
2462         } else {
2463           DCMPSTAT_WARN("cannot create Basic Film Box: referenced presentation LUT sequence number of items != 1");
2464           rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2465           result = OFFalse;
2466         }
2467       }
2468     }
2469 
2470   } /* if presentationLUTnegotiated */
2471 
2472   DcmSequenceOfItems *refFilmSessionSequence = NULL;
2473 
2474   // referenced film session sequence
2475   if (result)
2476   {
2477     stack.clear();
2478 
2479     if (rqDataset && (EC_Normal == rqDataset->search(DCM_ReferencedFilmSessionSequence, stack, ESM_fromHere, OFFalse)))
2480     {
2481       DcmUniqueIdentifier classUID(DCM_ReferencedSOPClassUID);
2482       DcmUniqueIdentifier instanceUID(DCM_ReferencedSOPInstanceUID);
2483       refFilmSessionSequence =(DcmSequenceOfItems *)stack.top();
2484       if (refFilmSessionSequence->card() ==1)
2485       {
2486          OFString aString;
2487          DcmItem *item = refFilmSessionSequence->getItem(0);
2488          stack.clear();
2489          READ_FROM_DATASET2(DcmUniqueIdentifier, EVR_UI, instanceUID)
2490          if (instanceUID.getLength() > 0)
2491          {
2492            instanceUID.getOFString(aString,0);
2493            if (aString != filmSessionUID)
2494            {
2495              DCMPSTAT_WARN("cannot create Basic Film Box: referenced film session instance UID incorrect");
2496              rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2497              result = OFFalse;
2498            } else {
2499              // check referenced SOP class UID
2500              stack.clear();
2501              READ_FROM_DATASET2(DcmUniqueIdentifier, EVR_UI, classUID)
2502              if (classUID.getLength() > 0)
2503              {
2504                 aString.clear();
2505                 classUID.getOFString(aString,0, OFTrue);
2506                 if (aString != UID_BasicFilmSessionSOPClass)
2507                 {
2508                   DCMPSTAT_WARN("cannot create Basic Film Box: referenced SOP class UID in referenced film session sequence incorrect:"
2509                       << DcmObject::PrintHelper(*stack.top(), DCMTypes::PF_shortenLongTagValues));
2510                   rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2511                   result = OFFalse;
2512                 }
2513              } else {
2514                 DCMPSTAT_WARN("cannot create Basic Film Box: no referenced SOP class UID in referenced film session sequence");
2515                 rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2516                 result = OFFalse;
2517              }
2518            }
2519          } else {
2520            DCMPSTAT_WARN("cannot create Basic Film Box: no referenced SOP instance UID in referenced film session sequence");
2521            rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2522            result = OFFalse;
2523          }
2524       } else {
2525         DCMPSTAT_WARN("cannot create Basic Film Box: referenced film session sequence number of items != 1");
2526         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2527         result = OFFalse;
2528       }
2529     } else {
2530       DCMPSTAT_WARN("cannot create Basic Film Box: referenced film session sequence absent");
2531       rsp.msg.NCreateRSP.DimseStatus = STATUS_N_MissingAttribute;
2532       result = OFFalse;
2533     }
2534   }
2535 
2536   // browse through rqDataset and check for unsupported attributes
2537   if (result && rqDataset)
2538   {
2539     OFBool intoSub = OFTrue;
2540     stack.clear();
2541     while (EC_Normal == rqDataset->nextObject(stack, intoSub))
2542     {
2543       intoSub = OFFalse;
2544       const DcmTagKey& currentTag = (stack.top())->getTag();
2545       if (currentTag.getElement() == 0x0000) /* group length */ ;
2546       else if (currentTag == DCM_ImageDisplayFormat) /* OK */ ;
2547       else if (currentTag == DCM_FilmOrientation) /* OK */ ;
2548       else if (currentTag == DCM_FilmSizeID) /* OK */ ;
2549       else if (currentTag == DCM_MagnificationType) /* OK */ ;
2550       else if (currentTag == DCM_SmoothingType) /* OK */ ;
2551       else if (currentTag == DCM_BorderDensity) /* OK */ ;
2552       else if (currentTag == DCM_EmptyImageDensity) /* OK */ ;
2553       else if (currentTag == DCM_MinDensity) /* OK */ ;
2554       else if (currentTag == DCM_MaxDensity) /* OK */ ;
2555       else if (currentTag == DCM_Trim) /* OK */ ;
2556       else if (currentTag == DCM_ConfigurationInformation) /* OK */ ;
2557       else if (currentTag == DCM_RequestedResolutionID) /* OK */ ;
2558       else if (currentTag == DCM_ReferencedFilmSessionSequence) /* OK */ ;
2559       else if (currentTag == DCM_Illumination)
2560       {
2561         if (! presentationLUTnegotiated)
2562         {
2563           DCMPSTAT_WARN("cannot create Basic Film Box: illumination received:\n"
2564                << DcmObject::PrintHelper(*stack.top(), DCMTypes::PF_shortenLongTagValues));
2565           rsp.msg.NCreateRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2566           result = OFFalse;
2567         }
2568       }
2569       else if (currentTag == DCM_ReflectedAmbientLight)
2570       {
2571         if (! presentationLUTnegotiated)
2572         {
2573           DCMPSTAT_WARN("cannot create Basic Film Box: reflected ambient light received:\n"
2574               << DcmObject::PrintHelper(*stack.top(), DCMTypes::PF_shortenLongTagValues));
2575           rsp.msg.NCreateRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2576           result = OFFalse;
2577         }
2578       }
2579       else if (currentTag == DCM_ReferencedPresentationLUTSequence)
2580       {
2581         if (! presentationLUTnegotiated)
2582         {
2583           DCMPSTAT_WARN("cannot create Basic Film Box: referenced presentation LUT sequence received:\n"
2584               << DcmObject::PrintHelper(*stack.top(), DCMTypes::PF_shortenLongTagValues));
2585           rsp.msg.NCreateRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2586           result = OFFalse;
2587         }
2588       }
2589       else
2590       {
2591         DCMPSTAT_WARN("cannot create Basic Film Box: unsupported attribute received:\n"
2592             << DcmObject::PrintHelper(*stack.top(), DCMTypes::PF_shortenLongTagValues));
2593         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2594         result = OFFalse;
2595       }
2596     }
2597   }
2598 
2599   // if n-create was successful, create response dataset
2600   if (result)
2601   {
2602     rspDataset = new DcmDataset;
2603     if (rspDataset)
2604     {
2605       OFCondition writeresult = EC_Normal;
2606       DcmElement *delem = NULL;
2607 
2608       if (refFilmSessionSequence) // should never be NULL if we get this far
2609       {
2610         DcmSequenceOfItems *newRefFilmSessionSequence = new DcmSequenceOfItems(*refFilmSessionSequence);
2611         if (newRefFilmSessionSequence) rspDataset->insert(newRefFilmSessionSequence, OFTrue /*replaceOld*/);
2612         else writeresult = EC_MemoryExhausted;
2613       }
2614 
2615       ADD_TO_PDATASET(DcmShortText, imageDisplayFormat)
2616       ADD_TO_PDATASET(DcmCodeString, filmOrientation)
2617       ADD_TO_PDATASET(DcmCodeString, filmSizeID)
2618       ADD_TO_PDATASET(DcmCodeString, magnificationType)
2619       ADD_TO_PDATASET(DcmUnsignedShort, maxDensity)
2620       ADD_TO_PDATASET(DcmShortText, configurationInformation)
2621       if (smoothingType.getLength() > 0) { ADD_TO_PDATASET(DcmCodeString, smoothingType) }
2622       if (borderDensity.getLength() > 0) { ADD_TO_PDATASET(DcmCodeString, borderDensity) }
2623       if (emptyImageDensity.getLength() > 0) { ADD_TO_PDATASET(DcmCodeString, emptyImageDensity) }
2624       if (minDensity.getLength() > 0) { ADD_TO_PDATASET(DcmUnsignedShort, minDensity) }
2625       if (trim.getLength() > 0) { ADD_TO_PDATASET(DcmCodeString, trim) }
2626       if (requestedResolutionID.getLength() > 0) { ADD_TO_PDATASET(DcmCodeString, requestedResolutionID) }
2627 
2628       if (presentationLUTnegotiated)
2629       {
2630         if (referencedPresentationLUTInstanceUID.getLength() == 0)
2631         {
2632           referencedPresentationLUTInstanceUID.putString(WELLKNOWN_IDENTITY_PLUT_UID);
2633           if (NULL == globalPresentationLUTList.findPresentationLUT(WELLKNOWN_IDENTITY_PLUT_UID))
2634           {
2635             DVPSPresentationLUT *wellknownlut = new DVPSPresentationLUT();
2636             if (wellknownlut)
2637             {
2638               writeresult = wellknownlut->setType(DVPSP_identity);
2639               if (EC_Normal == writeresult) writeresult = wellknownlut->setSOPInstanceUID(WELLKNOWN_IDENTITY_PLUT_UID);
2640               if (EC_Normal == writeresult) globalPresentationLUTList.insert(wellknownlut);
2641             } else writeresult = EC_MemoryExhausted;
2642           }
2643         }
2644         if (EC_Normal == writeresult) writeresult = addPresentationLUTReference(*rspDataset);
2645       }
2646 
2647       // create image boxes and referenced image box sequence
2648       if (imageBoxContentList.printSCPCreate(currentNumRows * currentNumCols, studyInstanceUID, imageSeriesInstanceUID, cfg.getNetworkAETitle()))
2649       {
2650         if (EC_Normal == writeresult) writeresult = imageBoxContentList.writeReferencedImageBoxSQ(*rspDataset);
2651       } else writeresult = EC_MemoryExhausted;
2652 
2653       if (EC_Normal == writeresult)
2654       {
2655         rsp.msg.NCreateRSP.DataSetType = DIMSE_DATASET_PRESENT;
2656       } else {
2657         delete rspDataset;
2658         rspDataset = NULL;
2659         rsp.msg.NCreateRSP.DimseStatus = STATUS_N_ProcessingFailure;
2660         result = OFFalse;
2661       }
2662     } else {
2663       rsp.msg.NCreateRSP.DimseStatus = STATUS_N_ProcessingFailure;
2664       result = OFFalse;
2665     }
2666   }
2667   return result;
2668 }
2669 
2670 
2671 
2672 
printSCPSet(DVConfiguration & cfg,const char * cfgname,DcmDataset * rqDataset,T_DIMSE_Message & rsp,DcmDataset * & rspDataset,OFBool presentationLUTnegotiated,DVPSPresentationLUT_PList & globalPresentationLUTList)2673 OFBool DVPSStoredPrint::printSCPSet(
2674   DVConfiguration& cfg,
2675   const char *cfgname,
2676   DcmDataset *rqDataset,
2677   T_DIMSE_Message& rsp,
2678   DcmDataset *& rspDataset,
2679   OFBool presentationLUTnegotiated,
2680   DVPSPresentationLUT_PList& globalPresentationLUTList)
2681 {
2682   OFBool result = OFTrue;
2683   DcmStack stack;
2684   OFCondition writeresult = EC_Normal;
2685   DcmElement *delem = NULL;
2686 
2687   rspDataset = new DcmDataset;
2688   if ((rqDataset == NULL)||(rspDataset == NULL))
2689   {
2690     rsp.msg.NSetRSP.DimseStatus = STATUS_N_ProcessingFailure;
2691     result = OFFalse;
2692   }
2693 
2694   // magnificationType
2695   if (result)
2696   {
2697     stack.clear();
2698     if (rqDataset && (EC_Normal == rqDataset->search((DcmTagKey &)magnificationType.getTag(), stack, ESM_fromHere, OFFalse)))
2699     {
2700       magnificationType = *((DcmCodeString *)(stack.top()));
2701       Uint32 numMagnifications = cfg.getTargetPrinterNumberOfMagnificationTypes(cfgname);
2702       OFString theMagnification;
2703       OFString aString;
2704       OFBool found = OFFalse;
2705       magnificationType.getOFString(theMagnification, 0, OFTrue);
2706       for (Uint32 i=0; i<numMagnifications; i++)
2707       {
2708         cfg.getTargetPrinterMagnificationType(cfgname, i, aString);
2709         if (theMagnification == aString)
2710         {
2711           found = OFTrue;
2712           break;
2713         }
2714       }
2715       if (! found)
2716       {
2717         DCMPSTAT_WARN("cannot update Basic Film Box: illegal magnification type: '" << theMagnification.c_str() << "'");
2718         rsp.msg.NSetRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2719         result = OFFalse;
2720       } else {
2721         ADD_TO_PDATASET(DcmCodeString, magnificationType)
2722       }
2723     }
2724   }
2725 
2726   // smoothingType
2727   if (result)
2728   {
2729 
2730     stack.clear();
2731     if (rqDataset && (EC_Normal == rqDataset->search((DcmTagKey &)smoothingType.getTag(), stack, ESM_fromHere, OFFalse)))
2732     {
2733       smoothingType = *((DcmCodeString *)(stack.top()));
2734       Uint32 numSmoothings = cfg.getTargetPrinterNumberOfSmoothingTypes(cfgname);
2735       OFString theSmoothing;
2736       OFString aString;
2737       OFBool found = OFFalse;
2738       smoothingType.getOFString(theSmoothing, 0, OFTrue);
2739       for (Uint32 i=0; i<numSmoothings; i++)
2740       {
2741         cfg.getTargetPrinterSmoothingType(cfgname, i, aString);
2742         if (theSmoothing == aString)
2743         {
2744           found = OFTrue;
2745           break;
2746         }
2747       }
2748       if (numSmoothings == 0)
2749       {
2750         DCMPSTAT_WARN("cannot update Basic Film Box: smoothing type requested but not supported.");
2751         rsp.msg.NSetRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2752         result = OFFalse;
2753       }
2754       else if (! found)
2755       {
2756         DCMPSTAT_WARN("cannot update Basic Film Box: illegal smoothing type: '" << theSmoothing.c_str() << "'");
2757         rsp.msg.NSetRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2758         result = OFFalse;
2759       }
2760       else
2761       {
2762         ADD_TO_PDATASET(DcmCodeString, smoothingType)
2763       }
2764     }
2765   }
2766 
2767 
2768   // borderDensity
2769   if (result)
2770   {
2771 
2772     stack.clear();
2773     if (rqDataset && (EC_Normal == rqDataset->search((DcmTagKey &)borderDensity.getTag(), stack, ESM_fromHere, OFFalse)))
2774     {
2775       borderDensity = *((DcmCodeString *)(stack.top()));
2776       Uint32 numBorderDensities = cfg.getTargetPrinterNumberOfBorderDensities(cfgname);
2777       if (numBorderDensities == 0) // we don't support border density
2778       {
2779         DCMPSTAT_WARN("cannot update Basic Film Box: border density requested but not supported.");
2780         rsp.msg.NSetRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2781         result = OFFalse;
2782       } else {
2783         OFString theBorderDensity;
2784         OFString aString;
2785         OFBool found = OFFalse;
2786         OFBool supportsNumericDensity = OFFalse;
2787         unsigned long l;
2788         borderDensity.getOFString(theBorderDensity, 0, OFTrue);
2789         for (Uint32 i=0; i<numBorderDensities; i++)
2790         {
2791           cfg.getTargetPrinterBorderDensity(cfgname, i, aString);
2792           if (theBorderDensity == aString)
2793           {
2794             found = OFTrue;
2795             break;
2796           } else {
2797             if (1 == sscanf(aString.c_str(), "%lu", &l)) supportsNumericDensity = OFTrue;
2798           }
2799         }
2800         if ((! found) && supportsNumericDensity)
2801         {
2802           // the density was not found in the list; check whether it is numerical
2803           if (1 == sscanf(theBorderDensity.c_str(), "%lu", &l)) found = OFTrue;
2804         }
2805 
2806         if (! found)
2807         {
2808           DCMPSTAT_WARN("cannot update Basic Film Box: illegal border density: '" << theBorderDensity.c_str() << "'");
2809           rsp.msg.NSetRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2810           result = OFFalse;
2811         }
2812         else
2813         {
2814           ADD_TO_PDATASET(DcmCodeString, borderDensity)
2815         }
2816       }
2817     }
2818   }
2819 
2820   // emptyImageDensity
2821   if (result)
2822   {
2823     stack.clear();
2824     if (rqDataset && (EC_Normal == rqDataset->search((DcmTagKey &)emptyImageDensity.getTag(), stack, ESM_fromHere, OFFalse)))
2825     {
2826       emptyImageDensity = *((DcmCodeString *)(stack.top()));
2827       Uint32 numEmptyImageDensities = cfg.getTargetPrinterNumberOfEmptyImageDensities(cfgname);
2828       if (numEmptyImageDensities == 0) // we don't support empty image density
2829       {
2830         DCMPSTAT_WARN("cannot update Basic Film Box: empty image density requested but not supported.");
2831         rsp.msg.NSetRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2832         result = OFFalse;
2833       } else {
2834         OFString theEIDensity;
2835         OFString aString;
2836         OFBool found = OFFalse;
2837         OFBool supportsNumericDensity = OFFalse;
2838         unsigned long l;
2839         emptyImageDensity.getOFString(theEIDensity, 0, OFTrue);
2840         for (Uint32 i=0; i<numEmptyImageDensities; i++)
2841         {
2842           cfg.getTargetPrinterEmptyImageDensity(cfgname, i, aString);
2843           if (theEIDensity == aString)
2844           {
2845             found = OFTrue;
2846             break;
2847           } else {
2848             if (1 == sscanf(aString.c_str(), "%lu", &l)) supportsNumericDensity = OFTrue;
2849           }
2850         }
2851         if ((! found) && supportsNumericDensity)
2852         {
2853           // the density was not found in the list; check whether it is numerical
2854           if (1 == sscanf(theEIDensity.c_str(), "%lu", &l)) found = OFTrue;
2855         }
2856 
2857         if (! found)
2858         {
2859           DCMPSTAT_WARN("cannot update Basic Film Box: illegal empty image density: '" << theEIDensity.c_str() << "'");
2860           rsp.msg.NSetRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2861           result = OFFalse;
2862         }
2863         else
2864         {
2865           ADD_TO_PDATASET(DcmCodeString, emptyImageDensity)
2866         }
2867       }
2868     }
2869   }
2870 
2871   // maxDensity
2872   if (result)
2873   {
2874     stack.clear();
2875     if (rqDataset && (EC_Normal == rqDataset->search((DcmTagKey &)maxDensity.getTag(), stack, ESM_fromHere, OFFalse)))
2876     {
2877       maxDensity = *((DcmUnsignedShort *)(stack.top()));
2878       // we don't check a max density set by the user (for now)
2879       ADD_TO_PDATASET(DcmUnsignedShort, maxDensity)
2880     }
2881   }
2882 
2883   // minDensity
2884   if (result)
2885   {
2886     stack.clear();
2887     if (rqDataset && (EC_Normal == rqDataset->search((DcmTagKey &)minDensity.getTag(), stack, ESM_fromHere, OFFalse)))
2888     {
2889       minDensity = *((DcmUnsignedShort *)(stack.top()));
2890       Uint32 numMinDensities = cfg.getTargetPrinterNumberOfMinDensities(cfgname);
2891       if (numMinDensities == 0) // we don't support min density
2892       {
2893         DCMPSTAT_WARN("cannot update Basic Film Box: min density requested but not supported.");
2894         rsp.msg.NSetRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2895         result = OFFalse;
2896       }
2897       else
2898       {
2899         // we don't check a min density set by the user (for now)
2900         ADD_TO_PDATASET(DcmUnsignedShort, minDensity)
2901       }
2902     }
2903   }
2904 
2905   // trim
2906   if (result)
2907   {
2908     stack.clear();
2909     if (rqDataset && (EC_Normal == rqDataset->search((DcmTagKey &)trim.getTag(), stack, ESM_fromHere, OFFalse)))
2910     {
2911       trim = *((DcmCodeString *)(stack.top()));
2912 
2913       if (cfg.getTargetPrinterSupportsTrim(cfgname))
2914       {
2915         OFString aString;
2916         trim.getOFString(aString, 0, OFTrue);
2917         if ((aString != "YES")&&(aString != "NO"))
2918         {
2919           DCMPSTAT_WARN("cannot update Basic Film Box: illegal trim: '" << aString.c_str() << "'");
2920           rsp.msg.NSetRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2921           result = OFFalse;
2922         } else {
2923           ADD_TO_PDATASET(DcmCodeString, trim)
2924         }
2925       } else {
2926         DCMPSTAT_WARN("cannot update Basic Film Box: trim requested but not supported.");
2927         rsp.msg.NSetRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2928         result = OFFalse;
2929       }
2930     }
2931   }
2932 
2933   // configurationInformation
2934   if (result)
2935   {
2936     stack.clear();
2937     if (rqDataset && (EC_Normal == rqDataset->search((DcmTagKey &)configurationInformation.getTag(), stack, ESM_fromHere, OFFalse)))
2938     {
2939       configurationInformation = *((DcmShortText *)(stack.top()));
2940       Uint32 numConfigurationInformation = cfg.getTargetPrinterNumberOfConfigurationSettings(cfgname);
2941       if (numConfigurationInformation == 0) // we don't support configuration information
2942       {
2943         DCMPSTAT_WARN("cannot update Basic Film Box: configuration information requested but not supported.");
2944         rsp.msg.NSetRSP.DimseStatus = STATUS_N_NoSuchAttribute;
2945         result = OFFalse;
2946       } else {
2947         OFString theConfiguration;
2948         OFBool found = OFFalse;
2949         configurationInformation.getOFString(theConfiguration, 0, OFTrue);
2950         for (Uint32 i=0; i<numConfigurationInformation; i++)
2951         {
2952           if (theConfiguration ==  cfg.getTargetPrinterConfigurationSetting(cfgname, i))
2953           {
2954             found = OFTrue;
2955             break;
2956           }
2957         }
2958         if (! found)
2959         {
2960           DCMPSTAT_WARN("cannot update Basic Film Box: illegal configuration information: '" << theConfiguration.c_str() << "'");
2961           rsp.msg.NSetRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
2962           result = OFFalse;
2963         }
2964         else
2965         {
2966           ADD_TO_PDATASET(DcmShortText, configurationInformation)
2967         }
2968       }
2969     }
2970   }
2971 
2972   if (presentationLUTnegotiated)
2973   {
2974 
2975     // illumination
2976     if (result)
2977     {
2978       stack.clear();
2979       if (rqDataset && (EC_Normal == rqDataset->search((DcmTagKey &)illumination.getTag(), stack, ESM_fromHere, OFFalse)))
2980       {
2981         illumination = *((DcmUnsignedShort *)(stack.top()));
2982         // we don't check illumination set by the user (for now)
2983         ADD_TO_PDATASET(DcmUnsignedShort, illumination)
2984       }
2985     }
2986 
2987     // reflectedAmbientLight
2988     if (result)
2989     {
2990       stack.clear();
2991       if (rqDataset && (EC_Normal == rqDataset->search((DcmTagKey &)reflectedAmbientLight.getTag(), stack, ESM_fromHere, OFFalse)))
2992       {
2993         reflectedAmbientLight = *((DcmUnsignedShort *)(stack.top()));
2994         // we don't check reflected ambient light set by the user (for now)
2995         ADD_TO_PDATASET(DcmUnsignedShort, reflectedAmbientLight)
2996       }
2997     }
2998 
2999     // referenced presentation LUT sequence
3000     if (result)
3001     {
3002       stack.clear();
3003 
3004       if (rqDataset && (EC_Normal == rqDataset->search(DCM_ReferencedPresentationLUTSequence, stack, ESM_fromHere, OFFalse)))
3005       {
3006         DcmSequenceOfItems *seq=(DcmSequenceOfItems *)stack.top();
3007         if (seq->card() ==1)
3008         {
3009            OFString aString;
3010            DcmItem *item = seq->getItem(0);
3011            stack.clear();
3012            READ_FROM_DATASET2(DcmUniqueIdentifier, EVR_UI, referencedPresentationLUTInstanceUID)
3013            if (referencedPresentationLUTInstanceUID.getLength() > 0)
3014            {
3015              referencedPresentationLUTInstanceUID.getOFString(aString,0);
3016              DVPSPresentationLUT *currentPLUT = globalPresentationLUTList.findPresentationLUT(aString.c_str());
3017              if (NULL == currentPLUT)
3018              {
3019                DCMPSTAT_WARN("cannot update Basic Film Box: presentation LUT reference cannot be resolved");
3020                rsp.msg.NSetRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
3021                result = OFFalse;
3022              } else {
3023                // check referenced SOP class UID
3024                DcmUniqueIdentifier refClassUID(DCM_ReferencedSOPClassUID);
3025                stack.clear();
3026                READ_FROM_DATASET2(DcmUniqueIdentifier, EVR_UI, refClassUID)
3027                if (refClassUID.getLength() > 0)
3028                {
3029                   aString.clear();
3030                   refClassUID.getOFString(aString,0, OFTrue);
3031                   if (aString != UID_PresentationLUTSOPClass)
3032                   {
3033                     DCMPSTAT_WARN("cannot update Basic Film Box: referenced SOP class UID in referenced presentation LUT sequence incorrect:\n"
3034                         << DcmObject::PrintHelper(*stack.top(), DCMTypes::PF_shortenLongTagValues));
3035                     rsp.msg.NSetRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
3036                     result = OFFalse;
3037                   } else {
3038                     referencedPresentationLUTAlignment = currentPLUT->getAlignment();
3039                     if ((cfg.getTargetPrinterPresentationLUTMatchRequired(cfgname)) &&
3040                         (! imageBoxContentList.matchesPresentationLUT(referencedPresentationLUTAlignment)))
3041                     {
3042                       DCMPSTAT_WARN("cannot update Basic Film Box: referenced presentation LUT number of entries does not match image bit depth.");
3043                       rsp.msg.NSetRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
3044                       result = OFFalse;
3045                     } else {
3046 
3047                       // referenced presentation LUT sequence is OK
3048                       // synchronize presentationLUTInstanceUID and referencedPresentationLUTInstanceUID
3049                       presentationLUTInstanceUID.clear();
3050                       referencedPresentationLUTInstanceUID.getOFString(presentationLUTInstanceUID,0);
3051                       DcmSequenceOfItems *newSeq = new DcmSequenceOfItems(*seq);
3052                       if (newSeq) rspDataset->insert(newSeq, OFTrue /*replaceOld*/);
3053                       else
3054                       {
3055                         writeresult = EC_MemoryExhausted;
3056                       }
3057                     }
3058                   }
3059                } else {
3060                   DCMPSTAT_WARN("cannot update Basic Film Box: no referenced SOP class UID in referenced presentation LUT sequence");
3061                   rsp.msg.NSetRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
3062                   result = OFFalse;
3063                }
3064              }
3065            } else {
3066              DCMPSTAT_WARN("cannot update Basic Film Box: no referenced SOP instance UID in referenced presentation LUT sequence");
3067              rsp.msg.NSetRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
3068              result = OFFalse;
3069            }
3070         } else {
3071           DCMPSTAT_WARN("cannot update Basic Film Box: referenced presentation LUT sequence number of items != 1");
3072           rsp.msg.NSetRSP.DimseStatus = STATUS_N_InvalidAttributeValue;
3073           result = OFFalse;
3074         }
3075       }
3076     }
3077 
3078   } /* if presentationLUTnegotiated */
3079 
3080 
3081   // browse through rqDataset and check for unsupported attributes
3082   if (result && rqDataset)
3083   {
3084     OFBool intoSub = OFTrue;
3085     stack.clear();
3086     while (EC_Normal == rqDataset->nextObject(stack, intoSub))
3087     {
3088       intoSub = OFFalse;
3089       const DcmTagKey& currentTag = (stack.top())->getTag();
3090       if (currentTag.getElement() == 0x0000) /* group length */ ;
3091       else if (currentTag == DCM_MagnificationType) /* OK */ ;
3092       else if (currentTag == DCM_SmoothingType) /* OK */ ;
3093       else if (currentTag == DCM_BorderDensity) /* OK */ ;
3094       else if (currentTag == DCM_EmptyImageDensity) /* OK */ ;
3095       else if (currentTag == DCM_MinDensity) /* OK */ ;
3096       else if (currentTag == DCM_MaxDensity) /* OK */ ;
3097       else if (currentTag == DCM_Trim) /* OK */ ;
3098       else if (currentTag == DCM_ConfigurationInformation) /* OK */ ;
3099       else if (currentTag == DCM_ReferencedFilmSessionSequence) /* OK */ ;
3100       else if (currentTag == DCM_Illumination)
3101       {
3102         if (! presentationLUTnegotiated)
3103         {
3104           DCMPSTAT_WARN("cannot update Basic Film Box: illumination received:\n"
3105               << DcmObject::PrintHelper(*stack.top(), DCMTypes::PF_shortenLongTagValues));
3106           rsp.msg.NSetRSP.DimseStatus = STATUS_N_NoSuchAttribute;
3107           result = OFFalse;
3108         }
3109       }
3110       else if (currentTag == DCM_ReflectedAmbientLight)
3111       {
3112         if (! presentationLUTnegotiated)
3113         {
3114           DCMPSTAT_WARN("cannot update Basic Film Box: reflected ambient light received:\n"
3115               << DcmObject::PrintHelper(*stack.top(), DCMTypes::PF_shortenLongTagValues));
3116           rsp.msg.NSetRSP.DimseStatus = STATUS_N_NoSuchAttribute;
3117           result = OFFalse;
3118         }
3119       }
3120       else if (currentTag == DCM_ReferencedPresentationLUTSequence)
3121       {
3122         if (! presentationLUTnegotiated)
3123         {
3124           DCMPSTAT_WARN("cannot update Basic Film Box: referenced presentation LUT sequence received:\n"
3125               << DcmObject::PrintHelper(*stack.top(), DCMTypes::PF_shortenLongTagValues));
3126           rsp.msg.NSetRSP.DimseStatus = STATUS_N_NoSuchAttribute;
3127           result = OFFalse;
3128         }
3129       }
3130       else
3131       {
3132         DCMPSTAT_WARN("cannot update Basic Film Box: unsupported attribute received:"
3133             << DcmObject::PrintHelper(*stack.top(), DCMTypes::PF_shortenLongTagValues));
3134         rsp.msg.NSetRSP.DimseStatus = STATUS_N_NoSuchAttribute;
3135         result = OFFalse;
3136       }
3137     }
3138   }
3139 
3140   // if n-set was successful, send back response dataset
3141   if (result && (EC_Normal == writeresult))
3142   {
3143     rsp.msg.NSetRSP.DataSetType = DIMSE_DATASET_PRESENT;
3144   } else {
3145     delete rspDataset;
3146     rspDataset = NULL;
3147     if (rsp.msg.NSetRSP.DimseStatus == 0) rsp.msg.NSetRSP.DimseStatus = STATUS_N_ProcessingFailure;
3148     result = OFFalse;
3149   }
3150   return result;
3151 }
3152 
3153 
usesPresentationLUT(const char * c)3154 OFBool DVPSStoredPrint::usesPresentationLUT(const char *c)
3155 {
3156   char *plut = NULL;
3157   if (c && (EC_Normal == referencedPresentationLUTInstanceUID.getString(plut)) && plut)
3158   {
3159     OFString aString(plut);
3160     if (aString == c) return OFTrue;
3161   }
3162   return OFFalse;
3163 }
3164 
updatePresentationLUTList(DVPSPresentationLUT_PList & globalPresentationLUTList)3165 void DVPSStoredPrint::updatePresentationLUTList(DVPSPresentationLUT_PList& globalPresentationLUTList)
3166 {
3167   presentationLUTList.clear();
3168   if (referencedPresentationLUTInstanceUID.getLength() > 0)
3169   {
3170     OFString aString;
3171     referencedPresentationLUTInstanceUID.getOFString(aString,0);
3172     DVPSPresentationLUT *currentPLUT = globalPresentationLUTList.findPresentationLUT(aString.c_str());
3173     if (currentPLUT) presentationLUTList.insert(currentPLUT->clone());
3174     else
3175     {
3176       referencedPresentationLUTInstanceUID.clear();
3177       presentationLUTInstanceUID.clear();
3178     }
3179   }
3180 }
3181 
overridePresentationLUTSettings(DcmUnsignedShort & newIllumination,DcmUnsignedShort & newReflectedAmbientLight,DcmUniqueIdentifier & newReferencedPLUT,DVPSPrintPresentationLUTAlignment newAlignment)3182 void DVPSStoredPrint::overridePresentationLUTSettings(
3183       DcmUnsignedShort& newIllumination,
3184       DcmUnsignedShort& newReflectedAmbientLight,
3185       DcmUniqueIdentifier& newReferencedPLUT,
3186       DVPSPrintPresentationLUTAlignment newAlignment)
3187 {
3188   illumination = newIllumination;
3189   reflectedAmbientLight = newReflectedAmbientLight;
3190   referencedPresentationLUTInstanceUID = newReferencedPLUT;
3191   presentationLUTInstanceUID.clear();
3192   referencedPresentationLUTInstanceUID.getOFString(presentationLUTInstanceUID,0);
3193   referencedPresentationLUTAlignment = newAlignment;
3194 }
3195