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: DicomOverlayPlane (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/dctagkey.h"
28 #include "dcmtk/dcmdata/dcpixel.h"
29 #include "dcmtk/ofstd/ofbmanip.h"
30 #include "dcmtk/ofstd/ofutil.h"
31 
32 #include "dcmtk/dcmimgle/diovpln.h"
33 #include "dcmtk/dcmimgle/didocu.h"
34 
35 
36 /*----------------*
37  *  constructors  *
38  *----------------*/
39 
DiOverlayPlane(const DiDocument * docu,const unsigned int group,Uint16 alloc,const Uint16 stored,const Uint16 high)40 DiOverlayPlane::DiOverlayPlane(const DiDocument *docu,
41                                const unsigned int group,
42                                Uint16 alloc,
43                                const Uint16 stored,
44                                const Uint16 high)
45   : NumberOfFrames(0),
46     ImageFrameOrigin(0),
47     FirstFrame(0),
48     Top(0),
49     Left(0),
50     Height(0),
51     Width(0),
52     Rows(0),
53     Columns(0),
54     BitsAllocated(0),
55     BitPosition(0),
56     Foreground(1),
57     Threshold(1),
58     PValue(0),
59     Mode(EMO_Graphic),
60     DefaultMode(EMO_Graphic),
61     Label(),
62     Description(),
63     GroupNumber(group),
64     Valid(0),
65     Visible(0),
66     BitPos(0),
67     StartBitPos(0),
68     StartLeft(0),
69     StartTop(0),
70     EmbeddedData(0),
71     Ptr(NULL),
72     StartPtr(NULL),
73     Data(NULL)
74 {
75     if (docu != NULL)
76     {
77         /* determine first frame to be processed */
78         FirstFrame = docu->getFrameStart();
79         /* specify overlay group number */
80         DcmTagKey tag(group, DCM_OverlayRows.getElement() /* dummy */);
81         /* get descriptive data */
82         tag.setElement(DCM_OverlayLabel.getElement());
83         docu->getValue(tag, Label);
84         tag.setElement(DCM_OverlayDescription.getElement());
85         docu->getValue(tag, Description);
86         /* get overlay type */
87         tag.setElement(DCM_OverlayType.getElement());
88         const char *str;
89         if ((docu->getValue(tag, str) > 0) && (str != NULL) && (strcmp(str, "R") == 0))
90             DefaultMode = Mode = EMO_RegionOfInterest;
91         Sint32 sl = 0;
92         /* multi-frame overlays */
93         tag.setElement(DCM_NumberOfFramesInOverlay.getElement());
94         docu->getValue(tag, sl);
95         NumberOfFrames = (sl < 1) ? 1 : OFstatic_cast(Uint32, sl);
96         tag.setElement(DCM_ImageFrameOrigin.getElement());
97         docu->getValue(tag, ImageFrameOrigin);
98         if (ImageFrameOrigin > 0)                                   // image frame origin is numbered from 1
99             --ImageFrameOrigin;
100         tag.setElement(DCM_OverlayOrigin.getElement());
101 #ifdef REVERSE_OVERLAY_ORIGIN_ORDER
102         Valid = (docu->getValue(tag, Left, 0) > 0);
103         if (Valid)
104         {
105             DCMIMGLE_DEBUG("processing overlay plane in group 0x" << STD_NAMESPACE hex << group);
106             if (docu->getValue(tag, Top, 1) < 2)
107                 DCMIMGLE_WARN("missing second value for 'OverlayOrigin' ... assuming 'Top' = " << Top);
108         }
109 #else
110         Valid = (docu->getValue(tag, Top, 0) > 0);
111         if (Valid)
112         {
113             DCMIMGLE_DEBUG("processing overlay plane in group 0x" << STD_NAMESPACE hex << group);
114             if (docu->getValue(tag, Left, 1) < 2)
115                 DCMIMGLE_WARN("missing second value for 'OverlayOrigin' ... assuming 'Left' = " << Left);
116         }
117 #endif
118         /* overlay origin is numbered from 1 */
119         --Top;
120         --Left;
121         /* check overlay resolution */
122         tag.setElement(DCM_OverlayRows.getElement());
123         Valid &= (docu->getValue(tag, Rows) > 0);
124         Height = Rows;
125         tag.setElement(DCM_OverlayColumns.getElement());
126         Valid &= (docu->getValue(tag, Columns) > 0);
127         Width = Columns;
128         /* check overlay encoding */
129         tag.setElement(DCM_OverlayBitsAllocated.getElement());
130         Valid &= (docu->getValue(tag, BitsAllocated) > 0);
131         tag.setElement(DCM_OverlayBitPosition.getElement());
132         Valid &= (docu->getValue(tag, BitPosition) > 0);
133         tag.setElement(DCM_OverlayData.getElement());
134         /* final validity checks */
135         if (Valid)
136         {
137             /* separate overlay data? */
138             unsigned long length = docu->getValue(tag, Data) * 2 /* bytes */;
139             if (length == 0)
140             {
141                 if (!(docu->getFlags() & CIF_NeverAccessEmbeddedOverlays))
142                 {
143                     if (!docu->isCompressed())
144                     {
145                         /* if not, check for embedded overlay data */
146                         DcmPixelData *pixelData = docu->getPixelData();
147                         if (pixelData != NULL)
148                         {
149                             ImageFrameOrigin = 0;                           // see supplement 4
150                             const OFBool loaded = pixelData->valueLoaded();
151                             if (pixelData->getUint16Array(OFconst_cast(Uint16 *&, Data)).good())
152                             {
153                                 length = pixelData->getLength(docu->getTransferSyntax());
154                                 EmbeddedData = (Data != NULL);
155                                 if (!loaded)
156                                     DCMIMGLE_DEBUG("loaded complete pixel data into memory for embedded overlay data: " << length << " bytes");
157                             }
158                         }
159                     } else
160                         DCMIMGLE_ERROR("embedded overlay data cannot be accessed since pixel data is still compressed");
161                 } else
162                     DCMIMGLE_WARN("ignoring possibly embedded overlay data by configuration");
163             } else
164                 alloc = 1;                                          // separately stored overlay data
165             /* check for correct value of BitsAllocated */
166             if (BitsAllocated != alloc)                             // see correction proposal 87
167             {
168                 DCMIMGLE_WARN("invalid value for 'OverlayBitsAllocated' (" << BitsAllocated << ") ... assuming " << alloc);
169                 BitsAllocated = alloc;
170             }
171             /* check for correct value of BitPosition */
172             if (BitPosition >= BitsAllocated)
173             {
174                 DCMIMGLE_WARN("invalid value for 'OverlayBitPosition' (" << BitPosition << ") ... assuming " << (BitsAllocated - 1));
175                 BitPosition = BitsAllocated - 1;
176             }
177             if (EmbeddedData && (BitPosition <= high) && (BitPosition + stored > high))
178             {
179                 DCMIMGLE_WARN("invalid value for 'OverlayBitPosition' (" << BitPosition << "), refers to bit position within stored pixel value");
180                 Data = NULL;    // invalid plane
181             }
182             /* expected length of overlay data */
183             const unsigned long expLen = (OFstatic_cast(unsigned long, NumberOfFrames) * OFstatic_cast(unsigned long, Rows) *
184                                           OFstatic_cast(unsigned long, Columns) * OFstatic_cast(unsigned long, BitsAllocated) + 7) / 8;
185             if ((Data != NULL) && ((length == 0) || (length < expLen)))
186             {
187                 DCMIMGLE_ERROR("overlay data length is too short, " << expLen << " bytes expected but " << length << " bytes found");
188                 Valid = 0;
189                 Data = NULL;
190             } else
191                 Valid = (Data != NULL);
192         }
193         if (Valid)
194         {
195             /* report that this group contains a valid overlay plane */
196             DCMIMGLE_TRACE("overlay plane in group 0x" << STD_NAMESPACE hex << group << " is present and can be processed");
197         } else {
198             /* report that this group does not contain a valid overlay plane */
199             DCMIMGLE_TRACE("overlay plane in group 0x" << STD_NAMESPACE hex << group << " is missing or incomplete");
200         }
201     }
202 }
203 
204 
DiOverlayPlane(const unsigned int group,const Sint16 left_pos,const Sint16 top_pos,const Uint16 columns,const Uint16 rows,const DcmOverlayData & data,const DcmLongString & label,const DcmLongString & description,const EM_Overlay mode)205 DiOverlayPlane::DiOverlayPlane(const unsigned int group,
206                                const Sint16 left_pos,
207                                const Sint16 top_pos,
208                                const Uint16 columns,
209                                const Uint16 rows,
210                                const DcmOverlayData &data,
211                                const DcmLongString &label,
212                                const DcmLongString &description,
213                                const EM_Overlay mode)
214   : NumberOfFrames(1),
215     ImageFrameOrigin(0),
216     FirstFrame(0),
217     Top(top_pos),
218     Left(left_pos),
219     Height(rows),
220     Width(columns),
221     Rows(rows),
222     Columns(columns),
223     BitsAllocated(1),
224     BitPosition(0),
225     Foreground(1),
226     Threshold(1),
227     PValue(0),
228     Mode(mode),
229     DefaultMode(mode),
230     Label(),
231     Description(),
232     GroupNumber(group),
233     Valid(0),
234     Visible((mode == EMO_BitmapShutter) ? 1 : 0),
235     BitPos(0),
236     StartBitPos(0),
237     StartLeft(0),
238     StartTop(0),
239     EmbeddedData(0),
240     Ptr(NULL),
241     StartPtr(NULL),
242     Data(NULL)
243 {
244     DiDocument::getElemValue(OFreinterpret_cast(const DcmElement *, &label), Label);
245     DiDocument::getElemValue(OFreinterpret_cast(const DcmElement *, &description), Description);
246     if ((Columns > 0) && (Rows > 0))
247     {
248         const unsigned long length = DiDocument::getElemValue(OFreinterpret_cast(const DcmElement *, &data), Data) * 2 /* Bytes */;
249         /* expected length of overlay data */
250         const unsigned long expLen = (OFstatic_cast(unsigned long, Rows) * OFstatic_cast(unsigned long, Columns) + 7) / 8;
251         if ((length == 0) || (length < expLen))
252         {
253             DCMIMGLE_ERROR("overlay data length is too short, " << expLen << " bytes expected but " << length << " bytes found");
254             /* Valid = 0;  =>  This is the default. */
255             Data = NULL;
256         } else
257             Valid = (Data != NULL);
258     }
259     --Top;                                                      // overlay origin is numbered from 1
260     --Left;
261 }
262 
263 
DiOverlayPlane(DiOverlayPlane * plane,const unsigned int bit,const Uint16 * data,Uint16 * temp,const Uint16 width,const Uint16 height,const Uint16 columns,const Uint16 rows)264 DiOverlayPlane::DiOverlayPlane(DiOverlayPlane *plane,
265                                const unsigned int bit,
266                                const Uint16 *data,
267                                Uint16 *temp,
268                                const Uint16 width,
269                                const Uint16 height,
270                                const Uint16 columns,
271                                const Uint16 rows)
272   : NumberOfFrames(plane->NumberOfFrames),
273     ImageFrameOrigin(plane->ImageFrameOrigin),
274     FirstFrame(plane->FirstFrame),
275     Top(plane->Top),
276     Left(plane->Left),
277     Height(plane->Height),
278     Width(plane->Width),
279     Rows(rows),
280     Columns(columns),
281     BitsAllocated(16),
282     BitPosition(bit),
283     Foreground(plane->Foreground),
284     Threshold(plane->Threshold),
285     PValue(0),
286     Mode(plane->Mode),
287     DefaultMode(plane->DefaultMode),
288     Label(plane->Label),
289     Description(plane->Description),
290     GroupNumber(plane->GroupNumber),
291     Valid(0),
292     Visible(plane->Visible),
293     BitPos(0),
294     StartBitPos(0),
295     StartLeft(plane->StartLeft),
296     StartTop(plane->StartTop),
297     EmbeddedData(0),
298     Ptr(NULL),
299     StartPtr(NULL),
300     Data(data)
301 {
302     if (temp != NULL)
303     {
304         Uint16 x;
305         Uint16 y;
306         Uint16 *q = temp;
307         const Uint16 mask = 1 << bit;
308         const Uint16 skip_x = width - plane->Columns;
309         const unsigned long skip_f = OFstatic_cast(unsigned long, height - plane->Rows) * OFstatic_cast(unsigned long, width);
310         for (unsigned long f = 0; f < NumberOfFrames; ++f)
311         {
312             if (plane->reset(f + ImageFrameOrigin))
313             {
314                 for (y = 0; y < plane->Rows; ++y)
315                 {
316                     for (x = 0; x < plane->Columns; ++x, ++q)
317                     {
318                         if (plane->getNextBit())
319                             *q |= mask;                         // set corresponding bit
320                         else
321                             *q &= ~mask;                        // unset ... bit
322                     }
323                     q += skip_x;                                // skip to next line start
324                 }
325                 q += skip_f;                                    // skip to next frame start
326             }
327         }
328     }
329     Valid = (Data != NULL);
330 }
331 
332 
333 /*--------------*
334  *  destructor  *
335  *--------------*/
336 
~DiOverlayPlane()337 DiOverlayPlane::~DiOverlayPlane()
338 {
339 }
340 
341 
342 /********************************************************************/
343 
344 
getData(const unsigned long frame,const Uint16 xmin,const Uint16 ymin,const Uint16 xmax,const Uint16 ymax,const int bits,const Uint16 fore,const Uint16 back,const OFBool useOrigin)345 void *DiOverlayPlane::getData(const unsigned long frame,
346                               const Uint16 xmin,
347                               const Uint16 ymin,
348                               const Uint16 xmax,
349                               const Uint16 ymax,
350                               const int bits,
351                               const Uint16 fore,
352                               const Uint16 back,
353                               const OFBool useOrigin)
354 {
355     const unsigned long count = OFstatic_cast(unsigned long, xmax - xmin) * OFstatic_cast(unsigned long, ymax - ymin);
356     if (Valid && (count > 0))
357     {
358         const Uint16 mask = OFstatic_cast(Uint16, DicomImageClass::maxval(bits));
359         if (bits == 1)
360         {
361             const unsigned long count8 = (count + 7) / 8;           // round value: 8 bit padding
362             Uint8 *data = new Uint8[count8];
363             if (data != NULL)
364             {
365                 if ((fore & mask) != (back & mask))
366                 {
367                     OFBitmanipTemplate<Uint8>::setMem(data, 0x0, count8);
368                     Uint16 x;
369                     Uint16 y;
370                     Uint8 value = 0;
371                     Uint8 *q = data;
372                     int bit = 0;
373                     if (reset(frame + ImageFrameOrigin))
374                     {
375                         for (y = ymin; y < ymax; ++y)
376                         {
377                             setStart(xmin, y, useOrigin);
378                             for (x = xmin; x < xmax; ++x)
379                             {
380                                 if (getNextBit())
381                                 {
382                                     if (fore)
383                                         value |= (1 << bit);
384                                 } else if (back)
385                                     value |= (1 << bit);
386                                 if (bit == 7)
387                                 {
388                                     *(q++) = value;
389                                     value = 0;
390                                     bit = 0;
391                                 } else {
392                                     ++bit;
393                                 }
394                             }
395                         }
396                         if (bit != 0)
397                             *(q++) = value;
398                     }
399                 } else {
400                     OFBitmanipTemplate<Uint8>::setMem(data, (fore) ? 0xff : 0x0, count8);
401                 }
402             }
403             return OFstatic_cast(void *, data);
404         }
405         else if ((bits > 1) && (bits <= 8))
406         {
407             Uint8 *data = new Uint8[count];
408             if (data != NULL)
409             {
410                 const Uint8 fore8 = OFstatic_cast(Uint8, fore & mask);
411                 const Uint8 back8 = OFstatic_cast(Uint8, back & mask);
412                 OFBitmanipTemplate<Uint8>::setMem(data, back8, count);
413                 if (fore8 != back8)                                     // optimization
414                 {
415                     Uint16 x;
416                     Uint16 y;
417                     Uint8 *q = data;
418                     if (reset(frame + ImageFrameOrigin))
419                     {
420                         for (y = ymin; y < ymax; ++y)
421                         {
422                             setStart(xmin, y, useOrigin);
423                             for (x = xmin; x < xmax; ++x, ++q)
424                             {
425                                 if (getNextBit())
426                                     *q = fore8;                         // set pixel value (default: 0xff)
427                             }
428                         }
429                     }
430                 }
431             }
432             return OFstatic_cast(void *, data);
433         }
434         else if ((bits > 8) && (bits <= 16))
435         {
436             Uint16 *data = new Uint16[count];
437             if (data != NULL)
438             {
439                 const Uint16 fore16 = fore & mask;
440                 const Uint16 back16 = back & mask;
441                 OFBitmanipTemplate<Uint16>::setMem(data, back16, count);
442                 if (fore16 != back16)                                   // optimization
443                 {
444                     Uint16 x;
445                     Uint16 y;
446                     Uint16 *q = data;
447                     if (reset(frame + ImageFrameOrigin))
448                     {
449                         for (y = ymin; y < ymax; ++y)
450                         {
451                             setStart(xmin, y, useOrigin);
452                             for (x = xmin; x < xmax; ++x, ++q)
453                             {
454                                 if (getNextBit())
455                                     *q = fore16;                        // set pixel value (default: 0xff)
456                             }
457                         }
458                     }
459                 }
460             }
461             return OFstatic_cast(void *, data);
462         }
463     }
464     return NULL;
465 }
466 
467 
create6xxx3000Data(Uint8 * & buffer,unsigned int & width,unsigned int & height,unsigned long & frames)468 unsigned long DiOverlayPlane::create6xxx3000Data(Uint8 *&buffer,
469                                                  unsigned int &width,
470                                                  unsigned int &height,
471                                                  unsigned long &frames)
472 {
473     buffer = NULL;
474     width = Width;
475     height = Height;
476     frames = NumberOfFrames;
477     const unsigned long count = OFstatic_cast(unsigned long, Width) * OFstatic_cast(unsigned long, Height) * NumberOfFrames;
478     if (Valid && (count > 0))
479     {
480         const unsigned long count8 = ((count + 15) / 16) * 2;           // round value: 16 bit padding
481         buffer = new Uint8[count8];
482         if (buffer != NULL)
483         {
484             OFBitmanipTemplate<Uint8>::setMem(buffer, 0x0, count8);
485             Uint16 x;
486             Uint16 y;
487             Uint8 value = 0;
488             Uint8 *q = buffer;
489             int bit = 0;
490             for (unsigned long f = 0; f < NumberOfFrames; ++f)
491             {
492                 if (reset(f + ImageFrameOrigin))
493                 {
494                     for (y = 0; y < Height; ++y)
495                     {
496                         for (x = 0; x < Width; ++x)
497                         {
498                             if (getNextBit())
499                                 value |= (1 << bit);
500                             if (bit == 7)
501                             {
502                                 *(q++) = value;
503                                 value = 0;
504                                 bit = 0;
505                             } else {
506                                 ++bit;
507                             }
508                         }
509                     }
510                 }
511                 if (bit != 0)
512                     *(q++) = value;
513             }
514             return count8;      // number of bytes
515         }
516     }
517     return 0;
518 }
519 
520 
show(const double fore,const double thresh,const EM_Overlay mode)521 void DiOverlayPlane::show(const double fore,
522                           const double thresh,
523                           const EM_Overlay mode)
524 {
525     Foreground = (fore < 0) ? 0 : (fore > 1) ? 1 : fore;
526     Threshold = (thresh < 0) ? 0 : (thresh > 1) ? 1 : thresh;
527     Mode = (mode == EMO_Default) ? DefaultMode : mode;
528     Visible = 1;
529 }
530 
531 
show(const Uint16 pvalue)532 int DiOverlayPlane::show(const Uint16 pvalue)
533 {
534     if (Mode == EMO_BitmapShutter)
535     {
536         PValue = pvalue;
537         Visible = 1;
538         return 1;
539     }
540     return 0;
541 }
542 
543 
place(const signed int left_pos,const signed int top_pos)544 void DiOverlayPlane::place(const signed int left_pos,
545                            const signed int top_pos)
546 {
547     Left = OFstatic_cast(Sint16, left_pos);
548     Top = OFstatic_cast(Sint16, top_pos);
549 }
550 
551 
setScaling(const double xfactor,const double yfactor)552 void DiOverlayPlane::setScaling(const double xfactor,
553                                 const double yfactor)
554 {
555     Left = OFstatic_cast(Sint16, xfactor * Left);
556     Top = OFstatic_cast(Sint16, yfactor * Top);
557     Width = OFstatic_cast(Uint16, xfactor * Width);
558     Height = OFstatic_cast(Uint16, yfactor * Height);
559     StartLeft = OFstatic_cast(unsigned int, xfactor * StartLeft);
560     StartTop = OFstatic_cast(unsigned int, yfactor * StartTop);
561 }
562 
563 
setFlipping(const int horz,const int vert,const signed long columns,const signed long rows)564 void DiOverlayPlane::setFlipping(const int horz,
565                                  const int vert,
566                                  const signed long columns,
567                                  const signed long rows)
568 {
569     if (horz)
570     {
571         Left = OFstatic_cast(Sint16, columns - Width - Left);
572         StartLeft = OFstatic_cast(unsigned int, OFstatic_cast(signed long, Columns) - Width - StartLeft);
573     }
574     if (vert)
575     {
576         Top = OFstatic_cast(Sint16, rows - Height - Top);
577         StartTop = OFstatic_cast(unsigned int, OFstatic_cast(signed long, Rows) - Height - StartTop);
578     }
579 }
580 
581 
setRotation(const int degree,const signed long left_pos,const signed long top_pos,const Uint16 columns,const Uint16 rows)582 void DiOverlayPlane::setRotation(const int degree,
583                                  const signed long left_pos,
584                                  const signed long top_pos,
585                                  const Uint16 columns,
586                                  const Uint16 rows)
587 {
588     if (degree == 180)                          // equal to v/h flip
589         setFlipping(1, 1, left_pos + columns, top_pos + rows);
590     else if ((degree == 90) || (degree == 270))
591     {
592         OFswap(Width, Height);                  // swap visible width/height
593 /*
594         OFswap(Columns, Rows);                  // swap stored columns/rows -> already done in the constructor !
595 */
596         if (degree == 90)                       // rotate right
597         {
598             const Sint16 ss = Left;
599             const unsigned int ui = StartLeft;
600             Left = OFstatic_cast(Sint16, OFstatic_cast(signed long, columns) - Width - Top + top_pos);
601             StartLeft = OFstatic_cast(unsigned int, OFstatic_cast(signed long, Columns) - Width - StartTop);
602             Top = OFstatic_cast(Sint16, ss - left_pos);
603             StartTop = ui;
604         } else {                                // rotate left
605             const Sint16 ss = Left;
606             const unsigned int ui = StartLeft;
607             Left = OFstatic_cast(Sint16, Top - top_pos);
608             StartLeft = StartTop;
609             Top = OFstatic_cast(Sint16, OFstatic_cast(signed long, rows) - Height - ss + left_pos);
610             StartTop = OFstatic_cast(unsigned int, OFstatic_cast(signed long, Rows) - Height - ui);
611         }
612     }
613 }
614