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