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