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_JpegTurboDecoder.h"
35 #include "FMedia_GifDecoder.h"
36 #include "FMedia_BmpDecoder.h"
37 #include "FMedia_TiffDecoder.h"
38 #include "FMedia_WbmpDecoder.h"
39 #include "FMedia_ImageUtil.h"
40 #include "FMedia_ExifUtil.h"
42 using namespace Tizen::Base;
43 using namespace Tizen::Io;
45 namespace Tizen { namespace Media
48 #define IS_VALID_DEC_PIXEL(x) \
49 ((x == MEDIA_PIXEL_FORMAT_RGB565LE) || (x == MEDIA_PIXEL_FORMAT_BGRA8888) \
50 || (x == MEDIA_PIXEL_FORMAT_RGBA8888))
53 ImageRotationType rotateType;
54 ImageFlipType flipType;
58 static const _ImageExifInfo _IMAGE_ROTATE_FLIP_MAP[] = {
59 { IMAGE_ROTATION_0, IMAGE_FLIP_NONE, false }, /* NONE */
60 { IMAGE_ROTATION_0, IMAGE_FLIP_NONE, false }, /* TOP_LEFT */
61 { IMAGE_ROTATION_0, IMAGE_FLIP_VERTICAL, false }, /* TOP_RIGHT */
62 { IMAGE_ROTATION_180, IMAGE_FLIP_NONE, false }, /* BOTTOM_RIGHT */
63 { IMAGE_ROTATION_0, IMAGE_FLIP_HORIZONTAL, false }, /* BOTTOM_LEFT */
64 { IMAGE_ROTATION_90, IMAGE_FLIP_VERTICAL, true }, /* LEFT_TOP */
65 { IMAGE_ROTATION_90, IMAGE_FLIP_NONE, true }, /* RIGHT_TOP */
66 { IMAGE_ROTATION_90, IMAGE_FLIP_HORIZONTAL, true }, /* RIGHT_BOTTOM */
67 { IMAGE_ROTATION_270, IMAGE_FLIP_NONE, true } /* LEFT_BOTTOM */
70 Tizen::Base::ByteBuffer*
71 _ImageDecoder::DecodeToBufferN(const Tizen::Base::String& filePath,
72 MediaPixelFormat pixelFormat, int &width, int &height, bool autoRotate)
76 std::unique_ptr<ByteBuffer> pBuf;
79 SysTryReturn(NID_MEDIA, filePath.GetLength() > 0 && filePath.GetLength() <= PATH_MAX, null, E_INVALID_ARG,
80 "[E_INVALID_ARG] Given filePath length is zero or exceeds system limitations Length = %d.",filePath.GetLength());
81 SysTryReturn(NID_MEDIA, File::IsFileExist(filePath), null, E_FILE_NOT_FOUND,
82 "[E_FILE_NOT_FOUND] filePath:%ls", filePath.GetPointer());
84 r = dec.Construct(filePath, pixelFormat, IMG_FORMAT_NONE, autoRotate);
85 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r,
86 "[%s] Decoder construct failed.", GetErrorMessage(r));
88 // Reset decoder output demension
89 pBuf.reset(dec.DecodeN());
91 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
93 r = dec.GetDimension(width, height);
94 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
96 SetLastResult(E_SUCCESS);
97 return pBuf.release();
100 Tizen::Base::ByteBuffer*
101 _ImageDecoder::DecodeRegionToBufferN(const Tizen::Base::String& filePath,
102 MediaPixelFormat pixelFormat, int x, int y, int width, int height)
104 result r = E_SUCCESS;
108 std::unique_ptr<ByteBuffer> pBuf;
110 r = dec.Construct(filePath, pixelFormat);
111 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] dec.Construct", GetErrorMessage(r));
112 r = dec.GetDimension(imgWidth, imgHeight);
113 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] dec.GetDimension", GetErrorMessage(r));
115 SysTryReturn(NID_MEDIA, imgWidth >= (x + width) && imgHeight >= (y + height),
117 "[E_INVALID_ARG] Bottom left point of region (%d, %d) should lie within dimensions of image (%d x %d)",
118 x, y, width, height, imgWidth, imgHeight);
120 r = dec.SetDecodingRegion(x, y, width, height);
121 SysTryReturn(NID_MEDIA, r == E_SUCCESS || r == E_UNSUPPORTED_OPERATION, null, r,
122 "[%s] dec.SetDecodingRegion failed for region (%d, %d) (%d x %d)",
123 GetErrorMessage(r), x, y, width, height);
127 pBuf.reset(dec.DecodeN());
128 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
130 else // E_UNSUPPORTED_OPERATION
133 ByteBuffer *pTmpBuf = null;
135 pBuf.reset(dec.DecodeN());
137 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
138 pTmpBuf = _ImageUtil::CropN(*pBuf.get(), pixelFormat, imgWidth, imgHeight, x, y, width, height);
139 SysTryReturn(NID_MEDIA, pTmpBuf != null, null, GetLastResult(),
140 "[%s] Crop failed for buffer(%x), pixelFormat(%d), image size(%dx%d), region(%d,%d), (%dx%d)",
141 GetErrorMessage(GetLastResult()), pBuf->GetPointer(), pixelFormat, imgWidth,
142 imgHeight, x, y, width, height);
146 SetLastResult(E_SUCCESS);
147 return pBuf.release();
150 Tizen::Base::ByteBuffer*
151 _ImageDecoder::DecodeRegionToBufferN(const Tizen::Base::ByteBuffer& srcBuf, MediaPixelFormat pixelFormat,
152 int x, int y, int width, int height)
154 result r = E_SUCCESS;
158 std::unique_ptr<ByteBuffer> pBuf;
160 r = dec.Construct(srcBuf, pixelFormat);
161 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] dec.Construct", GetErrorMessage(r));
162 r = dec.GetDimension(imgWidth, imgHeight);
163 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] dec.GetDimension", GetErrorMessage(r));
165 SysTryReturn(NID_MEDIA, imgWidth >= (x + width) && imgHeight >= (y + height),
167 "[E_INVALID_ARG] Bottom left point of region (%d, %d) should lie within dimensions of image (%d x %d)",
168 x, y, width, height, imgWidth, imgHeight);
170 r = dec.SetDecodingRegion(x, y, width, height);
171 SysTryReturn(NID_MEDIA, r == E_SUCCESS || r == E_UNSUPPORTED_OPERATION, null, r,
172 "[%s] dec.SetDecodingRegion failed for region (%d, %d) (%d x %d)",
173 GetErrorMessage(r), x, y, width, height);
177 pBuf.reset(dec.DecodeN());
178 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
180 else // E_UNSUPPORTED_OPERATION
183 ByteBuffer *pTmpBuf = null;
184 pBuf.reset(dec.DecodeN());
186 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
187 pTmpBuf = _ImageUtil::CropN(*pBuf.get(), pixelFormat, imgWidth, imgHeight, x, y, width, height);
188 SysTryReturn(NID_MEDIA, pTmpBuf != null, null, GetLastResult(),
189 "[%s] Crop failed for buffer(%x), pixelFormat(%d), image size(%dx%d), region(%d,%d), (%dx%d)",
190 GetErrorMessage(GetLastResult()), pBuf->GetPointer(), pixelFormat, imgWidth,
191 imgHeight, x, y, width, height);
195 SetLastResult(E_SUCCESS);
196 return pBuf.release();
200 _ImageDecoder::GetImageInfo(const Tizen::Base::String& filePath, ImageFormat &imgFormat,
201 int &width, int &height)
203 result r = E_SUCCESS;
206 r = dec.Construct(filePath);
207 SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] dec.Construct", GetErrorMessage(r));
208 imgFormat = dec.GetImageFormat();
209 r = dec.GetDimension(width, height);
210 SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] dec.GetDimension", GetErrorMessage(r));
216 _ImageDecoder::_ImageDecoder(void)
219 __imgFormat = IMG_FORMAT_NONE;
220 __pixelFormat = MEDIA_PIXEL_FORMAT_NONE;
226 __autoRotate = false;
227 __orientationInfo = 0;
230 _ImageDecoder::~_ImageDecoder(void)
235 _ImageDecoder::CreateDecoderN(ImageFormat srcFormat)
237 result r = E_SUCCESS;
238 std::unique_ptr<_IImageDecoder> pDec;
243 pDec.reset( new (std::nothrow) _JpegTurboDecoder());
247 pDec.reset( new (std::nothrow) _PngDecoder());
251 pDec.reset( new (std::nothrow) _GifDecoder());
255 pDec.reset( new (std::nothrow) _BmpDecoder());
258 case IMG_FORMAT_TIFF:
259 pDec.reset( new (std::nothrow) _TiffDecoder());
262 case IMG_FORMAT_WBMP:
263 pDec.reset( new (std::nothrow) _WbmpDecoder());
267 r = E_UNSUPPORTED_FORMAT;
271 //__imageFormat = srcFormat;
272 if (pDec.get() == null && r == E_SUCCESS)
277 return pDec.release();
282 _ImageDecoder::Construct(const Tizen::Base::String& srcPath,
283 MediaPixelFormat pixelFormat,
284 ImageFormat imgFormat, bool autoRotate)
286 result r = E_SUCCESS;
287 std::unique_ptr<ByteBuffer> pBuf;
290 pBuf.reset(_MediaUtil::FileToBufferN(srcPath));
291 SysTryReturn(NID_MEDIA, pBuf.get() != null, GetLastResult(), GetLastResult(),
292 "[%s] Propagated.", GetErrorMessage(GetLastResult()));
294 r = Construct(*pBuf.get(), pixelFormat, imgFormat);
295 SysTryReturn(NID_MEDIA, r == E_SUCCESS, r, r, "[%s] Propagated.", GetErrorMessage(r));
297 if (autoRotate == true)
301 imgExif.Construct(pBuf->GetPointer(), pBuf->GetCapacity());
302 imgExif.GetValue(EXIF_TAG_IMAGE_ORIENTATION, __orientationInfo);
303 // imgExif.GetValue() will return "r = E_OBJ_NOT_FOUND" if it could not be found exif infomation.
304 // However, the result should be decided by result of construct in this function.
305 SetLastResult(E_SUCCESS);
311 _ImageDecoder::Construct(const Tizen::Base::ByteBuffer& srcBuf,
312 MediaPixelFormat pixelFormat,
313 ImageFormat imgFormat)
315 result r = E_SUCCESS;
317 SysTryReturnResult(NID_MEDIA, __pDec.get() == null, E_INVALID_STATE, "Already constructed");
318 SysTryCatch(NID_MEDIA,
319 (pixelFormat == MEDIA_PIXEL_FORMAT_RGB565LE)|| (pixelFormat == MEDIA_PIXEL_FORMAT_BGRA8888) ||
320 (pixelFormat == MEDIA_PIXEL_FORMAT_RGBA8888), r = E_INVALID_ARG, E_INVALID_ARG,
321 "[E_INVALID_ARG] pixelFormat:%d", pixelFormat);
323 SysTryCatch(NID_MEDIA, &srcBuf != null && srcBuf.GetCapacity() > 0,
324 r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND,
325 "[E_OBJ_NOT_FOUND] buf:0x%x, %d", &srcBuf, &srcBuf ? srcBuf.GetCapacity() : 0);
327 __pixelFormat = pixelFormat;
329 __pSrcBuf.reset(new (std::nothrow) ByteBuffer());
330 SysTryCatch(NID_MEDIA, __pSrcBuf.get() != null, , r, "[%s] Propagated.", GetErrorMessage(r));
331 r = __pSrcBuf->Construct(srcBuf);
332 SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Propagated.", GetErrorMessage(r));
334 __imgFormat = _ImageUtil::GetImageFormat(srcBuf);
336 SysTryCatch(NID_MEDIA,
337 (__imgFormat > IMG_FORMAT_NONE) && (__imgFormat <= IMG_FORMAT_WBMP),
338 r = E_UNSUPPORTED_FORMAT, E_UNSUPPORTED_FORMAT, "[%s] Propagated.",
339 GetErrorMessage(GetLastResult()));
342 __pDec.reset(CreateDecoderN(__imgFormat));
343 SysTryCatch(NID_MEDIA, __pDec.get() != null, r = GetLastResult(), r,
344 "[%s] Could not create decoder for image format %d.",
345 GetErrorMessage(r), __imgFormat);
347 // Decoder construction
348 r = __pDec->Construct((byte*) __pSrcBuf->GetPointer(), __pSrcBuf->GetCapacity(), pixelFormat);
349 SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Propagated.", GetErrorMessage(r));
351 // Get original dimension
352 r = __pDec->GetDimension(__orgDim.width, __orgDim.height);
353 SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Propagated.", GetErrorMessage(r));
354 __outDim.width = __orgDim.width;
355 __outDim.height = __orgDim.height;
362 _ImageDecoder::DecodeN(int& outLength, ImageScalingMethod scalingMethod)
364 result r = E_SUCCESS;
366 std::unique_ptr<byte[]> pOutBuf;
367 std::unique_ptr<byte[]> pRawBuf;
368 std::unique_ptr<byte[]> pDstBuf;
369 SysTryReturn(NID_MEDIA, __pDec.get() != null, null, E_INVALID_STATE, "Not yet constructed");
372 pRawBuf.reset(__pDec->DecodeN(rawLength));
373 SysTryReturn(NID_MEDIA, pRawBuf.get() != null, null, GetLastResult(),
374 "[%s] buffer is null (%x), buffer length is %d.",
375 GetErrorMessage(GetLastResult()),pRawBuf.get(), rawLength);
377 // Get working dimension
378 if ((__outDim.width == 0) && (__outDim.height == 0))
380 __outDim.width = __orgDim.width;
381 __outDim.height = __orgDim.height;
384 // if no need to convert.
385 if ((__pDec->GetPixelFormat() == __pixelFormat)
386 && (__orgDim.width == __outDim.width)
387 && (__orgDim.height == __outDim.height))
389 pOutBuf.swap(pRawBuf);
390 outLength = rawLength;
396 // Converter construction
397 r = cvt.Construct(__pDec->GetPixelFormat(), __orgDim.width, __orgDim.height,
398 __pixelFormat, __outDim.width, __outDim.height, scalingMethod);
399 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
401 // Convert to output format
402 pOutBuf.reset(cvt.ConvertN(pRawBuf.get(), rawLength, outLength));
404 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
407 if (__autoRotate == true)
412 if (__orientationInfo == EXIF_ORIENTATION_TOP_LEFT || __orientationInfo == 0)
414 SetLastResult(E_SUCCESS);
415 return pOutBuf.release();
418 if (__orientationInfo > EXIF_ORIENTATION_LEFT_BOTTOM || __orientationInfo < EXIF_ORIENTATION_TOP_LEFT)
420 SetLastResult(E_SUCCESS);
421 return pOutBuf.release();
424 pDstBuf.reset(new (std::nothrow) byte[outLength]);
425 SysTryReturn(NID_MEDIA, pDstBuf.get() != null, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY]");
427 ImageRotationType rotateType = _IMAGE_ROTATE_FLIP_MAP[__orientationInfo].rotateType;
428 ImageFlipType flipType = _IMAGE_ROTATE_FLIP_MAP[__orientationInfo].flipType;
430 pDstBuf.reset(_ImageUtil::RotateN(pOutBuf.get(), __pixelFormat, __outDim.width, __outDim.height, rotateType, dstWidth, dstHeight));
432 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] _ImageUtil:Resize", GetErrorMessage(r));
434 __outDim.width = dstWidth;
435 __outDim.height = dstHeight;
437 pOutBuf.swap(pDstBuf);
438 if (flipType != IMAGE_FLIP_NONE)
440 pDstBuf.reset(_ImageUtil::FlipN(pOutBuf.get(), __pixelFormat, __outDim.width, __outDim.height, flipType));
442 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] _ImageUtil:Flip", GetErrorMessage(r));
444 pOutBuf.swap(pDstBuf);
447 SetLastResult(E_SUCCESS);
448 return pOutBuf.release();
451 // TODO: Change return type to ByteBuffer*
453 Tizen::Base::ByteBuffer*
454 _ImageDecoder::DecodeN(void)
456 result r = E_SUCCESS;
458 std::unique_ptr<byte[]> pTmpBuf;
459 std::unique_ptr<ByteBuffer> pByteBuf(new (std::nothrow) ByteBuffer());
461 SysTryReturn(NID_MEDIA, __pDec.get() != null, null, E_INVALID_STATE, "Not yet constructed");
463 pTmpBuf.reset(DecodeN(outLength));
464 SysTryReturn(NID_MEDIA, pTmpBuf.get() != null, null, GetLastResult(), "[%s] Propagated.", GetErrorMessage(GetLastResult()));
466 r = pByteBuf->Construct(outLength);
467 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r,
468 "[%s] Propagated. Could not construct Bytebuffer of size %d",
469 GetErrorMessage(r), outLength);
471 r = pByteBuf->SetArray((byte*) pTmpBuf.get(), 0, outLength);
472 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
475 SetLastResult(E_SUCCESS);
476 return pByteBuf.release();
480 _ImageDecoder::GetImageFormat(void) const
486 _ImageDecoder::SetDecodingRegion(int x, int y, int width, int height)
488 SysTryReturnResult(NID_MEDIA, __pDec.get() != null, E_INVALID_STATE, "Not yet constructed");
489 result r = E_SUCCESS;
491 r = __pDec->SetDecodingRegion(x, y, width, height);
494 __outDim.width = width;
495 __outDim.height = height;
496 __orgDim.width = width;
497 __orgDim.height = height;
503 _ImageDecoder::GetDimension(int &width, int &height) const
505 SysTryReturnResult(NID_MEDIA, __pDec.get() != null, E_INVALID_STATE, "Not yet constructed");
507 width = __outDim.width;
508 height = __outDim.height;
514 _ImageDecoder::GetPixelFormat(void) const
516 return __pixelFormat;
520 _ImageDecoder::SetOutputDimension(int width, int height, bool keepAspectRatio)
522 if (width == 0 || height == 0 || __orgDim.width == 0 ||
523 __orgDim.height == 0 || keepAspectRatio == false)
525 __outDim.width = width;
526 __outDim.height = height;
528 else // keep aspect ratio
530 double xRatio = Integer(width).ToDouble() / Integer(__orgDim.width).ToDouble();
531 double yRatio = Integer(height).ToDouble() / Integer(__orgDim.height).ToDouble();
532 if (xRatio >= 1.0 || yRatio >= 1.0)
534 __outDim.width = __orgDim.width;
535 __outDim.height = __orgDim.height;
537 else if (xRatio < yRatio)
539 __outDim.width = (int)(__orgDim.width * yRatio);
540 __outDim.height = height;
544 __outDim.width = width;
545 __outDim.height = (int)(__orgDim.height*xRatio);