Merge "Change "SLP" to "Tizen"" into tizen
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / tizen / 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 #include <cstdlib>
26
27 namespace Dali
28 {
29 using Integration::Bitmap;
30 using Dali::Integration::PixelBuffer;
31 namespace TizenPlatform
32 {
33
34 namespace
35 {
36 const unsigned int FileHeaderOffsetOfBF32V4 = 0x7A;
37 const unsigned int MaskForBFRGB565 = 0x80;
38 const unsigned int FileHeaderOffsetOfRGB24V5 = 0x8A;
39
40 enum BmpFormat
41 {
42   BMP_RGB1 = 14,    //BI_RGB & bpp =1
43   BMP_RGB4,         //BI_RGB & bpp = 4
44   BMP_RGB8,         //BI_RGB & bpp = 8
45   BMP_RGB555,       //BI_RGB & bpp = 16
46   BMP_BITFIELDS555, //BI_BITFIELDS & 16bit & R:G:B = 5:5:5
47   BMP_BITFIELDS32,  //BI_BITFIELDS & 32bit & R:G:B:A = 8:8:8:8
48   BMP_RLE8,         //BI_RLE8
49   BMP_RLE4,         //BI_RLE4
50   BMP_BITFIELDS32V4,//BI_BITFIELDS & 32bit
51   BMP_RGB24V5,      //BI_RGB & bpp = 24 & bmp version5
52   BMP_NOTEXIST
53 };
54
55 struct BmpFileHeader
56 {
57   unsigned short signature; // Bitmap file signature
58   unsigned int   fileSize;  // Bitmap file size in bytes
59   unsigned short reserved1; // Reserved bits
60   unsigned short reserved2; // Reserved bits
61   unsigned int   offset;    // Offset from BMP file header to BMP bits
62 } __attribute__ ( (__packed__)); // Stops the structure from being aligned to every 4 bytes
63
64 struct BmpInfoHeader
65 {
66   unsigned int   infoHeaderSize;  // Specifies the number of bytes required by the info header
67   unsigned int   width;           // The Image Width
68   int            height;          // The Image Height (negative value represents image data is flipped)
69   unsigned short planes;          // The number of color planes, must be 1
70   unsigned short bitsPerPixel;    // The bits per pixel
71   unsigned int   compression;     // The type of compression used by the image
72   unsigned int   imageSize;       // The size of the image in bytes
73   unsigned int   xPixelsPerMeter; // The number of pixels per meter in x axis
74   unsigned int   yPixelsPerMeter; // The number of pixels per meter in y axis
75   unsigned int   numberOfColors;  // The number of colors in the color table
76   unsigned int   importantColors; // The important color count
77 } __attribute__ ( (__packed__)); // Stops the structure from being aligned to every 4 bytes
78
79 /**
80  * Template function to read from the file directly into our structure.
81  * @param[in]  fp     The file to read from
82  * @param[out] header The structure we want to store our information in
83  * @return true, if read successful, false otherwise
84  */
85 template<typename T>
86 inline bool ReadHeader(FILE* fp, T& header)
87 {
88   unsigned int readLength = sizeof(T);
89
90   // Load the information directly into our structure
91   if (fread((void*)&header, 1, readLength, fp) != readLength)
92   {
93     return false;
94   }
95
96   return true;
97 }
98
99 bool LoadBmpHeader(FILE *fp, unsigned int &width, unsigned int &height, BmpFileHeader &fileHeader, BmpInfoHeader &infoHeader)
100 {
101   if (!ReadHeader(fp, fileHeader))
102   {
103     return false;
104   }
105
106   if (!ReadHeader(fp, infoHeader))
107   {
108     return false;
109   }
110
111   width = infoHeader.width;
112   height = infoHeader.height;
113
114   return true;
115 }
116
117 /**
118  * function to decode format BI_RGB & bpp = 24 & bmp version5.
119  * @param[in]  fp      The file to read from
120  * @param[out] pixels  The pointer that  we want to store bmp data  in
121  * @param[in]  width   bmp width
122  * @param[in]  height  bmp height
123  * @param[in]  offset  offset from bmp header to bmp image data
124  * @param[in]  topDown indicate image data is read from bottom or from top
125  * @param[in]  padding padded to a u_int32 boundary for each line
126  * @return true, if decode successful, false otherwise
127  */
128 bool DecodeRGB24V5(FILE *fp,
129                    PixelBuffer *pixels,
130                    unsigned int width,
131                    unsigned int height,
132                    unsigned int offset,
133                    bool topDown,
134                    unsigned int rowStride,
135                    unsigned int padding)
136 {
137   if(fp == NULL || pixels == NULL)
138   {
139     DALI_LOG_ERROR("Error decoding BMP_RGB24V5 format\n");
140     return false;
141   }
142   if ( fseek(fp, offset, SEEK_SET) )
143   {
144     DALI_LOG_ERROR("Error seeking BMP_RGB24V5 data\n");
145     return false;
146   }
147
148   for(unsigned int yPos = 0; yPos < height; yPos ++)
149   {
150     PixelBuffer *pixelsPtr = NULL;
151     if(topDown)
152     {
153       pixelsPtr = pixels + ( yPos * rowStride);
154     }
155     else
156     {
157       pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
158     }
159     if (fread(pixelsPtr, 1, rowStride, fp) != rowStride)
160     {
161       DALI_LOG_ERROR("Error reading the BMP image\n");
162       return false;
163     }
164     for(unsigned int i = 0; i < rowStride; i += 3)
165     {
166       unsigned char temp = pixelsPtr[i];
167       pixelsPtr[i] = pixelsPtr[i + 2];
168       pixelsPtr[i + 2] = temp;
169     }
170
171     if (padding)
172     {
173       // move past the padding.
174       if( fseek(fp, padding, SEEK_CUR) )
175       {
176         DALI_LOG_ERROR("Error moving past BMP_RGB24V5 padding\n");
177       }
178     }
179   }
180   return true;
181 }
182
183 /**
184  * function to decode format BI_BITFIELDS & bpp = 32 & bmp version4.
185  * @param[in]  fp        The file to read from
186  * @param[out] pixels    The pointer that  we want to store bmp data  in
187  * @param[in]  width     bmp width
188  * @param[in]  height    bmp height
189  * @param[in]  offset    offset from bmp header to bmp image data
190  * @param[in]  topDown   indicate image data is read from bottom or from top
191  * @param[in]  rowStride bits span for each line
192  * @param[in]  padding   padded to a u_int32 boundary for each line
193  * @return true, if decode successful, false otherwise
194  */
195 bool DecodeBF32V4(FILE *fp,
196                   PixelBuffer *pixels,
197                   unsigned int width,
198                   unsigned int height,
199                   unsigned int offset,
200                   bool topDown,
201                   unsigned int rowStride,
202                   unsigned int padding)
203 {
204   if(fp == NULL || pixels == NULL)
205   {
206     DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32V4 format\n");
207     return false;
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     PixelBuffer *pixelsPtr = NULL;
218     if(topDown)
219     {
220       pixelsPtr = pixels + ( yPos * rowStride);
221     }
222     else
223     {
224       pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
225     }
226     if (fread(pixelsPtr, 1, rowStride, fp) != rowStride)
227     {
228       DALI_LOG_ERROR("Error reading the BMP image\n");
229       return false;
230     }
231     for(unsigned int i = 0; i < rowStride; i += 4)
232     {
233       unsigned char temp = pixelsPtr[i];
234       pixelsPtr[i] = pixelsPtr[i + 2];
235       pixelsPtr[i + 2] = temp;
236     }
237     if (padding)
238     {
239       // move past the padding.
240       if( fseek(fp, padding, SEEK_CUR) )
241       {
242         DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32V4 padding\n");
243       }
244     }
245
246   }
247   return true;
248 }
249
250 /**
251  * function to decode format BI_BITFIELDS & bpp = 32
252  * @param[in]  fp        The file to read from
253  * @param[out] pixels    The pointer that  we want to store bmp data  in
254  * @param[in]  width     bmp width
255  * @param[in]  height    bmp height
256  * @param[in]  offset    offset from bmp header to bmp image data
257  * @param[in]  topDown   indicate image data is read from bottom or from top
258  * @param[in]  rowStride bits span for each line
259  * @param[in]  padding   padded to a u_int32 boundary for each line
260  * @return true, if decode successful, false otherwise
261  */
262 bool DecodeBF32(FILE *fp,
263                 PixelBuffer *pixels,
264                 unsigned int width,
265                 unsigned int height,
266                 unsigned int offset,
267                 bool topDown,
268                 unsigned int rowStride,
269                 unsigned int padding)
270 {
271   if(fp == NULL || pixels == NULL)
272   {
273     DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32 format\n");
274     return false;
275   }
276   if( fseek(fp, offset, SEEK_SET) )
277   {
278     DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32 data\n");
279     return false;
280   }
281
282   for (unsigned int yPos = 0; yPos < height; yPos++)
283   {
284     PixelBuffer *pixelsPtr;
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   if( fseek(fp, offset, SEEK_SET) )
343   {
344     DALI_LOG_ERROR("Error seeking RGB565 data\n");
345     return false;
346   }
347
348   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
349   unsigned int rowStride = width * 2;
350
351   for(unsigned int i = 0; i < height; i++)
352   {
353     PixelBuffer *pixelsPtr = NULL;
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
396   if( fseek(fp, offset, SEEK_SET) )
397   {
398     DALI_LOG_ERROR("Error seeking BMP_BITFIELDS555 data\n");
399     return false;
400   }
401
402   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
403
404   std::vector<char> raw(width * height * 2);
405   unsigned int rawStride = width * 2;
406   unsigned int rowStride = width * 3;
407
408   char *rawPtr = NULL;
409   for(unsigned int j = 0; j <  height; j ++)
410   {
411     rawPtr = &raw[0] + ( j * rawStride);
412     if(fread(rawPtr, 1, rawStride, fp) != rawStride)
413     {
414       return false;
415     }
416   }
417
418   for (unsigned int yPos = 0; yPos < height; yPos++)
419   {
420     PixelBuffer *pixelsPtr = NULL;
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   return true;
441 }
442
443 /**
444  * function to decode format BI_RGB & bpp = 16 & R:G:B = 5:5:5
445  * @param[in]  fp      The file to read from
446  * @param[out] pixels  The pointer that  we want to store bmp data  in
447  * @param[in]  width   bmp width
448  * @param[in]  height  bmp height
449  * @param[in]  offset  offset from bmp header to bmp image data
450  * @param[in]  topDown indicate image data is read from bottom or from top
451  * @return true, if decode successful, false otherwise
452  */
453 bool DecodeRGB555(FILE *fp,
454                   PixelBuffer *pixels,
455                   unsigned int width,
456                   unsigned int height,
457                   unsigned int offset,
458                   bool topDown)
459 {
460   if(fp == NULL || pixels == NULL)
461   {
462     DALI_LOG_ERROR("Error decoding BMP_RGB555 format\n");
463     return false;
464   }
465   if( fseek(fp, offset, SEEK_SET) )
466   {
467     DALI_LOG_ERROR("Error seeking BMP_RGB555 data\n");
468     return false;
469   }
470
471   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
472   std::vector<char> raw(width * height * 2);
473   unsigned int rawStride = width * 2;
474   unsigned int rowStride = width * 3;
475
476   char *rawPtr = NULL;
477   for(unsigned int j = 0; j <  height; j ++)
478   {
479     rawPtr = &raw[0] + ( j * rawStride);
480     if(fread(rawPtr, 1, rawStride, fp) != rawStride)
481     {
482       return false;
483     }
484   }
485   for(unsigned int i = 0; i < height; i++)
486   {
487     PixelBuffer *pixelsPtr = NULL;
488     if (topDown)
489     {
490       // the data in the file is top down, and we store the data top down
491       pixelsPtr = pixels + ( i * rowStride);
492     }
493     else
494     {
495       // the data in the file is bottom up, and we store the data top down
496       pixelsPtr = pixels + (((height - 1) - i) * rowStride);
497     }
498     for(unsigned int k = 0; k < width; k ++)
499     {
500       int index = i * rawStride + 2 * k;
501       pixelsPtr[3 * k] = ((raw[ index + 1] >> 2) & 0x1F) * 0xFF / 0x1F;
502       pixelsPtr[3 * k + 1] = (((raw[index + 1] & 0x03) << 3) | (raw[ index] >> 5))  * 0xFF/ 0x1F;
503       pixelsPtr[3 * k + 2] = (raw[ index] & 0x1F) * 0xFF / 0x1F;
504     }
505
506   }
507   return true;
508 }
509
510 /**
511  * function to decode format BI_RGB & bpp = 1
512  * @param[in]  fp      The file to read from
513  * @param[out] pixels  The pointer that  we want to store bmp data  in
514  * @param[in]  width   bmp width
515  * @param[in]  height  bmp height
516  * @param[in]  offset  offset from bmp header to bmp palette data
517  * @param[in]  topDown indicate image data is read from bottom or from top
518  * @return true, if decode successful, false otherwise
519  */
520 bool DecodeRGB1(FILE *fp,
521                 PixelBuffer *pixels,
522                 unsigned int width,
523                 unsigned int height,
524                 unsigned int offset,
525                 bool topDown)
526 {
527   if(fp == NULL || pixels == NULL)
528   {
529     DALI_LOG_ERROR("Error decoding BMP_RGB1 format\n");
530     return false;
531   }
532   if( fseek(fp, offset, SEEK_SET) )
533   {
534     DALI_LOG_ERROR("Error seeking BMP_RGB1 data\n");
535     return false;
536   }
537
538   unsigned char colorTable[8] = {0};
539   char cmd;
540   unsigned int fillw = ((width & 63) != 0) ? width + 64 - (width & 63) : width;
541   std::vector<char> colorIndex(fillw * height);
542   unsigned int rowStride = fillw * 3; // RGB
543
544
545   if(fread(colorTable, 1, 8, fp) != 8)
546   {
547     return false;
548   }
549
550   for(unsigned int i = 0; i < fillw * height; i += 8)
551   {
552     if(fread(&cmd, 1, 1, fp) != 1)
553     {
554       return false;
555     }
556
557     colorIndex[i]     = (cmd >> 7) & 0x01;
558     colorIndex[i + 1] = (cmd >> 6) & 0x01;
559     colorIndex[i + 2] = (cmd >> 5) & 0x01;
560     colorIndex[i + 3] = (cmd >> 4) & 0x01;
561     colorIndex[i + 4] = (cmd >> 3) & 0x01;
562     colorIndex[i + 5] = (cmd >> 2) & 0x01;
563     colorIndex[i + 6] = (cmd >> 1) & 0x01;
564     colorIndex[i + 7] = (cmd & 0x01);
565   }
566
567   for(unsigned int index = 0; index < height; index = index + 1)
568   {
569     PixelBuffer *pixelsPtr = NULL;
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   if( fseek(fp, offset, SEEK_SET) )
626   {
627     DALI_LOG_ERROR("Error seeking BMP_RGB4 data\n");
628     return false;
629   }
630
631   char colorTable[64];
632   char cmd;
633   unsigned int fillw = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
634   std::vector<char> colorIndex(fillw * height);
635   unsigned int rowStride = fillw  * 3;
636
637   if(fread(colorTable, 1, 64, fp) != 64)
638   {
639     return false;
640   }
641
642   for(unsigned int i = 0; i < fillw * height; i += 2)
643   {
644     if (fread(&cmd, 1, 1, fp) != 1)
645     {
646       return false;
647     }
648
649     colorIndex[i] = cmd >> 4;
650     colorIndex[i + 1] = cmd & (0x0F);
651   }
652   int ctIndex = 0;
653
654   for(unsigned int index = 0; index < height; index = index + 1)
655   {
656     PixelBuffer *pixelsPtr = NULL;
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   if( fseek(fp, offset, SEEK_SET) )
702   {
703     DALI_LOG_ERROR("Error seeking BMP_RGB8 data\n");
704     return false;
705   }
706
707   std::vector<char> colorTable(1024);
708   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
709   char cmd;
710   std::vector<char> colorIndex(width * height);
711   unsigned int rowStride = width * 3;//RGB8->RGB24
712
713   if(fread(&colorTable[0], 1, 1024, fp) != 1024)
714   {
715     return false;
716   }
717   for(unsigned int i = 0; i < width * height; i ++)
718   {
719     if (fread(&cmd, 1, 1, fp) != 1)
720     {
721       return false;
722     }
723
724     colorIndex[i] = cmd;
725   }
726   int ctIndex = 0;
727   for(unsigned int index = 0; index < height; index = index + 1)
728   {
729     PixelBuffer *pixelsPtr = NULL;
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, const ResourceLoadingClient& client )
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   return true;
1360 }
1361
1362 } // namespace TizenPlatform
1363
1364 } // namespace Dali