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