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