1 /*
2 *
3 * Copyright (C) 1997-2020, 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: dcmdata
15 *
16 * Author: Andreas Barth
17 *
18 * Purpose: abstract class DcmCodec and the class DcmCodecStruct
19 *
20 */
21
22 #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
23 #include "dcmtk/dcmdata/dccodec.h"
24 #include "dcmtk/ofstd/oflist.h"
25 #include "dcmtk/ofstd/ofthread.h"
26 #include "dcmtk/dcmdata/dcdeftag.h" /* for tag constants */
27 #include "dcmtk/dcmdata/dcuid.h" /* for dcmGenerateUniqueIdentifer()*/
28 #include "dcmtk/dcmdata/dcitem.h" /* for class DcmItem */
29 #include "dcmtk/dcmdata/dcsequen.h" /* for DcmSequenceOfItems */
30 #include "dcmtk/dcmdata/dcpixseq.h" /* for DcmPixelSequence */
31 #include "dcmtk/dcmdata/dcpxitem.h" /* for DcmPixelItem */
32 #include "dcmtk/dcmdata/dcswap.h" /* for swapIfNecessary */
33 #include "dcmtk/dcmdata/dcvrui.h" /* for DcmUniqueIdentifier */
34
35 // static member variables
36 OFList<DcmCodecList *> DcmCodecList::registeredCodecs;
37
38 #ifdef WITH_THREADS
39 OFReadWriteLock DcmCodecList::codecLock;
40 #endif
41
42 /* --------------------------------------------------------------- */
43
44 // DcmCodec static helper methods
45
insertStringIfMissing(DcmItem * dataset,const DcmTagKey & tag,const char * val)46 OFCondition DcmCodec::insertStringIfMissing(DcmItem *dataset, const DcmTagKey& tag, const char *val)
47 {
48 DcmStack stack;
49 if ((dataset->search(tag, stack, ESM_fromHere, OFFalse)).bad())
50 {
51 return dataset->putAndInsertString(tag, val, OFTrue);
52 }
53 return EC_Normal;
54 }
55
56
convertToSecondaryCapture(DcmItem * dataset)57 OFCondition DcmCodec::convertToSecondaryCapture(DcmItem *dataset)
58 {
59 if (dataset == NULL) return EC_IllegalCall;
60
61 OFCondition result = EC_Normal;
62 char buf[70];
63
64 // SOP Class UID - always replace
65 if (result.good()) result = dataset->putAndInsertString(DCM_SOPClassUID, UID_SecondaryCaptureImageStorage);
66
67 // SOP Instance UID - only insert if missing.
68 dcmGenerateUniqueIdentifier(buf);
69 if (result.good()) result = insertStringIfMissing(dataset, DCM_SOPInstanceUID, buf);
70
71 // Type 1 attributes - insert with value if missing
72 dcmGenerateUniqueIdentifier(buf, SITE_STUDY_UID_ROOT);
73 if (result.good()) result = insertStringIfMissing(dataset, DCM_StudyInstanceUID, buf);
74 dcmGenerateUniqueIdentifier(buf, SITE_SERIES_UID_ROOT);
75 if (result.good()) result = insertStringIfMissing(dataset, DCM_SeriesInstanceUID, buf);
76 if (result.good()) result = insertStringIfMissing(dataset, DCM_ConversionType, "WSD");
77 if (result.good()) result = insertStringIfMissing(dataset, DCM_Modality, "OT");
78
79 // Type 2 attributes - insert without value if missing
80 if (result.good()) result = insertStringIfMissing(dataset, DCM_PatientName, NULL);
81 if (result.good()) result = insertStringIfMissing(dataset, DCM_PatientID, NULL);
82 if (result.good()) result = insertStringIfMissing(dataset, DCM_PatientBirthDate, NULL);
83 if (result.good()) result = insertStringIfMissing(dataset, DCM_PatientSex, NULL);
84 if (result.good()) result = insertStringIfMissing(dataset, DCM_PatientOrientation, NULL);
85 if (result.good()) result = insertStringIfMissing(dataset, DCM_StudyDate, NULL);
86 if (result.good()) result = insertStringIfMissing(dataset, DCM_StudyTime, NULL);
87 if (result.good()) result = insertStringIfMissing(dataset, DCM_ReferringPhysicianName, NULL);
88 if (result.good()) result = insertStringIfMissing(dataset, DCM_StudyID, NULL);
89 if (result.good()) result = insertStringIfMissing(dataset, DCM_AccessionNumber, NULL);
90 if (result.good()) result = insertStringIfMissing(dataset, DCM_SeriesNumber, NULL);
91 if (result.good()) result = insertStringIfMissing(dataset, DCM_InstanceNumber, NULL);
92
93 return result;
94 }
95
96
insertCodeSequence(DcmItem * dataset,const DcmTagKey & tagKey,const char * codingSchemeDesignator,const char * codeValue,const char * codeMeaning)97 OFCondition DcmCodec::insertCodeSequence(
98 DcmItem *dataset,
99 const DcmTagKey &tagKey,
100 const char *codingSchemeDesignator,
101 const char *codeValue,
102 const char *codeMeaning)
103 {
104 if (dataset == NULL || codingSchemeDesignator == NULL ||
105 codeValue == NULL || codeMeaning == NULL) return EC_IllegalCall;
106
107 OFCondition result = EC_Normal;
108 DcmSequenceOfItems *dseq = new DcmSequenceOfItems(tagKey);
109 if (dseq)
110 {
111 DcmItem *ditem = new DcmItem();
112 if (ditem)
113 {
114 dseq->insert(ditem);
115 result = ditem->putAndInsertString(DCM_CodingSchemeDesignator, codingSchemeDesignator);
116 if (result.good()) result = ditem->putAndInsertString(DCM_CodeValue, codeValue);
117 if (result.good()) result = ditem->putAndInsertString(DCM_CodeMeaning, codeMeaning);
118 } else result = EC_MemoryExhausted;
119
120 // insert sequence into dataset if everything went well
121 if (result.good()) dataset->insert(dseq, OFTrue /*replaceOld*/); else delete dseq;
122 } else result = EC_MemoryExhausted;
123
124 return result;
125 }
126
127
newInstance(DcmItem * dataset,const char * purposeOfReferenceCodingScheme,const char * purposeOfReferenceCodeValue,const char * purposeOfReferenceCodeMeaning)128 OFCondition DcmCodec::newInstance(
129 DcmItem *dataset,
130 const char *purposeOfReferenceCodingScheme,
131 const char *purposeOfReferenceCodeValue,
132 const char *purposeOfReferenceCodeMeaning)
133 {
134 if (dataset == NULL) return EC_IllegalCall;
135 OFCondition result = EC_Normal;
136
137 // look up current SOP Class UID and SOP Instance UID
138 const char *classUID = NULL;
139 const char *instanceUID = NULL;
140
141 // search for existing SOP Class UID / SOP Instance UID
142 OFCondition tempResult = dataset->findAndGetString(DCM_SOPClassUID, classUID);
143 if (tempResult.good()) tempResult = dataset->findAndGetString(DCM_SOPInstanceUID, instanceUID);
144 if (tempResult.good() && classUID && instanceUID)
145 {
146 // create source image sequence
147 DcmSequenceOfItems *dseq = new DcmSequenceOfItems(DCM_SourceImageSequence);
148 if (dseq)
149 {
150 DcmItem *ditem = new DcmItem();
151 if (ditem)
152 {
153 dseq->insert(ditem);
154 DcmElement *elem1 = new DcmUniqueIdentifier(DCM_ReferencedSOPClassUID);
155 if (elem1)
156 {
157 result = elem1->putString(classUID);
158 ditem->insert(elem1, OFTrue /*replaceOld*/);
159 if (result.good())
160 {
161 DcmElement *elem2 = new DcmUniqueIdentifier(DCM_ReferencedSOPInstanceUID);
162 if (elem2)
163 {
164 result = elem2->putString(instanceUID);
165 ditem->insert(elem2, OFTrue /*replaceOld*/);
166 } else result = EC_MemoryExhausted;
167 }
168 } else result = EC_MemoryExhausted;
169
170 if (result.good() && purposeOfReferenceCodingScheme &&
171 purposeOfReferenceCodeValue && purposeOfReferenceCodeMeaning)
172 {
173 // add purpose of reference code sequence
174 result = DcmCodec::insertCodeSequence(ditem, DCM_PurposeOfReferenceCodeSequence,
175 purposeOfReferenceCodingScheme, purposeOfReferenceCodeValue, purposeOfReferenceCodeMeaning);
176 }
177 } else result = EC_MemoryExhausted;
178 if (result.good()) dataset->insert(dseq, OFTrue); else delete dseq;
179 } else result = EC_MemoryExhausted;
180 }
181
182 // create new SOP instance UID
183 if (result.good())
184 {
185 char new_uid[100];
186 DcmElement *elem = new DcmUniqueIdentifier(DCM_SOPInstanceUID);
187 if (elem)
188 {
189 if (EC_Normal == (result = elem->putString(dcmGenerateUniqueIdentifier(new_uid))))
190 dataset->insert(elem, OFTrue); // replace SOP Instance UID
191 else delete elem;
192 } else result = EC_MemoryExhausted;
193 }
194
195 return result;
196 }
197
198
updateImageType(DcmItem * dataset)199 OFCondition DcmCodec::updateImageType(DcmItem *dataset)
200 {
201 if (dataset == NULL) return EC_IllegalCall;
202
203 DcmStack stack;
204 OFString imageType("DERIVED");
205 OFString a;
206
207 /* find existing Image Type element */
208 OFCondition status = dataset->search(DCM_ImageType, stack, ESM_fromHere, OFFalse);
209 if (status.good())
210 {
211 DcmElement *elem = OFstatic_cast(DcmElement *, stack.top());
212 unsigned long pos = 1;
213
214 // append old image type information beginning with second entry
215 while ((elem->getOFString(a, pos++)).good())
216 {
217 imageType += "\\";
218 imageType += a;
219 }
220 }
221
222 // insert new Image Type, replace old value
223 return dataset->putAndInsertString(DCM_ImageType, imageType.c_str(), OFTrue);
224 }
225
226
determineStartFragment(Uint32 frameNo,Sint32 numberOfFrames,DcmPixelSequence * fromPixSeq,Uint32 & currentItem)227 OFCondition DcmCodec::determineStartFragment(
228 Uint32 frameNo,
229 Sint32 numberOfFrames,
230 DcmPixelSequence * fromPixSeq,
231 Uint32& currentItem)
232 {
233 Uint32 numberOfFragments = OFstatic_cast(Uint32, fromPixSeq->card());
234 if (numberOfFrames < 1 || numberOfFragments <= OFstatic_cast(Uint32, numberOfFrames) || frameNo >= OFstatic_cast(Uint32, numberOfFrames))
235 return EC_IllegalCall;
236
237 if (frameNo == 0)
238 {
239 // simple case: first frame is always at second fragment
240 currentItem = 1;
241 return EC_Normal;
242 }
243
244 if (numberOfFragments == OFstatic_cast(Uint32, numberOfFrames) + 1)
245 {
246 // standard case: there is one fragment per frame.
247 currentItem = frameNo + 1;
248 return EC_Normal;
249 }
250
251 // non-standard case: multiple fragments per frame.
252 // We now try to consult the offset table.
253 DcmPixelItem *pixItem = NULL;
254 Uint8 *rawOffsetTable = NULL;
255
256 // get first pixel item, i.e. the fragment containing the offset table
257 OFCondition result = fromPixSeq->getItem(pixItem, 0);
258 if (result.good())
259 {
260 Uint32 tableLength = pixItem->getLength();
261 result = pixItem->getUint8Array(rawOffsetTable);
262 if (result.good())
263 {
264 // check if the offset table is empty
265 if (tableLength == 0)
266 result = makeOFCondition(OFM_dcmdata, EC_CODE_CannotDetermineStartFragment, OF_error, "Cannot determine start fragment: basic offset table is empty");
267 // check if the offset table has the right size: 4 bytes for each frame (not fragment!)
268 else if (tableLength != 4 * OFstatic_cast(Uint32, numberOfFrames))
269 result = makeOFCondition(OFM_dcmdata, EC_CODE_CannotDetermineStartFragment, OF_error, "Cannot determine start fragment: basic offset table has wrong size");
270 else {
271
272 // byte swap offset table into local byte order. In file, the offset table is always in little endian
273 swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, rawOffsetTable, tableLength, sizeof(Uint32));
274
275 // cast offset table to Uint32.
276 Uint32 *offsetTable = OFreinterpret_cast(Uint32 *, rawOffsetTable);
277
278 // now access offset of the frame we're looking for
279 Uint32 offset = offsetTable[frameNo];
280
281 // OK, now let's look if we can find a fragment that actually corresponds to that offset.
282 // In counter we compute the offset for each frame by adding all fragment lengths
283 Uint32 counter = 0;
284 // now iterate over all fragments except the index table. The start of the first fragment
285 // is defined as zero.
286 for (Uint32 idx = 1; idx < numberOfFragments; ++idx)
287 {
288 if (counter == offset)
289 {
290 // hooray, we are lucky. We have found the fragment we're looking for
291 currentItem = idx;
292 return EC_Normal;
293 }
294
295 // access pixel item in order to determine its length
296 result = fromPixSeq->getItem(pixItem, idx);
297 if (result.bad())
298 return makeOFCondition(OFM_dcmdata, EC_CODE_CannotDetermineStartFragment, OF_error, "Cannot determine start fragment: cannot access referenced pixel item");
299
300 // add pixel item length plus 8 bytes overhead for the item tag and length field
301 counter += pixItem->getLength() + 8;
302 }
303
304 // bad luck. We have not found a fragment corresponding to the offset in the offset table.
305 // Either we cannot correctly add numbers, or they cannot :-)
306 result = makeOFCondition(OFM_dcmdata, EC_CODE_CannotDetermineStartFragment, OF_error, "Cannot determine start fragment: possibly wrong value in basic offset table");
307 }
308 } else
309 result = makeOFCondition(OFM_dcmdata, EC_CODE_CannotDetermineStartFragment, OF_error, "Cannot determine start fragment: cannot access content of basic offset table");
310 } else
311 result = makeOFCondition(OFM_dcmdata, EC_CODE_CannotDetermineStartFragment, OF_error, "Cannot determine start fragment: cannot access basic offset table (first item)");
312 return result;
313 }
314
315
316 /* --------------------------------------------------------------- */
317
DcmCodecList(const DcmCodec * aCodec,const DcmRepresentationParameter * aDefaultRepParam,const DcmCodecParameter * aCodecParameter)318 DcmCodecList::DcmCodecList(
319 const DcmCodec *aCodec,
320 const DcmRepresentationParameter *aDefaultRepParam,
321 const DcmCodecParameter *aCodecParameter)
322 : codec(aCodec)
323 , defaultRepParam(aDefaultRepParam)
324 , codecParameter(aCodecParameter)
325 {
326 }
327
~DcmCodecList()328 DcmCodecList::~DcmCodecList()
329 {
330 }
331
registerCodec(const DcmCodec * aCodec,const DcmRepresentationParameter * aDefaultRepParam,const DcmCodecParameter * aCodecParameter)332 OFCondition DcmCodecList::registerCodec(
333 const DcmCodec *aCodec,
334 const DcmRepresentationParameter *aDefaultRepParam,
335 const DcmCodecParameter *aCodecParameter)
336 {
337 if ((aCodec == NULL)||(aCodecParameter == NULL)) return EC_IllegalParameter;
338 #ifdef WITH_THREADS
339 if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
340 #endif
341
342 // acquire write lock on codec list. Will block if some codec is currently active.
343 OFCondition result = EC_Normal;
344 #ifdef WITH_THREADS
345 OFReadWriteLocker locker(codecLock);
346 if (0 == locker.wrlock())
347 {
348 #endif
349 DcmCodecList *listEntry = new DcmCodecList(aCodec, aDefaultRepParam, aCodecParameter);
350 if (listEntry)
351 {
352 // prevent codec from being registered twice
353 OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
354 OFListIterator(DcmCodecList *) last = registeredCodecs.end();
355 while (first != last)
356 {
357 if ((*first)->codec == aCodec)
358 {
359 // this codec is already registered.
360 first = last;
361 result = EC_IllegalCall;
362 } else ++first;
363 }
364 if (result.good()) registeredCodecs.push_back(listEntry); else delete listEntry;
365 } else result = EC_MemoryExhausted;
366 #ifdef WITH_THREADS
367 } else result = EC_IllegalCall;
368 #endif
369 return result;
370 }
371
deregisterCodec(const DcmCodec * aCodec)372 OFCondition DcmCodecList::deregisterCodec(const DcmCodec *aCodec)
373 {
374 if (aCodec == NULL) return EC_IllegalParameter;
375 #ifdef WITH_THREADS
376 if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
377 #endif
378 // acquire write lock on codec list. Will block if some codec is currently active.
379 OFCondition result = EC_Normal;
380
381 #ifdef WITH_THREADS
382 OFReadWriteLocker locker(codecLock);
383 if (0 == locker.wrlock())
384 {
385 #endif
386 OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
387 OFListIterator(DcmCodecList *) last = registeredCodecs.end();
388 while (first != last)
389 {
390 if ((*first)->codec == aCodec)
391 {
392 delete *first;
393 first = registeredCodecs.erase(first);
394 } else ++first;
395 }
396 #ifdef WITH_THREADS
397 } else result = EC_IllegalCall;
398 #endif
399 return result;
400 }
401
updateCodecParameter(const DcmCodec * aCodec,const DcmCodecParameter * aCodecParameter)402 OFCondition DcmCodecList::updateCodecParameter(
403 const DcmCodec *aCodec,
404 const DcmCodecParameter *aCodecParameter)
405 {
406 if ((aCodec == NULL)||(aCodecParameter == NULL)) return EC_IllegalParameter;
407 #ifdef WITH_THREADS
408 if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
409 #endif
410 // acquire write lock on codec list. Will block if some codec is currently active.
411 OFCondition result = EC_Normal;
412
413 #ifdef WITH_THREADS
414 OFReadWriteLocker locker(codecLock);
415 if (0 == locker.wrlock())
416 {
417 #endif
418 OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
419 OFListIterator(DcmCodecList *) last = registeredCodecs.end();
420 while (first != last)
421 {
422 if ((*first)->codec == aCodec) (*first)->codecParameter = aCodecParameter;
423 ++first;
424 }
425 #ifdef WITH_THREADS
426 } else result = EC_IllegalCall;
427 #endif
428 return result;
429 }
430
431
decode(const DcmXfer & fromType,const DcmRepresentationParameter * fromParam,DcmPixelSequence * fromPixSeq,DcmPolymorphOBOW & uncompressedPixelData,DcmStack & pixelStack,OFBool & removeOldRep)432 OFCondition DcmCodecList::decode(
433 const DcmXfer & fromType,
434 const DcmRepresentationParameter * fromParam,
435 DcmPixelSequence * fromPixSeq,
436 DcmPolymorphOBOW& uncompressedPixelData,
437 DcmStack & pixelStack,
438 OFBool& removeOldRep)
439 {
440 #ifdef WITH_THREADS
441 if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
442 #endif
443 OFCondition result = EC_CannotChangeRepresentation;
444
445 // acquire write lock on codec list. Will block if some write lock is currently active.
446 #ifdef WITH_THREADS
447 OFReadWriteLocker locker(codecLock);
448 if (0 == locker.rdlock())
449 {
450 #endif
451 E_TransferSyntax fromXfer = fromType.getXfer();
452 OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
453 OFListIterator(DcmCodecList *) last = registeredCodecs.end();
454 while (first != last)
455 {
456 if ((*first)->codec->canChangeCoding(fromXfer, EXS_LittleEndianExplicit))
457 {
458 result = (*first)->codec->decode(fromParam, fromPixSeq, uncompressedPixelData, (*first)->codecParameter, pixelStack, removeOldRep);
459 first = last;
460 } else ++first;
461 }
462 #ifdef WITH_THREADS
463 } else result = EC_IllegalCall;
464 #endif
465 return result;
466 }
467
468
decodeFrame(const DcmXfer & fromType,const DcmRepresentationParameter * fromParam,DcmPixelSequence * fromPixSeq,DcmItem * dataset,Uint32 frameNo,Uint32 & startFragment,void * buffer,Uint32 bufSize,OFString & decompressedColorModel)469 OFCondition DcmCodecList::decodeFrame(
470 const DcmXfer & fromType,
471 const DcmRepresentationParameter * fromParam,
472 DcmPixelSequence * fromPixSeq,
473 DcmItem *dataset,
474 Uint32 frameNo,
475 Uint32& startFragment,
476 void *buffer,
477 Uint32 bufSize,
478 OFString& decompressedColorModel)
479 {
480 #ifdef WITH_THREADS
481 if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
482 #endif
483 OFCondition result = EC_CannotChangeRepresentation;
484
485 // acquire write lock on codec list. Will block if some write lock is currently active.
486 #ifdef WITH_THREADS
487 OFReadWriteLocker locker(codecLock);
488 if (0 == locker.rdlock())
489 {
490 #endif
491 E_TransferSyntax fromXfer = fromType.getXfer();
492 OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
493 OFListIterator(DcmCodecList *) last = registeredCodecs.end();
494 while (first != last)
495 {
496 if ((*first)->codec->canChangeCoding(fromXfer, EXS_LittleEndianExplicit))
497 {
498 result = (*first)->codec->decodeFrame(fromParam, fromPixSeq, (*first)->codecParameter,
499 dataset, frameNo, startFragment, buffer, bufSize, decompressedColorModel);
500 first = last;
501 } else ++first;
502 }
503 #ifdef WITH_THREADS
504 } else result = EC_IllegalCall;
505 #endif
506 return result;
507 }
508
509
encode(const E_TransferSyntax fromRepType,const DcmRepresentationParameter * fromParam,DcmPixelSequence * fromPixSeq,const E_TransferSyntax toRepType,const DcmRepresentationParameter * toRepParam,DcmPixelSequence * & toPixSeq,DcmStack & pixelStack,OFBool & removeOldRep)510 OFCondition DcmCodecList::encode(
511 const E_TransferSyntax fromRepType,
512 const DcmRepresentationParameter * fromParam,
513 DcmPixelSequence * fromPixSeq,
514 const E_TransferSyntax toRepType,
515 const DcmRepresentationParameter * toRepParam,
516 DcmPixelSequence * & toPixSeq,
517 DcmStack & pixelStack,
518 OFBool& removeOldRep)
519 {
520 toPixSeq = NULL;
521 #ifdef WITH_THREADS
522 if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
523 #endif
524 OFCondition result = EC_CannotChangeRepresentation;
525
526 // acquire write lock on codec list. Will block if some write lock is currently active.
527 #ifdef WITH_THREADS
528 OFReadWriteLocker locker(codecLock);
529 if (0 == locker.rdlock())
530 {
531 #endif
532 OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
533 OFListIterator(DcmCodecList *) last = registeredCodecs.end();
534 while (first != last)
535 {
536 if ((*first)->codec->canChangeCoding(fromRepType, toRepType))
537 {
538 if (!toRepParam) toRepParam = (*first)->defaultRepParam;
539 result = (*first)->codec->encode(fromRepType, fromParam, fromPixSeq,
540 toRepParam, toPixSeq, (*first)->codecParameter, pixelStack, removeOldRep);
541 first = last;
542 } else ++first;
543 }
544 #ifdef WITH_THREADS
545 } else result = EC_IllegalCall;
546 #endif
547
548 return result;
549 }
550
encode(const E_TransferSyntax fromRepType,const Uint16 * pixelData,const Uint32 length,const E_TransferSyntax toRepType,const DcmRepresentationParameter * toRepParam,DcmPixelSequence * & toPixSeq,DcmStack & pixelStack,OFBool & removeOldRep)551 OFCondition DcmCodecList::encode(
552 const E_TransferSyntax fromRepType,
553 const Uint16 * pixelData,
554 const Uint32 length,
555 const E_TransferSyntax toRepType,
556 const DcmRepresentationParameter * toRepParam,
557 DcmPixelSequence * & toPixSeq,
558 DcmStack & pixelStack,
559 OFBool& removeOldRep)
560 {
561 toPixSeq = NULL;
562 #ifdef WITH_THREADS
563 if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
564 #endif
565 OFCondition result = EC_CannotChangeRepresentation;
566
567 // acquire write lock on codec list. Will block if some write lock is currently active.
568 #ifdef WITH_THREADS
569 OFReadWriteLocker locker(codecLock);
570 if (0 == locker.rdlock())
571 {
572 #endif
573 OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
574 OFListIterator(DcmCodecList *) last = registeredCodecs.end();
575 while (first != last)
576 {
577 if ((*first)->codec->canChangeCoding(fromRepType, toRepType))
578 {
579 if (!toRepParam) toRepParam = (*first)->defaultRepParam;
580 result = (*first)->codec->encode(pixelData, length, toRepParam, toPixSeq,
581 (*first)->codecParameter, pixelStack, removeOldRep);
582 first = last;
583 } else ++first;
584 }
585 #ifdef WITH_THREADS
586 } else result = EC_IllegalCall;
587 #endif
588
589 return result;
590 }
591
canChangeCoding(const E_TransferSyntax fromRepType,const E_TransferSyntax toRepType)592 OFBool DcmCodecList::canChangeCoding(
593 const E_TransferSyntax fromRepType,
594 const E_TransferSyntax toRepType)
595 {
596 #ifdef WITH_THREADS
597 if (! codecLock.initialized()) return OFFalse; // should never happen
598 #endif
599 OFBool result = OFFalse;
600
601 // acquire write lock on codec list. Will block if some write lock is currently active.
602 #ifdef WITH_THREADS
603 OFReadWriteLocker locker(codecLock);
604 if (0 == locker.rdlock())
605 {
606 #endif
607 OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
608 OFListIterator(DcmCodecList *) last = registeredCodecs.end();
609 while (first != last)
610 {
611 if ((*first)->codec->canChangeCoding(fromRepType, toRepType))
612 {
613 result = OFTrue;
614 first = last;
615 } else ++first;
616 }
617 #ifdef WITH_THREADS
618 }
619 #endif
620
621 return result;
622 }
623
determineDecompressedColorModel(const DcmXfer & fromType,const DcmRepresentationParameter * fromParam,DcmPixelSequence * fromPixSeq,DcmItem * dataset,OFString & decompressedColorModel)624 OFCondition DcmCodecList::determineDecompressedColorModel(
625 const DcmXfer &fromType,
626 const DcmRepresentationParameter *fromParam,
627 DcmPixelSequence *fromPixSeq,
628 DcmItem *dataset,
629 OFString &decompressedColorModel)
630 {
631 #ifdef WITH_THREADS
632 if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
633 #endif
634 OFCondition result = EC_CannotChangeRepresentation;
635
636 // acquire write lock on codec list. Will block if some write lock is currently active.
637 #ifdef WITH_THREADS
638 OFReadWriteLocker locker(codecLock);
639 if (0 == locker.rdlock())
640 {
641 #endif
642 E_TransferSyntax fromXfer = fromType.getXfer();
643 OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
644 OFListIterator(DcmCodecList *) last = registeredCodecs.end();
645 while (first != last)
646 {
647 if ((*first)->codec->canChangeCoding(fromXfer, EXS_LittleEndianExplicit))
648 {
649 result = (*first)->codec->determineDecompressedColorModel(fromParam, fromPixSeq, (*first)->codecParameter,
650 dataset, decompressedColorModel);
651 first = last;
652 } else ++first;
653 }
654 #ifdef WITH_THREADS
655 } else result = EC_IllegalCall;
656 #endif
657 return result;
658 }
659