1 /*
2  *
3  *  Copyright (C) 1996-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:  dcmimgle
15  *
16  *  Author:  Joerg Riesmeier
17  *
18  *  Purpose: DicomOverlay (Source)
19  *
20  */
21 
22 
23 #include "dcmtk/config/osconfig.h"
24 #include "dcmtk/dcmdata/dctypes.h"
25 
26 #include "dcmtk/dcmimgle/diovlay.h"
27 #include "dcmtk/dcmimgle/diovdat.h"
28 #include "dcmtk/dcmimgle/diovpln.h"
29 #include "dcmtk/dcmimgle/discalet.h"
30 #include "dcmtk/dcmimgle/diflipt.h"
31 #include "dcmtk/dcmimgle/dirotat.h"
32 #include "dcmtk/dcmimgle/didocu.h"
33 
34 
35 /*----------------------------*
36  *  constant initializations  *
37  *----------------------------*/
38 
39 const unsigned int DiOverlay::MaxOverlayCount   = 16;
40 const unsigned int DiOverlay::FirstOverlayGroup = 0x6000;
41 
42 
43 /*----------------*
44  *  constructors  *
45  *----------------*/
46 
DiOverlay(const DiDocument * docu,const Uint16 alloc,const Uint16 stored,const Uint16 high)47 DiOverlay::DiOverlay(const DiDocument *docu,
48                      const Uint16 alloc,
49                      const Uint16 stored,
50                      const Uint16 high)
51   : Left(0),
52     Top(0),
53     Width(0),
54     Height(0),
55     Frames(0),
56     AdditionalPlanes(docu == NULL),                                                    // planes are added later
57     Data(NULL)
58 {
59     Data = new DiOverlayData(MaxOverlayCount);                                         // can't determine number of overlays :-(
60     if ((docu != NULL) && (Data != NULL) && (Data->Planes != NULL))
61     {
62         unsigned int i;
63         for (i = 0; i < MaxOverlayCount; ++i)
64         {
65             Data->Planes[Data->Count] = new DiOverlayPlane(docu, convertToGroupNumber(i), alloc, stored, high);
66             if (Data->Planes[Data->Count] != NULL)
67             {
68                 if (checkPlane(Data->Count))
69                     ++(Data->Count);
70                 else {
71                     delete Data->Planes[Data->Count];
72                     Data->Planes[Data->Count] = NULL;
73                 }
74             }
75         }
76     }
77 }
78 
79 
80 // --- scale/clip overlay
81 
DiOverlay(const DiOverlay * overlay,const signed long left_pos,const signed long top_pos,const double xfactor,const double yfactor)82 DiOverlay::DiOverlay(const DiOverlay *overlay,
83                      const signed long left_pos,
84                      const signed long top_pos,
85                      const double xfactor,
86                      const double yfactor)
87   : Left(left_pos),
88     Top(top_pos),
89     Width(OFstatic_cast(Uint16, xfactor * overlay->Width)),
90     Height(OFstatic_cast(Uint16, yfactor * overlay->Height)),
91     Frames(overlay->Frames),
92     AdditionalPlanes(overlay->AdditionalPlanes),
93     Data(NULL)
94 {
95     Uint16 *temp = Init(overlay);
96     if (temp != NULL)
97     {
98         unsigned int i;
99         for (i = 0; i < Data->ArrayEntries; ++i)
100         {
101             if (Data->Planes[i] != NULL)
102                 Data->Planes[i]->setScaling(xfactor, yfactor);
103         }
104         DiScaleTemplate<Uint16> scale(1, overlay->Width, overlay->Height, Width, Height, Frames);
105         scale.scaleData(OFconst_cast(const Uint16 **, &temp), &(Data->DataBuffer), 0);
106         if (temp != overlay->Data->DataBuffer)
107             delete[] temp;
108     }
109 }
110 
111 
112 // --- flip overlay
113 
DiOverlay(const DiOverlay * overlay,const int horz,const int vert,const Uint16 columns,const Uint16 rows)114 DiOverlay::DiOverlay(const DiOverlay *overlay,
115                      const int horz,
116                      const int vert,
117                      const Uint16 columns,              // width of surrounding image
118                      const Uint16 rows)
119   : Left((horz) ? 0 : overlay->Left),
120     Top((vert) ? 0 : overlay->Top),
121     Width(overlay->Width),
122     Height(overlay->Height),
123     Frames(overlay->Frames),
124     AdditionalPlanes(overlay->AdditionalPlanes),
125     Data(NULL)
126 {
127     Uint16 *temp = Init(overlay);
128     if (temp != NULL)
129     {
130         DiFlipTemplate<Uint16> flip(1, Width, Height, Frames);
131         flip.flipData(OFconst_cast(const Uint16 **, &temp), &(Data->DataBuffer), horz, vert);
132         if (temp != overlay->Data->DataBuffer)
133             delete[] temp;
134         unsigned int i;
135         for (i = 0; i < Data->ArrayEntries; ++i)
136         {
137             if (Data->Planes[i] != NULL)
138             {
139                 Data->Planes[i]->setFlipping(horz, vert, OFstatic_cast(signed long, columns) + overlay->Left,
140                     OFstatic_cast(signed long, rows) + overlay->Top);
141             }
142         }
143     }
144 }
145 
146 
147 // --- rotate overlay
148 
DiOverlay(const DiOverlay * overlay,const int degree,const Uint16 columns,const Uint16 rows)149 DiOverlay::DiOverlay(const DiOverlay *overlay,
150                      const int degree,
151                      const Uint16 columns,              // width of surrounding image (already rotated)
152                      const Uint16 rows)
153   : Left(0),
154     Top(0),
155     Width(((degree == 90) || (degree == 270)) ? overlay->Height : overlay->Width),
156     Height(((degree == 90) || (degree == 270)) ? overlay->Width : overlay->Height),
157     Frames(overlay->Frames),
158     AdditionalPlanes(overlay->AdditionalPlanes),
159     Data(NULL)
160 {
161     Uint16 *temp = Init(overlay);
162     if (temp != NULL)
163     {
164         DiRotateTemplate<Uint16> rotate(1, overlay->Width, overlay->Height, Width, Height, Frames);
165         rotate.rotateData(OFconst_cast(const Uint16 **, &temp), &(Data->DataBuffer), degree);
166         if (temp != overlay->Data->DataBuffer)
167             delete[] temp;
168         unsigned int i;
169         for (i = 0; i < Data->ArrayEntries; ++i)
170         {
171             if (Data->Planes[i] != NULL)
172                 Data->Planes[i]->setRotation(degree, overlay->Left, overlay->Top, columns, rows);
173         }
174     }
175 }
176 
177 
178 /*--------------*
179  *  destructor  *
180  *--------------*/
181 
~DiOverlay()182 DiOverlay::~DiOverlay()
183 {
184     if (Data != NULL)
185         Data->removeReference();
186 }
187 
188 
189 /********************************************************************/
190 
191 
Init(const DiOverlay * overlay)192 Uint16 *DiOverlay::Init(const DiOverlay *overlay)
193 {
194     if ((overlay != NULL) && (overlay->Data != NULL) && (overlay->Data->Count > 0))
195     {
196         if (AdditionalPlanes)
197             Data = new DiOverlayData(overlay->Data->ArrayEntries);      // use same array size
198         else
199             Data = new DiOverlayData(overlay->Data->Count);             // shrink array size to minimal size
200         const unsigned long count = OFstatic_cast(unsigned long, overlay->Width) *
201             OFstatic_cast(unsigned long, overlay->Height) * overlay->Frames;
202         if ((Data != NULL) && (Data->Planes != NULL) && (count > 0))
203         {
204             const unsigned long bufSize = OFstatic_cast(unsigned long, Width) *
205                 OFstatic_cast(unsigned long, Height) * Frames;
206             if (bufSize > 0)                                            // avoid invalid buffer
207             {
208                 Data->DataBuffer = new Uint16[bufSize];
209                 if (Data->DataBuffer != NULL)
210                 {
211                     unsigned int i;
212                     Uint16 *temp = NULL;
213                     if (overlay->Data->DataBuffer == NULL)              // no data buffer
214                     {
215                         temp = new Uint16[count];                       // create temporary buffer
216                         if (temp != NULL)
217                             OFBitmanipTemplate<Uint16>::zeroMem(temp, count);
218                     }
219                     for (i = 0; i < Data->ArrayEntries; ++i)
220                     {
221                         if ((overlay->Data->Planes[i] != NULL) /*&& (overlay->Data->Planes[i]->isValid())*/)
222                         {
223                             Data->Planes[i] = new DiOverlayPlane(overlay->Data->Planes[i], i, Data->DataBuffer, temp,
224                                 overlay->Width, overlay->Height, Width, Height);
225                             ++(Data->Count);                            // increase number of valid planes
226                         }
227                     }
228                     if (Data->Count != overlay->Data->Count)            // assertion!
229                     {
230                         DCMIMGLE_WARN("different number of overlay planes for converted and original image");
231                     }
232                     if (overlay->Data->DataBuffer != NULL)              // existing data buffer
233                         temp = overlay->Data->DataBuffer;               // point to input buffer
234                     return temp;
235                 }
236             } else {
237                 DCMIMGLE_DEBUG("skipping overlay planes for converted image ... calculated buffer size is 0");
238             }
239         }
240     }
241     return NULL;
242 }
243 
244 
convertToPlaneNumber(unsigned int & plane,const int mode) const245 int DiOverlay::convertToPlaneNumber(unsigned int &plane,
246                                     const int mode) const
247 {
248     if ((Data != NULL) && (Data->Planes != NULL))
249     {
250         if (isValidGroupNumber(plane))
251         {
252             if (AdditionalPlanes)
253             {
254                 plane = (plane - FirstOverlayGroup) >> 1;                               // plane = (group - 0x6000) / 2
255                 if (Data->Planes[plane] != NULL)
256                     return 2;                                                           // plane already exists
257                 return 1;                                                               // ... is new
258             } else {
259                 unsigned int i;
260                 for (i = 0; i < Data->Count; ++i)
261                 {
262                     if ((Data->Planes[i] != NULL) && (Data->Planes[i]->getGroupNumber() == plane))
263                     {
264                         plane = i;                                                      // plane number
265                         return 2;
266                     }
267                 }
268             }
269         } else if (!mode && (plane < Data->Count) && (Data->Planes[plane] != NULL))     // valid plane number?
270             return 3;
271     }
272     return 0;
273 }
274 
275 
isValidGroupNumber(const unsigned int group) const276 int DiOverlay::isValidGroupNumber(const unsigned int group) const
277 {
278     return (group >= convertToGroupNumber(0)) && (group <= convertToGroupNumber(MaxOverlayCount - 1)) && !(group & 1);
279 }
280 
281 
checkPlane(const unsigned int plane,const int mode)282 int DiOverlay::checkPlane(const unsigned int plane,
283                           const int mode)
284 {
285     if ((Data != NULL) && (Data->Planes != NULL) && (plane < MaxOverlayCount) && (Data->Planes[plane] != NULL))
286     {
287         if (Data->Planes[plane]->isValid())
288         {
289             if (Data->Planes[plane]->getWidth() > Width)                              // determine maximum width
290                 Width = Data->Planes[plane]->getWidth();
291             if (Data->Planes[plane]->getHeight() > Height)                            // determine maximum height
292                 Height = Data->Planes[plane]->getHeight();
293             if (mode && (Data->Planes[plane]->getNumberOfFrames() > Frames))          // determine maximum frames
294                 Frames = Data->Planes[plane]->getNumberOfFrames();
295             return 1;
296         }
297     }
298     return 0;
299 }
300 
301 
isPlaneVisible(unsigned int plane)302 int DiOverlay::isPlaneVisible(unsigned int plane)
303 {
304     if (convertToPlaneNumber(plane, AdditionalPlanes) > 1)
305         return Data->Planes[plane]->isVisible();
306     return 0;
307 }
308 
309 
showPlane(unsigned int plane)310 int DiOverlay::showPlane(unsigned int plane)
311 {
312     if (convertToPlaneNumber(plane, AdditionalPlanes) > 1)
313     {
314         if (Data->Planes[plane]->isVisible())
315             return 2;
316         Data->Planes[plane]->show();
317         return 1;
318     }
319     return 0;
320 }
321 
322 
showPlane(unsigned int plane,const double fore,const double tresh,const EM_Overlay mode)323 int DiOverlay::showPlane(unsigned int plane,
324                          const double fore,
325                          const double tresh,
326                          const EM_Overlay mode)
327 {
328     if (convertToPlaneNumber(plane, AdditionalPlanes) > 1)
329     {
330         Data->Planes[plane]->show(fore, tresh, mode);
331         return 1;
332     }
333     return 0;
334 }
335 
336 
showPlane(unsigned int plane,const Uint16 pvalue)337 int DiOverlay::showPlane(unsigned int plane,
338                          const Uint16 pvalue)
339 {
340     if (convertToPlaneNumber(plane, AdditionalPlanes) > 1)
341         return Data->Planes[plane]->show(pvalue);
342     return 0;
343 }
344 
345 
showAllPlanes()346 int DiOverlay::showAllPlanes()
347 {
348     if ((Data != NULL) && (Data->Planes != NULL))
349     {
350         unsigned int i;
351         for (i = 0; i < Data->ArrayEntries; ++i)
352         {
353             if (Data->Planes[i] != NULL)
354                 Data->Planes[i]->show();
355         }
356         if (Data->Count > 0)
357             return 1;
358         return 2;
359     }
360     return 0;
361 }
362 
363 
showAllPlanes(const double fore,const double tresh,const EM_Overlay mode)364 int DiOverlay::showAllPlanes(const double fore,
365                              const double tresh,
366                              const EM_Overlay mode)
367 {
368     if ((Data != NULL) && (Data->Planes != NULL))
369     {
370         unsigned int i;
371         for (i = 0; i < Data->ArrayEntries; ++i)
372         {
373             if ((Data->Planes[i] != NULL))
374                 Data->Planes[i]->show(fore, tresh, mode);
375         }
376         if (Data->Count > 0)
377             return 1;
378         return 2;
379     }
380     return 0;
381 }
382 
383 
hidePlane(unsigned int plane)384 int DiOverlay::hidePlane(unsigned int plane)
385 {
386     if (convertToPlaneNumber(plane, AdditionalPlanes) > 1)
387     {
388         if (!Data->Planes[plane]->isVisible())
389             return 2;
390         Data->Planes[plane]->hide();
391         return 1;
392     }
393     return 0;
394 }
395 
396 
hideAllPlanes()397 int DiOverlay::hideAllPlanes()
398 {
399     if ((Data != NULL) && (Data->Planes != NULL))
400     {
401         unsigned int i;
402         for (i = 0; i < Data->ArrayEntries; ++i)
403         {
404             if (Data->Planes[i] != NULL)
405                 Data->Planes[i]->hide();
406         }
407         if (Data->Count > 0)
408             return 1;
409         return 2;
410     }
411     return 0;
412 }
413 
414 
placePlane(unsigned int plane,const signed int left_pos,const signed int top_pos)415 int DiOverlay::placePlane(unsigned int plane,
416                           const signed int left_pos,
417                           const signed int top_pos)
418 {
419     if (convertToPlaneNumber(plane, AdditionalPlanes) > 1)
420     {
421         if ((Data->Planes[plane]->getLeft() == left_pos) && (Data->Planes[plane]->getTop() == top_pos))
422             return 2;
423         Data->Planes[plane]->place(left_pos, top_pos);
424         return 1;
425     }
426     return 0;
427 }
428 
429 
getPlaneGroupNumber(unsigned int plane) const430 unsigned int DiOverlay::getPlaneGroupNumber(unsigned int plane) const
431 {
432     if (convertToPlaneNumber(plane, AdditionalPlanes) > 1)
433         return Data->Planes[plane]->getGroupNumber();
434     return 0;
435 }
436 
437 
getPlaneLabel(unsigned int plane) const438 const char *DiOverlay::getPlaneLabel(unsigned int plane) const
439 {
440     if (convertToPlaneNumber(plane, AdditionalPlanes) > 1)
441         return Data->Planes[plane]->getLabel();
442     return NULL;
443 }
444 
445 
getPlaneDescription(unsigned int plane) const446 const char *DiOverlay::getPlaneDescription(unsigned int plane) const
447 {
448     if (convertToPlaneNumber(plane, AdditionalPlanes) > 1)
449         return Data->Planes[plane]->getDescription();
450     return NULL;
451 }
452 
453 
getPlaneMode(unsigned int plane) const454 EM_Overlay DiOverlay::getPlaneMode(unsigned int plane) const
455 {
456     if (convertToPlaneNumber(plane, AdditionalPlanes) > 1)
457         return Data->Planes[plane]->getMode();
458     return EMO_Default;
459 }
460 
461 
hasEmbeddedData() const462 int DiOverlay::hasEmbeddedData() const
463 {
464     if ((Data != NULL) && (Data->Planes != NULL))
465     {
466         unsigned int i;
467         for (i = 0; i < Data->ArrayEntries; ++i)
468         {
469             if ((Data->Planes[i] != NULL) && (Data->Planes[i]->isEmbedded()))
470                 return 1;
471         }
472     }
473     return 0;
474 }
475 
476 
addPlane(const unsigned int group,const signed int left_pos,const signed int top_pos,const unsigned int columns,const unsigned int rows,const DcmOverlayData & data,const DcmLongString & label,const DcmLongString & description,const EM_Overlay mode)477 int DiOverlay::addPlane(const unsigned int group,
478                         const signed int left_pos,
479                         const signed int top_pos,
480                         const unsigned int columns,
481                         const unsigned int rows,
482                         const DcmOverlayData &data,
483                         const DcmLongString &label,
484                         const DcmLongString &description,
485                         const EM_Overlay mode)
486 {
487     int status = 0;
488     if (AdditionalPlanes && isValidGroupNumber(group))
489     {
490         unsigned int plane = group;
491         status = convertToPlaneNumber(plane, AdditionalPlanes);
492         if ((status != 0) && (plane < Data->ArrayEntries))
493         {
494             if (status == 1)                                                   // add new plane
495                 ++(Data->Count);
496             else if (status == 2)                                              // group number already exists
497                 delete Data->Planes[plane];
498             Data->Planes[plane] = new DiOverlayPlane(group, left_pos, top_pos, columns, rows, data, label, description, mode);
499             if (checkPlane(plane, 0))
500             {
501                 if (Data->Planes[plane]->getNumberOfFrames() > Frames)         // set maximum number of frames
502                     Frames = Data->Planes[plane]->getNumberOfFrames();
503             } else {
504                 delete Data->Planes[plane];                                    // remove invalid plane
505                 Data->Planes[plane] = NULL;
506                 if (status == 1)
507                     --(Data->Count);                                           // decrease number of planes
508                 status = 0;
509             }
510         }
511     }
512     return status;
513 }
514 
515 
removePlane(const unsigned int group)516 int DiOverlay::removePlane(const unsigned int group)
517 {
518     unsigned int plane = group;
519     if (AdditionalPlanes && (convertToPlaneNumber(plane, AdditionalPlanes) > 1))
520     {
521         delete Data->Planes[plane];                                           // remove invalid plane
522         Data->Planes[plane] = NULL;
523         --(Data->Count);                                                      // decrease number of planes
524         return 1;
525     }
526     return 0;
527 }
528 
529 
getPlaneData(const unsigned long frame,unsigned int plane,unsigned int & left_pos,unsigned int & top_pos,unsigned int & width,unsigned int & height,EM_Overlay & mode,const Uint16 columns,const Uint16 rows,const int bits,const Uint16 fore,const Uint16 back)530 void *DiOverlay::getPlaneData(const unsigned long frame,
531                               unsigned int plane,
532                               unsigned int &left_pos,
533                               unsigned int &top_pos,
534                               unsigned int &width,
535                               unsigned int &height,
536                               EM_Overlay &mode,
537                               const Uint16 columns,
538                               const Uint16 rows,
539                               const int bits,
540                               const Uint16 fore,
541                               const Uint16 back)
542 {
543     if (convertToPlaneNumber(plane, AdditionalPlanes) > 1)                    // plane does exist
544     {
545         DiOverlayPlane *op = Data->Planes[plane];
546         if ((op != NULL) && op->isValid())
547         {
548             const Uint16 xmin = (op->getLeft(Left) > 0) ? op->getLeft(Left) : 0;
549             const Uint16 ymin = (op->getTop(Top) > 0) ? op->getTop(Top) : 0;
550             const Uint16 xmax = (op->getRight(Left) < columns) ? op->getRight(Left) : columns;
551             const Uint16 ymax = (op->getBottom(Top) < rows) ? op->getBottom(Top) : rows;
552             left_pos = xmin;
553             top_pos = ymin;
554             width = xmax - xmin;
555             height = ymax - ymin;
556             mode = op->getMode();
557             return op->getData(frame, xmin, ymin, xmax, ymax, bits, fore, back);
558         }
559     }
560     return NULL;
561 }
562 
563 
getFullPlaneData(const unsigned long frame,unsigned int plane,unsigned int & width,unsigned int & height,const int bits,const Uint16 fore,const Uint16 back)564 void *DiOverlay::getFullPlaneData(const unsigned long frame,
565                                   unsigned int plane,
566                                   unsigned int &width,
567                                   unsigned int &height,
568                                   const int bits,
569                                   const Uint16 fore,
570                                   const Uint16 back)
571 {
572     if (convertToPlaneNumber(plane, AdditionalPlanes) > 1)                    // plane does exist
573     {
574         DiOverlayPlane *op = Data->Planes[plane];
575         if ((op != NULL) && op->isValid())
576         {
577             width = op->getWidth();
578             height = op->getHeight();
579             return op->getData(frame, 0, 0, width, height, bits, fore, back, OFFalse /*useOrigin*/);
580         }
581     }
582     return NULL;
583 }
584 
585 
create6xxx3000PlaneData(Uint8 * & buffer,unsigned int plane,unsigned int & width,unsigned int & height,unsigned long & frames)586 unsigned long DiOverlay::create6xxx3000PlaneData(Uint8 *&buffer,
587                                                  unsigned int plane,
588                                                  unsigned int &width,
589                                                  unsigned int &height,
590                                                  unsigned long &frames)
591 {
592     if (convertToPlaneNumber(plane, AdditionalPlanes) > 1)                    // plane does exist
593     {
594         DiOverlayPlane *op = Data->Planes[plane];
595         if ((op != NULL) && op->isValid())
596             return op->create6xxx3000Data(buffer, width, height, frames);
597     }
598     return 0;
599 }
600