fe87cf9c1b9ede4b2ace85a2d350e6403cf8fe62
[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     DALI_LOG_ERROR("File header read failed\n");
98     return false;
99   }
100
101   if(!ReadHeader(fp, infoHeader))
102   {
103     DALI_LOG_ERROR("Info header read failed\n");
104     return false;
105   }
106
107   width  = infoHeader.width;
108   height = abs(infoHeader.height);
109
110   if(infoHeader.width == 0)
111   {
112     DALI_LOG_ERROR("Invalid header size\n");
113     return false;
114   }
115
116   return true;
117 }
118
119 /**
120  * function to decode format BI_RGB & bpp = 24 & bmp version5.
121  * @param[in]  fp      The file to read from
122  * @param[out] pixels  The pointer that  we want to store bmp data  in
123  * @param[in]  width   bmp width
124  * @param[in]  height  bmp height
125  * @param[in]  offset  offset from bmp header to bmp image data
126  * @param[in]  topDown indicate image data is read from bottom or from top
127  * @param[in]  padding padded to a u_int32 boundary for each line
128  * @return true, if decode successful, false otherwise
129  */
130 bool DecodeRGB24V5(FILE*          fp,
131                    unsigned char* pixels,
132                    unsigned int   width,
133                    unsigned int   height,
134                    unsigned int   offset,
135                    bool           topDown,
136                    unsigned int   rowStride,
137                    unsigned int   padding)
138 {
139   if(fp == NULL || pixels == NULL)
140   {
141     DALI_LOG_ERROR("Error decoding BMP_RGB24V5 format\n");
142     return false;
143   }
144   if(fseek(fp, offset, SEEK_SET))
145   {
146     DALI_LOG_ERROR("Error seeking BMP_RGB24V5 data\n");
147     return false;
148   }
149
150   for(unsigned int yPos = 0; yPos < height; yPos++)
151   {
152     unsigned char* pixelsPtr = NULL;
153     if(topDown)
154     {
155       pixelsPtr = pixels + (yPos * rowStride);
156     }
157     else
158     {
159       pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
160     }
161     if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
162     {
163       DALI_LOG_ERROR("Error reading the BMP image\n");
164       return false;
165     }
166     for(unsigned int i = 0; i < rowStride; i += 3)
167     {
168       unsigned char temp = pixelsPtr[i];
169       pixelsPtr[i]       = pixelsPtr[i + 2];
170       pixelsPtr[i + 2]   = temp;
171     }
172
173     if(padding)
174     {
175       // move past the padding.
176       if(fseek(fp, padding, SEEK_CUR))
177       {
178         DALI_LOG_ERROR("Error moving past BMP_RGB24V5 padding\n");
179       }
180     }
181   }
182   return true;
183 }
184
185 /**
186  * function to decode format BI_BITFIELDS & bpp = 32 & bmp version4.
187  * @param[in]  fp        The file to read from
188  * @param[out] pixels    The pointer that  we want to store bmp data  in
189  * @param[in]  width     bmp width
190  * @param[in]  height    bmp height
191  * @param[in]  offset    offset from bmp header to bmp image data
192  * @param[in]  topDown   indicate image data is read from bottom or from top
193  * @param[in]  rowStride bits span for each line
194  * @param[in]  padding   padded to a u_int32 boundary for each line
195  * @return true, if decode successful, false otherwise
196  */
197 bool DecodeBF32V4(FILE*          fp,
198                   unsigned char* pixels,
199                   unsigned int   width,
200                   unsigned int   height,
201                   unsigned int   offset,
202                   bool           topDown,
203                   unsigned int   rowStride,
204                   unsigned int   padding)
205 {
206   if(fp == NULL || pixels == NULL)
207   {
208     DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32V4 format\n");
209     return false;
210   }
211   if(fseek(fp, offset, SEEK_SET))
212   {
213     DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32V4 data\n");
214     return false;
215   }
216
217   for(unsigned int yPos = 0; yPos < height; yPos++)
218   {
219     unsigned char* pixelsPtr = NULL;
220     if(topDown)
221     {
222       pixelsPtr = pixels + (yPos * rowStride);
223     }
224     else
225     {
226       pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
227     }
228     if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
229     {
230       DALI_LOG_ERROR("Error reading the BMP image\n");
231       return false;
232     }
233     for(unsigned int i = 0; i < rowStride; i += 4)
234     {
235       unsigned char temp = pixelsPtr[i];
236       pixelsPtr[i]       = pixelsPtr[i + 2];
237       pixelsPtr[i + 2]   = temp;
238     }
239     if(padding)
240     {
241       // move past the padding.
242       if(fseek(fp, padding, SEEK_CUR))
243       {
244         DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32V4 padding\n");
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   return true;
508 }
509
510 /**
511  * function to decode format BI_RGB & bpp = 1
512  * @param[in]  fp      The file to read from
513  * @param[out] pixels  The pointer that  we want to store bmp data  in
514  * @param[in]  width   bmp width
515  * @param[in]  height  bmp height
516  * @param[in]  offset  offset from bmp header to bmp palette data
517  * @param[in]  topDown indicate image data is read from bottom or from top
518  * @return true, if decode successful, false otherwise
519  */
520 bool DecodeRGB1(FILE*          fp,
521                 unsigned char* pixels,
522                 unsigned int   width,
523                 unsigned int   height,
524                 unsigned int   offset,
525                 bool           topDown)
526 {
527   if(fp == NULL || pixels == NULL)
528   {
529     DALI_LOG_ERROR("Error decoding BMP_RGB1 format\n");
530     return false;
531   }
532   if(fseek(fp, offset, SEEK_SET))
533   {
534     DALI_LOG_ERROR("Error seeking BMP_RGB1 data\n");
535     return false;
536   }
537
538   unsigned char     colorTable[8] = {0};
539   char              cmd;
540   unsigned int      fillw = ((width & 63) != 0) ? width + 64 - (width & 63) : width;
541   std::vector<char> colorIndex(fillw * height);
542   unsigned int      rowStride = fillw * 3; // RGB
543
544   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     unsigned char* 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       unsigned 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                 unsigned char* 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   unsigned int ctIndex = 0;
652
653   for(unsigned int index = 0; index < height; index = index + 1)
654   {
655     unsigned char* 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                 unsigned char* 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   unsigned int ctIndex = 0;
726   for(unsigned int index = 0; index < height; index = index + 1)
727   {
728     unsigned char* 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                 unsigned char* 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   unsigned char* 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   unsigned int      x  = 0;
780   unsigned int      y  = 0;
781   unsigned int      dx = 0;
782   unsigned 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                 unsigned char* 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   unsigned char* pixelsPtr = pixels;
941   unsigned int   x         = 0;
942   unsigned 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   unsigned int      dx         = 0;
962   unsigned 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 Dali::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 Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& 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_ERROR("%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_ERROR("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   int  imageW         = infoHeader.width;
1198   int  pixelBufferW   = infoHeader.width;
1199   int  pixelBufferH   = infoHeader.height;
1200   auto newPixelFormat = Pixel::Format::INVALID;
1201
1202   switch(customizedFormat)
1203   {
1204     case BMP_RLE8:
1205     case BMP_RGB8:
1206     case BMP_RGB4:
1207     case BMP_RLE4:
1208     case BMP_RGB555:
1209     case BMP_BITFIELDS555:
1210     {
1211       pixelBufferW   = ((imageW & 3) != 0) ? imageW + 4 - (imageW & 3) : imageW;
1212       pixelBufferH   = abs(infoHeader.height);
1213       newPixelFormat = Pixel::RGB888;
1214       break;
1215     }
1216     case BMP_RGB1:
1217     {
1218       pixelBufferW   = ((imageW & 63) != 0) ? imageW + 64 - (imageW & 63) : imageW;
1219       pixelBufferH   = abs(infoHeader.height);
1220       newPixelFormat = Pixel::RGB888;
1221       break;
1222     }
1223     case BMP_BITFIELDS32:
1224     case BMP_BITFIELDS32V4:
1225     {
1226       pixelBufferH   = abs(infoHeader.height);
1227       newPixelFormat = Pixel::RGB8888;
1228       break;
1229     }
1230     case BMP_RGB24V5:
1231     {
1232       newPixelFormat = Pixel::RGB888;
1233       break;
1234     }
1235     default:
1236       if(pixelFormat == Pixel::RGB565)
1237       {
1238         pixelBufferW   = ((imageW & 3) != 0) ? imageW + 4 - (imageW & 3) : imageW;
1239         pixelBufferH   = abs(infoHeader.height);
1240         newPixelFormat = Pixel::RGB565;
1241       }
1242       else
1243       {
1244         pixelBufferW   = infoHeader.width;
1245         pixelBufferH   = infoHeader.height;
1246         newPixelFormat = pixelFormat;
1247       }
1248       break;
1249   }
1250
1251   bitmap      = Dali::Devel::PixelBuffer::New(pixelBufferW, pixelBufferH, newPixelFormat);
1252   auto pixels = bitmap.GetBuffer();
1253
1254   // Read the raw bitmap data
1255   decltype(pixels) pixelsIterator = nullptr;
1256
1257   bool decodeResult(false);
1258   switch(customizedFormat)
1259   {
1260     case BMP_RGB1:
1261     {
1262       decodeResult = DecodeRGB1(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1263       break;
1264     }
1265     case BMP_RGB4:
1266     {
1267       decodeResult = DecodeRGB4(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1268       break;
1269     }
1270     case BMP_RLE4:
1271     {
1272       decodeResult = DecodeRLE4(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1273       break;
1274     }
1275     case BMP_BITFIELDS32:
1276     {
1277       decodeResult = DecodeBF32(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
1278       break;
1279     }
1280     case BMP_BITFIELDS555:
1281     {
1282       decodeResult = DecodeBF555(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown);
1283       break;
1284     }
1285     case BMP_RGB555:
1286     {
1287       decodeResult = DecodeRGB555(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown);
1288       break;
1289     }
1290     case BMP_RGB8:
1291     {
1292       decodeResult = DecodeRGB8(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1293       break;
1294     }
1295     case BMP_RLE8:
1296     {
1297       decodeResult = DecodeRLE8(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1298       break;
1299     }
1300     case BMP_RGB24V5:
1301     {
1302       decodeResult = DecodeRGB24V5(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
1303       break;
1304     }
1305     case BMP_BITFIELDS32V4:
1306     {
1307       decodeResult = DecodeBF32V4(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
1308       break;
1309     }
1310     default:
1311     {
1312       if(pixelFormat == Pixel::RGB565)
1313       {
1314         decodeResult = DecodeBF565(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown);
1315       }
1316       else
1317       {
1318         for(unsigned int yPos = 0; yPos < height; yPos++)
1319         {
1320           if(topDown)
1321           {
1322             // the data in the file is top down, and we store the data top down
1323             pixelsIterator = pixels + (yPos * rowStride);
1324           }
1325           else
1326           {
1327             // the data in the file is bottom up, and we store the data top down
1328             pixelsIterator = pixels + (((height - 1) - yPos) * rowStride);
1329           }
1330
1331           if(fread(pixelsIterator, 1, rowStride, fp) != rowStride)
1332           {
1333             DALI_LOG_ERROR("Error reading the BMP image\n");
1334             break;
1335           }
1336
1337           // If 24 bit mode then swap Blue and Red pixels
1338           // BGR888 doesn't seem to be supported by dali-core
1339           if(infoHeader.bitsPerPixel == 24)
1340           {
1341             for(unsigned int i = 0; i < rowStride; i += 3)
1342             {
1343               unsigned char temp    = pixelsIterator[i];
1344               pixelsIterator[i]     = pixelsIterator[i + 2];
1345               pixelsIterator[i + 2] = temp;
1346             }
1347           }
1348
1349           if(padding)
1350           {
1351             if(fseek(fp, padding, SEEK_CUR)) // move past the padding.
1352             {
1353               DALI_LOG_ERROR("Error moving past BMP padding\n");
1354             }
1355           }
1356         }
1357         decodeResult = true;
1358       }
1359       break;
1360     }
1361   } // switch
1362
1363   if(!decodeResult)
1364   {
1365     DALI_LOG_ERROR("Decoding failed\n");
1366     return false;
1367   }
1368
1369   return true;
1370 }
1371
1372 } // namespace TizenPlatform
1373
1374 } // namespace Dali