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