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