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
dng_tile_buffer(const dng_image & image,const dng_rect & tile,bool dirty)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
~dng_tile_buffer()45 dng_tile_buffer::~dng_tile_buffer ()
46 {
47
48 fImage.ReleaseTileBuffer (*this);
49
50 }
51
52 /*****************************************************************************/
53
dng_const_tile_buffer(const dng_image & image,const dng_rect & tile)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
~dng_const_tile_buffer()65 dng_const_tile_buffer::~dng_const_tile_buffer ()
66 {
67
68 }
69
70 /*****************************************************************************/
71
dng_dirty_tile_buffer(dng_image & image,const dng_rect & tile)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
~dng_dirty_tile_buffer()83 dng_dirty_tile_buffer::~dng_dirty_tile_buffer ()
84 {
85
86 }
87
88 /*****************************************************************************/
89
dng_image(const dng_rect & bounds,uint32 planes,uint32 pixelType)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
~dng_image()117 dng_image::~dng_image ()
118 {
119
120 }
121
122 /*****************************************************************************/
123
Clone() const124 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
SetPixelType(uint32 pixelType)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
PixelSize() const151 uint32 dng_image::PixelSize () const
152 {
153
154 return TagTypeSize (PixelType ());
155
156 }
157
158 /*****************************************************************************/
159
PixelRange() const160 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
RepeatingTile() const195 dng_rect dng_image::RepeatingTile () const
196 {
197
198 return fBounds;
199
200 }
201
202 /*****************************************************************************/
203
AcquireTileBuffer(dng_tile_buffer &,const dng_rect &,bool) const204 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
ReleaseTileBuffer(dng_tile_buffer &) const215 void dng_image::ReleaseTileBuffer (dng_tile_buffer & /* buffer */) const
216 {
217
218 }
219
220 /*****************************************************************************/
221
DoGet(dng_pixel_buffer & buffer) const222 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
DoPut(const dng_pixel_buffer & buffer)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
GetRepeat(dng_pixel_buffer & buffer,const dng_rect & srcArea,const dng_rect & dstArea) const268 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
GetEdge(dng_pixel_buffer & buffer,edge_option edgeOption,const dng_rect & srcArea,const dng_rect & dstArea) const415 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
Get(dng_pixel_buffer & buffer,edge_option edgeOption,uint32 repeatV,uint32 repeatH) const494 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
Put(const dng_pixel_buffer & buffer)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
Trim(const dng_rect & r)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
Rotate(const dng_orientation & orientation)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
CopyArea(const dng_image & src,const dng_rect & area,uint32 srcPlane,uint32 dstPlane,uint32 planes)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
EqualArea(const dng_image & src,const dng_rect & area,uint32 plane,uint32 planes) const785 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
SetConstant(uint32 value,const dng_rect & area)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