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