Tizen 2.1 base
[framework/osp/uifw.git] / src / graphics / effect / FGrp_EffectScale2.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Flora License, Version 1.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://floralicense.org/license/
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an AS IS BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 /*
19  * @file        FGrp_EffectScale2.cpp
20  * @brief       This is the header file for internal utility class.
21  *
22  */
23
24 #include <new>
25
26 #include "FGrp_Effect.h"
27
28
29 namespace // unnamed
30 {
31
32 int
33 _Ceil(float x)
34 {
35         int ix = int(x);
36
37         if (x >= 0)
38         {
39                 return (x - float(ix)) > 0 ? ix + 1 : ix;
40         }
41         else
42         {
43                 return ix;
44         }
45 }
46
47 int
48 _Floor(float x)
49 {
50         int ix = int(x);
51
52         if (x >= 0)
53         {
54                 return ix;
55         }
56         else
57         {
58                 return (float(ix) - x) > 0 ? ix - 1 : ix;
59         }
60 }
61
62 struct _Rectangle
63 {
64         int x;
65         int y;
66         int w;
67         int h;
68 };
69
70 inline bool
71 operator ==(const _Rectangle& lhs, const _Rectangle& rhs)
72 {
73         return (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.w == rhs.w) && (lhs.h == rhs.h);
74 }
75
76 struct _BufferDesc
77 {
78         int width;             // width of image
79         int height;            // height of image
80         int bytesPerLine;      // bytes per line
81         int depth;             // pixel depth of buffer
82         unsigned char* pBitmap; // start pointer to buffer
83         mutable long reserved;  // do you have ownership?
84 };
85
86 struct BufferDescUtil
87         : public _BufferDesc
88 {
89         BufferDescUtil(int width, int height, int depth, void* pBitmap, int bytesPerLine = 0)
90         {
91                 this->width = width;
92                 this->height = height;
93                 this->depth = depth;
94                 this->bytesPerLine = bytesPerLine,
95                 this->pBitmap = (unsigned char*) pBitmap;
96                 this->reserved = 0;
97
98                 if (bytesPerLine == 0)
99                 {
100                         this->bytesPerLine = width * depth / 8;
101                 }
102         }
103
104         ~BufferDescUtil(void)
105         {
106                 // if 'reserved' is not 0, buffer is released automatically
107                 if (reserved)
108                 {
109                         delete[] pBitmap;
110                 }
111         }
112
113         _BufferDesc GetSubBitmapUnsafe(long x, long y, long w, long h) const
114         {
115                 _BufferDesc retImage((_BufferDesc&) *this);
116                 ((_BufferDesc*) this)->reserved = retImage.reserved;
117                 retImage.reserved = 0;
118
119                 retImage.pBitmap += retImage.bytesPerLine * y + x * depth / 8;
120                 retImage.width = w;
121                 retImage.height = h;
122
123                 return retImage;
124         }
125
126 private:
127         BufferDescUtil(const BufferDescUtil& rhs);
128         BufferDescUtil& operator=(const BufferDescUtil& rhs);
129
130 };
131
132 template<typename SrcIter, typename DstIter>
133 inline DstIter
134 _Copy(SrcIter pFirst, SrcIter pLast, DstIter pTarget)
135 {
136         for ( ; pFirst != pLast; ++pTarget, ++pFirst)
137         {
138                 *pTarget = *pFirst;
139         }
140
141         return pTarget;
142 }
143
144 template<typename BaseType>
145 class _SmartArray
146 {
147 public:
148         explicit _SmartArray(unsigned char* pBuffer = 0)
149                 : __hasOwnership(pBuffer != 0)
150                 , __pPtr((BaseType*)pBuffer)
151         {
152         }
153
154         ~_SmartArray()
155         {
156                 if (__hasOwnership)
157                 {
158                         delete[] (unsigned char*) __pPtr;
159                 }
160         }
161
162         BaseType& operator [](unsigned int index) const
163         {
164                 return __pPtr[index];
165         }
166
167         void Bind(unsigned char* pBuffer)
168         {
169                 if (__pPtr == 0)
170                 {
171                         __hasOwnership = (pBuffer != 0);
172                         __pPtr = (BaseType*) pBuffer;
173                 }
174         }
175
176         BaseType* Get() const
177         {
178                 return __pPtr;
179         }
180
181         BaseType* Release() const
182         {
183                 ((_SmartArray <BaseType>*) this)->__hasOwnership = false;
184
185                 return __pPtr;
186         }
187
188 private:
189         bool __hasOwnership;
190         BaseType* __pPtr;
191
192 }; // _SmartArray
193
194 }
195
196
197 namespace Tizen { namespace Graphics
198 {
199
200 namespace _Effect
201 {
202
203 namespace Interpolation
204 {
205
206 namespace // unnamed
207 {
208         const float CONST_2_0 = 2.0f;
209         const float CONST_1_5 = 1.5f;
210         const float CONST_1_0 = 1.0f;
211         const float CONST_0_75 = 0.75f;
212         const float CONST_0_5 = 0.5f;
213         const float CONST_0_0 = 0.0f;
214         const float CONST_MINUS_0_5 = -0.5f;
215         const float CONST_MINUS_1_0 = -1.0f;
216
217         inline static float
218         MakeConst(float i)
219         {
220                 return float(i);
221         }
222
223         // memory allocation as a byte array
224         static inline unsigned char*
225         AllocMem(size_t size)
226         {
227                 return new (std::nothrow) unsigned char[size];
228         }
229 }
230
231 enum Filter
232 {
233         FILTER_BOX,
234         FILTER_TRIANGLE,
235         FILTER_BICUBIC,
236         FILTER_BELL,
237         FILTER_BSPLINE,
238         FILTER_MITCHELL
239 };
240
241 const Filter FILTER_GOOD = FILTER_BICUBIC;
242 const Filter FILTER_BEST = FILTER_MITCHELL;
243
244 // offset of the color component as the applied endian
245 enum
246 {
247 #if defined(BIG_ENDIAN)
248         OFFSET_ALPHA = 0,
249         OFFSET_RED = 1,
250         OFFSET_GREEN = 2,
251         OFFSET_BLUE = 3,
252 #else
253         OFFSET_ALPHA = 3,
254         OFFSET_RED = 2,
255         OFFSET_GREEN = 1,
256         OFFSET_BLUE = 0,
257 #endif
258         OFFSET_STRIDE = 4
259 };
260
261 ////////////////////////////////////////////////////////////////////////////
262 // ScaleImageDesc<>
263
264 template <typename Pixel, int offset>
265 struct ScaleImageDesc
266 {
267         ScaleImageDesc(long x, long y, long bytesPerLine, Pixel* pData);
268         inline unsigned char GetPixel(long x, long y) const;
269         inline void PutPixel(long x, long y, unsigned char pixel);
270
271         long           xSize;
272         long           ySize;
273         unsigned char* pData;
274         long           span;
275         long           shift;
276 };
277
278 ////////////////////////////////////////////////////////////////////////////
279 // ScaleImageDesc<unsigned long>
280
281 // OFFSET_RED
282 template <>
283 ScaleImageDesc<unsigned long, OFFSET_RED>::ScaleImageDesc(long x, long y, long bytesPerLine, unsigned long* pData)
284         : xSize(x)
285         , ySize(y)
286         , pData((unsigned char*)pData + OFFSET_RED)
287         , span(bytesPerLine)
288         , shift(0)
289 {
290 }
291
292 template <>
293 inline unsigned char
294 ScaleImageDesc<unsigned long, OFFSET_RED>::GetPixel(long x, long y) const
295 {
296         return pData[y * span + x * OFFSET_STRIDE];
297 }
298
299 template <>
300 inline void
301 ScaleImageDesc<unsigned long, OFFSET_RED>::PutPixel(long x, long y, unsigned char pixel)
302 {
303         pData[y * span + x * OFFSET_STRIDE] = pixel;
304 }
305
306 // OFFSET_GREEN
307 template <>
308 ScaleImageDesc<unsigned long, OFFSET_GREEN>::ScaleImageDesc(long x, long y, long bytesPerLine, unsigned long* pData)
309         : xSize(x)
310         , ySize(y)
311         , pData((unsigned char*)pData + OFFSET_GREEN)
312         , span(bytesPerLine)
313         , shift(0)
314 {
315 }
316
317 template <>
318 inline unsigned char
319 ScaleImageDesc<unsigned long, OFFSET_GREEN>::GetPixel(long x, long y) const
320 {
321         return pData[y * span + x * OFFSET_STRIDE];
322 }
323
324 template <>
325 inline void
326 ScaleImageDesc<unsigned long, OFFSET_GREEN>::PutPixel(long x, long y, unsigned char pixel)
327 {
328         pData[y * span + x * OFFSET_STRIDE] = pixel;
329 }
330
331 // OFFSET_BLUE
332 template <>
333 ScaleImageDesc<unsigned long, OFFSET_BLUE>::ScaleImageDesc(long x, long y, long bytesPerLine, unsigned long* pData)
334         : xSize(x)
335         , ySize(y)
336         , pData((unsigned char*)pData + OFFSET_BLUE)
337         , span(bytesPerLine)
338         , shift(0)
339 {
340 }
341
342 template <>
343 inline unsigned char
344 ScaleImageDesc<unsigned long, OFFSET_BLUE>::GetPixel(long x, long y) const
345 {
346         return pData[y * span + x * OFFSET_STRIDE];
347 }
348
349 template <>
350 inline void
351 ScaleImageDesc<unsigned long, OFFSET_BLUE>::PutPixel(long x, long y, unsigned char pixel)
352 {
353         pData[y * span + x * OFFSET_STRIDE] = pixel;
354 }
355
356 // OFFSET_ALPHA
357 template <>
358 ScaleImageDesc<unsigned long, OFFSET_ALPHA>::ScaleImageDesc(long x, long y, long bytesPerLine, unsigned long* pData)
359         : xSize(x)
360         , ySize(y)
361         , pData((unsigned char*)pData + OFFSET_ALPHA)
362         , span(bytesPerLine)
363         , shift(0)
364 {
365 }
366
367 template <>
368 inline unsigned char
369 ScaleImageDesc<unsigned long, OFFSET_ALPHA>::GetPixel(long x, long y) const
370 {
371         return pData[y * span + x * OFFSET_STRIDE];
372 }
373
374 template <>
375 inline void
376 ScaleImageDesc<unsigned long, OFFSET_ALPHA>::PutPixel(long x, long y, unsigned char pixel)
377 {
378         pData[y * span + x * OFFSET_STRIDE] = pixel;
379 }
380
381 ////////////////////////////////////////////////////////////////////////////
382 // ScaleImageDesc<unsigned short>
383
384 // OFFSET_RED
385 template <>
386 ScaleImageDesc<unsigned short, OFFSET_RED>::ScaleImageDesc(long x, long y, long bytesPerLine, unsigned short* pData)
387         : xSize(x)
388         , ySize(y)
389         , pData((unsigned char*)pData)
390         , span(bytesPerLine)
391         , shift(0)
392 {
393 }
394
395 template <>
396 inline unsigned char
397 ScaleImageDesc<unsigned short, OFFSET_RED>::GetPixel(long x, long y) const
398 {
399         return (*((unsigned short*)&pData[y * span + x * 2]) >> 11) & 0x001F;
400 }
401
402 template <>
403 inline void
404 ScaleImageDesc<unsigned short, OFFSET_RED>::PutPixel(long x, long y, unsigned char pixel)
405 {
406         unsigned short* pBuf = (unsigned short*)&pData[y * span + x * 2];
407         unsigned short color = (unsigned short)((pixel > 0x001F) ? 0x001F : pixel);
408         *pBuf = (*pBuf & ~0xF800) | ((color << 11) & 0xF800);
409 }
410
411 // OFFSET_GREEN
412 template <>
413 ScaleImageDesc<unsigned short, OFFSET_GREEN>::ScaleImageDesc(long x, long y, long bytesPerLine, unsigned short* pData)
414         : xSize(x)
415         , ySize(y)
416         , pData((unsigned char*)pData)
417         , span(bytesPerLine)
418         , shift(0)
419 {
420 }
421
422 template <>
423 inline unsigned char
424 ScaleImageDesc<unsigned short, OFFSET_GREEN>::GetPixel(long x, long y) const
425 {
426         return (*((unsigned short*)&pData[y * span + x * 2]) >> 5) & 0x003F;
427 }
428
429 template <>
430 inline void
431 ScaleImageDesc<unsigned short, OFFSET_GREEN>::PutPixel(long x, long y, unsigned char pixel)
432 {
433         unsigned short* pBuf = (unsigned short*)&pData[y * span + x * 2];
434         unsigned short color = (unsigned short)((pixel > 0x003F) ? 0x003F : pixel);
435         *pBuf = (*pBuf & ~0x07E0) | ((color << 5) & 0x07E0);
436 }
437
438 // OFFSET_BLUE
439 template <>
440 ScaleImageDesc<unsigned short, OFFSET_BLUE>::ScaleImageDesc(long x, long y, long bytesPerLine, unsigned short* pData)
441         : xSize(x)
442         , ySize(y)
443         , pData((unsigned char*)pData)
444         , span(bytesPerLine)
445         , shift(0)
446 {
447 }
448
449 template <>
450 inline unsigned char
451 ScaleImageDesc<unsigned short, OFFSET_BLUE>::GetPixel(long x, long y) const
452 {
453         return (*((unsigned short*)&pData[y * span + x * 2])) & 0x001F;
454 }
455
456 template <>
457 inline void
458 ScaleImageDesc<unsigned short, OFFSET_BLUE>::PutPixel(long x, long y, unsigned char pixel)
459 {
460         unsigned short* pBuf = (unsigned short*)&pData[y * span + x * 2];
461         unsigned short  color = (unsigned short)((pixel > 0x001F) ? 0x001F : pixel);
462         *pBuf = (*pBuf & ~0x001F) | (color & 0x001F);
463 }
464
465 // OFFSET_ALPHA
466 template <>
467 ScaleImageDesc<unsigned short, OFFSET_ALPHA>::ScaleImageDesc(long x, long y, long bytesPerLine, unsigned short* pData)
468         : xSize(x)
469         , ySize(y)
470         , pData((unsigned char*)pData)
471         , span(bytesPerLine)
472         , shift(0)
473 {
474 }
475
476 template <>
477 inline unsigned char
478 ScaleImageDesc<unsigned short, OFFSET_ALPHA>::GetPixel(long x, long y) const
479 {
480         return 0;
481 }
482
483 template <>
484 inline void
485 ScaleImageDesc<unsigned short, OFFSET_ALPHA>::PutPixel(long x, long y, unsigned char pixel)
486 {
487 }
488
489 ////////////////////////////////////////////////////////////////////////////
490 // FilterDesc
491
492 template <Filter FilterType>
493 struct FilterDesc
494 {
495         inline static float Apply(float t);
496         inline static float Width(void);
497 };
498
499 ////////////////////////////////////
500 // FilterDesc - FILTER_BOX
501
502 // rectangle filter
503 template <>
504 struct FilterDesc<FILTER_BOX>
505 {
506         inline static float Apply(float t)
507         {
508                 return ((t > CONST_MINUS_0_5) && t <= CONST_0_5) ? CONST_1_0 : CONST_0_0;
509         }
510
511         inline static float Width(void)
512         {
513                 return CONST_0_5;
514         }
515 };
516
517 ////////////////////////////////////
518 // FilterDesc - FILTER_TRIANGLE
519
520 // triangle filter
521 template <>
522 struct FilterDesc<FILTER_TRIANGLE>
523 {
524         inline static float Apply(float t)
525         {
526                 t = (t >= CONST_0_0) ? t : -t;
527                 return (t < CONST_1_0) ? (float(CONST_1_0) - t) : CONST_0_0;
528         }
529
530         inline static float Width(void)
531         {
532                 return CONST_1_0;
533         }
534 };
535
536 ////////////////////////////////////
537 // FilterDesc - FILTER_BICUBIC
538
539 // cubic curve
540 template <>
541 struct FilterDesc<FILTER_BICUBIC>
542 {
543         inline static float Apply(float t)
544         {
545                 t = (t >= CONST_0_0) ? t : -t;
546                 return (t < CONST_1_0) ? float((t * CONST_2_0 - MakeConst(3)) * t * t + CONST_1_0) : CONST_0_0;
547         }
548
549         inline static float Width(void)
550         {
551                 return CONST_1_0;
552         }
553 };
554
555 ////////////////////////////////////
556 // FilterDesc - FILTER_BELL
557
558 // bell curve, normal curve alike
559 template <>
560 struct FilterDesc<FILTER_BELL>
561 {
562         inline static float Apply(float t)
563         {
564                 //  box (*) box (*) box
565                 t = (t >= CONST_0_0) ? t : -t;
566
567                 if (t < CONST_0_5)
568                 {
569                         return float(CONST_0_75 - (t * t));
570                 }
571
572                 if (t < CONST_1_5)
573                 {
574                         t -= CONST_1_5;
575                         return float((t * t) * CONST_0_5);
576                 }
577
578                 return CONST_0_0;
579         }
580
581         inline static float Width(void)
582         {
583                 return CONST_1_5;
584         }
585 };
586
587 ////////////////////////////////////
588 // FilterDesc - FILTER_BSPLINE
589
590 // B-Spline interpolation, blurred
591 template <>
592 struct FilterDesc<FILTER_BSPLINE>
593 {
594         inline static float Apply(float t)
595         {
596                 // box (*) box (*) box (*) box
597                 t = (t >= CONST_0_0) ? t : -t;
598
599                 if (t < CONST_1_0)
600                 {
601                         float tt = t * t;
602                         return float((tt * t * CONST_0_5) - tt + (float(CONST_2_0) / MakeConst(3)));
603                 }
604
605                 if (t < CONST_2_0)
606                 {
607                         t = CONST_2_0 - t;
608                         return float((float(CONST_1_0) / MakeConst(6)) * (t * t * t));
609                 }
610
611                 return CONST_0_0;
612         }
613
614         inline static float Width(void)
615         {
616                 return CONST_2_0;
617         }
618 };
619
620 ////////////////////////////////////
621 // FilterDesc - FILTER_MITCHELL
622
623 // interpolation + high-pass filter
624 template <>
625 struct FilterDesc<FILTER_MITCHELL>
626 {
627         inline static float Apply(float t)
628         {
629                 const float b = float(CONST_1_0) / float(MakeConst(3));
630                 const float c = float(CONST_1_0) / float(MakeConst(3));
631
632                 float tt = t * t;
633
634                 t = (t >= CONST_0_0) ? t : -t;
635
636                 if (t < CONST_1_0)
637                 {
638                         t = float(((MakeConst(12) - b * MakeConst(9) - c * MakeConst(6)) * (t * tt))+((b * MakeConst(12) + c * MakeConst(6) - MakeConst(18)) * tt) + (MakeConst(6) - b * CONST_2_0));
639                         return float(t / MakeConst(6));
640                 }
641
642                 if (t < CONST_2_0)
643                 {
644                         t = float(((b * CONST_MINUS_1_0 - c * MakeConst(6)) * (t * tt)) + ((b * MakeConst(6) + c * MakeConst(30)) * tt) + ((b * MakeConst(-12) - c * MakeConst(48)) * t) + (b * MakeConst(8) + c * MakeConst(24)));
645                         return float(t / MakeConst(6));
646                 }
647
648                 return CONST_0_0;
649         }
650
651         inline static float Width(void)
652         {
653                 return CONST_2_0;
654         }
655 };
656
657 ////////////////////////////////////////////////////////////////////////////
658 // struct ScaleArray
659
660 // store pixel values and filtered weights
661 struct ScaleArray
662 {
663         ScaleArray()
664                 : pArray(0)
665                 , total(0)
666         {
667         }
668
669         struct Element
670         {
671                 int pixel;
672                 float weight;
673         }* pArray;
674
675         int total;
676
677         enum
678         {
679                 ELEMENT_SIZE = sizeof(Element)
680         };
681
682         // store pixel value and weight
683         inline void Push(int x, int max, float weight)
684         {
685                 if (x < 0)
686                 {
687                         x = -x - 1;
688                 }
689
690                 pArray[total].pixel = (x < max) ? x : max - 1 - x % max;
691                 pArray[total].weight = weight;
692                 total++;
693         }
694
695         // up-scaling
696         template <Filter defaultFilter>
697         inline void FillToExpand(int center, int xSize)
698         {
699                 total = 0;
700
701                 int left = (int)_Ceil(float(center) - FilterDesc<defaultFilter>::Width());
702                 int right = (int)_Floor(float(center) + FilterDesc<defaultFilter>::Width());
703
704                 for (int j = left; j <= right; ++j)
705                 {
706                         Push(j, xSize, FilterDesc<defaultFilter>::Apply(float(center) - float(j)));
707                 }
708         }
709
710         // down-scaling
711         template <Filter defaultFilter>
712         inline void FillToShrink(int center, int xSize, float Width, float scale)
713         {
714                 total = 0;
715
716                 int left = (int)_Ceil(float(center) - Width);
717                 int right = (int)_Floor(float(center) + Width);
718
719                 for (int j = left; j <= right; ++j)
720                 {
721                         Push(j, xSize, FilterDesc<defaultFilter>::Apply((float(center) - float(j)) / scale) / scale);
722                 }
723         }
724 };
725
726 // normalize as interger(0~255) from thw weight as float
727 inline unsigned char
728 PixelOfWeight(float weight)
729 {
730         if (weight <= CONST_0_0)
731         {
732                 return 0;
733         }
734
735         int p = (int)weight;
736
737         if (weight - float(p) >= CONST_0_5)
738         {
739                 p++;
740         }
741
742         return (p >= 255) ? 255 : (unsigned char)p;
743 }
744
745 template <Filter DefaultFilter, typename Pixel>
746 bool
747 ScaleImage(_BufferDesc* pDstImage, long wDest, int hDest, _BufferDesc* pSrcImage, const _Rectangle& validRect)
748 {
749         bool result = false;
750
751         Pixel* pSrcBuffer = (Pixel*)pSrcImage->pBitmap;
752         Pixel* pDstBuffer = 0;
753
754         long xSrcSize = pSrcImage->width;
755         long ySrcSize = pSrcImage->height;
756
757         _SmartArray<ScaleArray::Element> localArray;
758         _SmartArray<ScaleArray::Element> arrayMem;
759
760         // store pre-calculated pixel index and weight for all columns
761         _SmartArray<ScaleArray> ypwArrays(AllocMem(hDest * sizeof(ScaleArray)));
762
763         if (ypwArrays.Get() == 0)
764         {
765                 return false;
766         }
767
768         ScaleArray* pYpwArraysEnd = ypwArrays.Get() + hDest;
769
770         if (hDest < ySrcSize)
771         {
772                 // in case of shrinking for the y axis
773                 float width = float(ySrcSize) * FilterDesc<DefaultFilter>::Width() / float(hDest);
774                 float scalingRatio = float(ySrcSize) / float(hDest);
775                 size_t pwaSize = (size_t)float(width * CONST_2_0 + CONST_1_0);
776
777                 localArray.Bind(AllocMem(pwaSize * ScaleArray::ELEMENT_SIZE * hDest));
778
779                 if (localArray.Get() == 0)
780                 {
781                         return false;
782                 }
783
784                 ScaleArray::Element* pArray = localArray.Get();
785
786                 for (int yDst = 0; yDst < hDest; ++yDst)
787                 {
788                         ypwArrays[yDst].pArray = pArray;
789                         pArray += pwaSize;
790                         ypwArrays[yDst].FillToShrink<DefaultFilter>(yDst * ySrcSize / hDest, ySrcSize, width, scalingRatio);
791                 }
792         }
793         else
794         {
795                 // in case of expanding for the y axis
796                 size_t pwaSize = size_t(FilterDesc<DefaultFilter>::Width() * CONST_2_0 + CONST_1_0);
797
798                 localArray.Bind(AllocMem(pwaSize * ScaleArray::ELEMENT_SIZE * hDest));
799
800                 if (localArray.Get() == 0)
801                 {
802                         return false;
803                 }
804
805                 ScaleArray::Element* pArray = localArray.Get();
806
807                 for (int yDst = 0; yDst < hDest; ++yDst)
808                 {
809                         ypwArrays[yDst].pArray = pArray;
810                         pArray += pwaSize;
811                         ypwArrays[yDst].FillToExpand<DefaultFilter>(yDst * ySrcSize / hDest, ySrcSize);
812                 }
813         }
814
815         // allocate the pixel weight array within the one row
816         ScaleArray xpwArray;
817         float width = float(xSrcSize) * FilterDesc<DefaultFilter>::Width() / float(wDest);
818         float scalingRatio = float(xSrcSize) / float(wDest);
819         bool xShrink = (wDest < xSrcSize);
820
821         if (xShrink)
822         {
823                 // in case of shrinking for the x axis
824                 arrayMem.Bind(AllocMem((size_t)(width * CONST_2_0 + CONST_1_0) * ScaleArray::ELEMENT_SIZE));
825         }
826         else
827         {
828                 // in case of expanding for the x axis
829                 arrayMem.Bind(AllocMem((size_t)(FilterDesc<DefaultFilter>::Width() * CONST_2_0 + CONST_1_0) * ScaleArray::ELEMENT_SIZE));
830         }
831
832         if (arrayMem.Get() == 0)
833         {
834                 return false;
835         }
836
837         xpwArray.pArray = arrayMem.Get();
838
839         // allocate memory for each color component
840         _SmartArray<unsigned char> column(AllocMem(4 * ySrcSize * sizeof(unsigned char)));
841
842         if (column.Get() == 0)
843         {
844                 return false;
845         }
846
847         unsigned char* pColumnA = column.Get();
848         unsigned char* pColumnR = pColumnA + ySrcSize;
849         unsigned char* pColumnG = pColumnR + ySrcSize;
850         unsigned char* pColumnB = pColumnG + ySrcSize;
851
852         // divide color components for the source
853         ScaleImageDesc<Pixel, OFFSET_ALPHA> aSrc(xSrcSize, ySrcSize, pSrcImage->bytesPerLine, pSrcBuffer);
854         ScaleImageDesc<Pixel, OFFSET_RED> rSrc(xSrcSize, ySrcSize, pSrcImage->bytesPerLine, pSrcBuffer);
855         ScaleImageDesc<Pixel, OFFSET_GREEN> gSrc(xSrcSize, ySrcSize, pSrcImage->bytesPerLine, pSrcBuffer);
856         ScaleImageDesc<Pixel, OFFSET_BLUE> bSrc(xSrcSize, ySrcSize, pSrcImage->bytesPerLine, pSrcBuffer);
857
858         {
859                 pDstBuffer = (Pixel*)pDstImage->pBitmap;
860
861                 // divide color components for the destination
862                 ScaleImageDesc<Pixel, OFFSET_ALPHA> aDst(wDest, hDest, pDstImage->bytesPerLine, pDstBuffer);
863                 ScaleImageDesc<Pixel, OFFSET_RED> rDst(wDest, hDest, pDstImage->bytesPerLine, pDstBuffer);
864                 ScaleImageDesc<Pixel, OFFSET_GREEN> gDst(wDest, hDest, pDstImage->bytesPerLine, pDstBuffer);
865                 ScaleImageDesc<Pixel, OFFSET_BLUE> bDst(wDest, hDest, pDstImage->bytesPerLine, pDstBuffer);
866
867                 // interpolation
868                 for (int xDst = 0; xDst < wDest; ++xDst)
869                 {
870                         if ((xDst < validRect.x) || (xDst >= validRect.x + validRect.w))
871                         {
872                                 continue;
873                         }
874
875                         // calculate weight for one color component column
876                         if (xShrink)
877                         {
878                                 xpwArray.FillToShrink<DefaultFilter>(xDst * xSrcSize / wDest, xSrcSize, width, scalingRatio);
879                         }
880                         else
881                         {
882                                 xpwArray.FillToExpand<DefaultFilter>(xDst * xSrcSize / wDest, xSrcSize);
883                         }
884
885                         ScaleArray::Element* pXaEnd = xpwArray.pArray + xpwArray.total; // total is known at this line
886
887                         int pixel;
888                         float weight;
889
890                         // Apply horiz FilterDesc to make rDst column in pColumnR
891                         for (int ySrc = 0; ySrc < ySrcSize; ++ySrc)
892                         {
893                                 pixel = xpwArray.pArray->pixel;
894                                 weight = xpwArray.pArray->weight;
895
896                                 bool aPixelsSame = true;
897                                 bool rPixelsSame = true;
898                                 bool gPixelsSame = true;
899                                 bool bPixelsSame = true;
900
901                                 unsigned char a = aSrc.GetPixel(pixel, ySrc);
902                                 unsigned char r = rSrc.GetPixel(pixel, ySrc);
903                                 unsigned char g = gSrc.GetPixel(pixel, ySrc);
904                                 unsigned char b = bSrc.GetPixel(pixel, ySrc);
905
906                                 float aWeight = float(a) * weight;
907                                 float rWeight = float(r) * weight;
908                                 float gWeight = float(g) * weight;
909                                 float bWeight = float(b) * weight;
910
911                                 for (ScaleArray::Element* pXa = xpwArray.pArray + 1; pXa < pXaEnd; ++pXa)
912                                 {
913                                         pixel = pXa->pixel;
914                                         weight = pXa->weight;
915
916                                         unsigned char a2 = aSrc.GetPixel(pixel, ySrc);
917                                         unsigned char r2 = rSrc.GetPixel(pixel, ySrc);
918                                         unsigned char g2 = gSrc.GetPixel(pixel, ySrc);
919                                         unsigned char b2 = bSrc.GetPixel(pixel, ySrc);
920
921                                         aPixelsSame &= (a2 == a);
922                                         rPixelsSame &= (r2 == r);
923                                         gPixelsSame &= (g2 == g);
924                                         bPixelsSame &= (b2 == b);
925
926                                         aWeight += float(a2) * weight;
927                                         rWeight += float(r2) * weight;
928                                         gWeight += float(g2) * weight;
929                                         bWeight += float(b2) * weight;
930                                 }
931
932                                 pColumnA[ySrc] = aPixelsSame ? a : PixelOfWeight(aWeight);
933                                 pColumnR[ySrc] = rPixelsSame ? r : PixelOfWeight(rWeight);
934                                 pColumnG[ySrc] = gPixelsSame ? g : PixelOfWeight(gWeight);
935                                 pColumnB[ySrc] = bPixelsSame ? b : PixelOfWeight(bWeight);
936                         }
937
938                         // The temp column has been built. Now stretch it vertically into xDst column
939                         for (ScaleArray* pYpwArray = ypwArrays.Get(); pYpwArray < pYpwArraysEnd; ++pYpwArray)
940                         {
941                                 int yDst = (int)(pYpwArray - ypwArrays.Get());
942
943                                 if ((yDst < validRect.y) || (yDst >= validRect.y + validRect.h))
944                                 {
945                                         continue;
946                                 }
947
948                                 ScaleArray::Element* pYa = pYpwArray->pArray;
949                                 ScaleArray::Element* pYaEnd = pYa + pYpwArray->total;
950
951                                 pixel = pYa->pixel;
952                                 weight = pYa->weight;
953
954                                 bool aPixelsSame = true;
955                                 bool rPixelsSame = true;
956                                 bool gPixelsSame = true;
957                                 bool bPixelsSame = true;
958
959                                 unsigned char a = pColumnA[pixel];
960                                 unsigned char r = pColumnR[pixel];
961                                 unsigned char g = pColumnG[pixel];
962                                 unsigned char b = pColumnB[pixel];
963
964                                 float aWeight = float(a) * weight;
965                                 float rWeight = float(r) * weight;
966                                 float gWeight = float(g) * weight;
967                                 float bWeight = float(b) * weight;
968
969                                 ++pYa;
970
971                                 for (; pYa < pYaEnd; ++pYa)
972                                 {
973                                         if ((weight = pYa->weight) > 0)
974                                         {
975                                                 pixel = pYa->pixel;
976
977                                                 unsigned char a2 = pColumnA[pixel];
978                                                 unsigned char r2 = pColumnR[pixel];
979                                                 unsigned char g2 = pColumnG[pixel];
980                                                 unsigned char b2 = pColumnB[pixel];
981
982                                                 aPixelsSame &= (a2 == a);
983                                                 rPixelsSame &= (r2 == r);
984                                                 gPixelsSame &= (g2 == g);
985                                                 bPixelsSame &= (b2 == b);
986
987                                                 aWeight += float(a2) * weight;
988                                                 rWeight += float(r2) * weight;
989                                                 gWeight += float(g2) * weight;
990                                                 bWeight += float(b2) * weight;
991                                         }
992                                 }
993
994                                 {
995                                         aDst.PutPixel(xDst, yDst, aPixelsSame ? a : PixelOfWeight(aWeight));
996                                         rDst.PutPixel(xDst, yDst, rPixelsSame ? r : PixelOfWeight(rWeight));
997                                         gDst.PutPixel(xDst, yDst, gPixelsSame ? g : PixelOfWeight(gWeight));
998                                         bDst.PutPixel(xDst, yDst, bPixelsSame ? b : PixelOfWeight(bWeight));
999                                 }
1000                         }
1001                 }
1002
1003                 result = true;
1004         }
1005
1006         return result;
1007 }
1008
1009 } // Interpolation
1010
1011
1012 namespace Interpolation
1013 {
1014
1015 bool
1016 IntersectRect(_Rectangle& outRect, const _Rectangle& srcRect1, const _Rectangle& srcRect2)
1017 {
1018         struct LocalBound
1019         {
1020                 int x1;
1021                 int y1;
1022                 int x2;
1023                 int y2;
1024
1025                 LocalBound(const _Rectangle& rect)
1026                         : x1(rect.x)
1027                         , y1(rect.y)
1028                         , x2(rect.x + rect.w)
1029                         , y2(rect.y + rect.h)
1030                 {
1031                 }
1032         };
1033
1034         LocalBound srcBound1(srcRect1);
1035         LocalBound srcBound2(srcRect2);
1036
1037         if (((srcRect1.w > 0 && srcRect1.h > 0) && (srcRect2.w > 0 && srcRect2.h > 0))
1038                 && ((srcBound2.x2 > srcBound1.x1) && (srcBound2.x1 < srcBound1.x2) && (srcBound2.y2 > srcBound1.y1) && (srcBound2.y1 < srcBound1.y2)))
1039         {
1040                 outRect.x = (srcBound2.x1 <= srcBound1.x1) ? srcBound1.x1 : srcBound2.x1;
1041                 outRect.y = (srcBound2.y1 <= srcBound1.y1) ? srcBound1.y1 : srcBound2.y1;
1042                 outRect.w = ((srcBound2.x2 >= srcBound1.x2) ? srcBound1.x2 : srcBound2.x2) - outRect.x;
1043                 outRect.h = ((srcBound2.y2 >= srcBound1.y2) ? srcBound1.y2 : srcBound2.y2) - outRect.y;
1044
1045                 return true;
1046         }
1047         else
1048         {
1049                 outRect.x = 0;
1050                 outRect.y = 0;
1051                 outRect.w = 0;
1052                 outRect.h = 0;
1053
1054                 return false;
1055         }
1056 };
1057
1058 bool
1059 ScaleImage(const BufferDescUtil& retImage, long xDest, long yDest, long wDest, long hDest, const BufferDescUtil& srcImage, DefaultFilter defaultFilter)
1060 {
1061         _Rectangle outRect;
1062
1063         {
1064                 _Rectangle dstRect = { 0, 0, retImage.width, retImage.height };
1065                 _Rectangle tgtRect = { xDest, yDest, wDest, hDest };
1066
1067                 {
1068                         bool hasRegion = IntersectRect(outRect, tgtRect, dstRect);
1069                         if (!hasRegion)
1070                         {
1071                                 return true;
1072                         }
1073                 }
1074         }
1075
1076         {
1077                 _BufferDesc dstImage = retImage.GetSubBitmapUnsafe(xDest, yDest, wDest, hDest);
1078                 _Rectangle validRect = outRect;
1079
1080                 validRect.x -= xDest;
1081                 validRect.y -= yDest;
1082
1083                 switch (defaultFilter)
1084                 {
1085                 case DEFAULT_FILTER_GOOD:
1086                         switch (retImage.depth)
1087                         {
1088                         case 32:
1089                                 return _Effect::Interpolation::ScaleImage<FILTER_GOOD, unsigned long>((_BufferDesc*)&dstImage, wDest, hDest, (_BufferDesc*)&srcImage, validRect);
1090                         case 16:
1091                                 return _Effect::Interpolation::ScaleImage<FILTER_GOOD, unsigned short>((_BufferDesc*)&dstImage, wDest, hDest, (_BufferDesc*)&srcImage, validRect);
1092                         default:
1093                                 return false;
1094                         }
1095                         break;
1096                 case DEFAULT_FILTER_BEST:
1097                 default:
1098                         switch (retImage.depth)
1099                         {
1100                         case 32:
1101                                 return _Effect::Interpolation::ScaleImage<FILTER_BEST, unsigned long>((_BufferDesc*)&dstImage, wDest, hDest, (_BufferDesc*)&srcImage, validRect);
1102                         case 16:
1103                                 return _Effect::Interpolation::ScaleImage<FILTER_BEST, unsigned short>((_BufferDesc*)&dstImage, wDest, hDest, (_BufferDesc*)&srcImage, validRect);
1104                         default:
1105                                 return false;
1106                         }
1107                         break;
1108                 }
1109         }
1110 }
1111
1112 } // Interpolation
1113
1114 } // _Effect
1115
1116 }} // Tizen::Graphics
1117
1118
1119 #include "../util/FGrp_Util.h"
1120
1121 using namespace Tizen::Graphics;
1122
1123 bool
1124 Tizen::Graphics::_Effect::ScaleImageInterpolation(_Util::Pixmap& dstImage, long xDest, long yDest, long wDest, long hDest,
1125                                                                    const _Util::Pixmap& srcImage, DefaultFilter defaultFilter)
1126 {
1127         // verifiy the spcified parameters
1128         {
1129                 if ((srcImage.width < 0) || (srcImage.height < 0) || (srcImage.pBitmap == null))
1130                 {
1131                         return false;
1132                 }
1133
1134                 if ((dstImage.width < 0) || (dstImage.height < 0) || (dstImage.pBitmap == null))
1135                 {
1136                         return false;
1137                 }
1138
1139                 if ((wDest < 0) || (hDest < 0))
1140                 {
1141                         return false;
1142                 }
1143
1144                 if (srcImage.pBitmap == dstImage.pBitmap)
1145                 {
1146                         return false;
1147                 }
1148         }
1149
1150         {
1151                 if ((srcImage.width == 0) || (srcImage.height == 0))
1152                 {
1153                         return true;
1154                 }
1155
1156                 if ((dstImage.width == 0) || (dstImage.height == 0))
1157                 {
1158                         return true;
1159                 }
1160
1161                 if ((wDest == 0) || (hDest == 0))
1162                 {
1163                         return true;
1164                 }
1165
1166                 {
1167                         _Util::Rectangle<int> dstRect =
1168                         {
1169                                 0,
1170                                 0,
1171                                 dstImage.width,
1172                                 dstImage.height
1173                         };
1174
1175                         _Util::Rectangle<int> tgtRect =
1176                         {
1177                                 xDest,
1178                                 yDest,
1179                                 wDest,
1180                                 hDest
1181                         };
1182
1183                         _Util::Rectangle<int> outRect;
1184
1185                         if (!IntersectRect(outRect, tgtRect, dstRect))
1186                         {
1187                                 return true;
1188                         }
1189                 }
1190         }
1191
1192         BufferDescUtil srcBuffer(srcImage.width, srcImage.height, srcImage.depth, srcImage.pBitmap, srcImage.bytesPerLine);
1193         BufferDescUtil dstBuffer(dstImage.width, dstImage.height, dstImage.depth, dstImage.pBitmap, dstImage.bytesPerLine);
1194
1195         return _Effect::Interpolation::ScaleImage(dstBuffer, 0, 0, dstImage.width, dstImage.height, srcBuffer, defaultFilter);
1196 }
1197
1198 ////////////////////////////////////////////////////////////////////////////////
1199 // API for test case
1200
1201 #if 0
1202
1203 #include <FGrpBitmap.h>
1204
1205 namespace Tizen { namespace Graphics
1206 {
1207
1208 result _BitmapScale(Bitmap& dstBitmap, int scaleWidth, int scaleHeight)
1209 {
1210
1211 #define CHECK_THROW(cond, rslt) if (!(cond)) { r = rslt; break; }
1212
1213         result r = E_SUCCESS;
1214
1215         do
1216         {
1217                 _SmartArray<unsigned char> srcBuffer;
1218
1219                 BufferInfo srcBufferInfo;
1220                 BufferInfo dstBufferInfo;
1221
1222                 result r = dstBitmap.Lock(srcBufferInfo);
1223
1224                 CHECK_THROW(r == E_SUCCESS, r);
1225
1226                 srcBuffer.Bind(new (std::nothrow) unsigned char[srcBufferInfo.pitch * srcBufferInfo.height]);
1227
1228                 CHECK_THROW(srcBuffer.Get() && srcBufferInfo.pPixels, E_OUT_OF_MEMORY);
1229
1230                 // same as memcpy(srcBuffer.Get(), srcBufferInfo.pPixels, srcBufferInfo.pitch * srcBufferInfo.height);
1231                 {
1232                         unsigned char* pBegin = static_cast<unsigned char*>(srcBufferInfo.pPixels);
1233                         unsigned char* pEnd = pBegin + srcBufferInfo.pitch * srcBufferInfo.height;
1234                         unsigned char* pTarget = srcBuffer.Get();
1235
1236                         _Copy(pBegin, pEnd, pTarget);
1237                 }
1238
1239                 srcBufferInfo.pPixels = (void*)srcBuffer.Get();
1240
1241                 dstBitmap.Unlock();
1242
1243                 r = dstBitmap.Scale(Dimension(scaleWidth, scaleHeight));
1244
1245                 CHECK_THROW(r == E_SUCCESS, r);
1246
1247                 r = dstBitmap.Lock(dstBufferInfo);
1248
1249                 CHECK_THROW(r == E_SUCCESS, r);
1250
1251                 BufferDescUtil srcImage(srcBufferInfo.width, srcBufferInfo.height, srcBufferInfo.bitsPerPixel, srcBufferInfo.pPixels, srcBufferInfo.pitch);
1252                 BufferDescUtil dstImage(dstBufferInfo.width, dstBufferInfo.height, dstBufferInfo.bitsPerPixel, dstBufferInfo.pPixels, dstBufferInfo.pitch);
1253
1254                 _Effect::Interpolation::ScaleImage(dstImage, 0, 0, dstBufferInfo.width, dstBufferInfo.height, srcImage);
1255
1256                 dstBitmap.Unlock();
1257
1258         } while (false);
1259
1260         return r;
1261
1262 #undef CHECK_THROW
1263
1264 }
1265
1266 }} // Tizen::Graphics
1267
1268 #endif