2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "resource-thread-image.h"
19 #include <dali/public-api/common/ref-counted-dali-vector.h>
20 #include <dali/integration-api/bitmap.h>
21 #include <dali/integration-api/debug.h>
22 #include <dali/integration-api/resource-cache.h>
23 #include <dali/integration-api/resource-types.h>
24 #include <curl/curl.h>
25 #include "portable/file-closer.h"
26 #include "image-loaders/image-loader.h"
28 using namespace Dali::Integration;
36 ResourceThreadImage::ResourceThreadImage(ResourceLoader& resourceLoader, bool forRemoteImage)
37 : ResourceThreadBase(resourceLoader)
41 ResourceThreadImage::~ResourceThreadImage()
45 void ResourceThreadImage::Load(const ResourceRequest& request)
47 DALI_LOG_TRACE_METHOD( mLogFilter );
48 DALI_LOG_INFO( mLogFilter, Debug::Verbose, "%s(%s)\n", __FUNCTION__, request.GetPath().c_str() );
50 LoadImageFromLocalFile(request);
53 void ResourceThreadImage::Download(const ResourceRequest& request)
57 DALI_LOG_TRACE_METHOD( mLogFilter );
58 DALI_LOG_INFO( mLogFilter, Debug::Verbose, "%s(%s)\n", __FUNCTION__, request.GetPath().c_str() );
60 Dali::Vector<uint8_t> dataBuffer;
62 succeeded = DownloadRemoteImageIntoMemory( request, dataBuffer, dataSize );
65 DecodeImageFromMemory(static_cast<void*>(&dataBuffer[0]), dataBuffer.Size(), request);
69 void ResourceThreadImage::Decode(const ResourceRequest& request)
71 DALI_LOG_TRACE_METHOD( mLogFilter );
72 DALI_LOG_INFO(mLogFilter, Debug::Verbose, "%s(%s)\n", __FUNCTION__, request.GetPath().c_str());
74 // Get the blob of binary data that we need to decode:
75 DALI_ASSERT_DEBUG( request.GetResource() );
77 DALI_ASSERT_DEBUG( 0 != dynamic_cast<Dali::RefCountedVector<uint8_t>*>( request.GetResource().Get() ) && "Only blobs of binary data can be decoded." );
78 Dali::RefCountedVector<uint8_t>* const encodedBlob = reinterpret_cast<Dali::RefCountedVector<uint8_t>*>( request.GetResource().Get() );
80 if( 0 != encodedBlob )
82 const size_t blobSize = encodedBlob->GetVector().Size();
83 uint8_t * const blobBytes = &(encodedBlob->GetVector()[0]);
84 DecodeImageFromMemory(blobBytes, blobSize, request);
88 FailedResource resource(request.GetId(), FailureUnknown);
89 mResourceLoader.AddFailedLoad(resource);
93 void ResourceThreadImage::Save(const Integration::ResourceRequest& request)
95 DALI_LOG_TRACE_METHOD( mLogFilter );
96 DALI_ASSERT_DEBUG( request.GetType()->id == ResourceBitmap );
97 DALI_LOG_WARNING( "Image saving not supported on background resource threads." );
100 bool ResourceThreadImage::DownloadRemoteImageIntoMemory(const Integration::ResourceRequest& request, Dali::Vector<uint8_t>& dataBuffer, size_t& dataSize)
102 bool succeeded = true;
105 CURL* curl_handle = curl_easy_init();
106 curl_easy_setopt( curl_handle, CURLOPT_VERBOSE, 0 );
107 curl_easy_setopt( curl_handle, CURLOPT_URL, request.GetPath().c_str() );
108 curl_easy_setopt( curl_handle, CURLOPT_FAILONERROR, 1 );
110 // Download header first to get data size
111 char* headerBytes = NULL;
112 size_t headerSize = 0;
113 FILE* header_fp = open_memstream( &headerBytes, &headerSize );
116 if( NULL != header_fp)
118 curl_easy_setopt( curl_handle, CURLOPT_HEADER, 1 );
119 curl_easy_setopt( curl_handle, CURLOPT_NOBODY, 1 );
120 curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA, header_fp );
122 cresult = curl_easy_perform( curl_handle );
123 if( cresult == CURLE_OK )
125 curl_easy_getinfo( curl_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &size );
129 DALI_LOG_WARNING( "Failed to download file to load \"%s\"\n", request.GetPath().c_str() );
140 if( NULL != headerBytes )
147 // Download file data
148 dataSize = static_cast<size_t>( size );
149 dataBuffer.Reserve( dataSize );
150 dataBuffer.Resize( dataSize );
152 Dali::Internal::Platform::FileCloser fileCloser( static_cast<void*>(&dataBuffer[0]), dataSize, "wb" );
153 FILE* data_fp = fileCloser.GetFile();
154 if( NULL != data_fp )
156 curl_easy_setopt( curl_handle, CURLOPT_HEADER, 0 );
157 curl_easy_setopt( curl_handle, CURLOPT_NOBODY, 0 );
158 curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA, data_fp );
160 cresult = curl_easy_perform( curl_handle );
161 if( CURLE_OK != cresult )
163 DALI_LOG_WARNING( "Failed to download file to load \"%s\"\n", request.GetPath().c_str() );
173 curl_easy_cleanup( curl_handle );
177 FailedResource resource(request.GetId(), FailureUnknown);
178 mResourceLoader.AddFailedLoad(resource);
184 void ResourceThreadImage::LoadImageFromLocalFile(const Integration::ResourceRequest& request)
186 bool fileNotFound = false;
187 BitmapPtr bitmap = 0;
190 Dali::Internal::Platform::FileCloser fileCloser( request.GetPath().c_str(), "rb" );
191 FILE * const fp = fileCloser.GetFile();
195 result = ImageLoader::ConvertStreamToBitmap( *request.GetType(), request.GetPath(), fp, *this, bitmap );
196 // Last chance to interrupt a cancelled load before it is reported back to clients
197 // which have already stopped tracking it:
198 InterruptionPoint(); // Note: This can throw an exception.
199 if( result && bitmap )
201 // Construct LoadedResource and ResourcePointer for image data
202 LoadedResource resource( request.GetId(), request.GetType()->id, ResourcePointer( bitmap.Get() ) );
203 // Queue the loaded resource
204 mResourceLoader.AddLoadedResource( resource );
208 DALI_LOG_WARNING( "Unable to decode %s\n", request.GetPath().c_str() );
213 DALI_LOG_WARNING( "Failed to open file to load \"%s\"\n", request.GetPath().c_str() );
221 FailedResource resource(request.GetId(), FailureFileNotFound );
222 mResourceLoader.AddFailedLoad(resource);
226 FailedResource resource(request.GetId(), FailureUnknown);
227 mResourceLoader.AddFailedLoad(resource);
232 void ResourceThreadImage::DecodeImageFromMemory(void* blobBytes, size_t blobSize, const Integration::ResourceRequest& request)
234 BitmapPtr bitmap = 0;
236 DALI_ASSERT_DEBUG( blobSize > 0U );
237 DALI_ASSERT_DEBUG( blobBytes != 0U );
239 if( blobBytes != 0 && blobSize > 0U )
241 // Open a file handle on the memory buffer:
242 Dali::Internal::Platform::FileCloser fileCloser( blobBytes, blobSize, "rb" );
243 FILE * const fp = fileCloser.GetFile();
246 bool result = ImageLoader::ConvertStreamToBitmap( *request.GetType(), request.GetPath(), fp, StubbedResourceLoadingClient(), bitmap );
247 if ( result && bitmap )
249 // Construct LoadedResource and ResourcePointer for image data
250 LoadedResource resource( request.GetId(), request.GetType()->id, ResourcePointer( bitmap.Get() ) );
251 // Queue the loaded resource
252 mResourceLoader.AddLoadedResource( resource );
256 DALI_LOG_WARNING( "Unable to decode bitmap supplied as in-memory blob.\n" );
263 FailedResource resource(request.GetId(), FailureUnknown);
264 mResourceLoader.AddFailedLoad(resource);
268 } // namespace SlpPlatform