Merge "Apply EncodedImageBuffer with Atlas" into devel/master
authorDavid Steele <david.steele@samsung.com>
Fri, 13 May 2022 15:43:39 +0000 (15:43 +0000)
committerGerrit Code Review <gerrit@review>
Fri, 13 May 2022 15:43:39 +0000 (15:43 +0000)
automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp
dali-toolkit/internal/image-loader/image-atlas-impl.cpp
dali-toolkit/internal/image-loader/image-atlas-impl.h
dali-toolkit/internal/texture-manager/texture-manager-impl.cpp
dali-toolkit/internal/visuals/image-atlas-manager.cpp
dali-toolkit/internal/visuals/image-atlas-manager.h

index e16e93e..10d6445 100644 (file)
@@ -784,9 +784,25 @@ int UtcDaliImageViewAsyncLoadingEncodedBufferWithAtlasing(void)
   Property::Map imageMap;
 
   imageMap[ImageVisual::Property::URL]            = url.GetUrl();
+  imageMap[ImageVisual::Property::DESIRED_HEIGHT] = 600;
+  imageMap[ImageVisual::Property::DESIRED_WIDTH]  = 600;
+  imageMap[ImageVisual::Property::ATLASING]       = true;
+
+  // No atlasing with big image
+  ImageView imageView_bigdesired = ImageView::New();
+  imageView_bigdesired.SetProperty(ImageView::Property::IMAGE, imageMap);
+  imageView_bigdesired.SetProperty(Toolkit::Control::Property::PADDING, Extents(10u, 10u, 10u, 10u));
+
+  imageMap[ImageVisual::Property::DESIRED_HEIGHT] = 0;
+  imageMap[ImageVisual::Property::DESIRED_WIDTH]  = 0;
+
+  // No atlasing with zero desired size
+  ImageView imageView_nodesired = ImageView::New();
+  imageView_nodesired.SetProperty(ImageView::Property::IMAGE, imageMap);
+  imageView_nodesired.SetProperty(Toolkit::Control::Property::PADDING, Extents(10u, 10u, 10u, 10u));
+
   imageMap[ImageVisual::Property::DESIRED_HEIGHT] = 34;
   imageMap[ImageVisual::Property::DESIRED_WIDTH]  = 34;
-  imageMap[ImageVisual::Property::ATLASING]       = true;
 
   ImageView imageView = ImageView::New();
   imageView.SetProperty(ImageView::Property::IMAGE, imageMap);
@@ -794,10 +810,15 @@ int UtcDaliImageViewAsyncLoadingEncodedBufferWithAtlasing(void)
 
   // By default, Aysnc loading is used
   // loading is not started if the actor is offScene
-
   application.GetScene().Add(imageView);
+  application.GetScene().Add(imageView_bigdesired);
+  application.GetScene().Add(imageView_nodesired);
   application.SendNotification();
   application.Render(16);
+
+  // loading started, this waits for the loader thread for max 30 seconds
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
   application.Render(16);
   application.SendNotification();
 
@@ -848,6 +869,7 @@ int UtcDaliImageViewSyncLoadingEncodedBuffer(void)
     // Sync loading is used
     Property::Map syncLoadingMap;
     syncLoadingMap["url"]                = url.GetUrl();
+    syncLoadingMap["alphaMaskUrl"]       = gImage_34_RGBA;
     syncLoadingMap["desiredHeight"]      = 34;
     syncLoadingMap["desiredWidth"]       = 34;
     syncLoadingMap["synchronousLoading"] = true;
index 31c3351..08b4cd0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,8 +33,6 @@ namespace Toolkit
 {
 namespace Internal
 {
-typedef unsigned char PixelBuffer;
-
 Texture ImageAtlas::PackToAtlas(const std::vector<PixelData>& pixelData, Dali::Vector<Vector4>& textureRects)
 {
   // Record each block size
@@ -68,7 +66,7 @@ Texture ImageAtlas::PackToAtlas(const std::vector<PixelData>& pixelData, Dali::V
 
     // Apply the half pixel correction to avoid the color bleeding between neighbour blocks
     textureRects[index].x = (static_cast<float>(packPositionX) + 0.5f) / atlasWidth;                                 // left
-    textureRects[index].y = (static_cast<float>(packPositionY) + 0.5f) / atlasHeight;                                // right
+    textureRects[index].y = (static_cast<float>(packPositionY) + 0.5f) / atlasHeight;                                // top
     textureRects[index].z = (static_cast<float>(packPositionX + pixelData[index].GetWidth()) - 0.5f) / atlasWidth;   // right
     textureRects[index].w = (static_cast<float>(packPositionY + pixelData[index].GetHeight()) - 0.5f) / atlasHeight; // bottom
   }
@@ -158,15 +156,15 @@ bool ImageAtlas::Upload(Vector4&             textureRect,
     }
   }
 
-  unsigned int packPositionX = 0;
-  unsigned int packPositionY = 0;
+  uint32_t packPositionX = 0;
+  uint32_t packPositionY = 0;
   if(mPacker.Pack(dimensions.GetWidth(), dimensions.GetHeight(), packPositionX, packPositionY))
   {
-    unsigned short loadId = GetImplementation(mAsyncLoader).Load(url, size, fittingMode, SamplingMode::BOX_THEN_LINEAR, orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF);
+    uint32_t loadId = GetImplementation(mAsyncLoader).Load(url, size, fittingMode, SamplingMode::BOX_THEN_LINEAR, orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF);
     mLoadingTaskInfoContainer.PushBack(new LoadingTaskInfo(loadId, packPositionX, packPositionY, dimensions.GetWidth(), dimensions.GetHeight(), atlasUploadObserver));
     // apply the half pixel correction
     textureRect.x = (static_cast<float>(packPositionX) + 0.5f) / mWidth;                      // left
-    textureRect.y = (static_cast<float>(packPositionY) + 0.5f) / mHeight;                     // right
+    textureRect.y = (static_cast<float>(packPositionY) + 0.5f) / mHeight;                     // top
     textureRect.z = (static_cast<float>(packPositionX + dimensions.GetX()) - 0.5f) / mWidth;  // right
     textureRect.w = (static_cast<float>(packPositionY + dimensions.GetY()) - 0.5f) / mHeight; // bottom
 
@@ -183,17 +181,66 @@ bool ImageAtlas::Upload(Vector4&             textureRect,
   return false;
 }
 
+bool ImageAtlas::Upload(Vector4&                  textureRect,
+                        const EncodedImageBuffer& encodedImageBuffer,
+                        ImageDimensions           size,
+                        FittingMode::Type         fittingMode,
+                        bool                      orientationCorrection,
+                        AtlasUploadObserver*      atlasUploadObserver)
+{
+  ImageDimensions zero;
+  if(size == zero) // image size not provided
+  {
+    DALI_LOG_ERROR("Desired size is zero! We need to setup desired size for Atlas.\n");
+    // EncodedImageBuffer didn't support to get closest image size.
+    // Just draw broken image.
+    if(!mBrokenImageUrl.empty())
+    {
+      return Upload(textureRect, mBrokenImageUrl, mBrokenImageSize, FittingMode::DEFAULT, true, atlasUploadObserver);
+    }
+    else
+    {
+      textureRect = Vector4::ZERO;
+      return true;
+    }
+  }
+
+  uint32_t packPositionX = 0;
+  uint32_t packPositionY = 0;
+  if(mPacker.Pack(size.GetWidth(), size.GetHeight(), packPositionX, packPositionY))
+  {
+    uint32_t loadId = GetImplementation(mAsyncLoader).LoadEncodedImageBuffer(encodedImageBuffer, size, fittingMode, SamplingMode::BOX_THEN_LINEAR, orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF);
+    mLoadingTaskInfoContainer.PushBack(new LoadingTaskInfo(loadId, packPositionX, packPositionY, size.GetWidth(), size.GetHeight(), atlasUploadObserver));
+    // apply the half pixel correction
+    textureRect.x = (static_cast<float>(packPositionX) + 0.5f) / mWidth;                // left
+    textureRect.y = (static_cast<float>(packPositionY) + 0.5f) / mHeight;               // top
+    textureRect.z = (static_cast<float>(packPositionX + size.GetX()) - 0.5f) / mWidth;  // right
+    textureRect.w = (static_cast<float>(packPositionY + size.GetY()) - 0.5f) / mHeight; // bottom
+
+    if(atlasUploadObserver)
+    {
+      // register to the observer,
+      // Not that a matching unregister call should be invoked in UploadToAtlas if the observer is still alive by then.
+      atlasUploadObserver->Register(*this);
+    }
+
+    return true;
+  }
+
+  return false;
+}
+
 bool ImageAtlas::Upload(Vector4& textureRect, PixelData pixelData)
 {
-  unsigned int packPositionX = 0;
-  unsigned int packPositionY = 0;
+  uint32_t packPositionX = 0;
+  uint32_t packPositionY = 0;
   if(mPacker.Pack(pixelData.GetWidth(), pixelData.GetHeight(), packPositionX, packPositionY))
   {
     mAtlas.Upload(pixelData, 0u, 0u, packPositionX, packPositionY, pixelData.GetWidth(), pixelData.GetHeight());
 
     // apply the half pixel correction
     textureRect.x = (static_cast<float>(packPositionX) + 0.5f) / mWidth;                          // left
-    textureRect.y = (static_cast<float>(packPositionY) + 0.5f) / mHeight;                         // right
+    textureRect.y = (static_cast<float>(packPositionY) + 0.5f) / mHeight;                         // top
     textureRect.z = (static_cast<float>(packPositionX + pixelData.GetWidth()) - 0.5f) / mWidth;   // right
     textureRect.w = (static_cast<float>(packPositionY + pixelData.GetHeight()) - 0.5f) / mHeight; // bottom
 
@@ -228,7 +275,7 @@ void ImageAtlas::UploadToAtlas(uint32_t id, PixelData pixelData)
 {
   if(mLoadingTaskInfoContainer[0]->loadTaskId == id)
   {
-    Rect<unsigned int> packRect(mLoadingTaskInfoContainer[0]->packRect);
+    Rect<uint32_t> packRect(mLoadingTaskInfoContainer[0]->packRect);
     if(!pixelData || (pixelData.GetWidth() == 0 && pixelData.GetHeight() == 0))
     {
       if(!mBrokenImageUrl.empty()) // replace with the broken image
@@ -260,7 +307,7 @@ void ImageAtlas::UploadToAtlas(uint32_t id, PixelData pixelData)
   }
 }
 
-void ImageAtlas::UploadBrokenImage(const Rect<unsigned int>& area)
+void ImageAtlas::UploadBrokenImage(const Rect<uint32_t>& area)
 {
   Devel::PixelBuffer brokenBuffer = LoadImageFromFile(mBrokenImageUrl, ImageDimensions(area.width, area.height));
   SizeType           loadedWidth  = brokenBuffer.GetWidth();
index eab1551..e302d92 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_IMAGE_ATLAS_IMPL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
 
 // EXTERNAL INCLUDES
 #include <dali/devel-api/common/owner-container.h>
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
 #include <dali/public-api/common/intrusive-ptr.h>
 #include <dali/public-api/object/base-object.h>
 #include <dali/public-api/signals/connection-tracker.h>
@@ -26,8 +27,8 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/image-loader/image-atlas.h>
 #include <dali-toolkit/internal/image-loader/atlas-packer.h>
-#include <dali-toolkit/public-api/image-loader/async-image-loader.h>
 #include <dali-toolkit/internal/visuals/visual-url.h>
+#include <dali-toolkit/public-api/image-loader/async-image-loader.h>
 
 namespace Dali
 {
@@ -86,6 +87,32 @@ public:
               AtlasUploadObserver* atlasUploadObserver);
 
   /**
+   * @brief Upload a resource image to the atlas by encoded buffer.
+   *
+   * @note To make the atlasing efficient, a valid size should be provided.
+   *       If size is not provided, then SegFault occured.
+   *       Do not set a size that is bigger than the actual image size, as the up-scaling is not available,
+   *       the content of the area not covered by actual image is undefined, it will not be cleared.
+   *
+   * SamplingMode::BOX_THEN_LINEAR is used to sampling pixels from the input image while fitting it to desired size.
+   *
+   * @param [out] textureRect The texture area of the resource image in the atlas.
+   * @param [in] encodedImageBuffer The encoded raw buffer of the resource image file to use.
+   * @param [in] size The width and height to fit the loaded image to.
+   * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter.
+   * @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
+   * @param [in] atlasUploadObserver The observer to observe the upload state inside the ImageAtlas.
+   * @return True if there is enough space to fit this image in,false otherwise.
+   * @note The valid callback function here is required to have the signature of void( void ).
+   */
+  bool Upload(Vector4&                  textureRect,
+              const EncodedImageBuffer& encodedImageBuffer,
+              ImageDimensions           size,
+              FittingMode::Type         fittingMode,
+              bool                      orientationCorrection,
+              AtlasUploadObserver*      atlasUploadObserver);
+
+  /**
    * @copydoc Toolkit::ImageAtlas::Upload( Vector4&, PixelData )
    */
   bool Upload(Vector4& textureRect, PixelData pixelData);
@@ -117,7 +144,7 @@ private:
    *
    * @param[in] area The pixel area for uploading.
    */
-  void UploadBrokenImage(const Rect<unsigned int>& area);
+  void UploadBrokenImage(const Rect<uint32_t>& area);
 
   // Undefined
   ImageAtlas(const ImageAtlas& imageAtlas);
@@ -132,11 +159,11 @@ private:
    */
   struct LoadingTaskInfo
   {
-    LoadingTaskInfo(unsigned short       loadTaskId,
-                    unsigned int         packPositionX,
-                    unsigned int         packPositionY,
-                    unsigned int         width,
-                    unsigned int         height,
+    LoadingTaskInfo(uint32_t             loadTaskId,
+                    uint32_t             packPositionX,
+                    uint32_t             packPositionY,
+                    uint32_t             width,
+                    uint32_t             height,
                     AtlasUploadObserver* observer)
     : loadTaskId(loadTaskId),
       packRect(packPositionX, packPositionY, width, height),
@@ -144,8 +171,8 @@ private:
     {
     }
 
-    unsigned short       loadTaskId;
-    Rect<unsigned int>   packRect;
+    uint32_t             loadTaskId;
+    Rect<uint32_t>       packRect;
     AtlasUploadObserver* observer;
   };
 
index 6ace549..5b7597e 100644 (file)
@@ -305,43 +305,48 @@ TextureSet TextureManager::LoadTexture(
   else
   {
     // For Atlas
-    if(synchronousLoading && atlasingStatus && imageAtlasManager->CheckAtlasAvailable(url, desiredSize))
+    if(synchronousLoading && atlasingStatus)
     {
-      Devel::PixelBuffer pixelBuffer = LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection);
-
-      if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
+      const bool synchronousAtlasAvaliable = (desiredSize != ImageDimensions() || url.IsLocalResource()) ? imageAtlasManager->CheckAtlasAvailable(url, desiredSize)
+                                                                                                         : false;
+      if(synchronousAtlasAvaliable)
       {
-        Devel::PixelBuffer maskPixelBuffer = LoadImageSynchronously(maskInfo->mAlphaMaskUrl.GetUrl(), ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true);
-        if(maskPixelBuffer)
+        Devel::PixelBuffer pixelBuffer = LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection);
+
+        if(pixelBuffer && maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
         {
-          pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask);
+          Devel::PixelBuffer maskPixelBuffer = LoadImageSynchronously(maskInfo->mAlphaMaskUrl, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true);
+          if(maskPixelBuffer)
+          {
+            pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask);
+          }
         }
-      }
-
-      PixelData data;
-      if(pixelBuffer)
-      {
-        PreMultiply(pixelBuffer, preMultiplyOnLoad);
-        data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
 
-        if(data)
+        PixelData data;
+        if(pixelBuffer)
         {
-          textureSet = imageAtlasManager->Add(textureRect, data);
-          if(textureSet)
+          PreMultiply(pixelBuffer, preMultiplyOnLoad);
+          data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
+
+          if(data)
+          {
+            textureSet = imageAtlasManager->Add(textureRect, data);
+            if(textureSet)
+            {
+              textureRectSize.SetWidth(data.GetWidth());
+              textureRectSize.SetHeight(data.GetHeight());
+            }
+          }
+          else
           {
-            textureRectSize.SetWidth(data.GetWidth());
-            textureRectSize.SetHeight(data.GetHeight());
+            DALI_LOG_ERROR("TextureManager::LoadTexture: Synchronous Texture loading with atlasing is failed.\n");
           }
         }
-        else
+        if(!textureSet)
         {
-          DALI_LOG_ERROR("TextureManager::LoadTexture: Synchronous Texture loading with atlasing is failed.\n");
+          atlasingStatus = false;
         }
       }
-      if(!textureSet)
-      {
-        atlasingStatus = false;
-      }
     }
 
     if(!textureSet)
@@ -353,7 +358,18 @@ TextureSet TextureManager::LoadTexture(
       Dali::ImageDimensions atlasDesiredSize = desiredSize;
       if(atlasingStatus)
       {
-        textureSet = imageAtlasManager->Add(textureRect, url.GetUrl(), atlasDesiredSize, fittingMode, true, atlasObserver);
+        if(url.IsBufferResource())
+        {
+          const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(url.GetUrl());
+          if(encodedImageBuffer)
+          {
+            textureSet = imageAtlasManager->Add(textureRect, encodedImageBuffer, desiredSize, fittingMode, true, atlasObserver);
+          }
+        }
+        else
+        {
+          textureSet = imageAtlasManager->Add(textureRect, url, atlasDesiredSize, fittingMode, true, atlasObserver);
+        }
       }
       if(!textureSet) // big image, no atlasing or atlasing failed
       {
index 577a433..25fff39 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -84,7 +84,7 @@ TextureSet ImageAtlasManager::Add(Vector4&             textureRect,
   }
   size = dimensions;
 
-  unsigned int i = 0;
+  uint32_t i = 0;
   for(AtlasContainer::iterator iter = mAtlasList.begin(); iter != mAtlasList.end(); ++iter)
   {
     if(GetImplementation(*iter).Upload(textureRect, url, size, fittingMode, orientationCorrection, atlasUploadObserver))
@@ -99,6 +99,34 @@ TextureSet ImageAtlasManager::Add(Vector4&             textureRect,
   return mTextureSetList.back();
 }
 
+TextureSet ImageAtlasManager::Add(Vector4&                  textureRect,
+                                  const EncodedImageBuffer& encodedImageBuffer,
+                                  const ImageDimensions&    size,
+                                  FittingMode::Type         fittingMode,
+                                  bool                      orientationCorrection,
+                                  AtlasUploadObserver*      atlasUploadObserver)
+{
+  // big image, atlasing is not applied
+  if(static_cast<uint32_t>(size.GetWidth()) * static_cast<uint32_t>(size.GetHeight()) > MAX_ITEM_AREA || size.GetWidth() > DEFAULT_ATLAS_SIZE || size.GetHeight() > DEFAULT_ATLAS_SIZE)
+  {
+    return TextureSet();
+  }
+
+  uint32_t i = 0;
+  for(AtlasContainer::iterator iter = mAtlasList.begin(); iter != mAtlasList.end(); ++iter)
+  {
+    if(GetImplementation(*iter).Upload(textureRect, encodedImageBuffer, size, fittingMode, orientationCorrection, atlasUploadObserver))
+    {
+      return mTextureSetList[i];
+    }
+    i++;
+  }
+
+  CreateNewAtlas();
+  GetImplementation(mAtlasList.back()).Upload(textureRect, encodedImageBuffer, size, fittingMode, orientationCorrection, atlasUploadObserver);
+  return mTextureSetList.back();
+}
+
 TextureSet ImageAtlasManager::Add(Vector4&  textureRect,
                                   PixelData pixelData)
 {
@@ -108,7 +136,7 @@ TextureSet ImageAtlasManager::Add(Vector4&  textureRect,
     return TextureSet();
   }
 
-  unsigned int i = 0;
+  uint32_t i = 0;
   for(AtlasContainer::iterator iter = mAtlasList.begin(); iter != mAtlasList.end(); ++iter)
   {
     if((*iter).Upload(textureRect, pixelData))
@@ -125,7 +153,7 @@ TextureSet ImageAtlasManager::Add(Vector4&  textureRect,
 
 void ImageAtlasManager::Remove(TextureSet textureSet, const Vector4& textureRect)
 {
-  unsigned int i = 0;
+  uint32_t i = 0;
   for(TextureSetContainer::iterator iter = mTextureSetList.begin(); iter != mTextureSetList.end(); ++iter)
   {
     if((*iter) == textureSet)
index d2630c1..ec7a402 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_IMAGE_ATLAS_MANAGER_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
  */
 
 // EXTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
 #include <dali/public-api/common/vector-wrapper.h>
 #include <dali/public-api/object/ref-object.h>
 #include <dali/public-api/rendering/texture-set.h>
@@ -82,6 +83,29 @@ public:
                  FittingMode::Type    fittingMode           = FittingMode::DEFAULT,
                  bool                 orientationCorrection = true,
                  AtlasUploadObserver* atlasUploadObserver   = NULL);
+
+  /**
+   * @brief Add an image to the atlas.
+   *
+   * @note To make the atlasing efficient, an valid size should be provided.
+   *
+   * SamplingMode::BOX_THEN_LINEAR is used to sampling pixels from the input image while fitting it to desired size.
+   *
+   * @param [out] textureRect The texture area of the resource image in the atlas.
+   * @param [in] encodedImageBuffer The encoded buffer of the resource image file to use.
+   * @param [in] size The width and height to fit the loaded image to.
+   * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter.
+   * @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
+   * @param [in] atlasUploadObserver The object to observe the uploading state inside ImageAtlas.
+   * @return The texture set containing the image.
+   */
+  TextureSet Add(Vector4&                  textureRect,
+                 const EncodedImageBuffer& encodedImageBuffer,
+                 const ImageDimensions&    size,
+                 FittingMode::Type         fittingMode           = FittingMode::DEFAULT,
+                 bool                      orientationCorrection = true,
+                 AtlasUploadObserver*      atlasUploadObserver   = NULL);
+
   /**
    * @brief Add a pixel buffer to the atlas
    *