1 /*
2 *
3 * Copyright (C) 1996-2010, 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: dcmimgle
15 *
16 * Author: Joerg Riesmeier
17 *
18 * Purpose: DicomImage-Interface (Source)
19 *
20 */
21
22
23 #include "dcmtk/config/osconfig.h"
24
25 #include "dcmtk/dcmdata/dctypes.h"
26 #include "dcmtk/dcmdata/dcdeftag.h"
27 #include "dcmtk/dcmdata/dcobject.h"
28 #include "dcmtk/dcmdata/dcuid.h"
29 #include "dcmtk/dcmdata/dcdict.h"
30
31 #include "dcmtk/dcmimgle/dcmimage.h"
32 #include "dcmtk/dcmimgle/diovlimg.h"
33 #include "dcmtk/dcmimgle/dimo1img.h"
34 #include "dcmtk/dcmimgle/dimo2img.h"
35 #include "dcmtk/dcmimgle/didocu.h"
36 #include "dcmtk/dcmimgle/diregbas.h"
37 #include "dcmtk/dcmimgle/diplugin.h"
38 #include "dcmtk/dcmdata/dcdicent.h" /* needed by MSVC5 */
39
40 #define INCLUDE_CCTYPE
41 #include "dcmtk/ofstd/ofstdinc.h"
42
43 #ifndef FILENAME_MAX
44 #define FILENAME_MAX 255
45 #endif
46
47
48 /*------------------*
49 * initialization *
50 *------------------*/
51
52 DiRegisterBase *DiRegisterBase::Pointer = NULL;
53
54
55 /*----------------*
56 * constructors *
57 *----------------*/
58
59 // --- create 'DicomImage' from 'filename', for valid 'flags' see 'diutils.h'
60
DicomImage(const char * filename,const unsigned long flags,const unsigned long fstart,const unsigned long fcount)61 DicomImage::DicomImage(const char *filename,
62 const unsigned long flags,
63 const unsigned long fstart,
64 const unsigned long fcount)
65 : ImageStatus(EIS_Normal),
66 PhotometricInterpretation(EPI_Unknown),
67 Document(NULL),
68 Image(NULL)
69 {
70 if (checkDataDictionary()) // valid 'dicom.dic' found ?
71 {
72 Document = new DiDocument(filename, flags | CIF_MayDetachPixelData, fstart, fcount);
73 Init();
74 }
75 }
76
77
78 // --- create 'DicomImage' from valid 'DicomObject' with transfer syntax 'xfer'
79
DicomImage(DcmObject * object,const E_TransferSyntax xfer,const unsigned long flags,const unsigned long fstart,const unsigned long fcount)80 DicomImage::DicomImage(DcmObject *object,
81 const E_TransferSyntax xfer,
82 const unsigned long flags,
83 const unsigned long fstart,
84 const unsigned long fcount)
85 : ImageStatus(EIS_Normal),
86 PhotometricInterpretation(EPI_Unknown),
87 Document(NULL),
88 Image(NULL)
89 {
90 if (checkDataDictionary()) // valid 'dicom.dic' found ?
91 {
92 Document = new DiDocument(object, xfer, flags, fstart, fcount);
93 Init();
94 }
95 }
96
97
98 // --- create 'DicomImage' from valid 'DicomObject' with given rescale 'slope' and 'intercept'
99
DicomImage(DcmObject * object,const E_TransferSyntax xfer,const double slope,const double intercept,const unsigned long flags,const unsigned long fstart,const unsigned long fcount)100 DicomImage::DicomImage(DcmObject *object,
101 const E_TransferSyntax xfer,
102 const double slope,
103 const double intercept,
104 const unsigned long flags,
105 const unsigned long fstart,
106 const unsigned long fcount)
107 : ImageStatus(EIS_Normal),
108 PhotometricInterpretation(EPI_Unknown),
109 Document(NULL),
110 Image(NULL)
111 {
112 if (checkDataDictionary()) // valid 'dicom.dic' found ?
113 {
114 Document = new DiDocument(object, xfer, flags, fstart, fcount);
115 if ((Document != NULL) && (Document->good()))
116 {
117 PhotometricInterpretation = EPI_Monochrome2; // default for presentation states
118 Image = new DiMono2Image(Document, ImageStatus, slope, intercept);
119 }
120 }
121 }
122
123
124 // --- create 'DicomImage' from valid 'DicomObject' with given modality LUT (specified by 'data' and 'descriptor')
125
DicomImage(DcmObject * object,E_TransferSyntax xfer,const DcmUnsignedShort & data,const DcmUnsignedShort & descriptor,const DcmLongString * explanation,const unsigned long flags,const unsigned long fstart,const unsigned long fcount)126 DicomImage::DicomImage(DcmObject *object,
127 E_TransferSyntax xfer,
128 const DcmUnsignedShort &data,
129 const DcmUnsignedShort &descriptor,
130 const DcmLongString *explanation,
131 const unsigned long flags,
132 const unsigned long fstart,
133 const unsigned long fcount)
134 : ImageStatus(EIS_Normal),
135 PhotometricInterpretation(EPI_Unknown),
136 Document(NULL),
137 Image(NULL)
138 {
139 if (checkDataDictionary()) // valid 'dicom.dic' found ?
140 {
141 Document = new DiDocument(object, xfer, flags, fstart, fcount);
142 if ((Document != NULL) && (Document->good()))
143 {
144 PhotometricInterpretation = EPI_Monochrome2; // default for presentation states
145 Image = new DiMono2Image(Document, ImageStatus, data, descriptor, explanation);
146 }
147 }
148 }
149
150
151 // --- protected: create 'DicomImage' from source with different image data and photometric interpretation
152
DicomImage(const DicomImage * dicom,DiImage * image,const EP_Interpretation interpret)153 DicomImage::DicomImage(const DicomImage *dicom,
154 DiImage *image,
155 const EP_Interpretation interpret)
156 : ImageStatus(dicom->ImageStatus),
157 PhotometricInterpretation(dicom->PhotometricInterpretation),
158 Document(dicom->Document), // necessary, ever used ??
159 Image(image)
160 {
161 if (interpret != EPI_Unknown)
162 PhotometricInterpretation = interpret;
163 if (Document != NULL)
164 Document->addReference(); // 'Document' is only referenced not copied !
165 }
166
167
168 /*--------------*
169 * destructor *
170 *--------------*/
171
~DicomImage()172 DicomImage::~DicomImage()
173 {
174 delete Image;
175 if (Document != NULL)
176 Document->removeReference(); // only delete if object is no longer referenced
177 }
178
179
180 /*********************************************************************/
181
182 // --- initialize 'DicomImage' object (same procedure for every 'real' constructor)
183
Init()184 void DicomImage::Init()
185 {
186 if ((Document != NULL) && (Document->good()))
187 {
188 const char *str;
189 if (hasSOPclassUID(UID_RETIRED_StandaloneOverlayStorage))
190 {
191 PhotometricInterpretation = EPI_Monochrome2; // standalone overlays are handled like monochrome
192 Image = new DiOverlayImage(Document, ImageStatus); // images without pixel data
193 }
194 else if (Document->getFlags() & CIF_UsePresentationState)
195 {
196 PhotometricInterpretation = EPI_Monochrome2; // default for presentation states
197 Image = new DiMono2Image(Document, ImageStatus);
198 }
199 else if (strlen(str = Document->getPhotometricInterpretation()) > 0)
200 {
201 const SP_Interpretation *pin = PhotometricInterpretationNames;
202 char *cstr = new char[strlen(str) + 1];
203 if (cstr != NULL)
204 {
205 char *q = cstr;
206 unsigned char c;
207 for (const char *p = str; *p != 0; p++) // remove invalid chars
208 {
209 c = OFstatic_cast(unsigned char, *p);
210 if (isalpha(c))
211 *(q++) = toupper(c);
212 else if (isdigit(c))
213 *(q++) = c;
214 }
215 *q = '\0'; // end of C string
216 while ((pin->Name != NULL) && (strcmp(pin->Name, cstr) != 0))
217 ++pin;
218 delete[] cstr;
219 } else {
220 DCMIMGLE_WARN("can't create filtered version of 'PhotometricInterpretation' (" << str << ")");
221 cstr = OFconst_cast(char *, str); // just reference the original string
222 while ((pin->DefinedTerm != NULL) && (strcmp(pin->DefinedTerm, cstr) != 0))
223 ++pin;
224 }
225 PhotometricInterpretation = pin->Type; // unknown if last entry
226 switch (PhotometricInterpretation)
227 {
228 case EPI_Monochrome1: // create 'Image' depending on color model
229 Image = new DiMono1Image(Document, ImageStatus);
230 break;
231 case EPI_Monochrome2:
232 Image = new DiMono2Image(Document, ImageStatus);
233 break;
234 default: // unknown or unsupported color model
235 if (DiRegisterBase::Pointer != NULL)
236 Image = DiRegisterBase::Pointer->createImage(Document, ImageStatus, PhotometricInterpretation);
237 if (Image == NULL)
238 {
239 if (PhotometricInterpretation == EPI_Unknown)
240 {
241 ImageStatus = EIS_InvalidValue;
242 DCMIMGLE_ERROR("invalid value for 'PhotometricInterpretation' (" << str << ")");
243 } else {
244 ImageStatus = EIS_NotSupportedValue;
245 DCMIMGLE_ERROR("unsupported value for 'PhotometricInterpretation' (" << str << ")");
246 }
247 }
248 }
249 }
250 else if (Document->getFlags() & CIF_AcrNemaCompatibility) // ACR-NEMA has no 'photometric interpretation'
251 {
252 PhotometricInterpretation = EPI_Monochrome2;
253 Image = new DiMono2Image(Document, ImageStatus);
254 } else {
255 ImageStatus = EIS_MissingAttribute;
256 PhotometricInterpretation = EPI_Missing;
257 if (Document->getPixelData() != NULL)
258 DCMIMGLE_ERROR("mandatory attribute 'PhotometricInterpretation' is missing or can't be determined");
259 }
260 }
261 else
262 ImageStatus = EIS_InvalidDocument;
263 }
264
265
266 // --- check whether the loadable 'DataDictionary' is present/loaded
267
checkDataDictionary()268 int DicomImage::checkDataDictionary()
269 {
270 if (!dcmDataDict.isDictionaryLoaded())
271 {
272 ImageStatus = EIS_NoDataDictionary;
273 DCMIMGLE_ERROR("can't load data dictionary");
274 }
275 return ImageStatus == EIS_Normal;
276 }
277
278
279 /*********************************************************************/
280
281
getString(const EI_Status status)282 const char *DicomImage::getString(const EI_Status status)
283 {
284 switch (status)
285 {
286 case EIS_Normal:
287 return "Status OK";
288 case EIS_NoDataDictionary:
289 return "No data dictionary";
290 case EIS_InvalidDocument:
291 return "Invalid DICOM document";
292 case EIS_MissingAttribute:
293 return "Missing attribute";
294 case EIS_InvalidValue:
295 return "Invalid element value";
296 case EIS_NotSupportedValue:
297 return "Unsupported element value";
298 case EIS_MemoryFailure:
299 return "Out of memory";
300 case EIS_InvalidImage:
301 return "Invalid DICOM image";
302 case EIS_OtherError:
303 default:
304 return "Unspecified";
305 }
306 }
307
308
getString(const EP_Interpretation interpret)309 const char *DicomImage::getString(const EP_Interpretation interpret)
310 {
311 const SP_Interpretation *pin = PhotometricInterpretationNames;
312 while ((pin->DefinedTerm != NULL) && (pin->Type != interpret))
313 ++pin;
314 return pin->DefinedTerm;
315 }
316
317
318 // --- return unique 'SOPclassUID' string
319
getSOPclassUID() const320 const char *DicomImage::getSOPclassUID() const
321 {
322 if (Document != NULL)
323 {
324 const char *str;
325 if (Document->getValue(DCM_SOPClassUID, str))
326 return str;
327 }
328 return NULL;
329 }
330
331
332 // --- return 'true' (1) if 'Document' has the same 'SOPclassUID' as given in parameter 'uid'
333
hasSOPclassUID(const char * uid) const334 int DicomImage::hasSOPclassUID(const char *uid) const
335 {
336 const char *str = getSOPclassUID();
337 return (str != NULL) && (strcmp(str, uid) == 0);
338 }
339
340
341 // --- create new 'DicomImage' with 'fcount' frames starting with frame 'fstart'
342
createDicomImage(unsigned long fstart,unsigned long fcount) const343 DicomImage *DicomImage::createDicomImage(unsigned long fstart,
344 unsigned long fcount) const
345 {
346 if ((Image != NULL) && (fstart < getFrameCount()))
347 {
348 if ((fcount == 0) || (fstart + fcount > getFrameCount()))
349 fcount = getFrameCount() - fstart;
350 DiImage *image = Image->createImage(fstart, fcount);
351 if (image != NULL)
352 {
353 DicomImage *dicom = new DicomImage(this, image);
354 return dicom;
355 }
356 }
357 return NULL;
358 }
359
360
361 // --- create scaled to given size ('width' and 'height') image, memory isn't handled internally !
362 // --- if one dimension ist '0' the other is automatically adjusted (with respect to pixel aspect ratio)
363
createScaledImage(const unsigned long width,const unsigned long height,const int interpolate,int aspect) const364 DicomImage *DicomImage::createScaledImage(const unsigned long width,
365 const unsigned long height,
366 const int interpolate,
367 int aspect) const
368 {
369 return createScaledImage(0, 0, getWidth(), getHeight(), width, height, interpolate, aspect);
370 }
371
372
373 // --- create scaled with given factors ('xfactor' and 'yfactor') image, memory isn't handled internally !
374
createScaledImage(const double xfactor,const double yfactor,const int interpolate,const int aspect) const375 DicomImage *DicomImage::createScaledImage(const double xfactor,
376 const double yfactor,
377 const int interpolate,
378 const int aspect) const
379 {
380 return createScaledImage(0, 0, getWidth(), getHeight(), OFstatic_cast(unsigned long, xfactor * getWidth()),
381 OFstatic_cast(unsigned long, yfactor * getHeight()), interpolate, aspect);
382 }
383
384
385 // --- clip & scale
386
createScaledImage(const signed long left_pos,const signed long top_pos,unsigned long clip_width,unsigned long clip_height,unsigned long scale_width,unsigned long scale_height,const int interpolate,int aspect,const Uint16 pvalue) const387 DicomImage *DicomImage::createScaledImage(const signed long left_pos,
388 const signed long top_pos,
389 unsigned long clip_width,
390 unsigned long clip_height,
391 unsigned long scale_width,
392 unsigned long scale_height,
393 const int interpolate,
394 int aspect,
395 const Uint16 pvalue) const
396 {
397 const unsigned long gw = getWidth();
398 const unsigned long gh = getHeight();
399 if ((Image != NULL) && (gw > 0) && (gh > 0))
400 {
401 if ((clip_width == 0) && (left_pos < OFstatic_cast(signed long, gw))) // set 'width' if parameter is missing
402 clip_width = gw - left_pos;
403 if ((clip_height == 0) && (top_pos < OFstatic_cast(signed long, gh))) // same for 'height'
404 clip_height = gh - top_pos;
405 if ((scale_width == 0) && (scale_height == 0))
406 {
407 scale_width = clip_width; // auto-set width/height
408 scale_height = clip_height;
409 }
410 else if ((clip_width > 0) && (clip_height > 0))
411 {
412 if (aspect) // maintain pixel aspect ratio
413 {
414 if (scale_width == 0)
415 scale_width = OFstatic_cast(unsigned long, getWidthHeightRatio() * OFstatic_cast(double, scale_height * clip_width) / clip_height);
416 else if (scale_height == 0)
417 scale_height = OFstatic_cast(unsigned long, getHeightWidthRatio() * OFstatic_cast(double, scale_width * clip_height) / clip_width);
418 else
419 aspect = 0; // ignore pixel aspect ratio
420 }
421 else // ignore pixel aspect ratio
422 {
423 if (scale_width == 0)
424 scale_width = OFstatic_cast(unsigned long, OFstatic_cast(double, scale_height * clip_width) / clip_height);
425 else if (scale_height == 0)
426 scale_height = OFstatic_cast(unsigned long, OFstatic_cast(double, scale_width * clip_height) / clip_width);
427 }
428 }
429 const unsigned long maxvalue = DicomImageClass::maxval(bitsof(Uint16));
430 if (scale_width > maxvalue)
431 scale_width = maxvalue; // limit 'width' to maximum value (65535)
432 if (scale_height > maxvalue)
433 scale_height = maxvalue; // same for 'height'
434
435 /* need to limit clipping region ... !? */
436
437 if (((left_pos < 0) || (OFstatic_cast(unsigned long, left_pos + clip_width) > gw) ||
438 (top_pos < 0) || (OFstatic_cast(unsigned long, top_pos + clip_height) > gh)) &&
439 ((clip_width != scale_width) || (clip_height != scale_height)))
440 {
441 DCMIMGLE_ERROR("combined clipping & scaling outside image boundaries not yet supported");
442 }
443 else if ((scale_width > 0) && (scale_height > 0))
444 {
445 DiImage *image = Image->createScale(left_pos, top_pos, clip_width, clip_height, scale_width, scale_height,
446 interpolate, aspect, pvalue);
447 if (image != NULL)
448 {
449 DicomImage *dicom = new DicomImage(this, image);
450 return dicom;
451 }
452 }
453 }
454 return NULL;
455 }
456
457
458 // --- clip & scale
459
createScaledImage(const signed long left_pos,const signed long top_pos,unsigned long width,unsigned long height,const double xfactor,const double yfactor,const int interpolate,const int aspect,const Uint16 pvalue) const460 DicomImage *DicomImage::createScaledImage(const signed long left_pos,
461 const signed long top_pos,
462 unsigned long width,
463 unsigned long height,
464 const double xfactor,
465 const double yfactor,
466 const int interpolate,
467 const int aspect,
468 const Uint16 pvalue) const
469 {
470 if ((xfactor >= 0) && (yfactor >= 0))
471 {
472 const unsigned long gw = getWidth();
473 const unsigned long gh = getHeight();
474 if ((width == 0) && (left_pos < OFstatic_cast(signed long, gw))) // set 'width' if parameter is missing (0)
475 width = gw - left_pos;
476 if ((height == 0) && (top_pos < OFstatic_cast(signed long, gh))) // same for 'height'
477 height = gh - top_pos;
478 return createScaledImage(left_pos, top_pos, width, height, OFstatic_cast(unsigned long, xfactor * width),
479 OFstatic_cast(unsigned long, yfactor * height), interpolate, aspect, pvalue);
480 }
481 return NULL;
482 }
483
484
485 // --- create clipped to given box ('left_pos', 'top_pos' and 'width', 'height') image,
486 // ---- memory isn't handled internally! 'width' and 'height' are optional
487
createClippedImage(const signed long left_pos,const signed long top_pos,unsigned long width,unsigned long height,const Uint16 pvalue) const488 DicomImage *DicomImage::createClippedImage(const signed long left_pos,
489 const signed long top_pos,
490 unsigned long width,
491 unsigned long height,
492 const Uint16 pvalue) const
493 {
494 return createScaledImage(left_pos, top_pos, width, height, OFstatic_cast(unsigned long, 0),
495 OFstatic_cast(unsigned long, 0), 0, 0, pvalue);
496 }
497
498
499 // --- flip image (horizontal: x > 1 and/or vertical y > 1)
500
flipImage(int horz,int vert) const501 int DicomImage::flipImage(int horz,
502 int vert) const
503 {
504 if ((Image != NULL) && (horz || vert))
505 {
506 if (getWidth() <= 1)
507 horz = 0;
508 if (getHeight() <= 1)
509 vert = 0;
510 if (horz || vert)
511 return Image->flip(horz, vert);
512 else
513 return 2;
514 }
515 return 0;
516 }
517
518
519 // --- create flipped image (horizontal: x > 1 and/or vertical y > 1), memory isn't handled internally !
520
createFlippedImage(int horz,int vert) const521 DicomImage *DicomImage::createFlippedImage(int horz,
522 int vert) const
523 {
524 if ((Image != NULL) && (horz || vert))
525 {
526 if (getWidth() <= 1) // can't flip horizontally
527 horz = 0;
528 if (getHeight() <= 1) // can't flip vertically
529 vert = 0;
530 DiImage *image;
531 if (horz || vert) // flip at least one axis
532 image = Image->createFlip(horz, vert);
533 else // copy image
534 image = Image->createImage(0, getFrameCount());
535 if (image != NULL)
536 {
537 DicomImage *dicom = new DicomImage(this, image);
538 return dicom;
539 }
540 }
541 return NULL;
542 }
543
544
545 // -- normalize given 'degree' value to 0, 90, 180, 270
546
normalizeDegreeValue(signed int & degree) const547 int DicomImage::normalizeDegreeValue(signed int °ree) const
548 {
549 switch (degree)
550 {
551 case 0:
552 case 360:
553 case -360:
554 degree = 0;
555 return 1;
556 case 90:
557 case -270:
558 degree = 90;
559 return 1;
560 case 180:
561 case -180:
562 degree = 180;
563 return 1;
564 case 270:
565 case -90:
566 degree = 270;
567 return 1;
568 default:
569 return 0;
570 }
571 }
572
573
574 // --- rotate image by given 'degree'
575
rotateImage(signed int degree) const576 int DicomImage::rotateImage(signed int degree) const
577 {
578 if ((Image != NULL) && normalizeDegreeValue(degree))
579 {
580 if ((degree == 0) || (getWidth() * getHeight() <= 1)) // nothing to do
581 return 2;
582 else
583 return Image->rotate(OFstatic_cast(int, degree));
584 }
585 return 0;
586 }
587
588
589 // --- create by given 'degree' rotated image, memory isn't handled internally !
590
createRotatedImage(signed int degree) const591 DicomImage *DicomImage::createRotatedImage(signed int degree) const
592 {
593 if ((Image != NULL) && normalizeDegreeValue(degree))
594 {
595 DiImage *image = Image->createRotate(OFstatic_cast(int, degree));
596 if (image != NULL)
597 {
598 DicomImage *dicom = new DicomImage(this, image);
599 return dicom;
600 }
601 }
602 return NULL;
603 }
604
605
606 // --- create color-image to mono-image with given 'red', 'green' and 'blue' coefficients converted image, memory ... !
607
createMonochromeImage(const double red,const double green,const double blue) const608 DicomImage *DicomImage::createMonochromeImage(const double red,
609 const double green,
610 const double blue) const
611 {
612 if (Image != NULL)
613 {
614 DiImage *image = Image->createMono(red, green, blue); // create monochrome image data
615 if (image != NULL)
616 {
617 DicomImage *dicom = new DicomImage(this, image, EPI_Monochrome2);
618 return dicom;
619 }
620 }
621 return NULL;
622 }
623
624
625 // --- create monochrome output image of specified frame (incl. windowing)
626
createMonoOutputImage(const unsigned long frame,const int bits)627 DicomImage *DicomImage::createMonoOutputImage(const unsigned long frame,
628 const int bits)
629 {
630 if ((Image != NULL) && (Image->getMonoImagePtr() != NULL))
631 {
632 DiImage *image = Image->getMonoImagePtr()->createOutputImage(frame, bits);
633 if (image != NULL)
634 {
635 DicomImage *dicom = new DicomImage(this, image, EPI_Monochrome2);
636 return dicom;
637 }
638 }
639 return NULL;
640 }
641
642
643 /*********************************************************************/
644
645
646 // --- write 'frame' of image data to 'filename' with 'bits' depth
647
writePPM(const char * filename,const int bits,const unsigned long frame)648 int DicomImage::writePPM(const char *filename,
649 const int bits,
650 const unsigned long frame)
651 {
652 if ((filename != NULL) && (Image != NULL))
653 {
654 char fname[FILENAME_MAX + 1];
655 if (sprintf(fname, filename, frame) >= 0) // replace '%d' etc. with frame number
656 filename = fname;
657 FILE *stream = fopen(filename, "w"); // open text file for writing
658 int ok = writePPM(stream, bits, frame);
659 fclose(stream);
660 return ok;
661 }
662 return 0;
663 }
664
665
666 // --- same for C++ 'ostream'
667
writePPM(STD_NAMESPACE ostream & stream,const int bits,const unsigned long frame)668 int DicomImage::writePPM(STD_NAMESPACE ostream& stream,
669 const int bits,
670 const unsigned long frame)
671 {
672 if ((stream.good()) && (Image != NULL))
673 return Image->writePPM(stream, frame, Image->getBits(bits));
674 return 0;
675 }
676
677
678 // --- same for C 'FILE'
679
writePPM(FILE * stream,const int bits,const unsigned long frame)680 int DicomImage::writePPM(FILE *stream,
681 const int bits,
682 const unsigned long frame)
683 {
684 if ((stream != NULL) && (Image != NULL))
685 return Image->writePPM(stream, frame, Image->getBits(bits));
686 return 0;
687 }
688
689
690 // --- same for RAW PPM (binary form of PPM with a maximum of 8 bits depth)
691
writeRawPPM(const char * filename,const int bits,const unsigned long frame)692 int DicomImage::writeRawPPM(const char *filename,
693 const int bits,
694 const unsigned long frame)
695 {
696 if ((filename != NULL) && (Image != NULL) && (Image->getBits(bits) <= MAX_RAWPPM_BITS))
697 {
698 char fname[FILENAME_MAX + 1];
699 if (sprintf(fname, filename, frame) >= 0) // replace '%d' etc. with frame number
700 filename = fname;
701 FILE *stream = fopen(filename, "wb"); // open binary file for writing
702 if (stream != NULL)
703 {
704 int ok = Image->writeRawPPM(stream, frame, Image->getBits(bits));
705 fclose(stream);
706 return ok;
707 }
708 }
709 return 0;
710 }
711
712 // --- same for C 'FILE'
713
writeRawPPM(FILE * stream,const int bits,const unsigned long frame)714 int DicomImage::writeRawPPM(FILE *stream,
715 const int bits,
716 const unsigned long frame)
717 {
718 if ((stream != NULL) && (Image != NULL))
719 return Image->writeRawPPM(stream, frame, Image->getBits(bits));
720 return 0;
721 }
722
723
724 // --- write 'frame' of image data to 'filename' with 'bits' depth in BMP format
725
writeBMP(const char * filename,const int bits,const unsigned long frame)726 int DicomImage::writeBMP(const char *filename,
727 const int bits,
728 const unsigned long frame)
729 {
730 if ((filename != NULL) && (Image != NULL) &&
731 ((bits == 0) || ((bits == 8) && isMonochrome()) || (bits == 24) || (bits == 32)))
732 {
733 char fname[FILENAME_MAX + 1];
734 if (sprintf(fname, filename, frame) >= 0) // replace '%d' etc. with frame number
735 filename = fname;
736 FILE *stream = fopen(filename, "wb"); // open binary file for writing
737 if (stream != NULL)
738 {
739 int ok = Image->writeBMP(stream, frame, bits);
740 fclose(stream);
741 return ok;
742 }
743 }
744 return 0;
745 }
746
747
748 // --- same for open C 'FILE' in BMP format
749
writeBMP(FILE * stream,const int bits,const unsigned long frame)750 int DicomImage::writeBMP(FILE *stream,
751 const int bits,
752 const unsigned long frame)
753 {
754 if ((stream != NULL) && (Image != NULL) &&
755 ((bits == 0) || ((bits == 8) && isMonochrome()) || (bits == 24) || (bits == 32)))
756 {
757 return Image->writeBMP(stream, frame, bits);
758 }
759 return 0;
760 }
761
762
763 // --- write 'frame' of image data to 'filename' plugable image format
764
writePluginFormat(const DiPluginFormat * plugin,const char * filename,const unsigned long frame)765 int DicomImage::writePluginFormat(const DiPluginFormat *plugin,
766 const char *filename,
767 const unsigned long frame)
768 {
769 if ((plugin != NULL) && (filename != NULL) && (Image != NULL))
770 {
771 char fname[FILENAME_MAX + 1];
772 if (sprintf(fname, filename, frame) >= 0) // replace '%d' etc. with frame number
773 filename = fname;
774 FILE *stream = fopen(filename, "wb"); // open binary file for writing
775 if (stream != NULL)
776 {
777 int ok = plugin->write(Image, stream, frame);
778 fclose(stream);
779 return ok;
780 }
781 }
782 return 0;
783 }
784
785
786 // --- same for open C 'FILE' in plugable image format
787
writePluginFormat(const DiPluginFormat * plugin,FILE * stream,const unsigned long frame)788 int DicomImage::writePluginFormat(const DiPluginFormat *plugin,
789 FILE *stream,
790 const unsigned long frame)
791 {
792 if ((plugin != NULL) && (stream != NULL) && (Image != NULL))
793 return plugin->write(Image, stream, frame);
794 return 0;
795 }
796