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