Added new API to download images remotely 95/118695/4
authorDavid Steele <david.steele@samsung.com>
Mon, 13 Mar 2017 11:00:52 +0000 (11:00 +0000)
committerDavid Steele <david.steele@samsung.com>
Mon, 20 Mar 2017 10:33:49 +0000 (03:33 -0700)
Added "DownloadImageSynchronously()" method, which invokes libcurl to
download a URL.

Added global object to ensure curl is globally initialized and cleaned up,
this should allow usage of the above method in multiple threads simultaneously.

Also added "GetClosestImageSize" method, which partially loads the image file
to determine it's size.

Change-Id: Ie27f69d729abecfe5de3d5a90eae01a34f92c5b1
Signed-off-by: David Steele <david.steele@samsung.com>
adaptors/common/adaptor-impl.h
adaptors/devel-api/adaptor-framework/image-loading.cpp
adaptors/devel-api/adaptor-framework/image-loading.h
automated-tests/src/dali-adaptor/utc-Dali-ImageLoading.cpp
platform-abstractions/tizen/resource-loader/network/file-download.cpp
platform-abstractions/tizen/resource-loader/network/file-download.h
platform-abstractions/tizen/resource-loader/network/http-utils.cpp
platform-abstractions/tizen/resource-loader/network/http-utils.h

index 479e10ebda71a0926d23b4bb0a753f4fe6607549..4cbbdc2dbb3810e378bd16e94229d77eb2d3e4ad 100644 (file)
@@ -563,7 +563,7 @@ private: // Data
 
   Any                                   mNativeWindow;                ///< window identifier
   RenderSurface*                        mSurface;                     ///< Current surface
-  TizenPlatform::TizenPlatformAbstraction*  mPlatformAbstraction;         ///< Platform abstraction
+  TizenPlatform::TizenPlatformAbstraction* mPlatformAbstraction;         ///< Platform abstraction
 
   EventHandler*                         mEventHandler;                ///< event handler
   CallbackManager*                      mCallbackManager;             ///< Used to install callbacks
index 68cb698a60137bf3bb89ff931b02e8ad312fe19a..c194a7603c2ecb46faa20db781bb620381449f62 100644 (file)
 
 // INTERNAL INCLUDES
 #include "image-loaders/image-loader.h"
+#include <resource-loader/network/file-download.h>
+#include <platform-abstractions/portable/file-closer.h>
+#include <platform-abstractions/tizen/resource-loader/resource-loading-client.h>
 
 namespace Dali
 {
 
+namespace
+{
+// limit maximum image down load size to 50 MB
+const size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE  = 50 * 1024 * 1024 ;
+}
+
 PixelData LoadImageFromFile( const std::string& url, ImageDimensions size, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection )
 {
   Integration::BitmapResourceType resourceType( size, fittingMode, samplingMode, orientationCorrection );
@@ -44,4 +53,68 @@ PixelData LoadImageFromFile( const std::string& url, ImageDimensions size, Fitti
   return Dali::PixelData();
 }
 
+ImageDimensions GetClosestImageSize( const std::string& filename,
+                                     ImageDimensions size,
+                                     FittingMode::Type fittingMode,
+                                     SamplingMode::Type samplingMode,
+                                     bool orientationCorrection )
+{
+  return TizenPlatform::ImageLoader::GetClosestImageSize( filename, size, fittingMode, samplingMode, orientationCorrection );
+}
+
+
+PixelData DownloadImageSynchronously( const std::string& url, ImageDimensions size, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection )
+{
+  Integration::BitmapResourceType resourceType( size, fittingMode, samplingMode, orientationCorrection );
+
+  bool succeeded;
+  Dali::Vector<uint8_t> dataBuffer;
+  size_t dataSize;
+
+  succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory( url, dataBuffer, dataSize,
+                                                                    MAXIMUM_DOWNLOAD_IMAGE_SIZE );
+  if( succeeded )
+  {
+    void *blobBytes = static_cast<void*>(&dataBuffer[0]);
+    size_t blobSize = dataBuffer.Size();
+
+    DALI_ASSERT_DEBUG( blobSize > 0U );
+    DALI_ASSERT_DEBUG( blobBytes != 0U );
+
+    if( blobBytes != 0 && blobSize > 0U )
+    {
+      // Open a file handle on the memory buffer:
+      Dali::Internal::Platform::FileCloser fileCloser( blobBytes, blobSize, "rb" );
+      FILE * const fp = fileCloser.GetFile();
+      if ( NULL != fp )
+      {
+        Integration::BitmapPtr bitmap;
+        bool result = TizenPlatform::ImageLoader::ConvertStreamToBitmap(
+          resourceType,
+          url,
+          fp,
+          TizenPlatform::StubbedResourceLoadingClient(),
+          bitmap );
+
+        if ( result && bitmap )
+        {
+          return Dali::PixelData::New( bitmap->GetBufferOwnership(),
+                                       bitmap->GetBufferSize(),
+                                       bitmap->GetImageWidth(),
+                                       bitmap->GetImageHeight(),
+                                       bitmap->GetPixelFormat(),
+                                       Dali::PixelData::FREE );
+        }
+        else
+        {
+          DALI_LOG_WARNING( "Unable to decode bitmap supplied as in-memory blob.\n" );
+        }
+      }
+    }
+
+  }
+  return Dali::PixelData();
+}
+
+
 } // namespace Dali
index 3f20bb4445c35d67d45ba29a50cdab3066226a1d..124b27b5d3e16320587241163b8ed1289c98eff0 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_IMAGE_LOADING_H
 
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
@@ -38,11 +38,54 @@ namespace Dali
  * @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
  * @return handle to the loaded PixelData object or an empty handle in case loading failed.
  */
-DALI_IMPORT_API PixelData LoadImageFromFile( const std::string& url,
-                                             ImageDimensions size = ImageDimensions( 0, 0 ),
-                                             FittingMode::Type fittingMode = FittingMode::DEFAULT,
-                                             SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR,
-                                             bool orientationCorrection = true );
+DALI_IMPORT_API PixelData LoadImageFromFile(
+  const std::string& url,
+  ImageDimensions size = ImageDimensions( 0, 0 ),
+  FittingMode::Type fittingMode = FittingMode::DEFAULT,
+  SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR,
+  bool orientationCorrection = true );
+
+/**
+ * @brief Determine the size of an image that LoadImageFromFile will provide when
+ * given the same image loading parameters.
+ *
+ * This is a synchronous request.
+ * This function is used to determine the size of an image before it has loaded.
+ * @param[in] filename name of the image.
+ * @param[in] size The requested size for the image.
+ * @param[in] fittingMode The method to use to map the source image to the desired
+ * dimensions.
+ * @param[in] samplingMode The image filter to use if the image needs to be
+ * downsampled to the requested size.
+ * @param[in] orientationCorrection Whether to use image metadata to rotate or
+ * flip the image, e.g., from portrait to landscape.
+ * @return dimensions that image will have if it is loaded with given parameters.
+ */
+DALI_IMPORT_API ImageDimensions GetClosestImageSize(
+  const std::string& filename,
+  ImageDimensions size = ImageDimensions(0, 0),
+  FittingMode::Type fittingMode = FittingMode::DEFAULT,
+  SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR ,
+  bool orientationCorrection = true );
+
+/**
+ * @brief Load an image synchronously from a remote resource.
+ *
+ * @param [in] url The URL of the image file to load.
+ * @param [in] size The width and height to fit the loaded image to, 0.0 means whole image
+ * @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] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size.
+ * @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
+ *
+ * @return handle to the loaded PixelData object or an empty handle in case downloading or decoding failed.
+ */
+DALI_IMPORT_API PixelData DownloadImageSynchronously(
+  const std::string& url,
+  ImageDimensions size = ImageDimensions( 0, 0 ),
+  FittingMode::Type fittingMode = FittingMode::DEFAULT,
+  SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR,
+  bool orientationCorrection = true );
+
 
 } // Dali
 
index 75c2957029adf8e6c4a8c585c6803e703b0a95ee..a4682bc930d54f07924a44ab30d237a2037f9a01 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
@@ -67,3 +67,35 @@ int UtcDaliLoadImageN(void)
 
   END_TEST;
 }
+
+
+int UtcDaliDownloadImageP(void)
+{
+  std::string url("file://");
+  url.append( gImage_34_RGBA );
+
+  std::string url2("file://");
+  url2.append( gImage_128_RGB );
+
+  PixelData pixelData = Dali::DownloadImageSynchronously( url );
+  DALI_TEST_CHECK( pixelData );
+  DALI_TEST_EQUALS( pixelData.GetWidth(), 34u, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelData.GetHeight(), 34u, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION  );
+
+  PixelData pixelData2 = Dali::DownloadImageSynchronously( url2 );
+  DALI_TEST_CHECK( pixelData2 );
+  DALI_TEST_EQUALS( pixelData2.GetWidth(), 128u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelData2.GetHeight(), 128u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelData2.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+
+  END_TEST;
+}
+
+int UtcDaliDownloadImageN(void)
+{
+  PixelData pixelData = Dali::DownloadImageSynchronously( gImageNonExist );
+  DALI_TEST_CHECK( !pixelData );
+
+  END_TEST;
+}
index 03524218e710ef8ac8b226da4bf89588c79db3a6..1e33dc35f1259b2e0c53b51300c2dc8650984a27 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
@@ -48,6 +48,13 @@ const long INCLUDE_HEADER = 1L;
 const long INCLUDE_BODY = 0L;
 const long EXCLUDE_BODY = 1L;
 
+/**
+ * Curl library environment. Direct initialize ensures it's constructed before adaptor
+ * or application creates any threads.
+ */
+static Dali::TizenPlatform::Network::CurlEnvironment gCurlEnvironment;
+
+
 void ConfigureCurlOptions( CURL* curl_handle, const std::string& url )
 {
   curl_easy_setopt( curl_handle, CURLOPT_URL, url.c_str() );
@@ -138,14 +145,31 @@ bool DownloadFile( CURL* curl_handle,
   }
   return true;
 }
+
+
 } // unnamed namespace
 
 
+namespace Network
+{
+
+CurlEnvironment::CurlEnvironment()
+{
+  // Must be called before we attempt any loads. e.g. by using curl_easy_init()
+  // and before we start any threads.
+  curl_global_init(CURL_GLOBAL_ALL);
+}
+
+CurlEnvironment::~CurlEnvironment()
+{
+  curl_global_cleanup();
+}
+
 
-bool Network::DownloadRemoteFileIntoMemory( const std::string& url,
-                                            Dali::Vector<uint8_t>& dataBuffer,
-                                            size_t& dataSize,
-                                            size_t maximumAllowedSizeBytes )
+bool DownloadRemoteFileIntoMemory( const std::string& url,
+                                   Dali::Vector<uint8_t>& dataBuffer,
+                                   size_t& dataSize,
+                                   size_t maximumAllowedSizeBytes )
 {
   if( url.empty() )
   {
@@ -171,6 +195,7 @@ bool Network::DownloadRemoteFileIntoMemory( const std::string& url,
   return result;
 }
 
+} // namespace Network
 
 } // namespace TizenPlatform
 
index 0d31953fc3cecf9af5a6a53f41a9fb6c72d6ef8c..ee3d0f5d30ec9aa18f14d8f44a70582f66307ed2 100644 (file)
@@ -2,7 +2,7 @@
 #define __DALI_TIZEN_PLATFORM_NETWORK_FILE_DOWNLOAD_H__
 
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
@@ -32,9 +32,31 @@ namespace TizenPlatform
 namespace Network
 {
 
+/**
+ * Set up the cURL environment - this will ensure curl_global_init is called on startup
+ * and curl_global_cleanup is called on shutdown.
+ * Having this environment enables curl to be used in a single or multi-threaded
+ * program safely.
+ */
+class CurlEnvironment
+{
+public:
+  /**
+   * Constructor calls curl_global_init()
+   */
+  CurlEnvironment();
+
+  /**
+   * Destructor calls curl_global_cleanup()
+   */
+  ~CurlEnvironment();
+};
+
+
 /**
  * Download a requested file into a memory buffer.
- * Threading notes: This function can be called from multiple threads, however l
+ *
+ * @note Threading notes: This function can be called from multiple threads, however
  * we must explicitly call curl_global_init() from a single thread before using curl
  * as the global function calls are not thread safe.
  *
index 517dfbd6948f9d418e746311144da29557458270..a20142d289d97757377c4e4a6c656b3018680c8c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
index e7d225cdcc2ca5996599d050998bdac94a28962c..01bd89c47570119de3ba0dc40bc03322da8e45a5 100644 (file)
@@ -2,7 +2,7 @@
 #define __DALI_TIZEN_PLATFORM_NETWORK_UTILS_H__
 
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.