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-distance-field.h"
19 #include "dali/public-api/images/distance-field.h"
21 #include <dali/integration-api/bitmap.h>
22 #include <dali/integration-api/debug.h>
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"
30 using namespace Dali::Integration;
41 typedef bool (*LoadBitmapFunction)(FILE*, Bitmap&, ImageAttributes&, const ResourceLoadingClient& );
42 typedef bool (*LoadBitmapHeaderFunction)(FILE*, const ImageAttributes&, unsigned int&, unsigned int&);
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 )
50 A Standard Default Color Space for the Internet - sRGB.
51 [online] http://www.w3.org/Graphics/Color/sRGB
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)
58 * Stores the magic bytes, and the loader and header functions used for each image loader.
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
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.
72 const BitmapLoader BITMAP_LOADER_LOOKUP_TABLE[] =
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 },
80 const unsigned int BITMAP_LOADER_COUNT = sizeof(BITMAP_LOADER_LOOKUP_TABLE) / sizeof(BitmapLoader);
81 const unsigned int MAGIC_LENGTH = 2;
84 * Checks the magic bytes of the file first to determine which Image decoder to use to decode the
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
91 bool GetBitmapLoaderFunctions(FILE *fp, LoadBitmapFunction& loader, LoadBitmapHeaderFunction& header)
93 unsigned char magic[MAGIC_LENGTH];
94 size_t read = fread(magic, sizeof(unsigned char), MAGIC_LENGTH, fp);
96 if (read != MAGIC_LENGTH)
101 bool loaderFound = false;
103 const BitmapLoader *lookupPtr = BITMAP_LOADER_LOOKUP_TABLE;
104 for (unsigned int i = 0; i < BITMAP_LOADER_COUNT; ++i, ++lookupPtr)
106 if (lookupPtr->magicByte1 == magic[0] && lookupPtr->magicByte2 == magic[1])
108 loader = lookupPtr->loader;
109 header = lookupPtr->header;
115 // Reset to the start of the file.
116 if( fseek(fp, 0, SEEK_SET) )
118 DALI_LOG_ERROR("Error seeking to start of file\n");
126 ResourceThreadDistanceField::ResourceThreadDistanceField(ResourceLoader& resourceLoader)
127 : ResourceThreadBase(resourceLoader)
131 ResourceThreadDistanceField::~ResourceThreadDistanceField()
135 //----------------- Called from separate thread (mThread) -----------------
137 void ResourceThreadDistanceField::Load(const ResourceRequest& request)
139 DALI_LOG_TRACE_METHOD(mLogFilter);
140 DALI_ASSERT_DEBUG(request.GetType()->id == ResourceBitmap);
142 // TODO - down-scaling to requested size
144 DALI_LOG_INFO(mLogFilter, Debug::Verbose, "%s(%s)\n", __FUNCTION__, request.GetPath().c_str());
147 bool file_not_found = false;
149 BitmapPtr bitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::DISCARD );
151 DALI_LOG_SET_OBJECT_STRING(bitmap, request.GetPath());
152 BitmapResourceType& resType = static_cast<BitmapResourceType&>(*(request.GetType()));
153 ImageAttributes& attributes = resType.imageAttributes;
155 FILE *fp = fopen(request.GetPath().c_str(), "rb");
158 // Only png, jpg, bmp and gif files are supported
159 LoadBitmapFunction function = NULL;
160 LoadBitmapHeaderFunction header = NULL;
162 if (GetBitmapLoaderFunctions(fp, function, header))
164 result = function(fp, *bitmap, attributes, *this);
168 if ((bitmap->GetPixelFormat() == Pixel::RGBA8888) || (bitmap->GetPixelFormat() == Pixel::RGB888))
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());
174 uint8_t* srcPixels = bitmap->GetBuffer();
176 uint8_t destPixels[destBitmap->GetBufferSize()];
177 memset(destPixels, 0, destBitmap->GetBufferSize());
179 switch(bitmap->GetPixelFormat())
183 for(std::size_t i = 0; i < bitmap->GetBufferSize(); i+=3)
185 destPixels[dest++] = GREY8( srcPixels[i], srcPixels[i+1], srcPixels[i+2]);
191 case Pixel::RGBA8888:
193 for(std::size_t i = 0; i < bitmap->GetBufferSize(); i+=4)
195 uint8_t a = srcPixels[i+3];
196 // transparent pixels must have an alpha value of 0
199 destPixels[dest]= GREY8( srcPixels[i], srcPixels[i+1], srcPixels[i+2]);
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,
216 destBitmap->GetBuffer(),
218 attributes.GetFieldBorder(),
226 DALI_LOG_WARNING("Unable to decode %s\n", request.GetPath().c_str());
231 DALI_LOG_WARNING("Image Decoder for %s unavailable\n", request.GetPath().c_str());
238 DALI_LOG_WARNING("Failed to load \"%s\"\n", request.GetPath().c_str());
239 file_not_found = true;
244 // Construct LoadedResource and ResourcePointer for image data
245 LoadedResource resource( request.GetId(), request.GetType()->id, ResourcePointer(bitmap.Get()) );
247 // Queue the loaded resource
248 mResourceLoader.AddLoadedResource(resource);
252 // add to the failed queue
253 FailedResource resource(request.GetId(), file_not_found ? FailureFileNotFound : FailureUnknown);
254 mResourceLoader.AddFailedLoad(resource);
258 void ResourceThreadDistanceField::Save(const Integration::ResourceRequest& request)
260 DALI_LOG_TRACE_METHOD(mLogFilter);
261 DALI_ASSERT_DEBUG(request.GetType()->id == ResourceBitmap);
264 } // namespace SlpPlatform