Dali 3D User Interface Engine
image-loader.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 #include "image-loader.h"
18 
22 
23 #include "loader-astc.h"
24 #include "loader-bmp.h"
25 #include "loader-gif.h"
26 #include "loader-ico.h"
27 #include "loader-jpeg.h"
28 #include "loader-ktx.h"
29 #include "loader-png.h"
30 #include "loader-wbmp.h"
31 #include "image-operations.h"
32 #include "image-loader-input.h"
33 #include "portable/file-closer.h"
34 
35 using namespace Dali::Integration;
36 
37 namespace Dali
38 {
39 namespace TizenPlatform
40 {
41 
42 namespace
43 {
44 typedef bool (*LoadBitmapFunction)( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap );
45 typedef bool (*LoadBitmapHeaderFunction)( const ImageLoader::Input& input, unsigned int& width, unsigned int& height );
46 
47 #if defined(DEBUG_ENABLED)
48 Integration::Log::Filter* gLogFilter = Debug::Filter::New( Debug::Concise, false, "LOG_IMAGE_LOADING" );
49 #endif
50 
55 {
56  unsigned char magicByte1;
57  unsigned char magicByte2;
60  Bitmap::Profile profile;
61 
62 };
63 
68 {
69  // Unknown file format
71 
72  // formats that use magic bytes
81 
82  // formats after this one do not use magic bytes
85 };
86 
92 {
101 };
102 
103 const unsigned int MAGIC_LENGTH = 2;
104 
109 {
110  const std::string extension;
112 };
113 
115 {
116  { ".png", FORMAT_PNG },
117  { ".jpg", FORMAT_JPEG },
118  { ".bmp", FORMAT_BMP },
119  { ".gif", FORMAT_GIF },
120  { ".ktx", FORMAT_KTX },
121  { ".astc", FORMAT_ASTC },
122  { ".ico", FORMAT_ICO },
123  { ".wbmp", FORMAT_WBMP }
124 };
125 
126 const unsigned int FORMAT_EXTENSIONS_COUNT = sizeof(FORMAT_EXTENSIONS) / sizeof(FormatExtension);
127 
128 FileFormats GetFormatHint( const std::string& filename )
129 {
130  FileFormats format = FORMAT_UNKNOWN;
131 
132  for ( unsigned int i = 0; i < FORMAT_EXTENSIONS_COUNT; ++i )
133  {
134  unsigned int length = FORMAT_EXTENSIONS[i].extension.size();
135  if ( ( filename.size() > length ) &&
136  ( 0 == filename.compare( filename.size() - length, length, FORMAT_EXTENSIONS[i].extension ) ) )
137  {
138  format = FORMAT_EXTENSIONS[i].format;
139  break;
140  }
141  }
142 
143  return format;
144 }
145 
157  FileFormats format,
158  LoadBitmapFunction& loader,
159  LoadBitmapHeaderFunction& header,
160  Bitmap::Profile& profile )
161 {
162  unsigned char magic[MAGIC_LENGTH];
163  size_t read = fread(magic, sizeof(unsigned char), MAGIC_LENGTH, fp);
164 
165  // Reset to the start of the file.
166  if( fseek(fp, 0, SEEK_SET) )
167  {
168  DALI_LOG_ERROR("Error seeking to start of file\n");
169  }
170 
171  if (read != MAGIC_LENGTH)
172  {
173  return false;
174  }
175 
176  bool loaderFound = false;
177  const BitmapLoader *lookupPtr = BITMAP_LOADER_LOOKUP_TABLE;
178  ImageLoader::Input defaultInput( fp );
179 
180  // try hinted format first
181  if ( format != FORMAT_UNKNOWN )
182  {
183  lookupPtr = BITMAP_LOADER_LOOKUP_TABLE + format;
184  if ( format >= FORMAT_MAGIC_BYTE_COUNT ||
185  ( lookupPtr->magicByte1 == magic[0] && lookupPtr->magicByte2 == magic[1] ) )
186  {
187  unsigned int width = 0;
188  unsigned int height = 0;
189  loaderFound = lookupPtr->header( fp, width, height );
190  }
191  }
192 
193  // then try to get a match with formats that have magic bytes
194  if ( false == loaderFound )
195  {
196  for ( lookupPtr = BITMAP_LOADER_LOOKUP_TABLE;
197  lookupPtr < BITMAP_LOADER_LOOKUP_TABLE + FORMAT_MAGIC_BYTE_COUNT;
198  ++lookupPtr )
199  {
200  if ( lookupPtr->magicByte1 == magic[0] && lookupPtr->magicByte2 == magic[1] )
201  {
202  // to seperate ico file format and wbmp file format
203  unsigned int width = 0;
204  unsigned int height = 0;
205  loaderFound = lookupPtr->header(fp, width, height);
206  }
207  if (loaderFound)
208  {
209  break;
210  }
211  }
212  }
213 
214  // finally try formats that do not use magic bytes
215  if ( false == loaderFound )
216  {
217  for ( lookupPtr = BITMAP_LOADER_LOOKUP_TABLE + FORMAT_MAGIC_BYTE_COUNT;
218  lookupPtr < BITMAP_LOADER_LOOKUP_TABLE + FORMAT_TOTAL_COUNT;
219  ++lookupPtr )
220  {
221  // to seperate ico file format and wbmp file format
222  unsigned int width = 0;
223  unsigned int height = 0;
224  loaderFound = lookupPtr->header(fp, width, height);
225  if (loaderFound)
226  {
227  break;
228  }
229  }
230  }
231 
232  // if a loader was found set the outputs
233  if ( loaderFound )
234  {
235  loader = lookupPtr->loader;
236  header = lookupPtr->header;
237  profile = lookupPtr->profile;
238  }
239 
240  // Reset to the start of the file.
241  if( fseek(fp, 0, SEEK_SET) )
242  {
243  DALI_LOG_ERROR("Error seeking to start of file\n");
244  }
245 
246  return loaderFound;
247 }
248 
249 } // anonymous namespace
250 
251 
252 namespace ImageLoader
253 {
254 
255 bool ConvertStreamToBitmap( const ResourceType& resourceType, std::string path, FILE * const fp, const ResourceLoadingClient& client, BitmapPtr& ptr )
256 {
257  DALI_LOG_TRACE_METHOD( gLogFilter );
258  DALI_ASSERT_DEBUG( ResourceBitmap == resourceType.id );
259 
260  bool result = false;
261  BitmapPtr bitmap = 0;
262 
263  if (fp != NULL)
264  {
265  LoadBitmapFunction function;
267  Bitmap::Profile profile;
268 
269  if ( GetBitmapLoaderFunctions( fp,
270  GetFormatHint( path ),
271  function,
272  header,
273  profile ) )
274  {
275  bitmap = Bitmap::New( profile, ResourcePolicy::OWNED_DISCARD );
276 
277  DALI_LOG_SET_OBJECT_STRING( bitmap, path );
278  const BitmapResourceType& resType = static_cast<const BitmapResourceType&>( resourceType );
279  const ScalingParameters scalingParameters( resType.size, resType.scalingMode, resType.samplingMode );
280  const ImageLoader::Input input( fp, scalingParameters, resType.orientationCorrection );
281 
282  // Check for cancellation now we have hit the filesystem, done some allocation, and burned some cycles:
283  // This won't do anything from synchronous API, it's only useful when called from another thread.
284  client.InterruptionPoint(); // Note: By design, this can throw an exception
285 
286  // Run the image type decoder:
287  result = function( client, input, *bitmap );
288 
289  if (!result)
290  {
291  DALI_LOG_WARNING( "Unable to convert %s\n", path.c_str() );
292  bitmap = 0;
293  }
294 
295  // Apply the requested image attributes if not interrupted:
296  client.InterruptionPoint(); // Note: By design, this can throw an exception
297  bitmap = Internal::Platform::ApplyAttributesToBitmap( bitmap, resType.size, resType.scalingMode, resType.samplingMode );
298  }
299  else
300  {
301  DALI_LOG_WARNING( "Image Decoder for %s unavailable\n", path.c_str() );
302  }
303  }
304 
305  ptr.Reset( bitmap.Get() );
306  return result;
307 }
308 
309 ResourcePointer LoadResourceSynchronously( const Integration::ResourceType& resourceType, const std::string& resourcePath )
310 {
311  ResourcePointer resource;
312  BitmapPtr bitmap = 0;
313 
314  Internal::Platform::FileCloser fc( resourcePath.c_str(), "rb");
315  FILE * const fp = fc.GetFile();
316  if( fp != NULL )
317  {
318  bool result = ConvertStreamToBitmap( resourceType, resourcePath, fp, StubbedResourceLoadingClient(), bitmap );
319  if( result && bitmap )
320  {
321  resource.Reset(bitmap.Get());
322  }
323  }
324  return resource;
325 }
326 
328 ImageDimensions GetClosestImageSize( const std::string& filename,
329  ImageDimensions size,
330  FittingMode::Type fittingMode,
331  SamplingMode::Type samplingMode,
332  bool orientationCorrection )
333 {
334  unsigned int width = 0;
335  unsigned int height = 0;
336 
337  Internal::Platform::FileCloser fc(filename.c_str(), "rb");
338  FILE *fp = fc.GetFile();
339  if (fp != NULL)
340  {
341  LoadBitmapFunction loaderFunction;
342  LoadBitmapHeaderFunction headerFunction;
343  Bitmap::Profile profile;
344 
345  if ( GetBitmapLoaderFunctions( fp,
346  GetFormatHint(filename),
347  loaderFunction,
348  headerFunction,
349  profile ) )
350  {
351  const ImageLoader::Input input( fp, ScalingParameters( size, fittingMode, samplingMode ), orientationCorrection );
352 
353  const bool read_res = headerFunction( input, width, height );
354  if(!read_res)
355  {
356  DALI_LOG_WARNING("Image Decoder failed to read header for %s\n", filename.c_str());
357  }
358  }
359  else
360  {
361  DALI_LOG_WARNING("Image Decoder for %s unavailable\n", filename.c_str());
362  }
363  }
364  return ImageDimensions( width, height );
365 }
366 
367 
368 
370  ImageDimensions size,
371  FittingMode::Type fittingMode,
372  SamplingMode::Type samplingMode,
373  bool orientationCorrection )
374 {
375  unsigned int width = 0;
376  unsigned int height = 0;
377 
378  // Get the blob of binary data that we need to decode:
379  DALI_ASSERT_DEBUG( resourceBuffer );
380  Dali::RefCountedVector<uint8_t>* const encodedBlob = reinterpret_cast<Dali::RefCountedVector<uint8_t>*>( resourceBuffer.Get() );
381 
382  if( encodedBlob != 0 )
383  {
384  const size_t blobSize = encodedBlob->GetVector().Size();
385  uint8_t * const blobBytes = &(encodedBlob->GetVector()[0]);
386  DALI_ASSERT_DEBUG( blobSize > 0U );
387  DALI_ASSERT_DEBUG( blobBytes != 0U );
388 
389  if( blobBytes != 0 && blobSize > 0U )
390  {
391  // Open a file handle on the memory buffer:
392  Internal::Platform::FileCloser fc( blobBytes, blobSize, "rb" );
393  FILE *fp = fc.GetFile();
394  if ( fp != NULL )
395  {
396  LoadBitmapFunction loaderFunction;
397  LoadBitmapHeaderFunction headerFunction;
398  Bitmap::Profile profile;
399 
400  if ( GetBitmapLoaderFunctions( fp,
402  loaderFunction,
403  headerFunction,
404  profile ) )
405  {
406  const ImageLoader::Input input( fp, ScalingParameters( size, fittingMode, samplingMode ), orientationCorrection );
407  const bool read_res = headerFunction( input, width, height );
408  if( !read_res )
409  {
410  DALI_LOG_WARNING( "Image Decoder failed to read header for resourceBuffer\n" );
411  }
412  }
413  }
414  }
415  }
416  return ImageDimensions( width, height );
417 }
418 
419 } // ImageLoader
420 } // TizenPlatform
421 } // Dali
Dali Docs Home
Read more about Dali