2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <dali/internal/imaging/common/loader-bmp.h>
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>
24 #include <dali/internal/system/common/file-closer.h>
26 using namespace Dali::Internal::Platform;
31 namespace TizenPlatform
36 const unsigned int FileHeaderOffsetOfBF32V4 = 0x7A;
37 const unsigned int MaskForBFRGB565 = 0x80;
38 const unsigned int FileHeaderOffsetOfRGB24V5 = 0x8A;
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
50 BMP_BITFIELDS32V4,//BI_BITFIELDS & 32bit
51 BMP_RGB24V5, //BI_RGB & bpp = 24 & bmp version5
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
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
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
86 inline bool ReadHeader(FILE* fp, T& header)
88 const unsigned int readLength = sizeof(T);
90 // Load the information directly into our structure
91 if ( InternalFile::fread( &header, 1, readLength, fp ) != readLength )
99 bool LoadBmpHeader(FILE *fp, unsigned int &width, unsigned int &height, BmpFileHeader &fileHeader, BmpInfoHeader &infoHeader)
101 if (!ReadHeader(fp, fileHeader))
106 if (!ReadHeader(fp, infoHeader))
111 width = infoHeader.width;
112 height = abs(infoHeader.height);
114 if( infoHeader.width == 0 )
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
133 bool DecodeRGB24V5(FILE *fp,
134 unsigned char* pixels,
139 unsigned int rowStride,
140 unsigned int padding)
142 if(fp == NULL || pixels == NULL)
144 DALI_LOG_ERROR("Error decoding BMP_RGB24V5 format\n");
147 if ( InternalFile::fseek(fp, offset, SEEK_SET) )
149 DALI_LOG_ERROR("Error seeking BMP_RGB24V5 data\n");
153 for(unsigned int yPos = 0; yPos < height; yPos ++)
155 unsigned char* pixelsPtr = NULL;
158 pixelsPtr = pixels + ( yPos * rowStride);
162 pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
164 if (InternalFile::fread(pixelsPtr, 1, rowStride, fp) != rowStride)
166 DALI_LOG_ERROR("Error reading the BMP image\n");
169 for(unsigned int i = 0; i < rowStride; i += 3)
171 unsigned char temp = pixelsPtr[i];
172 pixelsPtr[i] = pixelsPtr[i + 2];
173 pixelsPtr[i + 2] = temp;
178 // move past the padding.
179 if( InternalFile::fseek(fp, padding, SEEK_CUR) )
181 DALI_LOG_ERROR("Error moving past BMP_RGB24V5 padding\n");
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
200 bool DecodeBF32V4(FILE *fp,
201 unsigned char* pixels,
206 unsigned int rowStride,
207 unsigned int padding)
209 if(fp == NULL || pixels == NULL)
211 DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32V4 format\n");
214 if( InternalFile::fseek(fp, offset, SEEK_SET) )
216 DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32V4 data\n");
220 for(unsigned int yPos = 0; yPos < height; yPos ++)
222 unsigned char* pixelsPtr = NULL;
225 pixelsPtr = pixels + ( yPos * rowStride);
229 pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
231 if (InternalFile::fread(pixelsPtr, 1, rowStride, fp) != rowStride)
233 DALI_LOG_ERROR("Error reading the BMP image\n");
236 for(unsigned int i = 0; i < rowStride; i += 4)
238 unsigned char temp = pixelsPtr[i];
239 pixelsPtr[i] = pixelsPtr[i + 2];
240 pixelsPtr[i + 2] = temp;
244 // move past the padding.
245 if( InternalFile::fseek(fp, padding, SEEK_CUR) )
247 DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32V4 padding\n");
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
267 bool DecodeBF32(FILE *fp,
268 unsigned char* pixels,
273 unsigned int rowStride,
274 unsigned int padding)
276 if(fp == NULL || pixels == NULL)
278 DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32 format\n");
281 if( InternalFile::fseek(fp, offset, SEEK_SET) )
283 DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32 data\n");
287 for (unsigned int yPos = 0; yPos < height; yPos++)
289 unsigned char* pixelsPtr;
292 // the data in the file is top down, and we store the data top down
293 pixelsPtr = pixels + ( yPos * rowStride);
297 // the data in the file is bottom up, and we store the data top down
298 pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
301 if (InternalFile::fread(pixelsPtr, 1, rowStride, fp) != rowStride)
303 DALI_LOG_ERROR("Error reading the BMP image\n");
306 for(unsigned int i = 0; i < rowStride; i += 4)
308 unsigned char temp = pixelsPtr[i];
309 pixelsPtr[i] = pixelsPtr[i + 2];
310 pixelsPtr[i + 2] = temp;
315 // move past the padding.
316 if( InternalFile::fseek(fp, padding, SEEK_CUR) )
318 DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32 padding\n");
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
335 bool DecodeBF565(FILE *fp,
336 unsigned char* pixels,
342 if(fp == NULL || pixels == NULL)
344 DALI_LOG_ERROR("Error decoding RGB565 format\n");
347 if( InternalFile::fseek(fp, offset, SEEK_SET) )
349 DALI_LOG_ERROR("Error seeking RGB565 data\n");
353 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
354 unsigned int rowStride = width * 2;
356 for(unsigned int i = 0; i < height; i++)
358 unsigned char* pixelsPtr = NULL;
361 // the data in the file is top down, and we store the data top down
362 pixelsPtr = pixels + ( i * rowStride);
366 // the data in the file is bottom up, and we store the data top down
367 pixelsPtr = pixels + (((height - 1) - i) * rowStride);
369 if(InternalFile::fread(pixelsPtr, 1, rowStride, fp) != rowStride)
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
388 bool DecodeBF555(FILE *fp,
389 unsigned char* pixels,
395 if(fp == NULL || pixels == NULL)
397 DALI_LOG_ERROR("Error decoding BMP_BITFIELDS555 format\n");
401 if( InternalFile::fseek(fp, offset, SEEK_SET) )
403 DALI_LOG_ERROR("Error seeking BMP_BITFIELDS555 data\n");
407 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
409 std::vector<char> raw(width * height * 2);
410 unsigned int rawStride = width * 2;
411 unsigned int rowStride = width * 3;
414 for(unsigned int j = 0; j < height; j ++)
416 rawPtr = &raw[0] + ( j * rawStride);
417 if(InternalFile::fread(rawPtr, 1, rawStride, fp) != rawStride)
423 for (unsigned int yPos = 0; yPos < height; yPos++)
425 unsigned char* pixelsPtr = NULL;
428 // the data in the file is top down, and we store the data top down
429 pixelsPtr = pixels + ( yPos * rowStride);
433 // the data in the file is bottom up, and we store the data top down
434 pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
437 for(unsigned int k = 0; k < width; k ++)
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;
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
458 bool DecodeRGB555(FILE *fp,
459 unsigned char* pixels,
465 if(fp == NULL || pixels == NULL)
467 DALI_LOG_ERROR("Error decoding BMP_RGB555 format\n");
470 if( InternalFile::fseek(fp, offset, SEEK_SET) )
472 DALI_LOG_ERROR("Error seeking BMP_RGB555 data\n");
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;
482 for(unsigned int j = 0; j < height; j ++)
484 rawPtr = &raw[0] + ( j * rawStride);
485 if(InternalFile::fread(rawPtr, 1, rawStride, fp) != rawStride)
490 for(unsigned int i = 0; i < height; i++)
492 unsigned char* pixelsPtr = NULL;
495 // the data in the file is top down, and we store the data top down
496 pixelsPtr = pixels + ( i * rowStride);
500 // the data in the file is bottom up, and we store the data top down
501 pixelsPtr = pixels + (((height - 1) - i) * rowStride);
503 for(unsigned int k = 0; k < width; k ++)
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;
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
525 bool DecodeRGB1(FILE *fp,
526 unsigned char* pixels,
532 if(fp == NULL || pixels == NULL)
534 DALI_LOG_ERROR("Error decoding BMP_RGB1 format\n");
537 if( InternalFile::fseek(fp, offset, SEEK_SET) )
539 DALI_LOG_ERROR("Error seeking BMP_RGB1 data\n");
543 unsigned char colorTable[8] = {0};
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
550 if(InternalFile::fread(colorTable, 1, 8, fp) != 8)
555 for(unsigned int i = 0; i < fillw * height; i += 8)
557 if(InternalFile::fread(&cmd, 1, 1, fp) != 1)
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);
572 for(unsigned int index = 0; index < height; index = index + 1)
574 unsigned char* pixelsPtr = NULL;
577 // the data in the file is top down, and we store the data top down
578 pixelsPtr = pixels + ( index * rowStride);
582 // the data in the file is bottom up, and we store the data top down
583 pixelsPtr = pixels + (((height - 1) - index) * rowStride);
585 for(unsigned int j = 0; j < fillw; j ++)
587 unsigned int ctIndex = 0;
588 if((fillw * index + j ) < (fillw * height))
590 ctIndex = colorIndex[ fillw * index + j ];
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))
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 ];
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
618 bool DecodeRGB4(FILE *fp,
619 unsigned char* pixels,
625 if(fp == NULL || pixels == NULL)
627 DALI_LOG_ERROR("Error decoding BMP_RGB4 format\n");
630 if( InternalFile::fseek(fp, offset, SEEK_SET) )
632 DALI_LOG_ERROR("Error seeking BMP_RGB4 data\n");
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;
642 if(InternalFile::fread(colorTable, 1, 64, fp) != 64)
647 for(unsigned int i = 0; i < fillw * height; i += 2)
649 if (InternalFile::fread(&cmd, 1, 1, fp) != 1)
654 colorIndex[i] = cmd >> 4;
655 colorIndex[i + 1] = cmd & (0x0F);
657 unsigned int ctIndex = 0;
659 for(unsigned int index = 0; index < height; index = index + 1)
661 unsigned char* pixelsPtr = NULL;
664 // the data in the file is top down, and we store the data top down
665 pixelsPtr = pixels + ( index * rowStride);
669 // the data in the file is bottom up, and we store the data top down
670 pixelsPtr = pixels + (((height - 1) - index) * rowStride);
672 for(unsigned int j = 0; j < fillw; j ++)
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 ];
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
694 bool DecodeRGB8(FILE *fp,
695 unsigned char* pixels,
701 if(fp == NULL || pixels == NULL)
703 DALI_LOG_ERROR("Error decoding BMP_RGB8 format\n");
706 if( InternalFile::fseek(fp, offset, SEEK_SET) )
708 DALI_LOG_ERROR("Error seeking BMP_RGB8 data\n");
712 std::vector<char> colorTable(1024);
713 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
715 std::vector<char> colorIndex(width * height);
716 unsigned int rowStride = width * 3;//RGB8->RGB24
718 if(InternalFile::fread(&colorTable[0], 1, 1024, fp) != 1024)
722 for(unsigned int i = 0; i < width * height; i ++)
724 if (InternalFile::fread(&cmd, 1, 1, fp) != 1)
731 unsigned int ctIndex = 0;
732 for(unsigned int index = 0; index < height; index = index + 1)
734 unsigned char* pixelsPtr = NULL;
737 // the data in the file is top down, and we store the data top down
738 pixelsPtr = pixels + ( index * rowStride);
742 // the data in the file is bottom up, and we store the data top down
743 pixelsPtr = pixels + (((height - 1) - index) * rowStride);
745 for(unsigned int j = 0; j < width; j ++)
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 ];
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
766 bool DecodeRLE4(FILE *fp,
767 unsigned char* pixels,
773 if(fp == NULL || pixels == NULL)
775 DALI_LOG_ERROR("Error decoding BMP_RLE4 format\n");
778 unsigned char* pixelsPtr = pixels;
779 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
781 unsigned int cmdStride = 2;
783 std::vector<char> colorIndex(width * height >> 1);
784 std::vector<char> run;
789 width += (width & 1);
794 if( InternalFile::fseek(fp, offset, SEEK_SET) )
796 DALI_LOG_ERROR("Error seeking BMP_RLE4 data\n");
800 if (InternalFile::fread(colorTable, 1, 64, fp) != 64)
805 while((x >> 1) + y * width < width * height)
811 if (InternalFile::fread(cmd, 1, cmdStride, fp) != cmdStride)
815 if(cmd[0] == 0) // ESCAPE
819 case 1: //end of bitmap
822 case 0: // end of line
827 if (InternalFile::fread(cmd, 1, cmdStride, fp) != cmdStride)
829 DALI_LOG_ERROR("Error reading the BMP image\n");
832 dx = cmd[0] & (0xFF);
833 dy = cmd[1] & (0xFF);
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);
844 bytesize += (bytesize & 1);
845 run.resize(bytesize);
846 if(InternalFile::fread(&run[0], 1, bytesize, fp) != bytesize)
848 DALI_LOG_ERROR("Error reading the BMP image\n");
853 length += (length & 1);
855 for(unsigned int i = 0; i < length; i += 1)
857 colorIndex[(x >> 1) + width * (height - y - 1) + i] = run[i];
862 for(unsigned int i = 0; i < length; i ++)
864 if((i & 1) == 0)//copy high to low
866 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((run[i >> 1] & 0xF0) >> 4);
868 else //copy low to high
870 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((run[i >> 1] & 0x0F) << 4);
874 x += cmd[1] & (0xFF);
880 unsigned int length = cmd[0] & (0xFF);
883 length += (length & 1);
885 for(unsigned int i = 0; i < length; i ++)
887 colorIndex[(height-y-1)*width + i + (x >> 1)] = cmd[1];
892 for(unsigned int i = 0; i < length; i ++)
896 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((cmd[1] & 0xF0) >> 4);
900 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((cmd[1] & 0x0F) << 4);
904 x += cmd[0] & (0xFF);
910 for(unsigned int index = 0; index < (width * height ); index = index + 1)
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 ];
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
934 bool DecodeRLE8(FILE *fp,
935 unsigned char* pixels,
941 if(fp == NULL || pixels == NULL)
943 DALI_LOG_ERROR("Error decoding BMP_RLE8 format\n");
946 unsigned char* pixelsPtr = pixels;
949 unsigned int cmdStride = 2;
951 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
952 std::vector<char> colorTable(1024);
954 std::vector<char> colorIndex(width * height);
956 if( InternalFile::fseek(fp, offset, SEEK_SET) )
958 DALI_LOG_ERROR("Error seeking BMP_RLE8 data\n");
962 if (InternalFile::fread(&colorTable[0], 1, 1024, fp) != 1024)
970 unsigned int length = 0;
971 unsigned int copylength = 0;
972 std::vector<char> run;
973 while((x + y * width) < width * height )
979 if (InternalFile::fread(cmd, 1, cmdStride, fp) != cmdStride)
984 if(cmd[0] == 0)//ESCAPE
988 case 1: // end of bitmap
991 case 0: // end of line
996 if (InternalFile::fread(cmd, 1, cmdStride, fp) != cmdStride)
998 DALI_LOG_ERROR("Error reading the BMP image\n");
1001 dx = cmd[0] & (0xFF);
1002 dy = cmd[1] & (0xFF);
1007 //decode a literal run
1008 length = cmd[1] & (0xFF);
1009 copylength = length;
1010 //absolute mode must be word-aligned
1011 length += (length & 1);
1013 if(InternalFile::fread(&run[0], 1, length, fp) != length)
1015 DALI_LOG_ERROR("Error reading the BMP image\n");
1019 for(unsigned int i = 0; i < length; i += 1)
1021 colorIndex[x + width * (height - y - 1) + i] = run[i];
1026 }// end if cmd[0] ==
1029 length = cmd[0] & (0xFF);
1030 for(unsigned int i = 0; i < length; i ++)
1032 colorIndex[(height - y - 1) * width + x] = cmd[1];
1038 for(unsigned int index = 0; index < width * height; index = index + 1)
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 ];
1048 } // unnamed namespace
1050 bool LoadBmpHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height )
1052 BmpFileHeader fileHeader;
1053 BmpInfoHeader infoHeader;
1055 bool ret = LoadBmpHeader( input.file, width, height, fileHeader, infoHeader );
1060 bool LoadBitmapFromBmp( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap )
1062 //DALI_ASSERT_DEBUG( bitmap.GetPackedPixelsProfile() != 0 && "Need a packed pixel bitmap to load into." );
1063 FILE* const fp = input.file;
1066 DALI_LOG_ERROR("Error loading bitmap\n");
1069 BmpFormat customizedFormat = BMP_NOTEXIST;
1070 BmpFileHeader fileHeader;
1071 BmpInfoHeader infoHeader;
1073 // Load the header info
1074 unsigned int width, height;
1076 if (!LoadBmpHeader(fp, width, height, fileHeader, infoHeader))
1081 Pixel::Format pixelFormat = Pixel::RGB888;
1082 switch(infoHeader.compression)
1085 switch (infoHeader.bitsPerPixel)
1088 pixelFormat = Pixel::BGR8888;
1092 if(fileHeader.offset == FileHeaderOffsetOfRGB24V5)//0x8A
1094 customizedFormat = BMP_RGB24V5;
1098 pixelFormat = Pixel::RGB888;
1103 customizedFormat = BMP_RGB555;
1107 customizedFormat = BMP_RGB8;
1111 customizedFormat = BMP_RGB4;
1115 customizedFormat = BMP_RGB1;
1118 DALI_LOG_WARNING("%d bits per pixel not supported for BMP files\n", infoHeader.bitsPerPixel);
1124 if(infoHeader.bitsPerPixel == 8)
1126 customizedFormat = BMP_RLE8;
1132 if(infoHeader.bitsPerPixel == 4)
1134 customizedFormat = BMP_RLE4;
1138 case 3: // // BI_BITFIELDS
1140 if(infoHeader.bitsPerPixel == 16)
1142 if( InternalFile::fseek(fp, 14 + infoHeader.infoHeaderSize + 1, SEEK_SET) )
1148 if(InternalFile::fread(&mask, 1, 1, fp) != 1)
1153 if((mask & 0x80) == MaskForBFRGB565) // mask is 0xF8
1155 pixelFormat = Pixel::RGB565;
1157 else if((mask & 0x80) == 0)// mask is 0x 7C
1159 customizedFormat = BMP_BITFIELDS555;
1166 else if(infoHeader.bitsPerPixel == 32)
1168 if(fileHeader.offset == FileHeaderOffsetOfBF32V4)// 0x7A
1170 customizedFormat = BMP_BITFIELDS32V4;
1174 customizedFormat = BMP_BITFIELDS32;
1180 DALI_LOG_WARNING("Compression not supported for BMP files\n");
1184 bool topDown = false;
1186 // if height is negative, bitmap data is top down
1187 if (infoHeader.height<0)
1189 infoHeader.height = abs(infoHeader.height);
1190 height = infoHeader.height;
1194 unsigned int rowStride = infoHeader.width * (infoHeader.bitsPerPixel >>3);
1196 // bitmaps row stride is padded to 4 bytes
1197 unsigned int padding = (rowStride % 4);
1200 padding = 4 - padding;
1203 int imageW = infoHeader.width;
1204 int pixelBufferW = infoHeader.width;
1205 int pixelBufferH = infoHeader.height;
1206 auto newPixelFormat = Pixel::Format::INVALID;
1208 switch(customizedFormat)
1215 case BMP_BITFIELDS555:
1217 pixelBufferW = ((imageW & 3) != 0) ? imageW + 4 - (imageW & 3) : imageW;
1218 pixelBufferH = abs(infoHeader.height);
1219 newPixelFormat = Pixel::RGB888;
1224 pixelBufferW = ((imageW & 63) != 0) ? imageW + 64 - (imageW & 63) : imageW;
1225 pixelBufferH = abs(infoHeader.height);
1226 newPixelFormat = Pixel::RGB888;
1229 case BMP_BITFIELDS32:
1230 case BMP_BITFIELDS32V4:
1232 pixelBufferH = abs(infoHeader.height);
1233 newPixelFormat = Pixel::RGB8888;
1238 newPixelFormat = Pixel::RGB888;
1242 if(pixelFormat == Pixel::RGB565 )
1244 pixelBufferW = ((imageW & 3) != 0) ? imageW + 4 - (imageW & 3) : imageW;
1245 pixelBufferH = abs(infoHeader.height);
1246 newPixelFormat = Pixel::RGB565;
1250 pixelBufferW = infoHeader.width;
1251 pixelBufferH = infoHeader.height;
1252 newPixelFormat = pixelFormat;
1257 bitmap = Dali::Devel::PixelBuffer::New(pixelBufferW, pixelBufferH, newPixelFormat);
1258 auto pixels = bitmap.GetBuffer();
1260 // Read the raw bitmap data
1261 decltype(pixels) pixelsIterator = nullptr;
1263 bool decodeResult(false);
1264 switch(customizedFormat)
1268 decodeResult = DecodeRGB1( fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1273 decodeResult = DecodeRGB4(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1278 decodeResult = DecodeRLE4( fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1281 case BMP_BITFIELDS32:
1283 decodeResult = DecodeBF32(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
1286 case BMP_BITFIELDS555:
1288 decodeResult = DecodeBF555(fp, pixels,infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown);
1293 decodeResult = DecodeRGB555(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown);
1298 decodeResult = DecodeRGB8(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1303 decodeResult = DecodeRLE8(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1308 decodeResult = DecodeRGB24V5(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
1311 case BMP_BITFIELDS32V4:
1313 decodeResult = DecodeBF32V4(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
1318 if(pixelFormat == Pixel::RGB565)
1320 decodeResult = DecodeBF565(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown);
1324 for (unsigned int yPos = 0; yPos < height; yPos++)
1328 // the data in the file is top down, and we store the data top down
1329 pixelsIterator = pixels + ( yPos * rowStride);
1333 // the data in the file is bottom up, and we store the data top down
1334 pixelsIterator = pixels + (((height-1)-yPos) * rowStride);
1337 if (InternalFile::fread(pixelsIterator, 1, rowStride, fp) != rowStride)
1339 DALI_LOG_ERROR("Error reading the BMP image\n");
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 )
1347 for(unsigned int i = 0; i < rowStride; i += 3)
1349 unsigned char temp = pixelsIterator[i];
1350 pixelsIterator[i] = pixelsIterator[i+2];
1351 pixelsIterator[i+2] = temp;
1357 if( InternalFile::fseek(fp, padding, SEEK_CUR) ) // move past the padding.
1359 DALI_LOG_ERROR("Error moving past BMP padding\n");
1363 decodeResult = true;
1377 } // namespace TizenPlatform