Added transparency support in RGB565 bitmap outputs, for gif decoder.
[platform/framework/native/image.git] / src / FMedia_ImageImpl.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
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   FMedia_ImageImpl.cpp
20  * @brief  This file contains the implementation of subsystem's Image.
21  */
22
23 #include <unique_ptr.h>
24 #include <FIoFile.h>
25 #include <FMediaImage.h>
26 #include <FMediaImageUtil.h>
27 #include <FMediaIImageEventListener.h>
28 #include <FBaseSysLog.h>
29 #include "FMedia_MediaUtil.h"
30 #include "FMedia_ImageImpl.h"
31 #include "FMedia_ImageUtil.h"
32 #include "FMedia_ImageUtilImpl.h"
33 #include "FMedia_ImageDecoder.h"
34 #include "FMedia_ImageEncoder.h"
35 #include "FMedia_ImageUriDataFactory.h"
36 #include "FGrp_BitmapImpl.h"
37 #include "FUi_CoordinateSystemUtils.h"
38
39
40 using namespace Tizen::Graphics;
41 using namespace Tizen::Base;
42 using namespace Tizen::Io;
43 using namespace Tizen::Ui;
44
45 namespace Tizen { namespace Media
46 {
47
48 static const float _SCALE_DOWN_RATIO = 0.5;
49 static const int _RGB565_PIXEL_DEPTH = 2;
50 static const int _MIN_ENCODE_QUALITY = 20; // Changed from 50 to 20 to allow greater compression.
51 static const int _MAX_ENCODE_QUALITY = 99;
52 static const int _DEFAULT_ENCODE_QUALITY = 50;
53 static const int _MAX_ENCODE_LOOP = 2;
54 static const int _MAX_ENCODE_RESIZE_LOOP = 2;
55 //static const int MAX_IMGFILE_SIZE = 4096000;
56
57 _ImageImpl::_ImageImpl(void)
58 {
59         __pUrlReqIDList.reset(null);
60 }
61
62 _ImageImpl::~_ImageImpl(void)
63 {
64         _ImageUriDataFactory *pFactory = null;
65
66         pFactory = _ImageUriDataFactory::GetInstance();
67         SysTryReturn(NID_MEDIA, pFactory != null, , GetLastResult(), "[%s] Failed to get Factory instance.",
68                 GetErrorMessage(GetLastResult()));
69
70         if (__pUrlReqIDList.get() != null)
71         {
72                 int num = 0;
73                 Object* pObj = null;
74
75                 // free the memory
76                 num = __pUrlReqIDList->GetCount();
77                 for (int i = 0; i < num; i++)
78                 {
79                         pObj = __pUrlReqIDList->GetAt(i);
80                         if (pObj != null)
81                         {
82                                 Integer *pValue = dynamic_cast<Integer*>(pObj);
83                                 RequestId reqId = (RequestId)(pValue->ToInt());
84
85                                 pFactory->Remove(reqId);
86                         }
87                 }
88                 __pUrlReqIDList->RemoveAll(true);
89         }
90 }
91
92 _ImageImpl*
93 _ImageImpl::GetInstance(Image* pImage)
94 {
95         if (pImage != null)
96         {
97                 return pImage->__pImageImpl;
98         }
99
100         return null;
101 }
102
103 const _ImageImpl*
104 _ImageImpl::GetInstance(const Image* pImage)
105 {
106         if (pImage != null)
107         {
108                 return pImage->__pImageImpl;
109         }
110
111         return null;
112 }
113
114 result
115 _ImageImpl::Construct(void)
116 {
117         return E_SUCCESS;
118 }
119
120 Bitmap* 
121 _ImageImpl::DecodeToBitmapN(const Tizen::Base::String& srcImagePath, Tizen::Graphics::BitmapPixelFormat pixelFormat)
122 {
123         std::unique_ptr<ByteBuffer> pBuf;
124         Bitmap* pBmp = null;
125
126         pBuf.reset(_MediaUtil::FileToBufferN(srcImagePath));
127         SysTryReturn(NID_MEDIA, pBuf.get() != null, null, GetLastResult(),
128                            "[%s] FileToBufferN %S", GetErrorMessage(GetLastResult()), srcImagePath.GetPointer());
129
130         pBmp = DecodeToBitmapN(*pBuf.get(), pixelFormat);
131         return pBmp;
132 }
133
134 Bitmap* 
135 _ImageImpl::DecodeToBitmapN(const Tizen::Base::ByteBuffer& srcImageBuf, Tizen::Graphics::BitmapPixelFormat pixelFormat)
136 {
137         result r = E_SUCCESS;
138         std::unique_ptr<ByteBuffer> pBuf;
139         std::unique_ptr<Bitmap> pBmp;
140         Dimension outDim;
141
142         _ImageDecoder dec;
143
144         r = dec.Construct(srcImageBuf, _ImageUtilImpl::ToMediaPixelFormat(pixelFormat));
145         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Decoder construct failed.", GetErrorMessage(r));
146
147         pBuf.reset(dec.DecodeN());
148         SysTryReturn(NID_MEDIA, pBuf.get() != null, null, GetLastResult(),
149                            "[%s] Propagated", GetErrorMessage(GetLastResult()));
150         r = GetLastResult();
151         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
152
153         r = dec.GetDimension(outDim.width, outDim.height);
154         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
155
156         pBmp.reset(new (std::nothrow) Bitmap);
157         SysTryReturn(NID_MEDIA, pBmp != null, null, E_OUT_OF_MEMORY,
158                            "[%s] new Bitmap", GetErrorMessage(GetLastResult()));
159         r = pBmp->Construct(*pBuf.get(), outDim, pixelFormat, BUFFER_SCALING_AUTO);
160         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
161
162         // Set transparency in case of rgb565 format
163         if (pixelFormat == BITMAP_PIXEL_FORMAT_RGB565)
164         {
165                 short rgb565Chroma = 0;
166                 Boolean transparency(false);
167                 Short chromaKey(0);
168                 byte red = 0;
169                 byte green = 0;
170                 byte blue = 0;
171                 Color *pMaskingColor = null;
172
173                 r = dec.GetValue(L"transparency", transparency);
174                 SysTryReturn(NID_MEDIA, r == E_SUCCESS, pBmp.release(), E_SUCCESS, "[%s] Propagated.", GetErrorMessage(r));
175                 if (transparency.ToBool() == true)
176                 {
177                         r = dec.GetValue(L"chromaKey", chromaKey);
178                         SysTryReturn(NID_MEDIA, r == E_SUCCESS, pBmp.release(), E_SUCCESS, "[%s] Propagated.", GetErrorMessage(r));
179
180                         rgb565Chroma = chromaKey.ToShort();
181                         red = (rgb565Chroma & 0xf800) >> 8;
182                         red = red | (red >> 5);
183                         green = (rgb565Chroma & 0x07e0) >> 3;
184                         green = green | (green >> 6);
185                         blue = (rgb565Chroma & 0x001f) << 3;
186                         blue = blue | (blue >> 5);
187
188                         pMaskingColor = new Color(red, green, blue);
189                         SysTryReturn(NID_MEDIA, pMaskingColor != null, pBmp.release(), E_SUCCESS,
190                                 "[%s] Could not apply masking color.", GetErrorMessage(r));
191                         r = pBmp->SetMaskingColor(pMaskingColor);
192                         SysTryReturn(NID_MEDIA, r == E_SUCCESS, pBmp.release(), E_SUCCESS,
193                                 "[%s] Could not set masking color.", GetErrorMessage(r));
194                 }
195         }
196
197         SetLastResult(E_SUCCESS);
198         return pBmp.release();
199 }
200
201 Bitmap*
202 _ImageImpl::DecodeToBitmapN(const Tizen::Base::String& srcImagePath, Tizen::Graphics::BitmapPixelFormat pixelFormat, const Tizen::Graphics::Dimension &destDim,
203                                                         Tizen::Graphics::BufferScaling bufferScaling)
204 {
205         std::unique_ptr<ByteBuffer> pBuf;
206         Bitmap* pBmp = null;
207
208         pBuf.reset(_MediaUtil::FileToBufferN(srcImagePath));
209         SysTryReturn(NID_MEDIA, pBuf.get() != null, null, GetLastResult(),
210                            "[%s] FileToBufferN %S", GetErrorMessage(GetLastResult()), srcImagePath.GetPointer());
211
212         pBmp = DecodeToBitmapN(*pBuf.get(), pixelFormat, destDim, bufferScaling);
213         return pBmp;
214 }
215
216 Bitmap*
217 _ImageImpl::DecodeToBitmapN(const Tizen::Base::ByteBuffer& srcImageBuf, Tizen::Graphics::BitmapPixelFormat pixelFormat, const Tizen::Graphics::Dimension &destDim,
218                                                         Tizen::Graphics::BufferScaling bufferScaling)
219 {
220         result r = E_SUCCESS;
221         std::unique_ptr<ByteBuffer> pBuf;
222         std::unique_ptr<Bitmap> pBmp;
223         Dimension outDim;
224
225         _ImageDecoder dec;
226
227         r = dec.Construct(srcImageBuf, _ImageUtilImpl::ToMediaPixelFormat(pixelFormat));
228         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Decoder construct failed.", GetErrorMessage(r));
229
230         // Reset decoder output demension
231         dec.SetOutputDimension(destDim.width, destDim.height, true);
232
233         pBuf.reset(dec.DecodeN());
234         SysTryReturn(NID_MEDIA, pBuf.get() != null, null, GetLastResult(),
235                            "[%s] Propagated", GetErrorMessage(GetLastResult()));
236         r = GetLastResult();
237         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
238
239         r = dec.GetDimension(outDim.width, outDim.height);
240         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
241
242         pBmp.reset(new (std::nothrow) Bitmap);
243         SysTryReturn(NID_MEDIA, pBmp != null, null, E_OUT_OF_MEMORY,
244                            "[%s] new Bitmap", GetErrorMessage(GetLastResult()));
245         r = pBmp->Construct(*pBuf.get(), outDim, pixelFormat, bufferScaling);
246         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
247
248         // Set transparency in case of rgb565 format
249         if (pixelFormat == BITMAP_PIXEL_FORMAT_RGB565)
250         {
251                 short rgb565Chroma = 0;
252                 Boolean transparency(false);
253                 Short chromaKey(0);
254                 byte red = 0;
255                 byte green = 0;
256                 byte blue = 0;
257                 Color *pMaskingColor = null;
258
259                 r = dec.GetValue(L"transparency", transparency);
260                 SysTryReturn(NID_MEDIA, r == E_SUCCESS, pBmp.release(), E_SUCCESS, "[%s] Propagated.", GetErrorMessage(r));
261                 if (transparency.ToBool() == true)
262                 {
263                         r = dec.GetValue(L"chromaKey", chromaKey);
264                         SysTryReturn(NID_MEDIA, r == E_SUCCESS, pBmp.release(), E_SUCCESS, "[%s] Propagated.", GetErrorMessage(r));
265
266                         rgb565Chroma = chromaKey.ToShort();
267                         red = (rgb565Chroma & 0xf800) >> 8;
268                         red = red | (red >> 5);
269                         green = (rgb565Chroma & 0x07e0) >> 3;
270                         green = green | (green >> 6);
271                         blue = (rgb565Chroma & 0x001f) << 3;
272                         blue = blue | (blue >> 5);
273
274                         pMaskingColor = new Color(red, green, blue);
275                         SysTryReturn(NID_MEDIA, pMaskingColor != null, pBmp.release(), E_SUCCESS,
276                                 "[%s] Could not apply masking color.", GetErrorMessage(r));
277                         r = pBmp->SetMaskingColor(pMaskingColor);
278                         SysTryReturn(NID_MEDIA, r == E_SUCCESS, pBmp.release(), E_SUCCESS,
279                                 "[%s] Could not set masking color.", GetErrorMessage(r));
280                 }
281         }
282
283         SetLastResult(E_SUCCESS);
284         return pBmp.release();
285 }
286
287 Bitmap*
288 _ImageImpl::DecodeToBitmapN(const Tizen::Base::ByteBuffer& srcImageBuf, Tizen::Graphics::BitmapPixelFormat pixelFormat,
289                                                         const Tizen::Graphics::FloatDimension &destDim)
290 {
291         result r = E_SUCCESS;
292         std::unique_ptr<ByteBuffer> pBuf;
293         std::unique_ptr<Bitmap> pBmp;
294         Dimension orgDim, tmpDim;
295         FloatDimension outDim;
296         BufferInfo bufInfo;
297
298         _ImageDecoder dec;
299
300         r = dec.Construct(srcImageBuf, _ImageUtilImpl::ToMediaPixelFormat(pixelFormat));
301         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Decoder construct failed.", GetErrorMessage(r));
302
303         r = dec.GetDimension(orgDim.width, orgDim.height);
304         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
305
306         // Reset decoder output demension
307         dec.SetOutputDimension(_CoordinateSystemUtils::ConvertToInteger(destDim.width),
308                                                    _CoordinateSystemUtils::ConvertToInteger(destDim.height),
309                                                    true);
310
311         pBuf.reset(dec.DecodeN());
312         SysTryReturn(NID_MEDIA, pBuf.get() != null, null, GetLastResult(),
313                            "[%s] Propagated", GetErrorMessage(GetLastResult()));
314
315         r = dec.GetDimension(tmpDim.width, tmpDim.height);
316         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
317
318         r = _ImageUtil::GetResizedDimension(orgDim.width, orgDim.height, destDim.width, destDim.height, outDim.width, outDim.height);
319         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
320
321         pBmp.reset(new (std::nothrow) Bitmap);
322         SysTryReturn(NID_MEDIA, pBmp.get() != null, null, E_OUT_OF_MEMORY,
323                            "[%s] new Bitmap", GetErrorMessage(GetLastResult()));
324
325         pBmp.reset(_BitmapImpl::GetNonScaledBitmapN(*pBuf.get(), tmpDim, pixelFormat, destDim));
326
327         // Set transparency in case of rgb565 format
328         if (pixelFormat == BITMAP_PIXEL_FORMAT_RGB565)
329         {
330                 short rgb565Chroma = 0;
331                 Boolean transparency(false);
332                 Short chromaKey(0);
333                 byte red = 0;
334                 byte green = 0;
335                 byte blue = 0;
336                 Color *pMaskingColor = null;
337
338                 r = dec.GetValue(L"transparency", transparency);
339                 SysTryReturn(NID_MEDIA, r == E_SUCCESS, pBmp.release(), E_SUCCESS, "[%s] Propagated.", GetErrorMessage(r));
340                 if (transparency.ToBool() == true)
341                 {
342                         r = dec.GetValue(L"chromaKey", chromaKey);
343                         SysTryReturn(NID_MEDIA, r == E_SUCCESS, pBmp.release(), E_SUCCESS, "[%s] Propagated.", GetErrorMessage(r));
344
345                         rgb565Chroma = chromaKey.ToShort();
346                         red = (rgb565Chroma & 0xf800) >> 8;
347                         red = red | (red >> 5);
348                         green = (rgb565Chroma & 0x07e0) >> 3;
349                         green = green | (green >> 6);
350                         blue = (rgb565Chroma & 0x001f) << 3;
351                         blue = blue | (blue >> 5);
352
353                         pMaskingColor = new Color(red, green, blue);
354                         SysTryReturn(NID_MEDIA, pMaskingColor != null, pBmp.release(), E_SUCCESS,
355                                 "[%s] Could not apply masking color.", GetErrorMessage(r));
356                         r = pBmp->SetMaskingColor(pMaskingColor);
357                         SysTryReturn(NID_MEDIA, r == E_SUCCESS, pBmp.release(), E_SUCCESS,
358                                 "[%s] Could not set masking color.", GetErrorMessage(r));
359                 }
360         }
361
362         SetLastResult(E_SUCCESS);
363         return pBmp.release();
364 }
365
366 Bitmap*
367 _ImageImpl::DecodeToBitmapN(const Tizen::Base::String& srcImagePath, Tizen::Graphics::BitmapPixelFormat pixelFormat,
368                                                         const Tizen::Graphics::FloatDimension &destDim)
369 {
370         std::unique_ptr<ByteBuffer> pBuf;
371         Bitmap* pBmp = null;
372
373         pBuf.reset(_MediaUtil::FileToBufferN(srcImagePath));
374         SysTryReturn(NID_MEDIA, pBuf.get() != null, null, GetLastResult(),
375                            "[%s] FileToBufferN %S", GetErrorMessage(GetLastResult()), srcImagePath.GetPointer());
376
377         pBmp = DecodeToBitmapN(*pBuf.get(), pixelFormat, destDim);
378         return pBmp;
379 }
380
381 Tizen::Base::ByteBuffer*
382 _ImageImpl::DecodeToBufferN(const Tizen::Base::String& srcImagePath,
383                                                         Tizen::Graphics::Dimension &restDim,
384                                                         const Tizen::Graphics::Dimension &dstDim,
385                                                         Tizen::Graphics::BitmapPixelFormat pixelFormat,
386                                                         ImageFormat imgFormat, bool keepAspectRatio)
387 {
388         std::unique_ptr<ByteBuffer> pBuf;
389         ByteBuffer* pRetBuf = null;
390
391         //SysTryCatch(NID_MEDIA, IS_VALID_DIMENSION(dstDim), , E_OUT_OF_RANGE,
392         //"[E_OUT_OF_RANGE] dest dimension:%d,%d", dstDim.width, dstDim.height);
393
394         pBuf.reset(_MediaUtil::FileToBufferN(srcImagePath));
395         SysTryReturn(NID_MEDIA, pBuf.get() != null, null, GetLastResult(),
396                            "[%s] FileToBufferN %S", GetErrorMessage(GetLastResult()), srcImagePath.GetPointer());
397
398         pRetBuf = DecodeToBufferN(*pBuf.get(), restDim, dstDim, pixelFormat, imgFormat, keepAspectRatio);
399         return pRetBuf;
400 }
401
402 Tizen::Base::ByteBuffer*
403 _ImageImpl::DecodeToBufferN(const Tizen::Base::ByteBuffer &srcImageBuf,
404                                                         Tizen::Graphics::Dimension &retDim,
405                                                         const Tizen::Graphics::Dimension &dstDim,
406                                                         Tizen::Graphics::BitmapPixelFormat pixelFormat,
407                                                         ImageFormat imgFormat, bool keepAspectRatio)
408 {
409         result r = E_SUCCESS;
410         std::unique_ptr<ByteBuffer> pBuf;
411         _ImageDecoder dec;
412
413         //SysTryCatch(NID_MEDIA, IS_VALID_BITMAP_PIXEL(pixelFormat), , E_INVALID_ARG,
414         //"[E_INVALID_ARG] pixelFormat:%d", pixelFormat);
415
416         r = dec.Construct(srcImageBuf, _ImageUtilImpl::ToMediaPixelFormat(pixelFormat), imgFormat);
417         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Decoder construct failed.", GetErrorMessage(r));
418
419         // Reset decoder output demension
420         dec.SetOutputDimension(dstDim.width, dstDim.height, keepAspectRatio);
421
422         pBuf.reset(dec.DecodeN());
423         r = GetLastResult();
424         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
425
426         r = dec.GetDimension(retDim.width, retDim.height);
427         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
428
429         SetLastResult(E_SUCCESS);
430         return pBuf.release();
431 }
432
433 Tizen::Base::ByteBuffer*
434 _ImageImpl::DecodeToBufferN(const Tizen::Base::String& srcImagePath,
435                                                         Tizen::Graphics::BitmapPixelFormat pixelFormat,
436                                                         int& imageWidth, int& imageHeight, bool keepAspectRatio)
437 {
438         ByteBuffer *pBuf = null;
439         Dimension dim;
440
441         pBuf = DecodeToBufferN(srcImagePath, dim, Dimension(0, 0), pixelFormat, IMG_FORMAT_NONE, keepAspectRatio);
442         imageWidth = dim.width;
443         imageHeight = dim.height;
444         return pBuf;
445 }
446
447
448 Tizen::Base::ByteBuffer*
449 _ImageImpl::DecodeN(const Tizen::Base::String& srcImagePath,
450                                         Tizen::Graphics::BitmapPixelFormat pixelFormat,
451                                         int destWidth, int destHeight, bool keepAspectRatio)
452 {
453         Dimension dim;
454
455         return DecodeToBufferN(srcImagePath, dim, Dimension(destWidth, destHeight), pixelFormat, IMG_FORMAT_NONE, keepAspectRatio);
456 }
457
458 result
459 _ImageImpl::DecodeUrl(const Tizen::Base::Utility::Uri& srcImageUrl,
460                                           Tizen::Graphics::BitmapPixelFormat colorFormat,
461                                           int destWidth, int destHeight, RequestId& reqId,
462                                           const IImageDecodeUrlEventListener& listener, long timeout)
463 {
464         result r = E_SUCCESS;
465
466         _ImageUriDataFactory *pFactory = null;
467
468         SysTryCatch(NID_MEDIA, (colorFormat > Tizen::Graphics::BITMAP_PIXEL_FORMAT_MIN)
469         && colorFormat < Tizen::Graphics::BITMAP_PIXEL_FORMAT_MAX, , E_INVALID_ARG,
470         "[E_INVALID_ARG] Wrong color format.");
471
472         SysTryCatch(NID_MEDIA, destWidth > 0 && destHeight > 0, , E_OUT_OF_RANGE,
473         "[E_OUT_OF_RANGE] The designated width and height SHOUL be greater than 0.");
474
475         SysTryCatch(NID_MEDIA, timeout == _TIMEOUT_INFINITE || timeout > 0 ,
476         r = E_OUT_OF_RANGE, E_OUT_OF_RANGE,
477         "[E_OUT_OF_RANGE] The designated timeout SHOUL be greater than 0");
478
479         pFactory = _ImageUriDataFactory::GetInstance();
480         SysTryCatch(NID_MEDIA, pFactory != null, r = GetLastResult(), r,
481         "[%s] Failed to GetInstance().", GetErrorMessage(r));
482
483         r = pFactory->DecodeUrl(srcImageUrl, colorFormat, destWidth,destHeight, reqId, listener, timeout);
484         SysTryCatch(NID_MEDIA, r == E_SUCCESS , , r,"[%s] Propagated.", GetErrorMessage(r));
485
486         if (__pUrlReqIDList.get() == null)
487         {
488                 __pUrlReqIDList.reset(new (std::nothrow)Collection::LinkedList());
489                 SysTryCatch(NID_MEDIA, __pUrlReqIDList.get() != null, r = E_OUT_OF_MEMORY, r,
490                         "[E_OUT_OF_MEMORY] Propagated. Failed to allocate a LinkedList.", GetErrorMessage(r));
491         }
492         __pUrlReqIDList->Add(new (std::nothrow) Integer(reqId));
493
494         return r;
495
496 CATCH:
497         return r;
498 }
499
500 ByteBuffer*
501 _ImageImpl::EncodeToBufferN(const Bitmap& srcBmp, ImageFormat dstFormat)
502 {
503         std::unique_ptr<ByteBuffer> pBuf;
504         BufferInfo bmpInfo;
505         Dimension dim;
506
507         // ClearLastResult();
508
509         Tizen::Graphics::Bitmap& tmpBmp = const_cast<Tizen::Graphics::Bitmap&>(srcBmp);
510
511         // Create src buf
512         tmpBmp.Lock(bmpInfo);
513
514         dim.SetSize(bmpInfo.width, bmpInfo.height);
515
516         // TODO: handle case that pitch != width * bpp/8
517         SysTryReturn(NID_MEDIA, bmpInfo.pitch == bmpInfo.width*bmpInfo.bitsPerPixel/8, null, E_SYSTEM,
518                            "[E_SYSTEM] pitch=%d bpp=%d", bmpInfo.pitch, bmpInfo.bitsPerPixel);
519
520         pBuf.reset(_ImageEncoder::EncodeN(dstFormat, (const byte*)bmpInfo.pPixels, bmpInfo.pitch * bmpInfo.height,
521                                                            dim.width, dim.height,
522                                                            _ImageUtilImpl::ToMediaPixelFormat(srcBmp.GetPixelColorFormat()),
523                                                            _DEFAULT_ENCODE_QUALITY));
524         SysTryReturn(NID_MEDIA, pBuf.get() != null, null, GetLastResult(), "[%s] Propagated. ", GetErrorMessage(GetLastResult()));
525
526         return pBuf.release();
527 }
528
529 result
530 _ImageImpl::EncodeToFile(const Bitmap& srcBmp, ImageFormat dstFormat,
531                                                  const String& dstPath, bool overwrite)
532 {
533         result r = E_SUCCESS;
534         std::unique_ptr<ByteBuffer> pBuf;
535
536         pBuf.reset(EncodeToBufferN(srcBmp, dstFormat));
537         SysTryReturn(NID_MEDIA, pBuf.get() != null, GetLastResult(), GetLastResult(),
538                            "[%s] Propagated.", GetErrorMessage(GetLastResult()));
539
540         r = _MediaUtil::BufferToFile(*pBuf.get(), dstPath, overwrite);
541         SysTryReturn(NID_MEDIA, r == E_SUCCESS, r, r, "[%s] Propagated. ", GetErrorMessage(r));
542
543         SetLastResult(r);
544         return r;
545 }
546
547 Tizen::Base::ByteBuffer*
548 _ImageImpl::CompressJpegN(const Tizen::Base::ByteBuffer& srcImageBuf, int limitSize)
549 {
550         result r = E_SUCCESS;
551         std::unique_ptr<ByteBuffer> pDecBuf;
552         std::unique_ptr<ByteBuffer> pEncBuf;
553         Dimension srcDim;
554         _ImageDecoder dec;
555         volatile int limit = limitSize;
556         MediaPixelFormat pixelFormat = MEDIA_PIXEL_FORMAT_BGRA8888;
557
558         // TODO : use yuv pixel format
559
560         r = dec.Construct(srcImageBuf, pixelFormat);
561         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Decoder construct failed.", GetErrorMessage(r));
562
563         pDecBuf.reset(dec.DecodeN());
564         r = GetLastResult();
565         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
566         SysTryReturn(NID_MEDIA, pDecBuf.get() != null, null, E_SYSTEM, "[E_SYSTEM] Propagated.");
567
568         r = dec.GetDimension(srcDim.width, srcDim.height);
569         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
570
571         for (int i = 0; i < _MAX_ENCODE_RESIZE_LOOP; i++)
572         {
573                 Dimension dstDim;
574                 ByteBuffer *pTmpBuf = null;
575
576                 pEncBuf.reset(EncodeToBufferLimitN(*pDecBuf.get(), srcDim, pixelFormat, IMG_FORMAT_JPG, limit));
577
578                 if (pEncBuf.get() != null)
579                 {
580                         break;
581                 }
582
583                 // halve and make even number
584                 dstDim.width = srcDim.width >> 2;
585                 dstDim.height = srcDim.height >> 2;
586
587                 dstDim.width = dstDim.width << 1;
588                 dstDim.height = dstDim.height << 1;
589
590                 SysTryReturn(NID_MEDIA, srcDim != dstDim && dstDim.width > 0 && dstDim.height > 0, null, E_SYSTEM,
591                                    "[E_SYSTEM] Resize failed:src:%dx%d dst:%dx%d, %d %d, %d",
592                                    srcDim.width, srcDim.height, dstDim.width, dstDim.height, i, _SCALE_DOWN_RATIO,
593                                    limit);
594
595                 pTmpBuf = _ImageUtilImpl::ResizeN(*pDecBuf.get(), srcDim, pixelFormat, dstDim);
596                 SysTryReturn(NID_MEDIA, pTmpBuf != null, null, GetLastResult(),
597                                    "[%s] ResizeN: %dx%d->%dx%d", GetErrorMessage(GetLastResult()),
598                                    srcDim.width, srcDim.height, dstDim.width, dstDim.height);
599
600                 srcDim = dstDim;
601                 pDecBuf.reset(pTmpBuf);
602         }
603         SysTryReturn(NID_MEDIA, pEncBuf.get() != null, null, E_SYSTEM, "[E_SYSTEM] Compress failed");
604         SetLastResult(E_SUCCESS);
605         return pEncBuf.release();
606 }
607
608 result
609 _ImageImpl::CompressJpeg(const Tizen::Base::String& srcImagePath,
610                                                  const Tizen::Base::String& dstImagePath, int limitSize)
611 {
612         File file;
613         result r = E_SUCCESS;
614         std::unique_ptr<ByteBuffer> pSrcBuf;
615         std::unique_ptr<ByteBuffer> pEncBuf;
616
617         pSrcBuf.reset(_MediaUtil::FileToBufferN(srcImagePath));
618         SysTryReturn(NID_MEDIA, pSrcBuf.get() != null, GetLastResult(), GetLastResult(),
619                            "[%s] Propagated. ", GetErrorMessage(GetLastResult()));
620
621 //      SysTryCatch(NID_MEDIA, pSrcBuf->GetCapacity() < MAX_IMGFILE_SIZE, r = E_OVERFLOW, E_OVERFLOW,
622 //                         "[E_OUT_OF_RANGE] Input file size is smaller than limitSize.");
623
624         SysTryReturn(NID_MEDIA, pSrcBuf.get()->GetCapacity() > limitSize, E_OUT_OF_RANGE, E_OUT_OF_RANGE,
625                            "[E_OUT_OF_RANGE] Input file size is smaller than limitSize.");
626
627         pEncBuf.reset(CompressJpegN(*pSrcBuf, limitSize));
628         SysTryReturn(NID_MEDIA, pEncBuf != null, GetLastResult(), GetLastResult(),
629                            "[%s] Propagated. ", GetErrorMessage(GetLastResult()));
630
631         if (File::IsFileExist(dstImagePath))
632         {
633                 File::Remove(dstImagePath);
634         }
635
636         r = file.Construct(dstImagePath, "wb", true);
637         SysTryReturn(NID_MEDIA, r == E_SUCCESS, r, r, "[%s] Propagated. ", GetErrorMessage(r));
638         r = file.Write(*pEncBuf);
639         SysTryReturn(NID_MEDIA, r == E_SUCCESS, r, r, "[%s] Propagated. ", GetErrorMessage(r));
640
641         return r;
642 }
643
644 Tizen::Base::ByteBuffer*
645 _ImageImpl::ConvertToBufferN(const Tizen::Base::String& srcImagePath, ImageFormat destImageFormat)
646 {
647         std::unique_ptr<Bitmap> pBmp;
648         ByteBuffer* pBuf = null;
649
650         pBmp.reset(DecodeToBitmapN(srcImagePath, BITMAP_PIXEL_FORMAT_ARGB8888, Dimension(0, 0),
651                                                    BUFFER_SCALING_NONE));
652         SysTryReturn(NID_MEDIA, pBmp.get(), null, GetLastResult(),
653                            "[%s] Propagated. ", GetErrorMessage(GetLastResult()));
654
655         pBuf = EncodeToBufferN(*pBmp.get(), destImageFormat);
656         SysTryReturn(NID_MEDIA, pBuf != null, null, GetLastResult(),
657                            "[%s] Propagated.", GetErrorMessage(GetLastResult()));
658
659         SetLastResult(E_SUCCESS);
660         return pBuf;
661 }
662
663 Tizen::Base::ByteBuffer*
664 _ImageImpl::EncodeToBufferLimitN(const Tizen::Base::ByteBuffer &srcBuf,
665                                                                  const Tizen::Graphics::Dimension& dim,
666                                                                  MediaPixelFormat pixelFormat, ImageFormat imgFormat, int limit)
667 {
668         int minQuality = _MIN_ENCODE_QUALITY;
669         int maxQuality = _MAX_ENCODE_QUALITY;
670         int curQuality = 0;
671         int minDiff = 0;
672         int maxDiff = 0;
673
674         std::unique_ptr<ByteBuffer> pMaxBuf;
675         std::unique_ptr<ByteBuffer> pMinBuf;
676
677         pMaxBuf.reset(EncodeToBufferQualityN(srcBuf, dim, pixelFormat, imgFormat, maxQuality));
678         SysTryReturn(NID_MEDIA, pMaxBuf.get() != null, pMinBuf.get(), E_SYSTEM, "[E_SYSTEM] maxBuf is null");
679         maxDiff = pMaxBuf->GetLimit() - limit;
680         SysLog(NID_MEDIA, "maxDiff:%d buf:%d limit:%d q:%d",
681                                 maxDiff, pMaxBuf->GetLimit(), limit, maxQuality);
682         if (maxDiff <= 0)
683         {
684                 SetLastResult(E_SUCCESS);
685                 return pMaxBuf.release();
686         }
687         pMinBuf.reset(EncodeToBufferQualityN(srcBuf, dim, pixelFormat, imgFormat, minQuality));
688         SysTryReturn(NID_MEDIA, pMinBuf.get() != null, pMinBuf.release(), E_SYSTEM, "[E_SYSTEM] minBuf is null");
689         minDiff = pMinBuf->GetLimit() - limit;
690         SysLog(NID_MEDIA, "minDiff:%d buf:%d limit:%d q:%d",
691                                         minDiff, pMinBuf->GetLimit(), limit, minQuality);
692         if (minDiff > 0)
693         {
694                 SetLastResult(E_OVERFLOW);
695                 return null;
696         }
697         if (minDiff == 0)
698         {
699                 SetLastResult(E_SUCCESS);
700                 return pMinBuf.release();
701         }
702
703         for (int i = 0; i < _MAX_ENCODE_LOOP; i++)
704         {
705                 int prevQuality = curQuality;
706                 int curDiff = 0;
707                 ByteBuffer *pCurBuf = null;
708
709                 curQuality = (minQuality + maxQuality) / 2;
710                 if (prevQuality == curQuality)
711                 {
712                         break;
713                 }
714                 pCurBuf = EncodeToBufferQualityN(srcBuf, dim, pixelFormat, imgFormat, curQuality);
715                 if (pCurBuf == null && pMinBuf.get() != null)
716                 {
717                         break;
718                 }
719                 SysTryReturn(NID_MEDIA, pCurBuf != null, pMinBuf.release(), E_SYSTEM,
720                                    "[E_SYSTEM] curBuf is null : %d %d %d", dim.width, dim.height, curQuality);
721                 curDiff = pCurBuf->GetLimit() - limit;
722                 SysLog(NID_MEDIA, "curDiff:%d buf:%d limit:%d q:%d",
723                                         curDiff, pCurBuf->GetLimit(), limit, curQuality);
724                 if (curDiff == 0)
725                 {
726                         SetLastResult(E_SUCCESS);
727                         return pCurBuf;
728                 }
729                 else if (curDiff > 0)
730                 {
731                         maxDiff = curDiff;
732                         maxQuality = curQuality;
733                         pMaxBuf.reset(pCurBuf);
734                 }
735                 else if (curDiff < 0)
736                 {
737                         pMinBuf.reset(pCurBuf);
738                         minDiff = curDiff;
739                         minQuality = curQuality;
740                 }
741         }
742         if (pMinBuf.get())
743         {
744                 SetLastResult(E_SUCCESS);
745         }
746         else
747         {
748                 // should not come here.
749                 SetLastResult(E_SYSTEM);
750         }
751         return pMinBuf.release();
752 }
753
754 Tizen::Base::ByteBuffer*
755 _ImageImpl::EncodeToBufferQualityN(const Tizen::Base::ByteBuffer &srcBuf,
756                                                                    const Tizen::Graphics::Dimension& dim,
757                                                                    MediaPixelFormat pixelFormat, ImageFormat imgFormat, int quality)
758 {
759         ByteBuffer* pBuf = null;
760
761         pBuf = _ImageEncoder::EncodeN(imgFormat, srcBuf.GetPointer(), srcBuf.GetLimit(),
762                                                            dim.width, dim.height, pixelFormat, quality);
763         SysTryReturn(NID_MEDIA, pBuf != null, pBuf, GetLastResult(),
764                 "[%s] enc.EncodeN. ", GetErrorMessage(GetLastResult()));
765
766         return pBuf;
767 }
768
769 result
770 _ImageImpl::GetImageInfo(const Tizen::Base::String& path, ImageFormat &imgFormat,
771                                                  Tizen::Graphics::Dimension &dim)
772 {
773         return _ImageDecoder::GetImageInfo(path, imgFormat, dim.width, dim.height);
774 }
775
776 }} // Tizen::Media