2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 * @file FMedia_ImageDecoder.cpp
20 * @brief This is the implementation file for the _ImageDecoder.
23 #include <unique_ptr.h>
24 #include <FBaseColArrayListT.h>
25 #include <FBaseSysLog.h>
26 #include <FBaseInteger.h>
28 #include <FMediaImageTypes.h>
29 #include "FMedia_MediaUtil.h"
30 #include "FMedia_Ffmpeg.h"
31 #include "FMedia_ColorConverter.h"
32 #include "FMedia_ImageDecoder.h"
33 #include "FMedia_PngDecoder.h"
34 #include "FMedia_JpegDecoder.h"
35 #include "FMedia_JpegTurboDecoder.h"
36 #include "FMedia_GifDecoder.h"
37 #include "FMedia_BmpDecoder.h"
38 #include "FMedia_TiffDecoder.h"
39 #include "FMedia_WbmpDecoder.h"
40 #include "FMedia_ImageUtil.h"
41 #include "FMedia_ExifUtil.h"
43 using namespace Tizen::Base;
44 using namespace Tizen::Io;
46 namespace Tizen { namespace Media
49 #define IS_VALID_DEC_PIXEL(x) \
50 ((x == MEDIA_PIXEL_FORMAT_RGB565LE) || (x == MEDIA_PIXEL_FORMAT_BGRA8888) \
51 || (x == MEDIA_PIXEL_FORMAT_RGBA8888))
54 ImageRotationType rotateType;
55 ImageFlipType flipType;
59 static const _ImageExifInfo _IMAGE_ROTATE_FLIP_MAP[] = {
60 { IMAGE_ROTATION_0, IMAGE_FLIP_NONE, false }, /* NONE */
61 { IMAGE_ROTATION_0, IMAGE_FLIP_NONE, false }, /* TOP_LEFT */
62 { IMAGE_ROTATION_0, IMAGE_FLIP_VERTICAL, false }, /* TOP_RIGHT */
63 { IMAGE_ROTATION_180, IMAGE_FLIP_NONE, false }, /* BOTTOM_RIGHT */
64 { IMAGE_ROTATION_0, IMAGE_FLIP_HORIZONTAL, false }, /* BOTTOM_LEFT */
65 { IMAGE_ROTATION_90, IMAGE_FLIP_VERTICAL, true }, /* LEFT_TOP */
66 { IMAGE_ROTATION_90, IMAGE_FLIP_NONE, true }, /* RIGHT_TOP */
67 { IMAGE_ROTATION_90, IMAGE_FLIP_HORIZONTAL, true }, /* RIGHT_BOTTOM */
68 { IMAGE_ROTATION_270, IMAGE_FLIP_NONE, true } /* LEFT_BOTTOM */
71 Tizen::Base::ByteBuffer*
72 _ImageDecoder::DecodeToBufferN(const Tizen::Base::String& filePath,
73 MediaPixelFormat pixelFormat, int &width, int &height, bool autoRotate)
77 std::unique_ptr<ByteBuffer> pBuf;
80 SysTryReturn(NID_MEDIA, filePath.GetLength() > 0 && filePath.GetLength() <= PATH_MAX, null, E_INVALID_ARG,
81 "[E_INVALID_ARG] Given filePath length is zero or exceeds system limitations Length = %d.",filePath.GetLength());
82 SysTryReturn(NID_MEDIA, File::IsFileExist(filePath), null, E_FILE_NOT_FOUND,
83 "[E_FILE_NOT_FOUND] filePath:%ls", filePath.GetPointer());
85 r = dec.Construct(filePath, pixelFormat, IMG_FORMAT_NONE, autoRotate);
86 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r,
87 "[%s] Decoder construct failed.", GetErrorMessage(r));
89 // Reset decoder output demension
90 pBuf.reset(dec.DecodeN());
92 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
94 r = dec.GetDimension(width, height);
95 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
97 SetLastResult(E_SUCCESS);
98 return pBuf.release();
101 Tizen::Base::ByteBuffer*
102 _ImageDecoder::DecodeRegionToBufferN(const Tizen::Base::String& filePath,
103 MediaPixelFormat pixelFormat, int x, int y, int width, int height)
105 result r = E_SUCCESS;
109 std::unique_ptr<ByteBuffer> pBuf;
111 r = dec.Construct(filePath, pixelFormat);
112 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] dec.Construct", GetErrorMessage(r));
113 r = dec.GetDimension(imgWidth, imgHeight);
114 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] dec.GetDimension", GetErrorMessage(r));
116 SysTryReturn(NID_MEDIA, imgWidth >= (x + width) && imgHeight >= (y + height),
118 "[E_INVALID_ARG] Bottom left point of region (%d, %d) should lie within dimensions of image (%d x %d)",
119 x, y, width, height, imgWidth, imgHeight);
121 r = dec.SetDecodingRegion(x, y, width, height);
122 SysTryReturn(NID_MEDIA, r == E_SUCCESS || r == E_UNSUPPORTED_OPERATION, null, r,
123 "[%s] dec.SetDecodingRegion failed for region (%d, %d) (%d x %d)",
124 GetErrorMessage(r), x, y, width, height);
128 pBuf.reset(dec.DecodeN());
129 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
131 else // E_UNSUPPORTED_OPERATION
134 ByteBuffer *pTmpBuf = null;
136 pBuf.reset(dec.DecodeN());
138 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
139 pTmpBuf = _ImageUtil::CropN(*pBuf.get(), pixelFormat, imgWidth, imgHeight, x, y, width, height);
140 SysTryReturn(NID_MEDIA, pTmpBuf != null, null, GetLastResult(),
141 "[%s] Crop failed for buffer(%x), pixelFormat(%d), image size(%dx%d), region(%d,%d), (%dx%d)",
142 GetErrorMessage(GetLastResult()), pBuf->GetPointer(), pixelFormat, imgWidth,
143 imgHeight, x, y, width, height);
147 SetLastResult(E_SUCCESS);
148 return pBuf.release();
151 Tizen::Base::ByteBuffer*
152 _ImageDecoder::DecodeRegionToBufferN(const Tizen::Base::ByteBuffer& srcBuf, MediaPixelFormat pixelFormat,
153 int x, int y, int width, int height)
155 result r = E_SUCCESS;
159 std::unique_ptr<ByteBuffer> pBuf;
161 r = dec.Construct(srcBuf, pixelFormat);
162 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] dec.Construct", GetErrorMessage(r));
163 r = dec.GetDimension(imgWidth, imgHeight);
164 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] dec.GetDimension", GetErrorMessage(r));
166 SysTryReturn(NID_MEDIA, imgWidth >= (x + width) && imgHeight >= (y + height),
168 "[E_INVALID_ARG] Bottom left point of region (%d, %d) should lie within dimensions of image (%d x %d)",
169 x, y, width, height, imgWidth, imgHeight);
171 r = dec.SetDecodingRegion(x, y, width, height);
172 SysTryReturn(NID_MEDIA, r == E_SUCCESS || r == E_UNSUPPORTED_OPERATION, null, r,
173 "[%s] dec.SetDecodingRegion failed for region (%d, %d) (%d x %d)",
174 GetErrorMessage(r), x, y, width, height);
178 pBuf.reset(dec.DecodeN());
179 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
181 else // E_UNSUPPORTED_OPERATION
184 ByteBuffer *pTmpBuf = null;
185 pBuf.reset(dec.DecodeN());
187 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
188 pTmpBuf = _ImageUtil::CropN(*pBuf.get(), pixelFormat, imgWidth, imgHeight, x, y, width, height);
189 SysTryReturn(NID_MEDIA, pTmpBuf != null, null, GetLastResult(),
190 "[%s] Crop failed for buffer(%x), pixelFormat(%d), image size(%dx%d), region(%d,%d), (%dx%d)",
191 GetErrorMessage(GetLastResult()), pBuf->GetPointer(), pixelFormat, imgWidth,
192 imgHeight, x, y, width, height);
196 SetLastResult(E_SUCCESS);
197 return pBuf.release();
201 _ImageDecoder::GetImageInfo(const Tizen::Base::String& filePath, ImageFormat &imgFormat,
202 int &width, int &height)
204 result r = E_SUCCESS;
207 r = dec.Construct(filePath);
208 SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] dec.Construct", GetErrorMessage(r));
209 imgFormat = dec.GetImageFormat();
210 r = dec.GetDimension(width, height);
211 SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] dec.GetDimension", GetErrorMessage(r));
217 _ImageDecoder::_ImageDecoder(void)
220 __imgFormat = IMG_FORMAT_NONE;
221 __pixelFormat = MEDIA_PIXEL_FORMAT_NONE;
227 __autoRotate = false;
228 __orientationInfo = 0;
231 _ImageDecoder::~_ImageDecoder(void)
236 _ImageDecoder::CreateDecoderN(ImageFormat srcFormat)
238 result r = E_SUCCESS;
239 std::unique_ptr<_IImageDecoder> pDec;
244 pDec.reset( new (std::nothrow) _JpegTurboDecoder());
248 pDec.reset( new (std::nothrow) _PngDecoder());
252 pDec.reset( new (std::nothrow) _GifDecoder());
256 pDec.reset( new (std::nothrow) _BmpDecoder());
259 case IMG_FORMAT_TIFF:
260 pDec.reset( new (std::nothrow) _TiffDecoder());
263 case IMG_FORMAT_WBMP:
264 pDec.reset( new (std::nothrow) _WbmpDecoder());
268 r = E_UNSUPPORTED_FORMAT;
272 //__imageFormat = srcFormat;
273 if (pDec.get() == null && r == E_SUCCESS)
278 return pDec.release();
283 _ImageDecoder::Construct(const Tizen::Base::String& srcPath,
284 MediaPixelFormat pixelFormat,
285 ImageFormat imgFormat, bool autoRotate)
287 result r = E_SUCCESS;
288 std::unique_ptr<ByteBuffer> pBuf;
291 pBuf.reset(_MediaUtil::FileToBufferN(srcPath));
292 SysTryReturn(NID_MEDIA, pBuf.get() != null, GetLastResult(), GetLastResult(),
293 "[%s] Propagated.", GetErrorMessage(GetLastResult()));
295 r = Construct(*pBuf.get(), pixelFormat, imgFormat);
296 SysTryReturn(NID_MEDIA, r == E_SUCCESS, r, r, "[%s] Propagated.", GetErrorMessage(r));
298 if (autoRotate == true)
302 imgExif.Construct(pBuf->GetPointer(), pBuf->GetCapacity());
303 imgExif.GetValue(EXIF_TAG_IMAGE_ORIENTATION, __orientationInfo);
304 // imgExif.GetValue() will return "r = E_OBJ_NOT_FOUND" if it could not be found exif infomation.
305 // However, the result should be decided by result of construct in this function.
306 SetLastResult(E_SUCCESS);
312 _ImageDecoder::Construct(const Tizen::Base::ByteBuffer& srcBuf,
313 MediaPixelFormat pixelFormat,
314 ImageFormat imgFormat)
316 result r = E_SUCCESS;
318 SysTryReturnResult(NID_MEDIA, __pDec.get() == null, E_INVALID_STATE, "Already constructed");
319 SysTryCatch(NID_MEDIA,
320 (pixelFormat == MEDIA_PIXEL_FORMAT_RGB565LE)|| (pixelFormat == MEDIA_PIXEL_FORMAT_BGRA8888) ||
321 (pixelFormat == MEDIA_PIXEL_FORMAT_RGBA8888), r = E_INVALID_ARG, E_INVALID_ARG,
322 "[E_INVALID_ARG] pixelFormat:%d", pixelFormat);
324 SysTryCatch(NID_MEDIA, &srcBuf != null && srcBuf.GetCapacity() > 0,
325 r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND,
326 "[E_OBJ_NOT_FOUND] buf:0x%x, %d", &srcBuf, &srcBuf ? srcBuf.GetCapacity() : 0);
328 __pixelFormat = pixelFormat;
330 __pSrcBuf.reset(new (std::nothrow) ByteBuffer());
331 SysTryCatch(NID_MEDIA, __pSrcBuf.get() != null, , r, "[%s] Propagated.", GetErrorMessage(r));
332 r = __pSrcBuf->Construct(srcBuf);
333 SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Propagated.", GetErrorMessage(r));
335 __imgFormat = _ImageUtil::GetImageFormat(srcBuf);
337 SysTryCatch(NID_MEDIA,
338 (__imgFormat > IMG_FORMAT_NONE) && (__imgFormat <= IMG_FORMAT_WBMP),
339 r = E_UNSUPPORTED_FORMAT, E_UNSUPPORTED_FORMAT, "[%s] Propagated.",
340 GetErrorMessage(GetLastResult()));
343 __pDec.reset(CreateDecoderN(__imgFormat));
344 SysTryCatch(NID_MEDIA, __pDec.get() != null, r = GetLastResult(), r,
345 "[%s] Could not create decoder for image format %d.",
346 GetErrorMessage(r), __imgFormat);
348 // Decoder construction
349 r = __pDec->Construct((byte*) __pSrcBuf->GetPointer(), __pSrcBuf->GetCapacity(), pixelFormat);
350 // TODO: enhance me. turbo jpeg construction failed.
351 if (IsFailed(r) && __imgFormat == IMG_FORMAT_JPG)
353 __pDec.reset(new (std::nothrow) _JpegDecoder());
354 SysTryCatch(NID_MEDIA, __pDec.get() != null, r = GetLastResult(), r,
355 "[%s] Could not create decoder for image format %d.",
356 GetErrorMessage(r), __imgFormat);
358 // Decoder construction
359 r = __pDec->Construct((byte*) __pSrcBuf->GetPointer(), __pSrcBuf->GetCapacity(), pixelFormat);
361 SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Propagated.", GetErrorMessage(r));
363 // Get original dimension
364 r = __pDec->GetDimension(__orgDim.width, __orgDim.height);
365 SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Propagated.", GetErrorMessage(r));
366 __outDim.width = __orgDim.width;
367 __outDim.height = __orgDim.height;
374 _ImageDecoder::DecodeN(int& outLength, ImageScalingMethod scalingMethod)
376 result r = E_SUCCESS;
378 std::unique_ptr<byte[]> pOutBuf;
379 std::unique_ptr<byte[]> pRawBuf;
380 std::unique_ptr<byte[]> pDstBuf;
381 SysTryReturn(NID_MEDIA, __pDec.get() != null, null, E_INVALID_STATE, "Not yet constructed");
384 pRawBuf.reset(__pDec->DecodeN(rawLength));
385 SysTryReturn(NID_MEDIA, pRawBuf.get() != null, null, GetLastResult(),
386 "[%s] buffer is null (%x), buffer length is %d.",
387 GetErrorMessage(GetLastResult()),pRawBuf.get(), rawLength);
389 // Get working dimension
390 if ((__outDim.width == 0) && (__outDim.height == 0))
392 __outDim.width = __orgDim.width;
393 __outDim.height = __orgDim.height;
396 // if no need to convert.
397 if ((__pDec->GetPixelFormat() == __pixelFormat)
398 && (__orgDim.width == __outDim.width)
399 && (__orgDim.height == __outDim.height))
401 pOutBuf.swap(pRawBuf);
402 outLength = rawLength;
408 // Converter construction
409 r = cvt.Construct(__pDec->GetPixelFormat(), __orgDim.width, __orgDim.height,
410 __pixelFormat, __outDim.width, __outDim.height, scalingMethod);
411 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
413 // Convert to output format
414 pOutBuf.reset(cvt.ConvertN(pRawBuf.get(), rawLength, outLength));
416 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
419 if (__autoRotate == true)
424 if (__orientationInfo == EXIF_ORIENTATION_TOP_LEFT || __orientationInfo == 0)
426 SetLastResult(E_SUCCESS);
427 return pOutBuf.release();
430 if (__orientationInfo > EXIF_ORIENTATION_LEFT_BOTTOM || __orientationInfo < EXIF_ORIENTATION_TOP_LEFT)
432 SetLastResult(E_SUCCESS);
433 return pOutBuf.release();
436 pDstBuf.reset(new (std::nothrow) byte[outLength]);
437 SysTryReturn(NID_MEDIA, pDstBuf.get() != null, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY]");
439 ImageRotationType rotateType = _IMAGE_ROTATE_FLIP_MAP[__orientationInfo].rotateType;
440 ImageFlipType flipType = _IMAGE_ROTATE_FLIP_MAP[__orientationInfo].flipType;
442 pDstBuf.reset(_ImageUtil::RotateN(pOutBuf.get(), __pixelFormat, __outDim.width, __outDim.height, rotateType, dstWidth, dstHeight));
444 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] _ImageUtil:Resize", GetErrorMessage(r));
446 __outDim.width = dstWidth;
447 __outDim.height = dstHeight;
449 pOutBuf.swap(pDstBuf);
450 if (flipType != IMAGE_FLIP_NONE)
452 pDstBuf.reset(_ImageUtil::FlipN(pOutBuf.get(), __pixelFormat, __outDim.width, __outDim.height, flipType));
454 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] _ImageUtil:Flip", GetErrorMessage(r));
456 pOutBuf.swap(pDstBuf);
459 SetLastResult(E_SUCCESS);
460 return pOutBuf.release();
463 // TODO: Change return type to ByteBuffer*
465 Tizen::Base::ByteBuffer*
466 _ImageDecoder::DecodeN(void)
468 result r = E_SUCCESS;
470 std::unique_ptr<byte[]> pTmpBuf;
471 std::unique_ptr<ByteBuffer> pByteBuf(new (std::nothrow) ByteBuffer());
473 SysTryReturn(NID_MEDIA, __pDec.get() != null, null, E_INVALID_STATE, "Not yet constructed");
475 pTmpBuf.reset(DecodeN(outLength));
476 SysTryReturn(NID_MEDIA, pTmpBuf.get() != null, null, GetLastResult(), "[%s] Propagated.", GetErrorMessage(GetLastResult()));
478 r = pByteBuf->Construct(outLength);
479 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r,
480 "[%s] Propagated. Could not construct Bytebuffer of size %d",
481 GetErrorMessage(r), outLength);
483 r = pByteBuf->SetArray((byte*) pTmpBuf.get(), 0, outLength);
484 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
487 SetLastResult(E_SUCCESS);
488 return pByteBuf.release();
492 _ImageDecoder::GetImageFormat(void) const
498 _ImageDecoder::SetDecodingRegion(int x, int y, int width, int height)
500 SysTryReturnResult(NID_MEDIA, __pDec.get() != null, E_INVALID_STATE, "Not yet constructed");
501 result r = E_SUCCESS;
503 r = __pDec->SetDecodingRegion(x, y, width, height);
506 __outDim.width = width;
507 __outDim.height = height;
508 __orgDim.width = width;
509 __orgDim.height = height;
515 _ImageDecoder::GetDimension(int &width, int &height) const
517 SysTryReturnResult(NID_MEDIA, __pDec.get() != null, E_INVALID_STATE, "Not yet constructed");
519 width = __outDim.width;
520 height = __outDim.height;
526 _ImageDecoder::GetPixelFormat(void) const
528 return __pixelFormat;
532 _ImageDecoder::GetValue(const Tizen::Base::String& key, Tizen::Base::Object &value)
534 SysTryReturnResult(NID_MEDIA, __pDec.get() != null, E_INVALID_STATE, "Not yet constructed");
536 return __pDec->GetValue(key, value);
540 _ImageDecoder::SetOutputDimension(int width, int height, bool keepAspectRatio)
542 if (width == 0 || height == 0 || __orgDim.width == 0 ||
543 __orgDim.height == 0 || keepAspectRatio == false)
545 __outDim.width = width;
546 __outDim.height = height;
548 else // keep aspect ratio
550 double xRatio = Integer(width).ToDouble() / Integer(__orgDim.width).ToDouble();
551 double yRatio = Integer(height).ToDouble() / Integer(__orgDim.height).ToDouble();
552 if (xRatio >= 1.0 || yRatio >= 1.0)
554 __outDim.width = __orgDim.width;
555 __outDim.height = __orgDim.height;
557 else if (xRatio < yRatio)
559 __outDim.width = (int)(__orgDim.width * yRatio);
560 __outDim.height = height;
564 __outDim.width = width;
565 __outDim.height = (int)(__orgDim.height*xRatio);