1 | /*****************************************************************************/ |
2 | // Copyright 2006-2008 Adobe Systems Incorporated |
3 | // All Rights Reserved. |
4 | // |
5 | // NOTICE: Adobe permits you to use, modify, and distribute this file in |
6 | // accordance with the terms of the Adobe license agreement accompanying it. |
7 | /*****************************************************************************/ |
8 | |
9 | /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_image.cpp#1 $ */ |
10 | /* $DateTime: 2012/05/30 13:28:51 $ */ |
11 | /* $Change: 832332 $ */ |
12 | /* $Author: tknoll $ */ |
13 | |
14 | /*****************************************************************************/ |
15 | |
16 | #include "dng_image.h" |
17 | |
18 | #include "dng_assertions.h" |
19 | #include "dng_exceptions.h" |
20 | #include "dng_orientation.h" |
21 | #include "dng_pixel_buffer.h" |
22 | #include "dng_tag_types.h" |
23 | #include "dng_tile_iterator.h" |
24 | #include "dng_utils.h" |
25 | |
26 | /*****************************************************************************/ |
27 | |
28 | dng_tile_buffer::dng_tile_buffer (const dng_image &image, |
29 | const dng_rect &tile, |
30 | bool dirty) |
31 | |
32 | : fImage (image) |
33 | , fRefData (NULL) |
34 | |
35 | { |
36 | |
37 | fImage.AcquireTileBuffer (*this, |
38 | tile, |
39 | dirty); |
40 | |
41 | } |
42 | |
43 | /*****************************************************************************/ |
44 | |
45 | dng_tile_buffer::~dng_tile_buffer () |
46 | { |
47 | |
48 | fImage.ReleaseTileBuffer (*this); |
49 | |
50 | } |
51 | |
52 | /*****************************************************************************/ |
53 | |
54 | dng_const_tile_buffer::dng_const_tile_buffer (const dng_image &image, |
55 | const dng_rect &tile) |
56 | |
57 | : dng_tile_buffer (image, tile, false) |
58 | |
59 | { |
60 | |
61 | } |
62 | |
63 | /*****************************************************************************/ |
64 | |
65 | dng_const_tile_buffer::~dng_const_tile_buffer () |
66 | { |
67 | |
68 | } |
69 | |
70 | /*****************************************************************************/ |
71 | |
72 | dng_dirty_tile_buffer::dng_dirty_tile_buffer (dng_image &image, |
73 | const dng_rect &tile) |
74 | |
75 | : dng_tile_buffer (image, tile, true) |
76 | |
77 | { |
78 | |
79 | } |
80 | |
81 | /*****************************************************************************/ |
82 | |
83 | dng_dirty_tile_buffer::~dng_dirty_tile_buffer () |
84 | { |
85 | |
86 | } |
87 | |
88 | /*****************************************************************************/ |
89 | |
90 | dng_image::dng_image (const dng_rect &bounds, |
91 | uint32 planes, |
92 | uint32 pixelType) |
93 | |
94 | : fBounds (bounds) |
95 | , fPlanes (planes) |
96 | , fPixelType (pixelType) |
97 | |
98 | { |
99 | |
100 | if (bounds.IsEmpty () || planes == 0 || PixelSize () == 0) |
101 | { |
102 | |
103 | #if qDNGValidate |
104 | |
105 | ReportError ("Fuzz: Attempt to create zero size image" ); |
106 | |
107 | #endif |
108 | |
109 | ThrowBadFormat (); |
110 | |
111 | } |
112 | |
113 | } |
114 | |
115 | /*****************************************************************************/ |
116 | |
117 | dng_image::~dng_image () |
118 | { |
119 | |
120 | } |
121 | |
122 | /*****************************************************************************/ |
123 | |
124 | dng_image * dng_image::Clone () const |
125 | { |
126 | |
127 | ThrowProgramError ("Clone is not supported by this dng_image subclass" ); |
128 | |
129 | return NULL; |
130 | |
131 | } |
132 | |
133 | /*****************************************************************************/ |
134 | |
135 | void dng_image::SetPixelType (uint32 pixelType) |
136 | { |
137 | |
138 | if (TagTypeSize (pixelType) != PixelSize ()) |
139 | { |
140 | |
141 | ThrowProgramError ("Cannot change pixel size for existing image" ); |
142 | |
143 | } |
144 | |
145 | fPixelType = pixelType; |
146 | |
147 | } |
148 | |
149 | /*****************************************************************************/ |
150 | |
151 | uint32 dng_image::PixelSize () const |
152 | { |
153 | |
154 | return TagTypeSize (PixelType ()); |
155 | |
156 | } |
157 | |
158 | /*****************************************************************************/ |
159 | |
160 | uint32 dng_image::PixelRange () const |
161 | { |
162 | |
163 | switch (fPixelType) |
164 | { |
165 | |
166 | case ttByte: |
167 | case ttSByte: |
168 | { |
169 | return 0x0FF; |
170 | } |
171 | |
172 | case ttShort: |
173 | case ttSShort: |
174 | { |
175 | return 0x0FFFF; |
176 | } |
177 | |
178 | case ttLong: |
179 | case ttSLong: |
180 | { |
181 | return 0xFFFFFFFF; |
182 | } |
183 | |
184 | default: |
185 | break; |
186 | |
187 | } |
188 | |
189 | return 0; |
190 | |
191 | } |
192 | |
193 | /*****************************************************************************/ |
194 | |
195 | dng_rect dng_image::RepeatingTile () const |
196 | { |
197 | |
198 | return fBounds; |
199 | |
200 | } |
201 | |
202 | /*****************************************************************************/ |
203 | |
204 | void dng_image::AcquireTileBuffer (dng_tile_buffer & /* buffer */, |
205 | const dng_rect & /* area */, |
206 | bool /* dirty */) const |
207 | { |
208 | |
209 | ThrowProgramError (); |
210 | |
211 | } |
212 | |
213 | /*****************************************************************************/ |
214 | |
215 | void dng_image::ReleaseTileBuffer (dng_tile_buffer & /* buffer */) const |
216 | { |
217 | |
218 | } |
219 | |
220 | /*****************************************************************************/ |
221 | |
222 | void dng_image::DoGet (dng_pixel_buffer &buffer) const |
223 | { |
224 | |
225 | dng_rect tile; |
226 | |
227 | dng_tile_iterator iter (*this, buffer.fArea); |
228 | |
229 | while (iter.GetOneTile (tile)) |
230 | { |
231 | |
232 | dng_const_tile_buffer tileBuffer (*this, tile); |
233 | |
234 | buffer.CopyArea (tileBuffer, |
235 | tile, |
236 | buffer.fPlane, |
237 | buffer.fPlanes); |
238 | |
239 | } |
240 | |
241 | } |
242 | |
243 | /*****************************************************************************/ |
244 | |
245 | void dng_image::DoPut (const dng_pixel_buffer &buffer) |
246 | { |
247 | |
248 | dng_rect tile; |
249 | |
250 | dng_tile_iterator iter (*this, buffer.fArea); |
251 | |
252 | while (iter.GetOneTile (tile)) |
253 | { |
254 | |
255 | dng_dirty_tile_buffer tileBuffer (*this, tile); |
256 | |
257 | tileBuffer.CopyArea (buffer, |
258 | tile, |
259 | buffer.fPlane, |
260 | buffer.fPlanes); |
261 | |
262 | } |
263 | |
264 | } |
265 | |
266 | /*****************************************************************************/ |
267 | |
268 | void dng_image::GetRepeat (dng_pixel_buffer &buffer, |
269 | const dng_rect &srcArea, |
270 | const dng_rect &dstArea) const |
271 | { |
272 | |
273 | // If we already have the entire srcArea in the |
274 | // buffer, we can just repeat that. |
275 | |
276 | if ((srcArea & buffer.fArea) == srcArea) |
277 | { |
278 | |
279 | buffer.RepeatArea (srcArea, |
280 | dstArea); |
281 | |
282 | } |
283 | |
284 | // Else we first need to get the srcArea into the buffer area. |
285 | |
286 | else |
287 | { |
288 | |
289 | // Find repeating pattern size. |
290 | |
291 | dng_point repeat = srcArea.Size (); |
292 | |
293 | // Find pattern phase at top-left corner of destination area. |
294 | |
295 | dng_point phase = dng_pixel_buffer::RepeatPhase (srcArea, |
296 | dstArea); |
297 | |
298 | // Find new source area at top-left of dstArea. |
299 | |
300 | dng_rect newArea = srcArea + (dstArea.TL () - |
301 | srcArea.TL ()); |
302 | |
303 | // Find quadrant split coordinates. |
304 | |
305 | int32 splitV = newArea.t + repeat.v - phase.v; |
306 | int32 splitH = newArea.l + repeat.h - phase.h; |
307 | |
308 | // Top-left quadrant. |
309 | |
310 | dng_rect dst1 (dng_rect (newArea.t, |
311 | newArea.l, |
312 | splitV, |
313 | splitH) & dstArea); |
314 | |
315 | if (dst1.NotEmpty ()) |
316 | { |
317 | |
318 | dng_pixel_buffer temp (buffer); |
319 | |
320 | temp.fArea = dst1 + (srcArea.TL () - |
321 | dstArea.TL () + |
322 | dng_point (phase.v, phase.h)); |
323 | |
324 | temp.fData = buffer.DirtyPixel (dst1.t, |
325 | dst1.l, |
326 | buffer.fPlane); |
327 | |
328 | DoGet (temp); |
329 | |
330 | } |
331 | |
332 | // Top-right quadrant. |
333 | |
334 | dng_rect dst2 (dng_rect (newArea.t, |
335 | splitH, |
336 | splitV, |
337 | newArea.r) & dstArea); |
338 | |
339 | if (dst2.NotEmpty ()) |
340 | { |
341 | |
342 | dng_pixel_buffer temp (buffer); |
343 | |
344 | temp.fArea = dst2 + (srcArea.TL () - |
345 | dstArea.TL () + |
346 | dng_point (phase.v, -phase.h)); |
347 | |
348 | temp.fData = buffer.DirtyPixel (dst2.t, |
349 | dst2.l, |
350 | buffer.fPlane); |
351 | |
352 | DoGet (temp); |
353 | |
354 | } |
355 | |
356 | // Bottom-left quadrant. |
357 | |
358 | dng_rect dst3 (dng_rect (splitV, |
359 | newArea.l, |
360 | newArea.b, |
361 | splitH) & dstArea); |
362 | |
363 | if (dst3.NotEmpty ()) |
364 | { |
365 | |
366 | dng_pixel_buffer temp (buffer); |
367 | |
368 | temp.fArea = dst3 + (srcArea.TL () - |
369 | dstArea.TL () + |
370 | dng_point (-phase.v, phase.h)); |
371 | |
372 | temp.fData = buffer.DirtyPixel (dst3.t, |
373 | dst3.l, |
374 | buffer.fPlane); |
375 | |
376 | DoGet (temp); |
377 | |
378 | } |
379 | |
380 | // Bottom-right quadrant. |
381 | |
382 | dng_rect dst4 (dng_rect (splitV, |
383 | splitH, |
384 | newArea.b, |
385 | newArea.r) & dstArea); |
386 | |
387 | if (dst4.NotEmpty ()) |
388 | { |
389 | |
390 | dng_pixel_buffer temp (buffer); |
391 | |
392 | temp.fArea = dst4 + (srcArea.TL () - |
393 | dstArea.TL () + |
394 | dng_point (-phase.v, -phase.h)); |
395 | |
396 | temp.fData = buffer.DirtyPixel (dst4.t, |
397 | dst4.l, |
398 | buffer.fPlane); |
399 | |
400 | DoGet (temp); |
401 | |
402 | } |
403 | |
404 | // Replicate this new source area. |
405 | |
406 | buffer.RepeatArea (newArea, |
407 | dstArea); |
408 | |
409 | } |
410 | |
411 | } |
412 | |
413 | /*****************************************************************************/ |
414 | |
415 | void dng_image::GetEdge (dng_pixel_buffer &buffer, |
416 | edge_option edgeOption, |
417 | const dng_rect &srcArea, |
418 | const dng_rect &dstArea) const |
419 | { |
420 | |
421 | switch (edgeOption) |
422 | { |
423 | |
424 | case edge_zero: |
425 | { |
426 | |
427 | buffer.SetZero (dstArea, |
428 | buffer.fPlane, |
429 | buffer.fPlanes); |
430 | |
431 | break; |
432 | |
433 | } |
434 | |
435 | case edge_repeat: |
436 | { |
437 | |
438 | GetRepeat (buffer, |
439 | srcArea, |
440 | dstArea); |
441 | |
442 | break; |
443 | |
444 | } |
445 | |
446 | case edge_repeat_zero_last: |
447 | { |
448 | |
449 | if (buffer.fPlanes > 1) |
450 | { |
451 | |
452 | dng_pixel_buffer buffer1 (buffer); |
453 | |
454 | buffer1.fPlanes--; |
455 | |
456 | GetEdge (buffer1, |
457 | edge_repeat, |
458 | srcArea, |
459 | dstArea); |
460 | |
461 | } |
462 | |
463 | dng_pixel_buffer buffer2 (buffer); |
464 | |
465 | buffer2.fPlane = buffer.fPlanes - 1; |
466 | buffer2.fPlanes = 1; |
467 | |
468 | buffer2.fData = buffer.DirtyPixel (buffer2.fArea.t, |
469 | buffer2.fArea.l, |
470 | buffer2.fPlane); |
471 | |
472 | GetEdge (buffer2, |
473 | edge_zero, |
474 | srcArea, |
475 | dstArea); |
476 | |
477 | break; |
478 | |
479 | } |
480 | |
481 | default: |
482 | { |
483 | |
484 | ThrowProgramError (); |
485 | |
486 | } |
487 | |
488 | } |
489 | |
490 | } |
491 | |
492 | /*****************************************************************************/ |
493 | |
494 | void dng_image::Get (dng_pixel_buffer &buffer, |
495 | edge_option edgeOption, |
496 | uint32 repeatV, |
497 | uint32 repeatH) const |
498 | { |
499 | |
500 | // Find the overlap with the image bounds. |
501 | |
502 | dng_rect overlap = buffer.fArea & fBounds; |
503 | |
504 | // Move the overlapping pixels. |
505 | |
506 | if (overlap.NotEmpty ()) |
507 | { |
508 | |
509 | dng_pixel_buffer temp (buffer); |
510 | |
511 | temp.fArea = overlap; |
512 | |
513 | temp.fData = buffer.DirtyPixel (overlap.t, |
514 | overlap.l, |
515 | buffer.fPlane); |
516 | |
517 | DoGet (temp); |
518 | |
519 | } |
520 | |
521 | // See if we need to pad the edge values. |
522 | |
523 | if ((edgeOption != edge_none) && (overlap != buffer.fArea)) |
524 | { |
525 | |
526 | dng_rect areaT (buffer.fArea); |
527 | dng_rect areaL (buffer.fArea); |
528 | dng_rect areaB (buffer.fArea); |
529 | dng_rect areaR (buffer.fArea); |
530 | |
531 | areaT.b = Min_int32 (areaT.b, fBounds.t); |
532 | areaL.r = Min_int32 (areaL.r, fBounds.l); |
533 | areaB.t = Max_int32 (areaB.t, fBounds.b); |
534 | areaR.l = Max_int32 (areaR.l, fBounds.r); |
535 | |
536 | dng_rect areaH (buffer.fArea); |
537 | dng_rect areaV (buffer.fArea); |
538 | |
539 | areaH.l = Max_int32 (areaH.l, fBounds.l); |
540 | areaH.r = Min_int32 (areaH.r, fBounds.r); |
541 | |
542 | areaV.t = Max_int32 (areaV.t, fBounds.t); |
543 | areaV.b = Min_int32 (areaV.b, fBounds.b); |
544 | |
545 | // Top left. |
546 | |
547 | dng_rect areaTL = areaT & areaL; |
548 | |
549 | if (areaTL.NotEmpty ()) |
550 | { |
551 | |
552 | GetEdge (buffer, |
553 | edgeOption, |
554 | dng_rect (fBounds.t, |
555 | fBounds.l, |
556 | fBounds.t + (int32)repeatV, |
557 | fBounds.l + (int32)repeatH), |
558 | areaTL); |
559 | |
560 | } |
561 | |
562 | // Top middle. |
563 | |
564 | dng_rect areaTM = areaT & areaH; |
565 | |
566 | if (areaTM.NotEmpty ()) |
567 | { |
568 | |
569 | GetEdge (buffer, |
570 | edgeOption, |
571 | dng_rect (fBounds.t, |
572 | areaTM.l, |
573 | fBounds.t + (int32)repeatV, |
574 | areaTM.r), |
575 | areaTM); |
576 | |
577 | } |
578 | |
579 | // Top right. |
580 | |
581 | dng_rect areaTR = areaT & areaR; |
582 | |
583 | if (areaTR.NotEmpty ()) |
584 | { |
585 | |
586 | GetEdge (buffer, |
587 | edgeOption, |
588 | dng_rect (fBounds.t, |
589 | fBounds.r - (int32)repeatH, |
590 | fBounds.t + (int32)repeatV, |
591 | fBounds.r), |
592 | areaTR); |
593 | |
594 | } |
595 | |
596 | // Left middle. |
597 | |
598 | dng_rect areaLM = areaL & areaV; |
599 | |
600 | if (areaLM.NotEmpty ()) |
601 | { |
602 | |
603 | GetEdge (buffer, |
604 | edgeOption, |
605 | dng_rect (areaLM.t, |
606 | fBounds.l, |
607 | areaLM.b, |
608 | fBounds.l + (int32)repeatH), |
609 | areaLM); |
610 | |
611 | } |
612 | |
613 | // Right middle. |
614 | |
615 | dng_rect areaRM = areaR & areaV; |
616 | |
617 | if (areaRM.NotEmpty ()) |
618 | { |
619 | |
620 | GetEdge (buffer, |
621 | edgeOption, |
622 | dng_rect (areaRM.t, |
623 | fBounds.r - (int32)repeatH, |
624 | areaRM.b, |
625 | fBounds.r), |
626 | areaRM); |
627 | |
628 | } |
629 | |
630 | // Bottom left. |
631 | |
632 | dng_rect areaBL = areaB & areaL; |
633 | |
634 | if (areaBL.NotEmpty ()) |
635 | { |
636 | |
637 | GetEdge (buffer, |
638 | edgeOption, |
639 | dng_rect (fBounds.b - (int32)repeatV, |
640 | fBounds.l, |
641 | fBounds.b, |
642 | fBounds.l + (int32)repeatH), |
643 | areaBL); |
644 | |
645 | } |
646 | |
647 | // Bottom middle. |
648 | |
649 | dng_rect areaBM = areaB & areaH; |
650 | |
651 | if (areaBM.NotEmpty ()) |
652 | { |
653 | |
654 | GetEdge (buffer, |
655 | edgeOption, |
656 | dng_rect (fBounds.b - (int32)repeatV, |
657 | areaBM.l, |
658 | fBounds.b, |
659 | areaBM.r), |
660 | areaBM); |
661 | |
662 | } |
663 | |
664 | // Bottom right. |
665 | |
666 | dng_rect areaBR = areaB & areaR; |
667 | |
668 | if (areaBR.NotEmpty ()) |
669 | { |
670 | |
671 | GetEdge (buffer, |
672 | edgeOption, |
673 | dng_rect (fBounds.b - (int32)repeatV, |
674 | fBounds.r - (int32)repeatH, |
675 | fBounds.b, |
676 | fBounds.r), |
677 | areaBR); |
678 | |
679 | } |
680 | |
681 | } |
682 | |
683 | } |
684 | |
685 | /*****************************************************************************/ |
686 | |
687 | void dng_image::Put (const dng_pixel_buffer &buffer) |
688 | { |
689 | |
690 | // Move the overlapping pixels. |
691 | |
692 | dng_rect overlap = buffer.fArea & fBounds; |
693 | |
694 | if (overlap.NotEmpty ()) |
695 | { |
696 | |
697 | dng_pixel_buffer temp (buffer); |
698 | |
699 | temp.fArea = overlap; |
700 | |
701 | temp.fData = (void *) buffer.ConstPixel (overlap.t, |
702 | overlap.l, |
703 | buffer.fPlane); |
704 | |
705 | // Move the overlapping planes. |
706 | |
707 | if (temp.fPlane < Planes ()) |
708 | { |
709 | |
710 | temp.fPlanes = Min_uint32 (temp.fPlanes, |
711 | Planes () - temp.fPlane); |
712 | |
713 | DoPut (temp); |
714 | |
715 | } |
716 | |
717 | } |
718 | |
719 | } |
720 | |
721 | /*****************************************************************************/ |
722 | |
723 | void dng_image::Trim (const dng_rect &r) |
724 | { |
725 | |
726 | if (r != Bounds ()) |
727 | { |
728 | |
729 | ThrowProgramError ("Trim is not support by this dng_image subclass" ); |
730 | |
731 | } |
732 | |
733 | } |
734 | |
735 | /*****************************************************************************/ |
736 | |
737 | void dng_image::Rotate (const dng_orientation &orientation) |
738 | { |
739 | |
740 | if (orientation != dng_orientation::Normal ()) |
741 | { |
742 | |
743 | ThrowProgramError ("Rotate is not support by this dng_image subclass" ); |
744 | |
745 | } |
746 | |
747 | } |
748 | |
749 | /*****************************************************************************/ |
750 | |
751 | void dng_image::CopyArea (const dng_image &src, |
752 | const dng_rect &area, |
753 | uint32 srcPlane, |
754 | uint32 dstPlane, |
755 | uint32 planes) |
756 | { |
757 | |
758 | if (&src == this) |
759 | return; |
760 | |
761 | dng_tile_iterator destIter(*this, area); |
762 | dng_rect destTileArea; |
763 | |
764 | while (destIter.GetOneTile(destTileArea)) |
765 | { |
766 | dng_tile_iterator srcIter(src, destTileArea); |
767 | dng_rect srcTileArea; |
768 | |
769 | while (srcIter.GetOneTile(srcTileArea)) |
770 | { |
771 | |
772 | dng_dirty_tile_buffer destTile(*this, srcTileArea); |
773 | dng_const_tile_buffer srcTile(src, srcTileArea); |
774 | |
775 | destTile.CopyArea (srcTile, srcTileArea, srcPlane, dstPlane, planes); |
776 | |
777 | } |
778 | |
779 | } |
780 | |
781 | } |
782 | |
783 | /*****************************************************************************/ |
784 | |
785 | bool dng_image::EqualArea (const dng_image &src, |
786 | const dng_rect &area, |
787 | uint32 plane, |
788 | uint32 planes) const |
789 | { |
790 | |
791 | if (&src == this) |
792 | return true; |
793 | |
794 | dng_tile_iterator destIter (*this, area); |
795 | |
796 | dng_rect destTileArea; |
797 | |
798 | while (destIter.GetOneTile (destTileArea)) |
799 | { |
800 | |
801 | dng_tile_iterator srcIter (src, destTileArea); |
802 | |
803 | dng_rect srcTileArea; |
804 | |
805 | while (srcIter.GetOneTile (srcTileArea)) |
806 | { |
807 | |
808 | dng_const_tile_buffer destTile (*this, srcTileArea); |
809 | dng_const_tile_buffer srcTile (src , srcTileArea); |
810 | |
811 | if (!destTile.EqualArea (srcTile, srcTileArea, plane, planes)) |
812 | { |
813 | return false; |
814 | } |
815 | |
816 | } |
817 | |
818 | } |
819 | |
820 | return true; |
821 | |
822 | } |
823 | |
824 | /*****************************************************************************/ |
825 | |
826 | void dng_image::SetConstant (uint32 value, |
827 | const dng_rect &area) |
828 | { |
829 | |
830 | dng_tile_iterator iter (*this, area); |
831 | |
832 | dng_rect tileArea; |
833 | |
834 | while (iter.GetOneTile (tileArea)) |
835 | { |
836 | |
837 | dng_dirty_tile_buffer buffer (*this, tileArea); |
838 | |
839 | buffer.SetConstant (tileArea, |
840 | 0, |
841 | fPlanes, |
842 | value); |
843 | |
844 | } |
845 | |
846 | } |
847 | |
848 | /*****************************************************************************/ |
849 | |