merge with master
[framework/osp/image-core.git] / src / FMedia_ImageDecoder.cpp
index c67f59c..a6499bc 100644 (file)
@@ -23,7 +23,6 @@
 #include <unique_ptr.h>
 #include <FBaseColArrayListT.h>
 #include <FBaseSysLog.h>
-#include <FMediaImageTypes.h>
 #include <FBaseInteger.h>
 #include <FIoFile.h>
 #include <FMediaImageTypes.h>
@@ -38,6 +37,7 @@
 #include "FMedia_TiffDecoder.h"
 #include "FMedia_WbmpDecoder.h"
 #include "FMedia_ImageUtil.h"
+#include "FMedia_ExifUtil.h"
 
 using namespace Tizen::Base;
 using namespace Tizen::Io;
@@ -49,11 +49,30 @@ namespace Tizen { namespace Media
        ((x == MEDIA_PIXEL_FORMAT_RGB565LE) || (x == MEDIA_PIXEL_FORMAT_BGRA8888) \
         || (x == MEDIA_PIXEL_FORMAT_RGBA8888))
 
+typedef struct {
+       ImageRotationType rotateType;
+       ImageFlipType flipType;
+       bool dimensionSwitch;
+} _ImageExifInfo;
+
+static const _ImageExifInfo _IMAGE_ROTATE_FLIP_MAP[] = {
+       { IMAGE_ROTATION_0,   IMAGE_FLIP_NONE,       false }, /* NONE         */
+       { IMAGE_ROTATION_0,   IMAGE_FLIP_NONE,       false }, /* TOP_LEFT     */
+       { IMAGE_ROTATION_0,   IMAGE_FLIP_VERTICAL,   false }, /* TOP_RIGHT    */
+       { IMAGE_ROTATION_180, IMAGE_FLIP_NONE,       false }, /* BOTTOM_RIGHT */
+       { IMAGE_ROTATION_0,   IMAGE_FLIP_HORIZONTAL, false }, /* BOTTOM_LEFT  */
+       { IMAGE_ROTATION_90,  IMAGE_FLIP_VERTICAL,   true  }, /* LEFT_TOP     */
+       { IMAGE_ROTATION_90,  IMAGE_FLIP_NONE,       true  }, /* RIGHT_TOP    */
+       { IMAGE_ROTATION_90,  IMAGE_FLIP_HORIZONTAL, true  }, /* RIGHT_BOTTOM */
+       { IMAGE_ROTATION_270, IMAGE_FLIP_NONE,       true  }  /* LEFT_BOTTOM  */
+};
+
 Tizen::Base::ByteBuffer*
 _ImageDecoder::DecodeToBufferN(const Tizen::Base::String& filePath,
-                               MediaPixelFormat pixelFormat, int &width, int &height)
+                               MediaPixelFormat pixelFormat, int &width, int &height, bool autoRotate)
 {
        result r = E_SUCCESS;
+
        std::unique_ptr<ByteBuffer> pBuf;
        _ImageDecoder dec;
 
@@ -62,7 +81,7 @@ _ImageDecoder::DecodeToBufferN(const Tizen::Base::String& filePath,
        SysTryReturn(NID_MEDIA, File::IsFileExist(filePath), null, E_FILE_NOT_FOUND,
                                "[E_FILE_NOT_FOUND] filePath:%ls", filePath.GetPointer());
 
-       r = dec.Construct(filePath, pixelFormat);
+       r = dec.Construct(filePath, pixelFormat, IMG_FORMAT_NONE, autoRotate);
        SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r,
                "[%s] Decoder construct failed.", GetErrorMessage(r));
 
@@ -204,6 +223,8 @@ _ImageDecoder::_ImageDecoder(void)
        __outDim.width = 0;
        __outDim.height = 0;
        __pSrcBuf = null;
+       __autoRotate = false;
+       __orientationInfo = 0;
 }
 
 _ImageDecoder::~_ImageDecoder(void)
@@ -260,7 +281,7 @@ _ImageDecoder::CreateDecoderN(ImageFormat srcFormat)
 result
 _ImageDecoder::Construct(const Tizen::Base::String& srcPath,
                                                 MediaPixelFormat pixelFormat,
-                                                ImageFormat imgFormat)
+                                                ImageFormat imgFormat, bool autoRotate)
 {
        result r = E_SUCCESS;
        std::unique_ptr<ByteBuffer> pBuf;
@@ -272,6 +293,17 @@ _ImageDecoder::Construct(const Tizen::Base::String& srcPath,
 
        r = Construct(*pBuf.get(), pixelFormat, imgFormat);
        SysTryReturn(NID_MEDIA, r == E_SUCCESS, r, r, "[%s] Propagated.", GetErrorMessage(r));
+
+       if (autoRotate == true)
+       {
+               __autoRotate = true;
+               _ExifUtil imgExif;
+               imgExif.Construct(pBuf->GetPointer(), pBuf->GetCapacity());
+               imgExif.GetValue(EXIF_TAG_IMAGE_ORIENTATION, __orientationInfo);
+               // imgExif.GetValue() will return "r = E_OBJ_NOT_FOUND" if it could not be found exif infomation.
+               // However, the result should be decided by result of construct in this function.
+               SetLastResult(E_SUCCESS);
+       }
        return r;
 }
 
@@ -283,7 +315,7 @@ _ImageDecoder::Construct(const Tizen::Base::ByteBuffer& srcBuf,
        result r = E_SUCCESS;
 
        SysTryReturnResult(NID_MEDIA, __pDec.get() == null, E_INVALID_STATE, "Already constructed");
-       SysTryCatch(NID_MEDIA, 
+       SysTryCatch(NID_MEDIA,
                (pixelFormat == MEDIA_PIXEL_FORMAT_RGB565LE)|| (pixelFormat == MEDIA_PIXEL_FORMAT_BGRA8888) ||
                (pixelFormat == MEDIA_PIXEL_FORMAT_RGBA8888), r = E_INVALID_ARG, E_INVALID_ARG,
                "[E_INVALID_ARG] pixelFormat:%d", pixelFormat);
@@ -327,18 +359,19 @@ CATCH:
 }
 
 byte*
-_ImageDecoder::DecodeN(int& outLength)
+_ImageDecoder::DecodeN(int& outLength, ImageScalingMethod scalingMethod)
 {
        result r = E_SUCCESS;
        int rawLength = 0;
-       byte* outBuf = null;
+       std::unique_ptr<byte[]> pOutBuf;
        std::unique_ptr<byte[]> pRawBuf;
+       std::unique_ptr<byte[]> pDstBuf;
        SysTryReturn(NID_MEDIA, __pDec.get() != null, null, E_INVALID_STATE, "Not yet constructed");
 
        // Decode
        pRawBuf.reset(__pDec->DecodeN(rawLength));
        SysTryReturn(NID_MEDIA, pRawBuf.get() != null, null, GetLastResult(),
-               "[%s] buffer is null (%x), buffer length is %d.", 
+               "[%s] buffer is null (%x), buffer length is %d.",
                GetErrorMessage(GetLastResult()),pRawBuf.get(), rawLength);
 
        // Get working dimension
@@ -353,7 +386,7 @@ _ImageDecoder::DecodeN(int& outLength)
                && (__orgDim.width == __outDim.width)
                && (__orgDim.height == __outDim.height))
        {
-               outBuf = pRawBuf.release();
+               pOutBuf.swap(pRawBuf);
                outLength = rawLength;
        }
        else
@@ -362,16 +395,57 @@ _ImageDecoder::DecodeN(int& outLength)
 
                // Converter construction
                r = cvt.Construct(__pDec->GetPixelFormat(), __orgDim.width, __orgDim.height,
-                                                 __pixelFormat, __outDim.width, __outDim.height);
+                                                 __pixelFormat, __outDim.width, __outDim.height, scalingMethod);
                SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
 
                // Convert to output format
-               outBuf = cvt.ConvertN(pRawBuf.get(), rawLength, outLength);
+               pOutBuf.reset(cvt.ConvertN(pRawBuf.get(), rawLength, outLength));
                r = GetLastResult();
                SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated.", GetErrorMessage(r));
        }
+
+       if (__autoRotate == true)
+       {
+               int dstWidth = 0;
+               int dstHeight = 0;
+
+               if (__orientationInfo == EXIF_ORIENTATION_TOP_LEFT || __orientationInfo == 0)
+               {
+                       SetLastResult(E_SUCCESS);
+                       return pOutBuf.release();
+               }
+
+               if (__orientationInfo > EXIF_ORIENTATION_LEFT_BOTTOM || __orientationInfo  < EXIF_ORIENTATION_TOP_LEFT)
+               {
+                       SetLastResult(E_SUCCESS);
+                       return pOutBuf.release();
+               }
+
+               pDstBuf.reset(new (std::nothrow) byte[outLength]);
+               SysTryReturn(NID_MEDIA, pDstBuf.get() != null, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY]");
+
+               ImageRotationType rotateType = _IMAGE_ROTATE_FLIP_MAP[__orientationInfo].rotateType;
+               ImageFlipType flipType = _IMAGE_ROTATE_FLIP_MAP[__orientationInfo].flipType;
+
+               pDstBuf.reset(_ImageUtil::RotateN(pOutBuf.get(), __pixelFormat, __outDim.width, __outDim.height, rotateType, dstWidth, dstHeight));
+               r = GetLastResult();
+               SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] _ImageUtil:Resize", GetErrorMessage(r));
+
+               __outDim.width = dstWidth;
+               __outDim.height = dstHeight;
+
+               pOutBuf.swap(pDstBuf);
+               if (flipType != IMAGE_FLIP_NONE)
+               {
+                       pDstBuf.reset(_ImageUtil::FlipN(pOutBuf.get(), __pixelFormat, __outDim.width, __outDim.height, flipType));
+                       r = GetLastResult();
+                       SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] _ImageUtil:Flip", GetErrorMessage(r));
+
+                       pOutBuf.swap(pDstBuf);
+               }
+       }
        SetLastResult(E_SUCCESS);
-       return outBuf;
+       return pOutBuf.release();
 }
 
 // TODO: Change return type to ByteBuffer*