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
28dng_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
45dng_tile_buffer::~dng_tile_buffer ()
46	{
47
48	fImage.ReleaseTileBuffer (*this);
49
50	}
51
52/*****************************************************************************/
53
54dng_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
65dng_const_tile_buffer::~dng_const_tile_buffer ()
66	{
67
68	}
69
70/*****************************************************************************/
71
72dng_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
83dng_dirty_tile_buffer::~dng_dirty_tile_buffer ()
84	{
85
86	}
87
88/*****************************************************************************/
89
90dng_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
117dng_image::~dng_image ()
118	{
119
120	}
121
122/*****************************************************************************/
123
124dng_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
135void 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
151uint32 dng_image::PixelSize () const
152	{
153
154	return TagTypeSize (PixelType ());
155
156	}
157
158/*****************************************************************************/
159
160uint32 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
195dng_rect dng_image::RepeatingTile () const
196	{
197
198	return fBounds;
199
200	}
201
202/*****************************************************************************/
203
204void 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
215void dng_image::ReleaseTileBuffer (dng_tile_buffer & /* buffer */) const
216	{
217
218	}
219
220/*****************************************************************************/
221
222void 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
245void 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
268void 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
415void 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
494void 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
687void 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
723void 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
737void 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
751void 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
785bool 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
826void 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