765a6890cbad342bc4d3646818d68581b2f362f9
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / slp / resource-loader / resource-thread-distance-field.cpp
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
18 #include "resource-thread-distance-field.h"
19 #include "dali/public-api/images/distance-field.h"
20
21 #include <dali/integration-api/bitmap.h>
22 #include <dali/integration-api/debug.h>
23 #include <stdint.h>
24
25 #include "image-loaders/loader-bmp.h"
26 #include "image-loaders/loader-gif.h"
27 #include "image-loaders/loader-jpeg.h"
28 #include "image-loaders/loader-png.h"
29
30 using namespace Dali::Integration;
31
32 namespace Dali
33 {
34
35 namespace SlpPlatform
36 {
37
38 namespace
39 {
40
41 typedef bool (*LoadBitmapFunction)(FILE*, Bitmap&, ImageAttributes&, const ResourceLoadingClient& );
42 typedef bool (*LoadBitmapHeaderFunction)(FILE*, const ImageAttributes&, unsigned int&, unsigned int&);
43
44 /*
45  * Extract the luminance channel L from a RGBF image.
46    Luminance is calculated from the sRGB model using a D65 white point, using the Rec.709 formula :
47    L = ( 0.2126 * r ) + ( 0.7152 * g ) + ( 0.0722 * b )
48
49    Reference :
50    A Standard Default Color Space for the Internet - sRGB.
51    [online] http://www.w3.org/Graphics/Color/sRGB
52 */
53
54 #define LUMA_REC709(r, g, b) (0.2126f * r + 0.7152f * g + 0.0722f * b)
55 #define GREY8(r, g, b) (uint8_t)LUMA_REC709(r, g, b)
56
57 /**
58  * Stores the magic bytes, and the loader and header functions used for each image loader.
59  */
60 struct BitmapLoader
61 {
62   unsigned char magicByte1;        ///< The first byte in the file should be this
63   unsigned char magicByte2;        ///< The second byte in the file should be this
64   LoadBitmapFunction loader;       ///< The function which decodes the file
65   LoadBitmapHeaderFunction header; ///< The function which decodes the header of the file
66 };
67
68 /**
69  * A lookup table containing all the bitmap loaders with the appropriate information.
70  * The grey-scale converter only supports 8-bit channels as input, the image needs to be rgb8 or rgba8 format.
71  */
72 const BitmapLoader BITMAP_LOADER_LOOKUP_TABLE[] =
73 {
74   { Png::MAGIC_BYTE_1,  Png::MAGIC_BYTE_2,  LoadBitmapFromPng,  LoadPngHeader  },
75   { Jpeg::MAGIC_BYTE_1, Jpeg::MAGIC_BYTE_2, LoadBitmapFromJpeg, LoadJpegHeader },
76   { Bmp::MAGIC_BYTE_1,  Bmp::MAGIC_BYTE_2,  LoadBitmapFromBmp,  LoadBmpHeader  },
77   { Gif::MAGIC_BYTE_1,  Gif::MAGIC_BYTE_2,  LoadBitmapFromGif,  LoadGifHeader  },
78 };
79
80 const unsigned int BITMAP_LOADER_COUNT = sizeof(BITMAP_LOADER_LOOKUP_TABLE) / sizeof(BitmapLoader);
81 const unsigned int MAGIC_LENGTH = 2;
82
83 /**
84  * Checks the magic bytes of the file first to determine which Image decoder to use to decode the
85  * bitmap.
86  * @param[in]   fp      The file to decode
87  * @param[out]  loader  Set with the function to use to decode the image
88  * @param[out]  header  Set with the function to use to decode the header
89  * @return true, if we can decode the image, false otherwise
90  */
91 bool GetBitmapLoaderFunctions(FILE *fp, LoadBitmapFunction& loader, LoadBitmapHeaderFunction& header)
92 {
93   unsigned char magic[MAGIC_LENGTH];
94   size_t read = fread(magic, sizeof(unsigned char), MAGIC_LENGTH, fp);
95
96   if (read != MAGIC_LENGTH)
97   {
98     return false;
99   }
100
101   bool loaderFound = false;
102
103   const BitmapLoader *lookupPtr = BITMAP_LOADER_LOOKUP_TABLE;
104   for (unsigned int i = 0; i < BITMAP_LOADER_COUNT; ++i, ++lookupPtr)
105   {
106     if (lookupPtr->magicByte1 == magic[0] && lookupPtr->magicByte2 == magic[1])
107     {
108       loader = lookupPtr->loader;
109       header = lookupPtr->header;
110       loaderFound = true;
111       break;
112     }
113   }
114
115   // Reset to the start of the file.
116   if( fseek(fp, 0, SEEK_SET) )
117   {
118     DALI_LOG_ERROR("Error seeking to start of file\n");
119   }
120
121   return loaderFound;
122 }
123
124 }
125
126 ResourceThreadDistanceField::ResourceThreadDistanceField(ResourceLoader& resourceLoader)
127 : ResourceThreadBase(resourceLoader)
128 {
129 }
130
131 ResourceThreadDistanceField::~ResourceThreadDistanceField()
132 {
133 }
134
135 //----------------- Called from separate thread (mThread) -----------------
136
137 void ResourceThreadDistanceField::Load(const ResourceRequest& request)
138 {
139   DALI_LOG_TRACE_METHOD(mLogFilter);
140   DALI_ASSERT_DEBUG(request.GetType()->id == ResourceBitmap);
141
142   // TODO - down-scaling to requested size
143
144   DALI_LOG_INFO(mLogFilter, Debug::Verbose, "%s(%s)\n", __FUNCTION__, request.GetPath().c_str());
145
146   bool result = false;
147   bool file_not_found = false;
148
149   BitmapPtr bitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::DISCARD );
150
151   DALI_LOG_SET_OBJECT_STRING(bitmap, request.GetPath());
152   BitmapResourceType& resType = static_cast<BitmapResourceType&>(*(request.GetType()));
153   ImageAttributes& attributes  = resType.imageAttributes;
154
155   FILE *fp = fopen(request.GetPath().c_str(), "rb");
156   if (fp != NULL)
157   {
158     // Only png, jpg, bmp and gif files are supported
159     LoadBitmapFunction function = NULL;
160     LoadBitmapHeaderFunction header = NULL;
161
162     if (GetBitmapLoaderFunctions(fp, function, header))
163     {
164       result = function(fp, *bitmap, attributes, *this);
165
166       if (result)
167       {
168         if ((bitmap->GetPixelFormat() == Pixel::RGBA8888) || (bitmap->GetPixelFormat() == Pixel::RGB888))
169         {
170           // create a bitmap, so we can get its buffersize - to avoid a slow copy.
171           BitmapPtr destBitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::DISCARD );
172           destBitmap->GetPackedPixelsProfile()->ReserveBuffer(Pixel::A8, attributes.GetWidth(), attributes.GetHeight());
173
174           uint8_t* srcPixels = bitmap->GetBuffer();
175           uint32_t dest = 0;
176           uint8_t destPixels[destBitmap->GetBufferSize()];
177           memset(destPixels, 0, destBitmap->GetBufferSize());
178
179           switch(bitmap->GetPixelFormat())
180           {
181             case Pixel::RGB888:
182             {
183               for(std::size_t i = 0; i < bitmap->GetBufferSize(); i+=3)
184               {
185                 destPixels[dest++] = GREY8( srcPixels[i], srcPixels[i+1], srcPixels[i+2]);
186               }
187
188               break;
189             }
190
191             case Pixel::RGBA8888:
192             {
193               for(std::size_t i = 0; i < bitmap->GetBufferSize(); i+=4)
194               {
195                 uint8_t a = srcPixels[i+3];
196                 // transparent pixels must have an alpha value of 0
197                 if (a > 0x0)
198                 {
199                   destPixels[dest]= GREY8( srcPixels[i], srcPixels[i+1], srcPixels[i+2]);
200                 }
201
202                 ++dest;
203               }
204
205               break;
206             }
207
208             default:
209               break;
210           }
211
212           // now we have an 8 bit luminance map in workbuffer, time to convert it to distance map.
213           Size imageSize(destBitmap->GetPackedPixelsProfile()->GetBufferWidth(), destBitmap->GetPackedPixelsProfile()->GetBufferHeight());
214           GenerateDistanceFieldMap( destPixels,
215                                     imageSize,
216                                     destBitmap->GetBuffer(),
217                                     imageSize,
218                                     attributes.GetFieldBorder(),
219                                     imageSize,
220                                     true );
221           bitmap = destBitmap;
222         }
223       }
224       else
225       {
226         DALI_LOG_WARNING("Unable to decode %s\n", request.GetPath().c_str());
227       }
228     }
229     else
230     {
231       DALI_LOG_WARNING("Image Decoder for %s unavailable\n", request.GetPath().c_str());
232     }
233
234     fclose(fp);
235   }
236   else
237   {
238     DALI_LOG_WARNING("Failed to load \"%s\"\n", request.GetPath().c_str());
239     file_not_found = true;
240   }
241
242   if (result)
243   {
244     // Construct LoadedResource and ResourcePointer for image data
245     LoadedResource resource( request.GetId(), request.GetType()->id, ResourcePointer(bitmap.Get()) );
246
247     // Queue the loaded resource
248     mResourceLoader.AddLoadedResource(resource);
249   }
250   else
251   {
252     // add to the failed queue
253     FailedResource resource(request.GetId(), file_not_found ? FailureFileNotFound : FailureUnknown);
254     mResourceLoader.AddFailedLoad(resource);
255   }
256 }
257
258 void ResourceThreadDistanceField::Save(const Integration::ResourceRequest& request)
259 {
260   DALI_LOG_TRACE_METHOD(mLogFilter);
261   DALI_ASSERT_DEBUG(request.GetType()->id == ResourceBitmap);
262 }
263
264 } // namespace SlpPlatform
265
266 } // namespace Dali