Adaptor: Fix Klocwork issues
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / slp / image-loaders / loader-bmp.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 "loader-bmp.h"
19
20 #include <dali/public-api/common/vector-wrapper.h>
21 #include <dali/integration-api/debug.h>
22 #include <dali/integration-api/bitmap.h>
23 #include <dali/public-api/images/image-attributes.h>
24
25 namespace Dali
26 {
27 using Integration::Bitmap;
28 using Dali::Integration::PixelBuffer;
29 namespace SlpPlatform
30 {
31
32 namespace
33 {
34 const unsigned int FileHeaderOffsetOfBF32V4 = 0x7A;
35 const unsigned int MaskForBFRGB565 = 0x80;
36 const unsigned int FileHeaderOffsetOfRGB24V5 = 0x8A;
37
38 enum BmpFormat
39 {
40   BMP_RGB1 = 14,    //BI_RGB & bpp =1
41   BMP_RGB4,         //BI_RGB & bpp = 4
42   BMP_RGB8,         //BI_RGB & bpp = 8
43   BMP_RGB555,       //BI_RGB & bpp = 16
44   BMP_BITFIELDS555, //BI_BITFIELDS & 16bit & R:G:B = 5:5:5
45   BMP_BITFIELDS32,  //BI_BITFIELDS & 32bit & R:G:B:A = 8:8:8:8
46   BMP_RLE8,         //BI_RLE8
47   BMP_RLE4,         //BI_RLE4
48   BMP_BITFIELDS32V4,//BI_BITFIELDS & 32bit
49   BMP_RGB24V5,      //BI_RGB & bpp = 24 & bmp version5
50   BMP_NOTEXIST
51 };
52
53 struct BmpFileHeader
54 {
55   unsigned short signature; // Bitmap file signature
56   unsigned int   fileSize;  // Bitmap file size in bytes
57   unsigned short reserved1; // Reserved bits
58   unsigned short reserved2; // Reserved bits
59   unsigned int   offset;    // Offset from BMP file header to BMP bits
60 } __attribute__ ( (__packed__)); // Stops the structure from being aligned to every 4 bytes
61
62 struct BmpInfoHeader
63 {
64   unsigned int   infoHeaderSize;  // Specifies the number of bytes required by the info header
65   unsigned int   width;           // The Image Width
66   int            height;          // The Image Height (negative value represents image data is flipped)
67   unsigned short planes;          // The number of color planes, must be 1
68   unsigned short bitsPerPixel;    // The bits per pixel
69   unsigned int   compression;     // The type of compression used by the image
70   unsigned int   imageSize;       // The size of the image in bytes
71   unsigned int   xPixelsPerMeter; // The number of pixels per meter in x axis
72   unsigned int   yPixelsPerMeter; // The number of pixels per meter in y axis
73   unsigned int   numberOfColors;  // The number of colors in the color table
74   unsigned int   importantColors; // The important color count
75 } __attribute__ ( (__packed__)); // Stops the structure from being aligned to every 4 bytes
76
77 /**
78  * Template function to read from the file directly into our structure.
79  * @param[in]  fp     The file to read from
80  * @param[out] header The structure we want to store our information in
81  * @return true, if read successful, false otherwise
82  */
83 template<typename T>
84 inline bool ReadHeader(FILE* fp, T& header)
85 {
86   unsigned int readLength = sizeof(T);
87
88   // Load the information directly into our structure
89   if (fread((void*)&header, 1, readLength, fp) != readLength)
90   {
91     return false;
92   }
93
94   return true;
95 }
96
97 bool LoadBmpHeader(FILE *fp, unsigned int &width, unsigned int &height, BmpFileHeader &fileHeader, BmpInfoHeader &infoHeader)
98 {
99   if (!ReadHeader(fp, fileHeader))
100   {
101     return false;
102   }
103
104   if (!ReadHeader(fp, infoHeader))
105   {
106     return false;
107   }
108
109   width = infoHeader.width;
110   height = infoHeader.height;
111
112   return true;
113 }
114
115 /**
116  * function to decode format BI_RGB & bpp = 24 & bmp version5.
117  * @param[in]  fp      The file to read from
118  * @param[out] pixels  The pointer that  we want to store bmp data  in
119  * @param[in]  width   bmp width
120  * @param[in]  height  bmp height
121  * @param[in]  offset  offset from bmp header to bmp image data
122  * @param[in]  topDown indicate image data is read from bottom or from top
123  * @param[in]  padding padded to a u_int32 boundary for each line
124  * @return true, if decode successful, false otherwise
125  */
126 bool DecodeRGB24V5(FILE *fp,
127                    PixelBuffer *pixels,
128                    unsigned int width,
129                    unsigned int height,
130                    unsigned int offset,
131                    bool topDown,
132                    unsigned int rowStride,
133                    unsigned int padding)
134 {
135   if(fp == NULL || pixels == NULL)
136   {
137     DALI_LOG_ERROR("Error decoding BMP_RGB24V5 format\n");
138     return false;
139   }
140   if ( fseek(fp, offset, SEEK_SET) )
141   {
142     DALI_LOG_ERROR("Error seeking BMP_RGB24V5 data\n");
143     return false;
144   }
145
146   for(unsigned int yPos = 0; yPos < height; yPos ++)
147   {
148     PixelBuffer *pixelsPtr = NULL;
149     if(topDown)
150     {
151       pixelsPtr = pixels + ( yPos * rowStride);
152     }
153     else
154     {
155       pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
156     }
157     if (fread(pixelsPtr, 1, rowStride, fp) != rowStride)
158     {
159       DALI_LOG_ERROR("Error reading the BMP image\n");
160       return false;
161     }
162     for(unsigned int i = 0; i < rowStride; i += 3)
163     {
164       unsigned char temp = pixelsPtr[i];
165       pixelsPtr[i] = pixelsPtr[i + 2];
166       pixelsPtr[i + 2] = temp;
167     }
168
169     if (padding)
170     {
171       // move past the padding.
172       if( fseek(fp, padding, SEEK_CUR) )
173       {
174         DALI_LOG_ERROR("Error moving past BMP_RGB24V5 padding\n");
175       }
176     }
177   }
178   return true;
179 }
180
181 /**
182  * function to decode format BI_BITFIELDS & bpp = 32 & bmp version4.
183  * @param[in]  fp        The file to read from
184  * @param[out] pixels    The pointer that  we want to store bmp data  in
185  * @param[in]  width     bmp width
186  * @param[in]  height    bmp height
187  * @param[in]  offset    offset from bmp header to bmp image data
188  * @param[in]  topDown   indicate image data is read from bottom or from top
189  * @param[in]  rowStride bits span for each line
190  * @param[in]  padding   padded to a u_int32 boundary for each line
191  * @return true, if decode successful, false otherwise
192  */
193 bool DecodeBF32V4(FILE *fp,
194                   PixelBuffer *pixels,
195                   unsigned int width,
196                   unsigned int height,
197                   unsigned int offset,
198                   bool topDown,
199                   unsigned int rowStride,
200                   unsigned int padding)
201 {
202   if(fp == NULL || pixels == NULL)
203   {
204     DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32V4 format\n");
205     return false;
206   }
207   if( fseek(fp, offset, SEEK_SET) )
208   {
209     DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32V4 data\n");
210     return false;
211   }
212
213   for(unsigned int yPos = 0; yPos < height; yPos ++)
214   {
215     PixelBuffer *pixelsPtr = NULL;
216     if(topDown)
217     {
218       pixelsPtr = pixels + ( yPos * rowStride);
219     }
220     else
221     {
222       pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
223     }
224     if (fread(pixelsPtr, 1, rowStride, fp) != rowStride)
225     {
226       DALI_LOG_ERROR("Error reading the BMP image\n");
227       return false;
228     }
229     for(unsigned int i = 0; i < rowStride; i += 4)
230     {
231       unsigned char temp = pixelsPtr[i];
232       pixelsPtr[i] = pixelsPtr[i + 2];
233       pixelsPtr[i + 2] = temp;
234     }
235     if (padding)
236     {
237       // move past the padding.
238       if( fseek(fp, padding, SEEK_CUR) )
239       {
240         DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32V4 padding\n");
241       }
242     }
243
244   }
245   return true;
246 }
247
248 /**
249  * function to decode format BI_BITFIELDS & bpp = 32
250  * @param[in]  fp        The file to read from
251  * @param[out] pixels    The pointer that  we want to store bmp data  in
252  * @param[in]  width     bmp width
253  * @param[in]  height    bmp height
254  * @param[in]  offset    offset from bmp header to bmp image data
255  * @param[in]  topDown   indicate image data is read from bottom or from top
256  * @param[in]  rowStride bits span for each line
257  * @param[in]  padding   padded to a u_int32 boundary for each line
258  * @return true, if decode successful, false otherwise
259  */
260 bool DecodeBF32(FILE *fp,
261                 PixelBuffer *pixels,
262                 unsigned int width,
263                 unsigned int height,
264                 unsigned int offset,
265                 bool topDown,
266                 unsigned int rowStride,
267                 unsigned int padding)
268 {
269   if(fp == NULL || pixels == NULL)
270   {
271     DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32 format\n");
272     return false;
273   }
274   if( fseek(fp, offset, SEEK_SET) )
275   {
276     DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32 data\n");
277     return false;
278   }
279
280   for (unsigned int yPos = 0; yPos < height; yPos++)
281   {
282     PixelBuffer *pixelsPtr;
283     if (topDown)
284     {
285       // the data in the file is top down, and we store the data top down
286       pixelsPtr = pixels + ( yPos * rowStride);
287     }
288     else
289     {
290       // the data in the file is bottom up, and we store the data top down
291       pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
292     }
293
294     if (fread(pixelsPtr, 1, rowStride, fp) != rowStride)
295     {
296       DALI_LOG_ERROR("Error reading the BMP image\n");
297       return false;
298     }
299     for(unsigned int i = 0; i < rowStride; i += 4)
300     {
301       unsigned char temp = pixelsPtr[i];
302       pixelsPtr[i] = pixelsPtr[i + 2];
303       pixelsPtr[i + 2] = temp;
304     }
305
306     if (padding)
307     {
308       // move past the padding.
309       if( fseek(fp, padding, SEEK_CUR) )
310       {
311         DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32 padding\n");
312       }
313     }
314   }
315   return true;
316 }
317
318 /**
319  * function to decode format BI_BITFIELDS & bpp = 16 & R:G:B = 5:6:5
320  * @param[in]  fp      The file to read from
321  * @param[out] pixels  The pointer that  we want to store bmp data  in
322  * @param[in]  width   bmp width
323  * @param[in]  height  bmp height
324  * @param[in]  offset  offset from bmp header to bmp image data
325  * @param[in]  topDown indicate image data is read from bottom or from top
326  * @return true, if decode successful, false otherwise
327  */
328 bool DecodeBF565(FILE *fp,
329                  PixelBuffer *pixels,
330                  unsigned int width,
331                  unsigned int height,
332                  unsigned int offset,
333                  bool topDown)
334 {
335   if(fp == NULL || pixels == NULL)
336   {
337     DALI_LOG_ERROR("Error decoding RGB565 format\n");
338     return false;
339   }
340   if( fseek(fp, offset, SEEK_SET) )
341   {
342     DALI_LOG_ERROR("Error seeking RGB565 data\n");
343     return false;
344   }
345
346   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
347   unsigned int rowStride = width * 2;
348
349   for(unsigned int i = 0; i < height; i++)
350   {
351     PixelBuffer *pixelsPtr = NULL;
352     if (topDown)
353     {
354       // the data in the file is top down, and we store the data top down
355       pixelsPtr = pixels + ( i * rowStride);
356     }
357     else
358     {
359       // the data in the file is bottom up, and we store the data top down
360       pixelsPtr = pixels + (((height - 1) - i) * rowStride);
361     }
362     if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
363     {
364       return false;
365     }
366   }
367
368   return true;
369 }
370
371 /**
372  * function to decode format BI_BITFIELDS & bpp = 16 & R:G:B = 5:5:5
373  * @param[in]  fp      The file to read from
374  * @param[out] pixels  The pointer that  we want to store bmp data  in
375  * @param[in]  width   bmp width
376  * @param[in]  height  bmp height
377  * @param[in]  offset  offset from bmp header to bmp image data
378  * @param[in]  topDown indicate image data is read from bottom or from top
379  * @return true, if decode successful, false otherwise
380  */
381 bool DecodeBF555(FILE *fp,
382                  PixelBuffer *pixels,
383                  unsigned int width,
384                  unsigned int height,
385                  unsigned int offset,
386                  bool topDown)
387 {
388   if(fp == NULL || pixels == NULL)
389   {
390     DALI_LOG_ERROR("Error decoding BMP_BITFIELDS555 format\n");
391     return false;
392   }
393
394   if( fseek(fp, offset, SEEK_SET) )
395   {
396     DALI_LOG_ERROR("Error seeking BMP_BITFIELDS555 data\n");
397     return false;
398   }
399
400   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
401
402   std::vector<char> raw(width * height * 2);
403   unsigned int rawStride = width * 2;
404   unsigned int rowStride = width * 3;
405
406   char *rawPtr = NULL;
407   for(unsigned int j = 0; j <  height; j ++)
408   {
409     rawPtr = &raw[0] + ( j * rawStride);
410     if(fread(rawPtr, 1, rawStride, fp) != rawStride)
411     {
412       return false;
413     }
414   }
415
416   for (unsigned int yPos = 0; yPos < height; yPos++)
417   {
418     PixelBuffer *pixelsPtr = NULL;
419     if (topDown)
420     {
421       // the data in the file is top down, and we store the data top down
422       pixelsPtr = pixels + ( yPos * rowStride);
423     }
424     else
425     {
426       // the data in the file is bottom up, and we store the data top down
427       pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
428     }
429
430     for(unsigned int k = 0; k < width; k ++)
431     {
432       int index = yPos * rawStride + 2 * k;
433       pixelsPtr[3 * k] = ((raw[ index + 1] >> 2) & 0x1F) * 0xFF / 0x1F;
434       pixelsPtr[3 * k + 1] = (((raw[index + 1] & 0x03) << 3) | (raw[ index] >> 5))  * 0xFF/ 0x1F;
435       pixelsPtr[3 * k + 2] = (raw[ index] & 0x1F) * 0xFF / 0x1F;
436     }
437   }
438   return true;
439 }
440
441 /**
442  * function to decode format BI_RGB & bpp = 16 & R:G:B = 5:5:5
443  * @param[in]  fp      The file to read from
444  * @param[out] pixels  The pointer that  we want to store bmp data  in
445  * @param[in]  width   bmp width
446  * @param[in]  height  bmp height
447  * @param[in]  offset  offset from bmp header to bmp image data
448  * @param[in]  topDown indicate image data is read from bottom or from top
449  * @return true, if decode successful, false otherwise
450  */
451 bool DecodeRGB555(FILE *fp,
452                   PixelBuffer *pixels,
453                   unsigned int width,
454                   unsigned int height,
455                   unsigned int offset,
456                   bool topDown)
457 {
458   if(fp == NULL || pixels == NULL)
459   {
460     DALI_LOG_ERROR("Error decoding BMP_RGB555 format\n");
461     return false;
462   }
463   if( fseek(fp, offset, SEEK_SET) )
464   {
465     DALI_LOG_ERROR("Error seeking BMP_RGB555 data\n");
466     return false;
467   }
468
469   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
470   std::vector<char> raw(width * height * 2);
471   unsigned int rawStride = width * 2;
472   unsigned int rowStride = width * 3;
473
474   char *rawPtr = NULL;
475   for(unsigned int j = 0; j <  height; j ++)
476   {
477     rawPtr = &raw[0] + ( j * rawStride);
478     if(fread(rawPtr, 1, rawStride, fp) != rawStride)
479     {
480       return false;
481     }
482   }
483   for(unsigned int i = 0; i < height; i++)
484   {
485     PixelBuffer *pixelsPtr = NULL;
486     if (topDown)
487     {
488       // the data in the file is top down, and we store the data top down
489       pixelsPtr = pixels + ( i * rowStride);
490     }
491     else
492     {
493       // the data in the file is bottom up, and we store the data top down
494       pixelsPtr = pixels + (((height - 1) - i) * rowStride);
495     }
496     for(unsigned int k = 0; k < width; k ++)
497     {
498       int index = i * rawStride + 2 * k;
499       pixelsPtr[3 * k] = ((raw[ index + 1] >> 2) & 0x1F) * 0xFF / 0x1F;
500       pixelsPtr[3 * k + 1] = (((raw[index + 1] & 0x03) << 3) | (raw[ index] >> 5))  * 0xFF/ 0x1F;
501       pixelsPtr[3 * k + 2] = (raw[ index] & 0x1F) * 0xFF / 0x1F;
502     }
503
504   }
505   return true;
506 }
507
508 /**
509  * function to decode format BI_RGB & bpp = 1
510  * @param[in]  fp      The file to read from
511  * @param[out] pixels  The pointer that  we want to store bmp data  in
512  * @param[in]  width   bmp width
513  * @param[in]  height  bmp height
514  * @param[in]  offset  offset from bmp header to bmp palette data
515  * @param[in]  topDown indicate image data is read from bottom or from top
516  * @return true, if decode successful, false otherwise
517  */
518 bool DecodeRGB1(FILE *fp,
519                 PixelBuffer *pixels,
520                 unsigned int width,
521                 unsigned int height,
522                 unsigned int offset,
523                 bool topDown)
524 {
525   if(fp == NULL || pixels == NULL)
526   {
527     DALI_LOG_ERROR("Error decoding BMP_RGB1 format\n");
528     return false;
529   }
530   if( fseek(fp, offset, SEEK_SET) )
531   {
532     DALI_LOG_ERROR("Error seeking BMP_RGB1 data\n");
533     return false;
534   }
535
536   unsigned char colorTable[8] = {0};
537   char cmd;
538   unsigned int fillw = ((width & 63) != 0) ? width + 64 - (width & 63) : width;
539   std::vector<char> colorIndex(fillw * height);
540   unsigned int rowStride = fillw * 3; // RGB
541
542
543   if(fread(colorTable, 1, 8, fp) != 8)
544   {
545     return false;
546   }
547
548   for(unsigned int i = 0; i < fillw * height; i += 8)
549   {
550     if(fread(&cmd, 1, 1, fp) != 1)
551     {
552       return false;
553     }
554
555     colorIndex[i]     = (cmd >> 7) & 0x01;
556     colorIndex[i + 1] = (cmd >> 6) & 0x01;
557     colorIndex[i + 2] = (cmd >> 5) & 0x01;
558     colorIndex[i + 3] = (cmd >> 4) & 0x01;
559     colorIndex[i + 4] = (cmd >> 3) & 0x01;
560     colorIndex[i + 5] = (cmd >> 2) & 0x01;
561     colorIndex[i + 6] = (cmd >> 1) & 0x01;
562     colorIndex[i + 7] = (cmd & 0x01);
563   }
564
565   for(unsigned int index = 0; index < height; index = index + 1)
566   {
567     PixelBuffer *pixelsPtr = NULL;
568     if (topDown)
569     {
570       // the data in the file is top down, and we store the data top down
571       pixelsPtr = pixels + ( index * rowStride);
572     }
573     else
574     {
575       // the data in the file is bottom up, and we store the data top down
576       pixelsPtr = pixels + (((height - 1) - index) * rowStride);
577     }
578     for(unsigned int j = 0; j < fillw; j ++)
579     {
580       int ctIndex = 0;
581       if((fillw * index + j ) < (fillw * height))
582       {
583         ctIndex = colorIndex[ fillw * index + j ];
584       }
585       else
586       {
587         break;
588       }
589       // temp solution for PLM bug P130411-5268, there is one mono bmp that cause DecodeRGB1 API crash.
590       if( ((3 * j + 2) < height * fillw * 3) && (ctIndex < 2))
591       {
592         pixelsPtr[ 3 * j ] = colorTable[4 * ctIndex + 2];
593         pixelsPtr[3 * j + 1] = colorTable[4 * ctIndex + 1];
594         pixelsPtr[3 * j + 2] = colorTable[4 * ctIndex ];
595       }
596     }
597   }
598   return true;
599 }
600
601 /**
602  * function to decode format BI_RGB & bpp = 4
603  * @param[in]  fp      The file to read from
604  * @param[out] pixels  The pointer that  we want to store bmp data  in
605  * @param[in]  width   bmp width
606  * @param[in]  height  bmp height
607  * @param[in]  offset  offset from bmp header to bmp palette data
608  * @param[in]  topDown indicate image data is read from bottom or from top
609  * @return true, if decode successful, false otherwise
610  */
611 bool DecodeRGB4(FILE *fp,
612                 PixelBuffer *pixels,
613                 unsigned int width,
614                 unsigned int height,
615                 unsigned int offset,
616                 bool topDown)
617 {
618   if(fp == NULL || pixels == NULL)
619   {
620     DALI_LOG_ERROR("Error decoding BMP_RGB4 format\n");
621     return false;
622   }
623   if( fseek(fp, offset, SEEK_SET) )
624   {
625     DALI_LOG_ERROR("Error seeking BMP_RGB4 data\n");
626     return false;
627   }
628
629   char colorTable[64];
630   char cmd;
631   unsigned int fillw = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
632   std::vector<char> colorIndex(fillw * height);
633   unsigned int rowStride = fillw  * 3;
634
635   if(fread(colorTable, 1, 64, fp) != 64)
636   {
637     return false;
638   }
639
640   for(unsigned int i = 0; i < fillw * height; i += 2)
641   {
642     if (fread(&cmd, 1, 1, fp) != 1)
643     {
644       return false;
645     }
646
647     colorIndex[i] = cmd >> 4;
648     colorIndex[i + 1] = cmd & (0x0F);
649   }
650   int ctIndex = 0;
651
652   for(unsigned int index = 0; index < height; index = index + 1)
653   {
654     PixelBuffer *pixelsPtr = NULL;
655     if (topDown)
656     {
657       // the data in the file is top down, and we store the data top down
658       pixelsPtr = pixels + ( index * rowStride);
659     }
660     else
661     {
662       // the data in the file is bottom up, and we store the data top down
663       pixelsPtr = pixels + (((height - 1) - index) * rowStride);
664     }
665     for(unsigned int j = 0; j < fillw; j ++)
666     {
667       ctIndex = colorIndex[ fillw * index + j ];
668       pixelsPtr[ 3 * j ] = colorTable[4 * ctIndex + 2];
669       pixelsPtr[(3 * j + 1)] = colorTable[4 * ctIndex + 1];
670       pixelsPtr[(3 * j + 2)] = colorTable[4 * ctIndex ];
671     }
672   }
673
674   return true;
675 }
676
677 /**
678  * function to decode format BI_RGB & bpp = 8
679  * @param[in]  fp      The file to read from
680  * @param[out] pixels  The pointer that  we want to store bmp data  in
681  * @param[in]  width   bmp width
682  * @param[in]  height  bmp height
683  * @param[in]  offset  offset from bmp header to bmp palette data
684  * @param[in]  topDown indicate image data is read from bottom or from top
685  * @return true, if decode successful, false otherwise
686  */
687 bool DecodeRGB8(FILE *fp,
688                 PixelBuffer *pixels,
689                 unsigned int width,
690                 unsigned int height,
691                 unsigned int offset,
692                 bool topDown)
693 {
694   if(fp == NULL || pixels == NULL)
695   {
696     DALI_LOG_ERROR("Error decoding BMP_RGB8 format\n");
697     return false;
698   }
699   if( fseek(fp, offset, SEEK_SET) )
700   {
701     DALI_LOG_ERROR("Error seeking BMP_RGB8 data\n");
702     return false;
703   }
704
705   std::vector<char> colorTable(1024);
706   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
707   char cmd;
708   std::vector<char> colorIndex(width * height);
709   unsigned int rowStride = width * 3;//RGB8->RGB24
710
711   if(fread(&colorTable[0], 1, 1024, fp) != 1024)
712   {
713     return false;
714   }
715   for(unsigned int i = 0; i < width * height; i ++)
716   {
717     if (fread(&cmd, 1, 1, fp) != 1)
718     {
719       return false;
720     }
721
722     colorIndex[i] = cmd;
723   }
724   int ctIndex = 0;
725   for(unsigned int index = 0; index < height; index = index + 1)
726   {
727     PixelBuffer *pixelsPtr = NULL;
728     if (topDown)
729     {
730       // the data in the file is top down, and we store the data top down
731       pixelsPtr = pixels + ( index * rowStride);
732     }
733     else
734     {
735       // the data in the file is bottom up, and we store the data top down
736       pixelsPtr = pixels + (((height - 1) - index) * rowStride);
737     }
738     for(unsigned int j = 0; j < width; j ++)
739     {
740       ctIndex = colorIndex[ width * index + j ];
741       pixelsPtr[ 3 * j ] = colorTable[4 * ctIndex + 2];
742       pixelsPtr[(3 * j + 1)] = colorTable[4 * ctIndex + 1];
743       pixelsPtr[(3 * j + 2)] = colorTable[4 * ctIndex ];
744     }
745   }
746   return true;
747 }
748
749 /**
750  * function to decode format BI_RLE4 & bpp = 4
751  * @param[in]  fp      The file to read from
752  * @param[out] pixels  The pointer that  we want to store bmp data  in
753  * @param[in]  width   bmp width
754  * @param[in]  height  bmp height
755  * @param[in]  offset  offset from bmp header to bmp palette data
756  * @param[in]  topDown indicate image data is read from bottom or from top
757  * @return true, if decode successful, false otherwise
758  */
759 bool DecodeRLE4(FILE *fp,
760                 PixelBuffer *pixels,
761                 unsigned int width,
762                 unsigned int height,
763                 unsigned int offset,
764                 bool topDown)
765 {
766   if(fp == NULL || pixels == NULL)
767   {
768     DALI_LOG_ERROR("Error decoding BMP_RLE4 format\n");
769     return false;
770   }
771   PixelBuffer *pixelsPtr = pixels;
772   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
773   char cmd[2];
774   unsigned int cmdStride = 2;
775   char colorTable[64];
776   std::vector<char> colorIndex(width * height >> 1);
777   std::vector<char> run;
778   int x = 0;
779   int y = 0;
780   int dx = 0;
781   int dy = 0;
782   width += (width & 1);
783   width = width >> 1;
784
785   bool finish = false;
786
787   if( fseek(fp, offset, SEEK_SET) )
788   {
789     DALI_LOG_ERROR("Error seeking BMP_RLE4 data\n");
790     return false;
791   }
792
793   if (fread(colorTable, 1, 64, fp) != 64)
794   {
795     return false;
796   }
797
798   while((x >> 1) + y * width < width * height)
799   {
800     if (finish)
801     {
802       break;
803     }
804     if (fread(cmd, 1, cmdStride, fp) != cmdStride)
805     {
806       return false;
807     }
808     if(cmd[0] == 0) // ESCAPE
809     {
810       switch(cmd[1])
811       {
812         case 1: //end of bitmap
813           finish = true;
814           break;
815         case 0: // end of line
816           x = 0;
817           y ++;
818           break;
819         case 2: // delta
820           if (fread(cmd, 1, cmdStride, fp) != cmdStride)
821           {
822             DALI_LOG_ERROR("Error reading the BMP image\n");
823             return false;
824           }
825           dx = cmd[0] & (0xFF);
826           dy = cmd[1] & (0xFF);
827           x += dx;
828           y += dy;
829           break;
830         default:
831           // decode a literal run
832           unsigned int length = cmd[1] & (0xFF);
833           //size of run, which is word aligned
834           unsigned int bytesize = length;
835           bytesize += (bytesize & 1);
836           bytesize >>= 1;
837           bytesize += (bytesize & 1);
838           run.resize(bytesize);
839           if(fread(&run[0], 1, bytesize, fp) != bytesize)
840           {
841             DALI_LOG_ERROR("Error reading the BMP image\n");
842             return false;
843           }
844           if((x & 1) == 0)
845           {
846             length += (length & 1);
847             length >>= 1;
848             for(unsigned int i = 0; i < length; i += 1)
849             {
850               colorIndex[(x >> 1) + width * (height - y - 1) + i] = run[i];
851             }
852           }
853           else
854           {
855             for(unsigned int i = 0; i < length; i ++)
856             {
857               if((i & 1) == 0)//copy high to low
858               {
859                 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((run[i >> 1] & 0xF0) >> 4);
860               }
861               else //copy low to high
862               {
863                 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((run[i >> 1] & 0x0F) << 4);
864               }
865             }
866           }
867           x += cmd[1] & (0xFF);
868           break;
869       }
870     }
871     else
872     {
873       unsigned int length = cmd[0] & (0xFF);
874       if((x & 1) == 0)
875       {
876         length += (length & 1);
877         length >>= 1;
878         for(unsigned int i = 0; i < length; i ++)
879         {
880           colorIndex[(height-y-1)*width + i + (x >> 1)] = cmd[1];
881         }
882       }
883       else
884       {
885         for(unsigned int i = 0; i < length; i ++)
886         {
887           if((i & 1) == 0)
888           {
889             colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((cmd[1] & 0xF0) >> 4);
890           }
891           else
892           {
893             colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((cmd[1] & 0x0F) << 4);
894           }
895         }
896       }
897       x += cmd[0] & (0xFF);
898     }
899   }
900
901   int ctIndexHigh = 0;
902   int ctIndexLow = 0;
903   for(unsigned int index = 0; index < (width * height ); index = index + 1)
904   {
905     ctIndexHigh = colorIndex[ index] >> 4;
906     ctIndexLow = colorIndex[index] & (0x0F);
907     pixelsPtr[6 * index ] = colorTable[4 * ctIndexHigh + 2];
908     pixelsPtr[6 * index + 1] = colorTable[4 * ctIndexHigh + 1];
909     pixelsPtr[6 * index + 2] = colorTable[4 * ctIndexHigh ];
910     pixelsPtr[6 * index + 3] = colorTable[4 * ctIndexLow + 2];
911     pixelsPtr[6 * index + 4] = colorTable[4 * ctIndexLow + 1];
912     pixelsPtr[6 * index + 5] = colorTable[4 * ctIndexLow ];
913   }
914   return true;
915 }
916
917 /**
918  * function to decode format BI_RLE8 & bpp = 8
919  * @param[in]  fp      The file to read from
920  * @param[out] pixels  The pointer that  we want to store bmp data  in
921  * @param[in]  width   bmp width
922  * @param[in]  height  bmp height
923  * @param[in]  offset  offset from bmp header to bmp palette data
924  * @param[in]  topDown indicate image data is read from bottom or from top
925  * @return true, if decode successful, false otherwise
926  */
927 bool DecodeRLE8(FILE *fp,
928                 PixelBuffer *pixels,
929                 unsigned int width,
930                 unsigned int height,
931                 unsigned int offset,
932                 bool topDown)
933 {
934   if(fp == NULL || pixels == NULL)
935   {
936     DALI_LOG_ERROR("Error decoding BMP_RLE8 format\n");
937     return false;
938   }
939   PixelBuffer *pixelsPtr = pixels;
940   int x = 0;
941   int y = 0;
942   unsigned int cmdStride = 2;
943
944   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
945   std::vector<char> colorTable(1024);
946   char cmd[2];
947   std::vector<char> colorIndex(width * height);
948
949   if( fseek(fp, offset, SEEK_SET) )
950   {
951     DALI_LOG_ERROR("Error seeking BMP_RLE8 data\n");
952     return false;
953   }
954
955   if (fread(&colorTable[0], 1, 1024, fp) != 1024)
956   {
957     return false;
958   }
959
960   int dx = 0;
961   int dy = 0;
962   bool finish = false;
963   unsigned int length = 0;
964   unsigned int copylength = 0;
965   std::vector<char> run;
966   while((x + y * width) < width * height )
967   {
968     if (finish)
969     {
970       break;
971     }
972     if (fread(cmd, 1, cmdStride, fp) != cmdStride)
973     {
974       return false;
975     }
976
977     if(cmd[0] == 0)//ESCAPE
978     {
979       switch(cmd[1])
980       {
981         case 1: // end of bitmap
982           finish = true;
983           break;
984         case 0: // end of line
985           x = 0;
986           y ++;
987           break;
988         case 2: // delta
989           if (fread(cmd, 1, cmdStride, fp) != cmdStride)
990           {
991             DALI_LOG_ERROR("Error reading the BMP image\n");
992             return false;
993           }
994           dx = cmd[0] & (0xFF);
995           dy = cmd[1] & (0xFF);
996           x += dx;
997           y += dy;
998           break;
999         default:
1000           //decode a literal run
1001           length = cmd[1] & (0xFF);
1002           copylength = length;
1003           //absolute mode must be word-aligned
1004           length += (length & 1);
1005           run.resize(length);
1006           if(fread(&run[0], 1, length, fp) != length)
1007           {
1008             DALI_LOG_ERROR("Error reading the BMP image\n");
1009             return false;
1010           }
1011
1012           for(unsigned int i = 0; i < length; i += 1)
1013           {
1014             colorIndex[x + width * (height - y - 1) + i] = run[i];
1015           }
1016           x += copylength;
1017           break;
1018       }
1019     }// end if cmd[0] ==
1020     else
1021     {
1022       length = cmd[0] & (0xFF);
1023       for(unsigned int i = 0; i < length; i ++)
1024       {
1025         colorIndex[(height - y - 1) * width + x] = cmd[1];
1026         x++;
1027       }
1028     }
1029   }
1030   int ctIndex = 0;
1031   for(unsigned int index = 0; index < width * height; index = index + 1)
1032   {
1033     ctIndex = colorIndex[ index];
1034     pixelsPtr[3 * index ] = colorTable[4 * ctIndex + 2];
1035     pixelsPtr[3 * index + 1] = colorTable[4 * ctIndex + 1];
1036     pixelsPtr[3 * index + 2] = colorTable[4 * ctIndex ];
1037   }
1038   return true;
1039 }
1040
1041 } // unnamed namespace
1042
1043 bool LoadBmpHeader(FILE *fp, const ImageAttributes& attributes, unsigned int &width, unsigned int &height)
1044 {
1045   BmpFileHeader fileHeader;
1046   BmpInfoHeader infoHeader;
1047
1048   bool ret = LoadBmpHeader(fp, width, height, fileHeader, infoHeader);
1049
1050   return ret;
1051 }
1052
1053 bool LoadBitmapFromBmp( FILE *fp, Bitmap& bitmap, ImageAttributes& attributes, const ResourceLoadingClient& client )
1054 {
1055   DALI_ASSERT_DEBUG(bitmap.GetPackedPixelsProfile() != 0 && "Need a packed pixel bitmap to load into.");
1056   if(fp == NULL)
1057   {
1058     DALI_LOG_ERROR("Error loading bitmap\n");
1059     return false;
1060   }
1061   BmpFormat customizedFormat = BMP_NOTEXIST;
1062   BmpFileHeader fileHeader;
1063   BmpInfoHeader infoHeader;
1064
1065   // Load the header info
1066   unsigned int width, height;
1067
1068   if (!LoadBmpHeader(fp, width, height, fileHeader, infoHeader))
1069   {
1070       return false;
1071   }
1072
1073   Pixel::Format pixelFormat = Pixel::RGB888;
1074   switch(infoHeader.compression)
1075   {
1076     case 0:
1077       switch (infoHeader.bitsPerPixel)
1078       {
1079         case 32:
1080           pixelFormat = Pixel::BGR8888;
1081           break;
1082
1083         case 24:
1084           if(fileHeader.offset == FileHeaderOffsetOfRGB24V5)//0x8A
1085           {
1086             customizedFormat = BMP_RGB24V5;
1087           }
1088           else
1089           {
1090             pixelFormat = Pixel::RGB888;
1091           }
1092           break;
1093
1094         case 16:
1095           customizedFormat = BMP_RGB555;
1096           break;
1097
1098         case 8:
1099           customizedFormat = BMP_RGB8;
1100           break;
1101
1102         case 4: // RGB4
1103           customizedFormat = BMP_RGB4;
1104           break;
1105
1106         case 1: //RGB1
1107           customizedFormat = BMP_RGB1;
1108           break;
1109         default:
1110           DALI_LOG_WARNING("%d bits per pixel not supported for BMP files\n", infoHeader.bitsPerPixel);
1111           return false;
1112       }
1113     break;
1114     case 1: //// RLE8
1115     {
1116       if(infoHeader.bitsPerPixel == 8)
1117       {
1118         customizedFormat = BMP_RLE8;
1119       }
1120       break;
1121     }
1122     case 2: // RLE4
1123     {
1124       if(infoHeader.bitsPerPixel == 4)
1125       {
1126         customizedFormat = BMP_RLE4;
1127       }
1128       break;
1129     }
1130     case 3: // // BI_BITFIELDS
1131     {
1132       if(infoHeader.bitsPerPixel == 16)
1133       {
1134         if( fseek(fp, 14 + infoHeader.infoHeaderSize + 1, SEEK_SET) )
1135         {
1136           return false;
1137         }
1138
1139         char mask;
1140         if(fread(&mask, 1, 1, fp) != 1)
1141         {
1142           return false;
1143         }
1144
1145         if((mask & 0x80) == MaskForBFRGB565) // mask is 0xF8
1146         {
1147           pixelFormat = Pixel::RGB565;
1148         }
1149         else if((mask & 0x80) == 0)// mask is 0x 7C
1150         {
1151           customizedFormat = BMP_BITFIELDS555;
1152         }
1153         else
1154         {
1155           return false;
1156         }
1157       }
1158       else if(infoHeader.bitsPerPixel == 32)
1159       {
1160         if(fileHeader.offset == FileHeaderOffsetOfBF32V4)// 0x7A
1161         {
1162           customizedFormat = BMP_BITFIELDS32V4;
1163         }
1164         else
1165         {
1166           customizedFormat = BMP_BITFIELDS32;
1167         }
1168       }
1169       break;
1170     }
1171     default:
1172       DALI_LOG_WARNING("Compression not supported for BMP files\n");
1173       return false;
1174   }
1175
1176   bool topDown = false;
1177
1178   // if height is negative, bitmap data is top down
1179   if (infoHeader.height<0)
1180   {
1181     infoHeader.height =  abs(infoHeader.height);
1182     height = infoHeader.height;
1183     topDown = true;
1184   }
1185
1186   unsigned int rowStride = infoHeader.width * (infoHeader.bitsPerPixel >>3);
1187
1188   // bitmaps row stride is padded to 4 bytes
1189   unsigned int padding = (rowStride % 4);
1190   if (padding)
1191   {
1192     padding = 4 - padding;
1193   }
1194
1195   PixelBuffer *pixels =  NULL;
1196   int imageW = infoHeader.width;
1197   int pixelBufferW = 0;
1198   switch(customizedFormat)
1199   {
1200   case BMP_RLE8:
1201   case BMP_RGB8:
1202   case BMP_RGB4:
1203   case BMP_RLE4:
1204   case BMP_RGB555:
1205   case BMP_BITFIELDS555:
1206   {
1207     pixelBufferW = ((imageW & 3) != 0) ? imageW + 4 - (imageW & 3) : imageW;
1208     pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGB888, pixelBufferW, abs(infoHeader.height));
1209     break;
1210   }
1211   case BMP_RGB1:
1212   {
1213     pixelBufferW = ((imageW & 63) != 0) ? imageW + 64 - (imageW & 63) : imageW;
1214     pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGB888, pixelBufferW, abs(infoHeader.height));
1215     break;
1216   }
1217   case BMP_BITFIELDS32:
1218   case BMP_BITFIELDS32V4:
1219   {
1220     pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGB8888, infoHeader.width, abs(infoHeader.height));
1221     break;
1222   }
1223   case BMP_RGB24V5:
1224   {
1225     pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGB888, infoHeader.width, infoHeader.height);
1226     break;
1227   }
1228   default:
1229     if(pixelFormat == Pixel::RGB565 )
1230     {
1231       pixelBufferW = ((imageW & 3) != 0) ? imageW + 4 - (imageW & 3) : imageW;
1232       pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGB565, pixelBufferW, abs(infoHeader.height));
1233     }
1234     else
1235     {
1236       pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(pixelFormat, infoHeader.width, infoHeader.height);
1237     }
1238     break;
1239   }
1240
1241   // TODO: Add scaling support
1242
1243   // Read the raw bitmap data
1244   PixelBuffer *pixelsPtr;
1245   bool decodeResult(false);
1246   switch(customizedFormat)
1247   {
1248     case BMP_RGB1:
1249     {
1250       decodeResult = DecodeRGB1( fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1251       break;
1252     }
1253     case BMP_RGB4:
1254     {
1255       decodeResult = DecodeRGB4(fp, pixels, infoHeader.width, infoHeader.height, 14 + infoHeader.infoHeaderSize, topDown);
1256       break;
1257     }
1258     case BMP_RLE4:
1259     {
1260       decodeResult = DecodeRLE4( fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1261       break;
1262     }
1263     case BMP_BITFIELDS32:
1264     {
1265       decodeResult = DecodeBF32(fp, pixels, infoHeader.width,  abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
1266       break;
1267     }
1268     case BMP_BITFIELDS555:
1269     {
1270       decodeResult = DecodeBF555(fp, pixels,infoHeader.width,  abs(infoHeader.height), fileHeader.offset, topDown);
1271       break;
1272     }
1273     case BMP_RGB555:
1274     {
1275       decodeResult = DecodeRGB555(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown);
1276       break;
1277     }
1278     case BMP_RGB8:
1279     {
1280       decodeResult = DecodeRGB8(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1281       break;
1282     }
1283     case BMP_RLE8:
1284     {
1285       decodeResult = DecodeRLE8(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1286       break;
1287     }
1288     case BMP_RGB24V5:
1289     {
1290       decodeResult = DecodeRGB24V5(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
1291       break;
1292     }
1293     case BMP_BITFIELDS32V4:
1294     {
1295       decodeResult = DecodeBF32V4(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
1296       break;
1297     }
1298     default:
1299     {
1300       if(pixelFormat == Pixel::RGB565)
1301       {
1302         decodeResult = DecodeBF565(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset,  topDown);
1303       }
1304       else
1305       {
1306         for (unsigned int yPos = 0; yPos < height; yPos++)
1307         {
1308           if (topDown)
1309           {
1310             // the data in the file is top down, and we store the data top down
1311             pixelsPtr = pixels + ( yPos * rowStride);
1312           }
1313           else
1314           {
1315             // the data in the file is bottom up, and we store the data top down
1316             pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
1317           }
1318
1319           if (fread(pixelsPtr, 1, rowStride, fp) != rowStride)
1320           {
1321             DALI_LOG_ERROR("Error reading the BMP image\n");
1322             break;
1323           }
1324
1325           // If 24 bit mode then swap Blue and Red pixels
1326           // BGR888 doesn't seem to be supported by dali-core
1327           if (infoHeader.bitsPerPixel == 24 )
1328           {
1329             for(unsigned int i = 0; i < rowStride; i += 3)
1330             {
1331               unsigned char temp = pixelsPtr[i];
1332               pixelsPtr[i] = pixelsPtr[i+2];
1333               pixelsPtr[i+2] = temp;
1334             }
1335           }
1336
1337           if (padding)
1338           {
1339             if( fseek(fp, padding, SEEK_CUR) )  // move past the padding.
1340             {
1341               DALI_LOG_ERROR("Error moving past BMP padding\n");
1342             }
1343           }
1344         }
1345         decodeResult = true;
1346       }
1347       break;
1348     }
1349   } // switch
1350
1351   if( !decodeResult )
1352   {
1353     return false;
1354   }
1355
1356   attributes.SetSize(infoHeader.width, infoHeader.height);
1357   attributes.SetPixelFormat(pixelFormat);
1358
1359   switch(customizedFormat)
1360   {
1361     case BMP_RLE8:
1362     case BMP_RGB8:
1363     case BMP_RGB4:
1364     case BMP_RGB1:
1365     case BMP_RLE4:
1366     case BMP_RGB555:
1367     case BMP_BITFIELDS555:
1368     case BMP_RGB24V5:
1369       attributes.SetPixelFormat(Pixel::RGB888);
1370       break;
1371     case BMP_BITFIELDS32:
1372     case BMP_BITFIELDS32V4:
1373       attributes.SetPixelFormat(Pixel::RGB8888);
1374       break;
1375     default:
1376       break;
1377   }
1378   return true;
1379 }
1380
1381 } // namespace SlpPlatform
1382
1383 } // namespace Dali