[4.0] ImageVisual API for Orientation Correction 46/158546/1
authorAgnelo Vaz <agnelo.vaz@samsung.com>
Mon, 23 Oct 2017 13:27:17 +0000 (14:27 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 1 Nov 2017 18:10:04 +0000 (18:10 +0000)
Added Property OrientationCorrection which can control if the image should be rotated
to it's Orientation as defined by exif data.

Provided for JPEG images containing the exif data for Orientation.

Limitations:

The image provided will be cached, the orientation of the first cached image will be
used for subsequent images until the cache image is released.

Change-Id: I7627839c143c06dfde63a32eb8171e2205bf18af
Signed-off-by: Adeel Kazmi <adeel.kazmi@samsung.com>
12 files changed:
automated-tests/resources/keyboard-Landscape.jpg [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
dali-toolkit/devel-api/visuals/image-visual-properties-devel.h
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/image/image-visual.h
dali-toolkit/internal/visuals/texture-manager-impl.cpp
dali-toolkit/internal/visuals/texture-manager-impl.h
dali-toolkit/internal/visuals/visual-string-constants.cpp
dali-toolkit/internal/visuals/visual-string-constants.h

diff --git a/automated-tests/resources/keyboard-Landscape.jpg b/automated-tests/resources/keyboard-Landscape.jpg
new file mode 100644 (file)
index 0000000..5bc6f39
Binary files /dev/null and b/automated-tests/resources/keyboard-Landscape.jpg differ
index 24c5c5d..c2161d1 100644 (file)
@@ -60,7 +60,8 @@ int UtcTextureManagerRequestLoad(void)
     FittingMode::SCALE_TO_FILL,
     SamplingMode::BOX_THEN_LINEAR,
     TextureManager::NO_ATLAS,
-    &observer );
+    &observer,
+    true );
 
   const VisualUrl& url = textureManager.GetVisualUrl( textureId );
 
index 1bd6203..3de6688 100644 (file)
@@ -49,6 +49,7 @@ const char* TEST_REMOTE_IMAGE_FILE_NAME = "https://www.tizen.org/sites/all/theme
 const char* TEST_INVALID_FILE_NAME =  TEST_RESOURCE_DIR  "/invalid.jpg";
 const char* TEST_REMOTE_INVALID_FILE_NAME = "https://www.tizen.org/invalid.png";
 const char* TEST_MASK_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/mask.png";
+const char* TEST_ROTATED_IMAGE =  TEST_RESOURCE_DIR  "/keyboard-Landscape.jpg";
 
 
 bool gResourceReadySignalFired = false;
@@ -1720,3 +1721,61 @@ int UtcDaliImageVisualLoadPolicy03(void)
 
   END_TEST;
 }
+
+int UtcDaliImageVisualOrientationCorrection(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualOrientationCorrection Enabling OrientationCorrection should rotate an image with exif (90deg) orientation data with requested" );
+
+  VisualFactory factory = VisualFactory::Get();
+  tet_infoline( "Create visual with Orientation correction set OFF" );
+  Property::Map propertyMap;
+  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_ROTATED_IMAGE );
+  propertyMap.Insert( DevelImageVisual::Property::ORIENTATION_CORRECTION, false );
+  Visual::Base imageVisual = factory.CreateVisual( propertyMap );
+
+  tet_infoline( "Create control for visual, need to loaded it" );
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  Stage::GetCurrent().Add( actor );
+
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual );
+  // Wait for image to load
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  Vector2 originalImageSize;
+  tet_infoline( "Get size of original visual to compare later with rotated image" );
+  imageVisual.GetNaturalSize( originalImageSize );
+  DALI_TEST_GREATER( originalImageSize.width, originalImageSize.height, TEST_LOCATION ); // Width and Height must be different for this test.
+  imageVisual.Reset();  // remove handle so can unregister it and remove from cache
+  dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL );
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Create visual with Orientation correction set ON " );
+  propertyMap.Clear();
+  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_ROTATED_IMAGE );
+  propertyMap.Insert( DevelImageVisual::Property::ORIENTATION_CORRECTION, true );
+  imageVisual = factory.CreateVisual( propertyMap );
+
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual );
+  // Wait for image to load
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  Vector2 rotatedImageSize;
+  imageVisual.GetNaturalSize( rotatedImageSize );
+  tet_infoline( "Confirm that visual has rotated" );
+  DALI_TEST_EQUALS( originalImageSize.width, rotatedImageSize.height , TEST_LOCATION );
+  DALI_TEST_EQUALS( originalImageSize.height, rotatedImageSize.width , TEST_LOCATION );
+
+  Property::Map resultMap;
+  imageVisual.CreatePropertyMap( resultMap );
+
+  // check the Property::ORIENTATION_CORRECTION value from the returned map
+  Property::Value* typeValue = resultMap.Find( DevelImageVisual::Property::ORIENTATION_CORRECTION,  Property::BOOLEAN );
+  DALI_TEST_EQUALS( typeValue->Get<bool>(), true, TEST_LOCATION );
+
+  END_TEST;
+}
index e37d712..acb9b11 100644 (file)
@@ -105,6 +105,13 @@ enum Type
    * @see ReleasePolicy::Type
    */
   RELEASE_POLICY = CROP_TO_MASK + 2,
+
+  /**
+   * @brief Determines if image orientation should be corrected so the image displays as it was intended.
+   * @details Name "orientationCorrection", Type Property::BOOLEAN, if true the image's orientation will be corrected.
+   * @note Default true
+   */
+  ORIENTATION_CORRECTION = CROP_TO_MASK + 3,
 };
 
 } //namespace Property
index d60834f..32f2bc0 100644 (file)
@@ -24,6 +24,11 @@ namespace Toolkit
 namespace Internal
 {
 
+namespace
+{
+const bool ENABLE_ORIENTATION_CORRECTION( true );
+} // namespace
+
 FixedImageCache::FixedImageCache(
   TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer,
   unsigned int batchSize )
@@ -100,7 +105,7 @@ void FixedImageCache::LoadBatch()
     mImageUrls[ mUrlIndex ].mTextureId =
       mTextureManager.RequestLoad( url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
                                    SamplingMode::BOX_THEN_LINEAR, TextureManager::NO_ATLAS,
-                                   this );
+                                   this, ENABLE_ORIENTATION_CORRECTION );
     mRequestingLoad = false;
     ++mUrlIndex;
   }
index 8abe059..847e681 100644 (file)
@@ -45,6 +45,9 @@ Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "
 #else
   #define LOG_CACHE
 #endif
+
+const bool ENABLE_ORIENTATION_CORRECTION( true );
+
 }
 
 namespace Dali
@@ -139,7 +142,7 @@ void RollingImageCache::LoadBatch()
     mImageUrls[ imageFrame.mUrlIndex ].mTextureId =
       mTextureManager.RequestLoad( url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
                                    SamplingMode::BOX_THEN_LINEAR, TextureManager::NO_ATLAS,
-                                   this );
+                                   this, ENABLE_ORIENTATION_CORRECTION );
     mRequestingLoad = false;
   }
 
index 9522618..ea3c49c 100644 (file)
@@ -303,7 +303,8 @@ ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, const Image& image )
   mLoadPolicy( DevelImageVisual::LoadPolicy::ATTACHED ),
   mReleasePolicy( DevelImageVisual::ReleasePolicy::DESTROYED ),
   mAttemptAtlasing( false ),
-  mLoading( false )
+  mLoading( false ),
+  mOrientationCorrection( true )
 {
 }
 
@@ -399,6 +400,10 @@ void ImageVisual::DoSetProperties( const Property::Map& propertyMap )
       {
         DoSetProperty( Toolkit::DevelImageVisual::Property::RELEASE_POLICY, keyValue.second );
       }
+      else if( keyValue.first == ORIENTATION_CORRECTION_NAME )
+      {
+        DoSetProperty( Toolkit::DevelImageVisual::Property::ORIENTATION_CORRECTION, keyValue.second );
+      }
     }
   }
 
@@ -406,7 +411,7 @@ void ImageVisual::DoSetProperties( const Property::Map& propertyMap )
   if ( mLoadPolicy == DevelImageVisual::LoadPolicy::IMMEDIATE )
   {
     auto attemptAtlasing = mAttemptAtlasing;
-    LoadTexture( attemptAtlasing, mAtlasRect, mTextures );
+    LoadTexture( attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection );
   }
 }
 
@@ -557,6 +562,16 @@ void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& v
       int loadPolicy;
       Scripting::GetEnumerationProperty( value, LOAD_POLICY_TABLE, LOAD_POLICY_TABLE_COUNT, loadPolicy );
       mLoadPolicy = DevelImageVisual::LoadPolicy::Type( loadPolicy );
+      break;
+    }
+    case Toolkit::DevelImageVisual::Property::ORIENTATION_CORRECTION:
+    {
+      bool orientationCorrection( mOrientationCorrection );
+      if( value.Get( orientationCorrection ) )
+      {
+        mOrientationCorrection = orientationCorrection;
+      }
+      break;
     }
   }
 }
@@ -740,7 +755,7 @@ bool ImageVisual::IsSynchronousResourceLoading() const
   return mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
 }
 
-void ImageVisual::LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& textures )
+void ImageVisual::LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& textures, bool orientationCorrection )
 {
   TextureManager& textureManager = mFactoryCache.GetTextureManager();
 
@@ -757,7 +772,7 @@ void ImageVisual::LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& t
   textures = textureManager.LoadTexture( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode,
                                          mMaskingData, IsSynchronousResourceLoading(), mTextureId,
                                          atlasRect, atlasing, mLoading, mWrapModeU,
-                                         mWrapModeV, textureObserver, atlasUploadObserver, atlasManager );
+                                         mWrapModeV, textureObserver, atlasUploadObserver, atlasManager, mOrientationCorrection );
 }
 
 void ImageVisual::InitializeRenderer()
@@ -769,7 +784,7 @@ void ImageVisual::InitializeRenderer()
 
   if( mTextureId == TextureManager::INVALID_TEXTURE_ID && ! mTextures ) // Only load the texture once
   {
-    LoadTexture( attemptAtlasing, mAtlasRect, mTextures );
+    LoadTexture( attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection );
   }
 
   if( attemptAtlasing ) // Flag needs to be set before creating renderer
@@ -921,7 +936,7 @@ void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const
 
   map.Insert( Toolkit::DevelImageVisual::Property::LOAD_POLICY, mLoadPolicy );
   map.Insert( Toolkit::DevelImageVisual::Property::RELEASE_POLICY, mReleasePolicy );
-
+  map.Insert( Toolkit::DevelImageVisual::Property::ORIENTATION_CORRECTION, mOrientationCorrection );
 }
 
 void ImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
index 87111b7..e485904 100644 (file)
@@ -53,20 +53,21 @@ typedef IntrusivePtr< ImageVisual > ImageVisualPtr;
  *
  * The following properties are optional
  *
- * | %Property Name     | Type              |
- * |--------------------|-------------------|
- * | url                | STRING            |
- * | alphaMaskUrl       | STRING            |
- * | fittingMode        | INTEGER OR STRING |
- * | samplingMode       | INTEGER OR STRING |
- * | desiredWidth       | INTEGER           |
- * | desiredHeight      | INTEGER           |
- * | synchronousLoading | BOOLEAN           |
- * | pixelArea          | VECTOR4           |
- * | wrapModeU          | INTEGER OR STRING |
- * | wrapModeV          | INTEGER OR STRING |
- * | loadPolicy         | INTEGER OR STRING |
- * | releasePolicy      | INTEGER OR STRING |
+ * | %Property Name        | Type              |
+ * |-----------------------|-------------------|
+ * | url                   | STRING            |
+ * | alphaMaskUrl          | STRING            |
+ * | fittingMode           | INTEGER OR STRING |
+ * | samplingMode          | INTEGER OR STRING |
+ * | desiredWidth          | INTEGER           |
+ * | desiredHeight         | INTEGER           |
+ * | synchronousLoading    | BOOLEAN           |
+ * | pixelArea             | VECTOR4           |
+ * | wrapModeU             | INTEGER OR STRING |
+ * | wrapModeV             | INTEGER OR STRING |
+ * | loadPolicy            | INTEGER OR STRING |
+ * | releasePolicy         | INTEGER OR STRING |
+ * | orientationCorrection | BOOLEAN           |
  *
  * where pixelArea is a rectangular area.
  * In its Vector4 value, the first two elements indicate the top-left position of the area,
@@ -273,8 +274,9 @@ private:
    * @param[in, out] atlasing flag if the image has been put in a atlas (true), passing false will not atlas even if possible.
    * @param[out] atlasRect if atlasing is used this the texture area of the image in the atlas.
    * @param[out] textures resulting texture set from the image loading.
+   * @param[in] orientationCorrection flag determines if orientation correction should be performed
    */
-  void LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& textures );
+  void LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& textures, bool orientationCorrection );
 
   /**
    * @brief Initializes the Dali::Renderer from the image url
@@ -355,6 +357,7 @@ private:
   Vector4 mAtlasRect;
   bool mAttemptAtlasing; ///< If true will attempt atlasing, otherwise create unique texture
   bool mLoading;  ///< True if the texture is still loading.
+  bool mOrientationCorrection; ///< true if the image will have it's orientation corrected.
 };
 
 
index e795863..308b1ee 100644 (file)
@@ -108,7 +108,7 @@ TextureSet TextureManager::LoadTexture(
     bool synchronousLoading, TextureManager::TextureId& textureId, Vector4& textureRect,
     bool& atlasingStatus, bool& loadingStatus, Dali::WrapMode::Type wrapModeU,
     Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver,
-    AtlasUploadObserver* atlasObserver, ImageAtlasManagerPtr imageAtlasManager)
+    AtlasUploadObserver* atlasObserver, ImageAtlasManagerPtr imageAtlasManager, bool orientationCorrection )
 {
   TextureSet textureSet;
 
@@ -135,7 +135,7 @@ TextureSet TextureManager::LoadTexture(
     PixelData data;
     if( url.IsValid() )
     {
-      Devel::PixelBuffer pixelBuffer = LoadImageFromFile( url.GetUrl(), desiredSize, fittingMode, samplingMode );
+      Devel::PixelBuffer pixelBuffer = LoadImageFromFile( url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection  );
       if( pixelBuffer )
       {
         data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
@@ -185,7 +185,7 @@ TextureSet TextureManager::LoadTexture(
       atlasingStatus = false;
       if( !maskInfo )
       {
-        textureId = RequestLoad( url, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, textureObserver );
+        textureId = RequestLoad( url, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, textureObserver, orientationCorrection );
       }
       else
       {
@@ -196,7 +196,8 @@ TextureSet TextureManager::LoadTexture(
                                  fittingMode, samplingMode,
                                  TextureManager::NO_ATLAS,
                                  maskInfo->mCropToMask,
-                                 textureObserver );
+                                 textureObserver,
+                                 orientationCorrection);
       }
 
       TextureManager::LoadState loadState = GetTextureState( textureId );
@@ -226,9 +227,10 @@ TextureManager::TextureId TextureManager::RequestLoad(
   FittingMode::Type        fittingMode,
   Dali::SamplingMode::Type samplingMode,
   const UseAtlas           useAtlas,
-  TextureUploadObserver*   observer )
+  TextureUploadObserver*   observer,
+  bool                     orientationCorrection )
 {
-  return RequestLoadInternal( url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas, false, UPLOAD_TO_TEXTURE, observer );
+  return RequestLoadInternal( url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas, false, UPLOAD_TO_TEXTURE, observer, orientationCorrection );
 }
 
 TextureManager::TextureId TextureManager::RequestLoad(
@@ -240,15 +242,16 @@ TextureManager::TextureId TextureManager::RequestLoad(
   Dali::SamplingMode::Type samplingMode,
   const UseAtlas           useAtlas,
   bool                     cropToMask,
-  TextureUploadObserver*   observer )
+  TextureUploadObserver*   observer,
+  bool                     orientationCorrection )
 {
-  return RequestLoadInternal( url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, cropToMask, UPLOAD_TO_TEXTURE, observer );
+  return RequestLoadInternal( url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, cropToMask, UPLOAD_TO_TEXTURE, observer, orientationCorrection );
 }
 
 TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& maskUrl )
 {
   // Use the normal load procedure to get the alpha mask.
-  return RequestLoadInternal( maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, false, KEEP_PIXEL_BUFFER, NULL );
+  return RequestLoadInternal( maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, false, KEEP_PIXEL_BUFFER, NULL, true );
 }
 
 TextureManager::TextureId TextureManager::RequestLoadInternal(
@@ -261,7 +264,8 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
   UseAtlas                 useAtlas,
   bool                     cropToMask,
   StorageType              storageType,
-  TextureUploadObserver*   observer )
+  TextureUploadObserver*   observer,
+  bool                     orientationCorrection )
 {
   // First check if the requested Texture is cached.
   const TextureHash textureHash = GenerateHash( url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId );
@@ -287,7 +291,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
     textureId = GenerateUniqueTextureId();
     mTextureInfoContainer.push_back( TextureInfo( textureId, maskTextureId, url.GetUrl(),
                                                   desiredSize, contentScale, fittingMode, samplingMode,
-                                                  false, cropToMask, useAtlas, textureHash ) );
+                                                  false, cropToMask, useAtlas, textureHash, orientationCorrection ) );
     cacheIndex = mTextureInfoContainer.size() - 1u;
 
     DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId );
@@ -299,6 +303,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
   TextureInfo& textureInfo( mTextureInfoContainer[ cacheIndex ] );
   textureInfo.maskTextureId = maskTextureId;
   textureInfo.storageType = storageType;
+  textureInfo.orientationCorrection = orientationCorrection;
 
   DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureInfo loadState:%s\n",
                  textureInfo.loadState == TextureManager::NOT_STARTED ? "NOT_STARTED" :
@@ -489,7 +494,7 @@ bool TextureManager::LoadTexture( TextureInfo& textureInfo )
       DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End());
       loadingHelperIt->Load(textureInfo.textureId, textureInfo.url,
                             textureInfo.desiredSize, textureInfo.fittingMode,
-                            textureInfo.samplingMode, true);
+                            textureInfo.samplingMode, textureInfo.orientationCorrection );
     }
   }
 
index 7a243fd..7693b1c 100644 (file)
@@ -138,7 +138,8 @@ public:
                          bool& atlasingStatus, bool& loadingStatus, Dali::WrapMode::Type wrapModeU,
                          Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver,
                          AtlasUploadObserver* atlasObserver,
-                         ImageAtlasManagerPtr imageAtlasManager);
+                         ImageAtlasManagerPtr imageAtlasManager,
+                         bool orientationCorrection );
 
   /**
    * @brief Requests an image load of the given URL.
@@ -148,22 +149,24 @@ public:
    *
    * When the client has finished with the Texture, Remove() should be called.
    *
-   * @param[in] url               The URL of the image to load
-   * @param[in] desiredSize       The size the image is likely to appear at. This can be set to 0,0 for automatic
-   * @param[in] fittingMode       The FittingMode to use
-   * @param[in] samplingMode      The SamplingMode to use
-   * @param[in] useAtlasing       Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
-   *                              but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
-   * @param[in] observer          The client object should inherit from this and provide the "UploadCompleted" virtual.
-   *                              This is called when an image load completes (or fails).
-   * @return                      A TextureId to use as a handle to reference this Texture
+   * @param[in] url                   The URL of the image to load
+   * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
+   * @param[in] fittingMode           The FittingMode to use
+   * @param[in] samplingMode          The SamplingMode to use
+   * @param[in] useAtlasing           Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
+   *                                  but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
+   * @param[in] observer              The client object should inherit from this and provide the "UploadCompleted" virtual.
+   *                                  This is called when an image load completes (or fails).
+   * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
+   * @return                          A TextureId to use as a handle to reference this Texture
    */
   TextureId RequestLoad( const VisualUrl&         url,
                          const ImageDimensions    desiredSize,
                          FittingMode::Type        fittingMode,
                          Dali::SamplingMode::Type samplingMode,
                          const UseAtlas           useAtlasing,
-                         TextureUploadObserver*   observer );
+                         TextureUploadObserver*   observer,
+                         bool                     orientationCorrection );
 
   /**
    * @brief Requests an image load of the given URL, when the texture has
@@ -175,18 +178,19 @@ public:
    *
    * When the client has finished with the Texture, Remove() should be called.
    *
-   * @param[in] url               The URL of the image to load
-   * @param[in] maskTextureId     The texture id of an image to mask this with (can be INVALID if no masking required)
-   * @param[in] contentScale      The scale factor to apply to the image before masking
-   * @param[in] desiredSize       The size the image is likely to appear at. This can be set to 0,0 for automatic
-   * @param[in] fittingMode       The FittingMode to use
-   * @param[in] samplingMode      The SamplingMode to use
-   * @param[in] useAtlasing       Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
-   *                              but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
-   * @param[in] cropToMask        Only used with masking, this will crop the scaled image to the mask size. If false, then the mask will be scaled to fit the image before being applied.
-   * @param[in] observer          The client object should inherit from this and provide the "UploadCompleted" virtual.
-   *                              This is called when an image load completes (or fails).
-   * @return                      A TextureId to use as a handle to reference this Texture
+   * @param[in] url                   The URL of the image to load
+   * @param[in] maskTextureId         The texture id of an image to mask this with (can be INVALID if no masking required)
+   * @param[in] contentScale          The scale factor to apply to the image before masking
+   * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
+   * @param[in] fittingMode           The FittingMode to use
+   * @param[in] samplingMode          The SamplingMode to use
+   * @param[in] useAtlasing           Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
+   *                                  but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
+   * @param[in] cropToMask            Only used with masking, this will crop the scaled image to the mask size. If false, then the mask will be scaled to fit the image before being applied.
+   * @param[in] observer              The client object should inherit from this and provide the "UploadCompleted" virtual.
+   *                                  This is called when an image load completes (or fails).
+   * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
+   * @return                          A TextureId to use as a handle to reference this Texture
    */
   TextureId RequestLoad( const VisualUrl&         url,
                          TextureId                maskTextureId,
@@ -196,7 +200,8 @@ public:
                          Dali::SamplingMode::Type samplingMode,
                          const UseAtlas           useAtlasing,
                          bool                     cropToMask,
-                         TextureUploadObserver*   observer );
+                         TextureUploadObserver*   observer,
+                         bool                     orientationCorrection );
 
   /**
    * Requests a masking image to be loaded. This mask is not uploaded to GL,
@@ -260,19 +265,20 @@ private:
    *
    * When the client has finished with the Texture, Remove() should be called.
    *
-   * @param[in] url               The URL of the image to load
-   * @param[in] maskTextureId     The texture id of an image to use as a mask. If no mask is required, then set to INVALID_TEXTURE_ID
-   * @param[in] contentScale      The scaling factor to apply to the content when masking
-   * @param[in] desiredSize       The size the image is likely to appear at. This can be set to 0,0 for automatic
-   * @param[in] fittingMode       The FittingMode to use
-   * @param[in] samplingMode      The SamplingMode to use
-   * @param[in] useAtlasing       Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
-   *                              but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
-   * @param[in] cropToMask        Whether to crop the target after masking, or scale the mask to the image before masking.
-   * @param[in] storageType,      Whether the pixel data is stored in the cache or uploaded to the GPU
-   * @param[in] observer          The client object should inherit from this and provide the "UploadCompleted" virtual.
-   *                              This is called when an image load completes (or fails).
-   * @return                      A TextureId to use as a handle to reference this Texture
+   * @param[in] url                   The URL of the image to load
+   * @param[in] maskTextureId         The texture id of an image to use as a mask. If no mask is required, then set to INVALID_TEXTURE_ID
+   * @param[in] contentScale          The scaling factor to apply to the content when masking
+   * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
+   * @param[in] fittingMode           The FittingMode to use
+   * @param[in] samplingMode          The SamplingMode to use
+   * @param[in] useAtlasing           Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
+   *                                  but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
+   * @param[in] cropToMask            Whether to crop the target after masking, or scale the mask to the image before masking.
+   * @param[in] storageType,          Whether the pixel data is stored in the cache or uploaded to the GPU
+   * @param[in] observer              The client object should inherit from this and provide the "UploadCompleted" virtual.
+   *                                  This is called when an image load completes (or fails).
+   * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
+   * @return                          A TextureId to use as a handle to reference this Texture
    */
   TextureId RequestLoadInternal(
     const VisualUrl&         url,
@@ -284,7 +290,8 @@ private:
     UseAtlas                 useAtlas,
     bool                     cropToMask,
     StorageType              storageType,
-    TextureUploadObserver*   observer );
+    TextureUploadObserver*   observer,
+    bool                     orientationCorrection );
 
 
   typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
@@ -304,7 +311,8 @@ private:
                  bool loadSynchronously,
                  bool cropToMask,
                  UseAtlas useAtlas,
-                 TextureManager::TextureHash hash )
+                 TextureManager::TextureHash hash,
+                 bool orientationCorrection )
     : url( url ),
       desiredSize( desiredSize ),
       useSize( desiredSize ),
@@ -320,7 +328,8 @@ private:
       storageType( UPLOAD_TO_TEXTURE ),
       loadSynchronously( loadSynchronously ),
       useAtlas( useAtlas ),
-      cropToMask( cropToMask )
+      cropToMask( cropToMask ),
+      orientationCorrection( true )
     {
     }
 
@@ -349,6 +358,7 @@ private:
     bool loadSynchronously:1;      ///< True if synchronous loading was requested
     UseAtlas useAtlas:1;           ///< USE_ATLAS if an atlas was requested. This is updated to false if atlas is not used
     bool cropToMask:1;             ///< true if the image should be cropped to the mask size.
+    bool orientationCorrection:1;  ///< true if the image should be rotated to match exif orientation data
   };
 
   // Structs:
index 6282559..e28a910 100644 (file)
@@ -87,6 +87,7 @@ const char * const MASK_CONTENT_SCALE_NAME("maskContentScale");
 const char * const CROP_TO_MASK_NAME("cropToMask");
 const char * const LOAD_POLICY_NAME("loadPolicy");
 const char * const RELEASE_POLICY_NAME("releasePolicy");
+const char * const ORIENTATION_CORRECTION_NAME("orientationCorrection");
 
 // Text visual
 const char * const TEXT_PROPERTY( "text" );
index 27030df..50f809f 100644 (file)
@@ -75,6 +75,7 @@ extern const char * const MASK_CONTENT_SCALE_NAME;
 extern const char * const CROP_TO_MASK_NAME;
 extern const char * const LOAD_POLICY_NAME;
 extern const char * const RELEASE_POLICY_NAME;
+extern const char * const ORIENTATION_CORRECTION_NAME;
 
 // Text visual
 extern const char * const TEXT_PROPERTY;