Cleanup for removal of ImageAttributes from public API
[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
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   unsigned int readLength = sizeof(T);
88
89   // Load the information directly into our structure
90   if (fread((void*)&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 = infoHeader.height;
112
113   return true;
114 }
115
116 /**
117  * function to decode format BI_RGB & bpp = 24 & bmp version5.
118  * @param[in]  fp      The file to read from
119  * @param[out] pixels  The pointer that  we want to store bmp data  in
120  * @param[in]  width   bmp width
121  * @param[in]  height  bmp height
122  * @param[in]  offset  offset from bmp header to bmp image data
123  * @param[in]  topDown indicate image data is read from bottom or from top
124  * @param[in]  padding padded to a u_int32 boundary for each line
125  * @return true, if decode successful, false otherwise
126  */
127 bool DecodeRGB24V5(FILE *fp,
128                    PixelBuffer *pixels,
129                    unsigned int width,
130                    unsigned int height,
131                    unsigned int offset,
132                    bool topDown,
133                    unsigned int rowStride,
134                    unsigned int padding)
135 {
136   if(fp == NULL || pixels == NULL)
137   {
138     DALI_LOG_ERROR("Error decoding BMP_RGB24V5 format\n");
139     return false;
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     PixelBuffer *pixelsPtr = NULL;
150     if(topDown)
151     {
152       pixelsPtr = pixels + ( yPos * rowStride);
153     }
154     else
155     {
156       pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
157     }
158     if (fread(pixelsPtr, 1, rowStride, fp) != rowStride)
159     {
160       DALI_LOG_ERROR("Error reading the BMP image\n");
161       return false;
162     }
163     for(unsigned int i = 0; i < rowStride; i += 3)
164     {
165       unsigned char temp = pixelsPtr[i];
166       pixelsPtr[i] = pixelsPtr[i + 2];
167       pixelsPtr[i + 2] = temp;
168     }
169
170     if (padding)
171     {
172       // move past the padding.
173       if( fseek(fp, padding, SEEK_CUR) )
174       {
175         DALI_LOG_ERROR("Error moving past BMP_RGB24V5 padding\n");
176       }
177     }
178   }
179   return true;
180 }
181
182 /**
183  * function to decode format BI_BITFIELDS & bpp = 32 & bmp version4.
184  * @param[in]  fp        The file to read from
185  * @param[out] pixels    The pointer that  we want to store bmp data  in
186  * @param[in]  width     bmp width
187  * @param[in]  height    bmp height
188  * @param[in]  offset    offset from bmp header to bmp image data
189  * @param[in]  topDown   indicate image data is read from bottom or from top
190  * @param[in]  rowStride bits span for each line
191  * @param[in]  padding   padded to a u_int32 boundary for each line
192  * @return true, if decode successful, false otherwise
193  */
194 bool DecodeBF32V4(FILE *fp,
195                   PixelBuffer *pixels,
196                   unsigned int width,
197                   unsigned int height,
198                   unsigned int offset,
199                   bool topDown,
200                   unsigned int rowStride,
201                   unsigned int padding)
202 {
203   if(fp == NULL || pixels == NULL)
204   {
205     DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32V4 format\n");
206     return false;
207   }
208   if( fseek(fp, offset, SEEK_SET) )
209   {
210     DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32V4 data\n");
211     return false;
212   }
213
214   for(unsigned int yPos = 0; yPos < height; yPos ++)
215   {
216     PixelBuffer *pixelsPtr = NULL;
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   if( fseek(fp, offset, SEEK_SET) )
276   {
277     DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32 data\n");
278     return false;
279   }
280
281   for (unsigned int yPos = 0; yPos < height; yPos++)
282   {
283     PixelBuffer *pixelsPtr;
284     if (topDown)
285     {
286       // the data in the file is top down, and we store the data top down
287       pixelsPtr = pixels + ( yPos * rowStride);
288     }
289     else
290     {
291       // the data in the file is bottom up, and we store the data top down
292       pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
293     }
294
295     if (fread(pixelsPtr, 1, rowStride, fp) != rowStride)
296     {
297       DALI_LOG_ERROR("Error reading the BMP image\n");
298       return false;
299     }
300     for(unsigned int i = 0; i < rowStride; i += 4)
301     {
302       unsigned char temp = pixelsPtr[i];
303       pixelsPtr[i] = pixelsPtr[i + 2];
304       pixelsPtr[i + 2] = temp;
305     }
306
307     if (padding)
308     {
309       // move past the padding.
310       if( fseek(fp, padding, SEEK_CUR) )
311       {
312         DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32 padding\n");
313       }
314     }
315   }
316   return true;
317 }
318
319 /**
320  * function to decode format BI_BITFIELDS & bpp = 16 & R:G:B = 5:6:5
321  * @param[in]  fp      The file to read from
322  * @param[out] pixels  The pointer that  we want to store bmp data  in
323  * @param[in]  width   bmp width
324  * @param[in]  height  bmp height
325  * @param[in]  offset  offset from bmp header to bmp image data
326  * @param[in]  topDown indicate image data is read from bottom or from top
327  * @return true, if decode successful, false otherwise
328  */
329 bool DecodeBF565(FILE *fp,
330                  PixelBuffer *pixels,
331                  unsigned int width,
332                  unsigned int height,
333                  unsigned int offset,
334                  bool topDown)
335 {
336   if(fp == NULL || pixels == NULL)
337   {
338     DALI_LOG_ERROR("Error decoding RGB565 format\n");
339     return false;
340   }
341   if( fseek(fp, offset, SEEK_SET) )
342   {
343     DALI_LOG_ERROR("Error seeking RGB565 data\n");
344     return false;
345   }
346
347   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
348   unsigned int rowStride = width * 2;
349
350   for(unsigned int i = 0; i < height; i++)
351   {
352     PixelBuffer *pixelsPtr = NULL;
353     if (topDown)
354     {
355       // the data in the file is top down, and we store the data top down
356       pixelsPtr = pixels + ( i * rowStride);
357     }
358     else
359     {
360       // the data in the file is bottom up, and we store the data top down
361       pixelsPtr = pixels + (((height - 1) - i) * rowStride);
362     }
363     if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
364     {
365       return false;
366     }
367   }
368
369   return true;
370 }
371
372 /**
373  * function to decode format BI_BITFIELDS & bpp = 16 & R:G:B = 5:5:5
374  * @param[in]  fp      The file to read from
375  * @param[out] pixels  The pointer that  we want to store bmp data  in
376  * @param[in]  width   bmp width
377  * @param[in]  height  bmp height
378  * @param[in]  offset  offset from bmp header to bmp image data
379  * @param[in]  topDown indicate image data is read from bottom or from top
380  * @return true, if decode successful, false otherwise
381  */
382 bool DecodeBF555(FILE *fp,
383                  PixelBuffer *pixels,
384                  unsigned int width,
385                  unsigned int height,
386                  unsigned int offset,
387                  bool topDown)
388 {
389   if(fp == NULL || pixels == NULL)
390   {
391     DALI_LOG_ERROR("Error decoding BMP_BITFIELDS555 format\n");
392     return false;
393   }
394
395   if( fseek(fp, offset, SEEK_SET) )
396   {
397     DALI_LOG_ERROR("Error seeking BMP_BITFIELDS555 data\n");
398     return false;
399   }
400
401   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
402
403   std::vector<char> raw(width * height * 2);
404   unsigned int rawStride = width * 2;
405   unsigned int rowStride = width * 3;
406
407   char *rawPtr = NULL;
408   for(unsigned int j = 0; j <  height; j ++)
409   {
410     rawPtr = &raw[0] + ( j * rawStride);
411     if(fread(rawPtr, 1, rawStride, fp) != rawStride)
412     {
413       return false;
414     }
415   }
416
417   for (unsigned int yPos = 0; yPos < height; yPos++)
418   {
419     PixelBuffer *pixelsPtr = NULL;
420     if (topDown)
421     {
422       // the data in the file is top down, and we store the data top down
423       pixelsPtr = pixels + ( yPos * rowStride);
424     }
425     else
426     {
427       // the data in the file is bottom up, and we store the data top down
428       pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
429     }
430
431     for(unsigned int k = 0; k < width; k ++)
432     {
433       int index = yPos * rawStride + 2 * k;
434       pixelsPtr[3 * k] = ((raw[ index + 1] >> 2) & 0x1F) * 0xFF / 0x1F;
435       pixelsPtr[3 * k + 1] = (((raw[index + 1] & 0x03) << 3) | (raw[ index] >> 5))  * 0xFF/ 0x1F;
436       pixelsPtr[3 * k + 2] = (raw[ index] & 0x1F) * 0xFF / 0x1F;
437     }
438   }
439   return true;
440 }
441
442 /**
443  * function to decode format BI_RGB & bpp = 16 & R:G:B = 5:5:5
444  * @param[in]  fp      The file to read from
445  * @param[out] pixels  The pointer that  we want to store bmp data  in
446  * @param[in]  width   bmp width
447  * @param[in]  height  bmp height
448  * @param[in]  offset  offset from bmp header to bmp image data
449  * @param[in]  topDown indicate image data is read from bottom or from top
450  * @return true, if decode successful, false otherwise
451  */
452 bool DecodeRGB555(FILE *fp,
453                   PixelBuffer *pixels,
454                   unsigned int width,
455                   unsigned int height,
456                   unsigned int offset,
457                   bool topDown)
458 {
459   if(fp == NULL || pixels == NULL)
460   {
461     DALI_LOG_ERROR("Error decoding BMP_RGB555 format\n");
462     return false;
463   }
464   if( fseek(fp, offset, SEEK_SET) )
465   {
466     DALI_LOG_ERROR("Error seeking BMP_RGB555 data\n");
467     return false;
468   }
469
470   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
471   std::vector<char> raw(width * height * 2);
472   unsigned int rawStride = width * 2;
473   unsigned int rowStride = width * 3;
474
475   char *rawPtr = NULL;
476   for(unsigned int j = 0; j <  height; j ++)
477   {
478     rawPtr = &raw[0] + ( j * rawStride);
479     if(fread(rawPtr, 1, rawStride, fp) != rawStride)
480     {
481       return false;
482     }
483   }
484   for(unsigned int i = 0; i < height; i++)
485   {
486     PixelBuffer *pixelsPtr = NULL;
487     if (topDown)
488     {
489       // the data in the file is top down, and we store the data top down
490       pixelsPtr = pixels + ( i * rowStride);
491     }
492     else
493     {
494       // the data in the file is bottom up, and we store the data top down
495       pixelsPtr = pixels + (((height - 1) - i) * rowStride);
496     }
497     for(unsigned int k = 0; k < width; k ++)
498     {
499       int index = i * rawStride + 2 * k;
500       pixelsPtr[3 * k] = ((raw[ index + 1] >> 2) & 0x1F) * 0xFF / 0x1F;
501       pixelsPtr[3 * k + 1] = (((raw[index + 1] & 0x03) << 3) | (raw[ index] >> 5))  * 0xFF/ 0x1F;
502       pixelsPtr[3 * k + 2] = (raw[ index] & 0x1F) * 0xFF / 0x1F;
503     }
504
505   }
506   return true;
507 }
508
509 /**
510  * function to decode format BI_RGB & bpp = 1
511  * @param[in]  fp      The file to read from
512  * @param[out] pixels  The pointer that  we want to store bmp data  in
513  * @param[in]  width   bmp width
514  * @param[in]  height  bmp height
515  * @param[in]  offset  offset from bmp header to bmp palette data
516  * @param[in]  topDown indicate image data is read from bottom or from top
517  * @return true, if decode successful, false otherwise
518  */
519 bool DecodeRGB1(FILE *fp,
520                 PixelBuffer *pixels,
521                 unsigned int width,
522                 unsigned int height,
523                 unsigned int offset,
524                 bool topDown)
525 {
526   if(fp == NULL || pixels == NULL)
527   {
528     DALI_LOG_ERROR("Error decoding BMP_RGB1 format\n");
529     return false;
530   }
531   if( fseek(fp, offset, SEEK_SET) )
532   {
533     DALI_LOG_ERROR("Error seeking BMP_RGB1 data\n");
534     return false;
535   }
536
537   unsigned char colorTable[8] = {0};
538   char cmd;
539   unsigned int fillw = ((width & 63) != 0) ? width + 64 - (width & 63) : width;
540   std::vector<char> colorIndex(fillw * height);
541   unsigned int rowStride = fillw * 3; // RGB
542
543
544   if(fread(colorTable, 1, 8, fp) != 8)
545   {
546     return false;
547   }
548
549   for(unsigned int i = 0; i < fillw * height; i += 8)
550   {
551     if(fread(&cmd, 1, 1, fp) != 1)
552     {
553       return false;
554     }
555
556     colorIndex[i]     = (cmd >> 7) & 0x01;
557     colorIndex[i + 1] = (cmd >> 6) & 0x01;
558     colorIndex[i + 2] = (cmd >> 5) & 0x01;
559     colorIndex[i + 3] = (cmd >> 4) & 0x01;
560     colorIndex[i + 4] = (cmd >> 3) & 0x01;
561     colorIndex[i + 5] = (cmd >> 2) & 0x01;
562     colorIndex[i + 6] = (cmd >> 1) & 0x01;
563     colorIndex[i + 7] = (cmd & 0x01);
564   }
565
566   for(unsigned int index = 0; index < height; index = index + 1)
567   {
568     PixelBuffer *pixelsPtr = NULL;
569     if (topDown)
570     {
571       // the data in the file is top down, and we store the data top down
572       pixelsPtr = pixels + ( index * rowStride);
573     }
574     else
575     {
576       // the data in the file is bottom up, and we store the data top down
577       pixelsPtr = pixels + (((height - 1) - index) * rowStride);
578     }
579     for(unsigned int j = 0; j < fillw; j ++)
580     {
581       int ctIndex = 0;
582       if((fillw * index + j ) < (fillw * height))
583       {
584         ctIndex = colorIndex[ fillw * index + j ];
585       }
586       else
587       {
588         break;
589       }
590       // temp solution for PLM bug P130411-5268, there is one mono bmp that cause DecodeRGB1 API crash.
591       if( ((3 * j + 2) < height * fillw * 3) && (ctIndex < 2))
592       {
593         pixelsPtr[ 3 * j ] = colorTable[4 * ctIndex + 2];
594         pixelsPtr[3 * j + 1] = colorTable[4 * ctIndex + 1];
595         pixelsPtr[3 * j + 2] = colorTable[4 * ctIndex ];
596       }
597     }
598   }
599   return true;
600 }
601
602 /**
603  * function to decode format BI_RGB & bpp = 4
604  * @param[in]  fp      The file to read from
605  * @param[out] pixels  The pointer that  we want to store bmp data  in
606  * @param[in]  width   bmp width
607  * @param[in]  height  bmp height
608  * @param[in]  offset  offset from bmp header to bmp palette data
609  * @param[in]  topDown indicate image data is read from bottom or from top
610  * @return true, if decode successful, false otherwise
611  */
612 bool DecodeRGB4(FILE *fp,
613                 PixelBuffer *pixels,
614                 unsigned int width,
615                 unsigned int height,
616                 unsigned int offset,
617                 bool topDown)
618 {
619   if(fp == NULL || pixels == NULL)
620   {
621     DALI_LOG_ERROR("Error decoding BMP_RGB4 format\n");
622     return false;
623   }
624   if( fseek(fp, offset, SEEK_SET) )
625   {
626     DALI_LOG_ERROR("Error seeking BMP_RGB4 data\n");
627     return false;
628   }
629
630   char colorTable[64];
631   char cmd;
632   unsigned int fillw = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
633   std::vector<char> colorIndex(fillw * height);
634   unsigned int rowStride = fillw  * 3;
635
636   if(fread(colorTable, 1, 64, fp) != 64)
637   {
638     return false;
639   }
640
641   for(unsigned int i = 0; i < fillw * height; i += 2)
642   {
643     if (fread(&cmd, 1, 1, fp) != 1)
644     {
645       return false;
646     }
647
648     colorIndex[i] = cmd >> 4;
649     colorIndex[i + 1] = cmd & (0x0F);
650   }
651   int ctIndex = 0;
652
653   for(unsigned int index = 0; index < height; index = index + 1)
654   {
655     PixelBuffer *pixelsPtr = NULL;
656     if (topDown)
657     {
658       // the data in the file is top down, and we store the data top down
659       pixelsPtr = pixels + ( index * rowStride);
660     }
661     else
662     {
663       // the data in the file is bottom up, and we store the data top down
664       pixelsPtr = pixels + (((height - 1) - index) * rowStride);
665     }
666     for(unsigned int j = 0; j < fillw; j ++)
667     {
668       ctIndex = colorIndex[ fillw * index + j ];
669       pixelsPtr[ 3 * j ] = colorTable[4 * ctIndex + 2];
670       pixelsPtr[(3 * j + 1)] = colorTable[4 * ctIndex + 1];
671       pixelsPtr[(3 * j + 2)] = colorTable[4 * ctIndex ];
672     }
673   }
674
675   return true;
676 }
677
678 /**
679  * function to decode format BI_RGB & bpp = 8
680  * @param[in]  fp      The file to read from
681  * @param[out] pixels  The pointer that  we want to store bmp data  in
682  * @param[in]  width   bmp width
683  * @param[in]  height  bmp height
684  * @param[in]  offset  offset from bmp header to bmp palette data
685  * @param[in]  topDown indicate image data is read from bottom or from top
686  * @return true, if decode successful, false otherwise
687  */
688 bool DecodeRGB8(FILE *fp,
689                 PixelBuffer *pixels,
690                 unsigned int width,
691                 unsigned int height,
692                 unsigned int offset,
693                 bool topDown)
694 {
695   if(fp == NULL || pixels == NULL)
696   {
697     DALI_LOG_ERROR("Error decoding BMP_RGB8 format\n");
698     return false;
699   }
700   if( fseek(fp, offset, SEEK_SET) )
701   {
702     DALI_LOG_ERROR("Error seeking BMP_RGB8 data\n");
703     return false;
704   }
705
706   std::vector<char> colorTable(1024);
707   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
708   char cmd;
709   std::vector<char> colorIndex(width * height);
710   unsigned int rowStride = width * 3;//RGB8->RGB24
711
712   if(fread(&colorTable[0], 1, 1024, fp) != 1024)
713   {
714     return false;
715   }
716   for(unsigned int i = 0; i < width * height; i ++)
717   {
718     if (fread(&cmd, 1, 1, fp) != 1)
719     {
720       return false;
721     }
722
723     colorIndex[i] = cmd;
724   }
725   int ctIndex = 0;
726   for(unsigned int index = 0; index < height; index = index + 1)
727   {
728     PixelBuffer *pixelsPtr = NULL;
729     if (topDown)
730     {
731       // the data in the file is top down, and we store the data top down
732       pixelsPtr = pixels + ( index * rowStride);
733     }
734     else
735     {
736       // the data in the file is bottom up, and we store the data top down
737       pixelsPtr = pixels + (((height - 1) - index) * rowStride);
738     }
739     for(unsigned int j = 0; j < width; j ++)
740     {
741       ctIndex = colorIndex[ width * index + j ];
742       pixelsPtr[ 3 * j ] = colorTable[4 * ctIndex + 2];
743       pixelsPtr[(3 * j + 1)] = colorTable[4 * ctIndex + 1];
744       pixelsPtr[(3 * j + 2)] = colorTable[4 * ctIndex ];
745     }
746   }
747   return true;
748 }
749
750 /**
751  * function to decode format BI_RLE4 & bpp = 4
752  * @param[in]  fp      The file to read from
753  * @param[out] pixels  The pointer that  we want to store bmp data  in
754  * @param[in]  width   bmp width
755  * @param[in]  height  bmp height
756  * @param[in]  offset  offset from bmp header to bmp palette data
757  * @param[in]  topDown indicate image data is read from bottom or from top
758  * @return true, if decode successful, false otherwise
759  */
760 bool DecodeRLE4(FILE *fp,
761                 PixelBuffer *pixels,
762                 unsigned int width,
763                 unsigned int height,
764                 unsigned int offset,
765                 bool topDown)
766 {
767   if(fp == NULL || pixels == NULL)
768   {
769     DALI_LOG_ERROR("Error decoding BMP_RLE4 format\n");
770     return false;
771   }
772   PixelBuffer *pixelsPtr = pixels;
773   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
774   char cmd[2];
775   unsigned int cmdStride = 2;
776   char colorTable[64];
777   std::vector<char> colorIndex(width * height >> 1);
778   std::vector<char> run;
779   int x = 0;
780   int y = 0;
781   int dx = 0;
782   int dy = 0;
783   width += (width & 1);
784   width = width >> 1;
785
786   bool finish = false;
787
788   if( fseek(fp, offset, SEEK_SET) )
789   {
790     DALI_LOG_ERROR("Error seeking BMP_RLE4 data\n");
791     return false;
792   }
793
794   if (fread(colorTable, 1, 64, fp) != 64)
795   {
796     return false;
797   }
798
799   while((x >> 1) + y * width < width * height)
800   {
801     if (finish)
802     {
803       break;
804     }
805     if (fread(cmd, 1, cmdStride, fp) != cmdStride)
806     {
807       return false;
808     }
809     if(cmd[0] == 0) // ESCAPE
810     {
811       switch(cmd[1])
812       {
813         case 1: //end of bitmap
814           finish = true;
815           break;
816         case 0: // end of line
817           x = 0;
818           y ++;
819           break;
820         case 2: // delta
821           if (fread(cmd, 1, cmdStride, fp) != cmdStride)
822           {
823             DALI_LOG_ERROR("Error reading the BMP image\n");
824             return false;
825           }
826           dx = cmd[0] & (0xFF);
827           dy = cmd[1] & (0xFF);
828           x += dx;
829           y += dy;
830           break;
831         default:
832           // decode a literal run
833           unsigned int length = cmd[1] & (0xFF);
834           //size of run, which is word aligned
835           unsigned int bytesize = length;
836           bytesize += (bytesize & 1);
837           bytesize >>= 1;
838           bytesize += (bytesize & 1);
839           run.resize(bytesize);
840           if(fread(&run[0], 1, bytesize, fp) != bytesize)
841           {
842             DALI_LOG_ERROR("Error reading the BMP image\n");
843             return false;
844           }
845           if((x & 1) == 0)
846           {
847             length += (length & 1);
848             length >>= 1;
849             for(unsigned int i = 0; i < length; i += 1)
850             {
851               colorIndex[(x >> 1) + width * (height - y - 1) + i] = run[i];
852             }
853           }
854           else
855           {
856             for(unsigned int i = 0; i < length; i ++)
857             {
858               if((i & 1) == 0)//copy high to low
859               {
860                 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((run[i >> 1] & 0xF0) >> 4);
861               }
862               else //copy low to high
863               {
864                 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((run[i >> 1] & 0x0F) << 4);
865               }
866             }
867           }
868           x += cmd[1] & (0xFF);
869           break;
870       }
871     }
872     else
873     {
874       unsigned int length = cmd[0] & (0xFF);
875       if((x & 1) == 0)
876       {
877         length += (length & 1);
878         length >>= 1;
879         for(unsigned int i = 0; i < length; i ++)
880         {
881           colorIndex[(height-y-1)*width + i + (x >> 1)] = cmd[1];
882         }
883       }
884       else
885       {
886         for(unsigned int i = 0; i < length; i ++)
887         {
888           if((i & 1) == 0)
889           {
890             colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((cmd[1] & 0xF0) >> 4);
891           }
892           else
893           {
894             colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((cmd[1] & 0x0F) << 4);
895           }
896         }
897       }
898       x += cmd[0] & (0xFF);
899     }
900   }
901
902   int ctIndexHigh = 0;
903   int ctIndexLow = 0;
904   for(unsigned int index = 0; index < (width * height ); index = index + 1)
905   {
906     ctIndexHigh = colorIndex[ index] >> 4;
907     ctIndexLow = colorIndex[index] & (0x0F);
908     pixelsPtr[6 * index ] = colorTable[4 * ctIndexHigh + 2];
909     pixelsPtr[6 * index + 1] = colorTable[4 * ctIndexHigh + 1];
910     pixelsPtr[6 * index + 2] = colorTable[4 * ctIndexHigh ];
911     pixelsPtr[6 * index + 3] = colorTable[4 * ctIndexLow + 2];
912     pixelsPtr[6 * index + 4] = colorTable[4 * ctIndexLow + 1];
913     pixelsPtr[6 * index + 5] = colorTable[4 * ctIndexLow ];
914   }
915   return true;
916 }
917
918 /**
919  * function to decode format BI_RLE8 & bpp = 8
920  * @param[in]  fp      The file to read from
921  * @param[out] pixels  The pointer that  we want to store bmp data  in
922  * @param[in]  width   bmp width
923  * @param[in]  height  bmp height
924  * @param[in]  offset  offset from bmp header to bmp palette data
925  * @param[in]  topDown indicate image data is read from bottom or from top
926  * @return true, if decode successful, false otherwise
927  */
928 bool DecodeRLE8(FILE *fp,
929                 PixelBuffer *pixels,
930                 unsigned int width,
931                 unsigned int height,
932                 unsigned int offset,
933                 bool topDown)
934 {
935   if(fp == NULL || pixels == NULL)
936   {
937     DALI_LOG_ERROR("Error decoding BMP_RLE8 format\n");
938     return false;
939   }
940   PixelBuffer *pixelsPtr = pixels;
941   int x = 0;
942   int y = 0;
943   unsigned int cmdStride = 2;
944
945   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
946   std::vector<char> colorTable(1024);
947   char cmd[2];
948   std::vector<char> colorIndex(width * height);
949
950   if( fseek(fp, offset, SEEK_SET) )
951   {
952     DALI_LOG_ERROR("Error seeking BMP_RLE8 data\n");
953     return false;
954   }
955
956   if (fread(&colorTable[0], 1, 1024, fp) != 1024)
957   {
958     return false;
959   }
960
961   int dx = 0;
962   int dy = 0;
963   bool finish = false;
964   unsigned int length = 0;
965   unsigned int copylength = 0;
966   std::vector<char> run;
967   while((x + y * width) < width * height )
968   {
969     if (finish)
970     {
971       break;
972     }
973     if (fread(cmd, 1, cmdStride, fp) != cmdStride)
974     {
975       return false;
976     }
977
978     if(cmd[0] == 0)//ESCAPE
979     {
980       switch(cmd[1])
981       {
982         case 1: // end of bitmap
983           finish = true;
984           break;
985         case 0: // end of line
986           x = 0;
987           y ++;
988           break;
989         case 2: // delta
990           if (fread(cmd, 1, cmdStride, fp) != cmdStride)
991           {
992             DALI_LOG_ERROR("Error reading the BMP image\n");
993             return false;
994           }
995           dx = cmd[0] & (0xFF);
996           dy = cmd[1] & (0xFF);
997           x += dx;
998           y += dy;
999           break;
1000         default:
1001           //decode a literal run
1002           length = cmd[1] & (0xFF);
1003           copylength = length;
1004           //absolute mode must be word-aligned
1005           length += (length & 1);
1006           run.resize(length);
1007           if(fread(&run[0], 1, length, fp) != length)
1008           {
1009             DALI_LOG_ERROR("Error reading the BMP image\n");
1010             return false;
1011           }
1012
1013           for(unsigned int i = 0; i < length; i += 1)
1014           {
1015             colorIndex[x + width * (height - y - 1) + i] = run[i];
1016           }
1017           x += copylength;
1018           break;
1019       }
1020     }// end if cmd[0] ==
1021     else
1022     {
1023       length = cmd[0] & (0xFF);
1024       for(unsigned int i = 0; i < length; i ++)
1025       {
1026         colorIndex[(height - y - 1) * width + x] = cmd[1];
1027         x++;
1028       }
1029     }
1030   }
1031   int ctIndex = 0;
1032   for(unsigned int index = 0; index < width * height; index = index + 1)
1033   {
1034     ctIndex = colorIndex[ index];
1035     pixelsPtr[3 * index ] = colorTable[4 * ctIndex + 2];
1036     pixelsPtr[3 * index + 1] = colorTable[4 * ctIndex + 1];
1037     pixelsPtr[3 * index + 2] = colorTable[4 * ctIndex ];
1038   }
1039   return true;
1040 }
1041
1042 } // unnamed namespace
1043
1044 bool LoadBmpHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height )
1045 {
1046   BmpFileHeader fileHeader;
1047   BmpInfoHeader infoHeader;
1048
1049   bool ret = LoadBmpHeader( input.file, width, height, fileHeader, infoHeader );
1050
1051   return ret;
1052 }
1053
1054 bool LoadBitmapFromBmp( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap )
1055 {
1056   DALI_ASSERT_DEBUG( bitmap.GetPackedPixelsProfile() != 0 && "Need a packed pixel bitmap to load into." );
1057   FILE* const fp = input.file;
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   return true;
1359 }
1360
1361 } // namespace TizenPlatform
1362
1363 } // namespace Dali