2 * Copyright (c) 2021 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/devel-api/adaptor-framework/pixel-buffer.h>
21 #include <dali/integration-api/debug.h>
22 #include <dali/public-api/common/vector-wrapper.h>
26 namespace TizenPlatform
30 const unsigned int FileHeaderOffsetOfBF32V4 = 0x7A;
31 const unsigned int MaskForBFRGB565 = 0x80;
32 const unsigned int FileHeaderOffsetOfRGB24V5 = 0x8A;
36 BMP_RGB1 = 14, //BI_RGB & bpp =1
37 BMP_RGB4, //BI_RGB & bpp = 4
38 BMP_RGB8, //BI_RGB & bpp = 8
39 BMP_RGB555, //BI_RGB & bpp = 16
40 BMP_BITFIELDS555, //BI_BITFIELDS & 16bit & R:G:B = 5:5:5
41 BMP_BITFIELDS32, //BI_BITFIELDS & 32bit & R:G:B:A = 8:8:8:8
44 BMP_BITFIELDS32V4, //BI_BITFIELDS & 32bit
45 BMP_RGB24V5, //BI_RGB & bpp = 24 & bmp version5
51 unsigned short signature; // Bitmap file signature
52 unsigned int fileSize; // Bitmap file size in bytes
53 unsigned short reserved1; // Reserved bits
54 unsigned short reserved2; // Reserved bits
55 unsigned int offset; // Offset from BMP file header to BMP bits
56 } __attribute__((__packed__)); // Stops the structure from being aligned to every 4 bytes
60 unsigned int infoHeaderSize; // Specifies the number of bytes required by the info header
61 unsigned int width; // The Image Width
62 int height; // The Image Height (negative value represents image data is flipped)
63 unsigned short planes; // The number of color planes, must be 1
64 unsigned short bitsPerPixel; // The bits per pixel
65 unsigned int compression; // The type of compression used by the image
66 unsigned int imageSize; // The size of the image in bytes
67 unsigned int xPixelsPerMeter; // The number of pixels per meter in x axis
68 unsigned int yPixelsPerMeter; // The number of pixels per meter in y axis
69 unsigned int numberOfColors; // The number of colors in the color table
70 unsigned int importantColors; // The important color count
71 } __attribute__((__packed__)); // Stops the structure from being aligned to every 4 bytes
74 * Template function to read from the file directly into our structure.
75 * @param[in] fp The file to read from
76 * @param[out] header The structure we want to store our information in
77 * @return true, if read successful, false otherwise
80 inline bool ReadHeader(FILE* fp, T& header)
82 const unsigned int readLength = sizeof(T);
84 // Load the information directly into our structure
85 if(fread(&header, 1, readLength, fp) != readLength)
93 bool LoadBmpHeader(FILE* fp, unsigned int& width, unsigned int& height, BmpFileHeader& fileHeader, BmpInfoHeader& infoHeader)
95 if(!ReadHeader(fp, fileHeader))
100 if(!ReadHeader(fp, infoHeader))
105 width = infoHeader.width;
106 height = abs(infoHeader.height);
108 if(infoHeader.width == 0)
117 * function to decode format BI_RGB & bpp = 24 & bmp version5.
118 * @param[in] fp The file to read from
119 * @param[out] pixels The pointer that we want to store bmp data in
120 * @param[in] width bmp width
121 * @param[in] height bmp height
122 * @param[in] offset offset from bmp header to bmp image data
123 * @param[in] topDown indicate image data is read from bottom or from top
124 * @param[in] padding padded to a u_int32 boundary for each line
125 * @return true, if decode successful, false otherwise
127 bool DecodeRGB24V5(FILE* fp,
128 unsigned char* pixels,
133 unsigned int rowStride,
134 unsigned int padding)
136 if(fp == NULL || pixels == NULL)
138 DALI_LOG_ERROR("Error decoding BMP_RGB24V5 format\n");
141 if(fseek(fp, offset, SEEK_SET))
143 DALI_LOG_ERROR("Error seeking BMP_RGB24V5 data\n");
147 for(unsigned int yPos = 0; yPos < height; yPos++)
149 unsigned char* pixelsPtr = NULL;
152 pixelsPtr = pixels + (yPos * rowStride);
156 pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
158 if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
160 DALI_LOG_ERROR("Error reading the BMP image\n");
163 for(unsigned int i = 0; i < rowStride; i += 3)
165 unsigned char temp = pixelsPtr[i];
166 pixelsPtr[i] = pixelsPtr[i + 2];
167 pixelsPtr[i + 2] = temp;
172 // move past the padding.
173 if(fseek(fp, padding, SEEK_CUR))
175 DALI_LOG_ERROR("Error moving past BMP_RGB24V5 padding\n");
183 * function to decode format BI_BITFIELDS & bpp = 32 & bmp version4.
184 * @param[in] fp The file to read from
185 * @param[out] pixels The pointer that we want to store bmp data in
186 * @param[in] width bmp width
187 * @param[in] height bmp height
188 * @param[in] offset offset from bmp header to bmp image data
189 * @param[in] topDown indicate image data is read from bottom or from top
190 * @param[in] rowStride bits span for each line
191 * @param[in] padding padded to a u_int32 boundary for each line
192 * @return true, if decode successful, false otherwise
194 bool DecodeBF32V4(FILE* fp,
195 unsigned char* pixels,
200 unsigned int rowStride,
201 unsigned int padding)
203 if(fp == NULL || pixels == NULL)
205 DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32V4 format\n");
208 if(fseek(fp, offset, SEEK_SET))
210 DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32V4 data\n");
214 for(unsigned int yPos = 0; yPos < height; yPos++)
216 unsigned char* pixelsPtr = NULL;
219 pixelsPtr = pixels + (yPos * rowStride);
223 pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
225 if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
227 DALI_LOG_ERROR("Error reading the BMP image\n");
230 for(unsigned int i = 0; i < rowStride; i += 4)
232 unsigned char temp = pixelsPtr[i];
233 pixelsPtr[i] = pixelsPtr[i + 2];
234 pixelsPtr[i + 2] = temp;
238 // move past the padding.
239 if(fseek(fp, padding, SEEK_CUR))
241 DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32V4 padding\n");
249 * function to decode format BI_BITFIELDS & bpp = 32
250 * @param[in] fp The file to read from
251 * @param[out] pixels The pointer that we want to store bmp data in
252 * @param[in] width bmp width
253 * @param[in] height bmp height
254 * @param[in] offset offset from bmp header to bmp image data
255 * @param[in] topDown indicate image data is read from bottom or from top
256 * @param[in] rowStride bits span for each line
257 * @param[in] padding padded to a u_int32 boundary for each line
258 * @return true, if decode successful, false otherwise
260 bool DecodeBF32(FILE* fp,
261 unsigned char* pixels,
266 unsigned int rowStride,
267 unsigned int padding)
269 if(fp == NULL || pixels == NULL)
271 DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32 format\n");
274 if(fseek(fp, offset, SEEK_SET))
276 DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32 data\n");
280 for(unsigned int yPos = 0; yPos < height; yPos++)
282 unsigned char* pixelsPtr;
285 // the data in the file is top down, and we store the data top down
286 pixelsPtr = pixels + (yPos * rowStride);
290 // the data in the file is bottom up, and we store the data top down
291 pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
294 if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
296 DALI_LOG_ERROR("Error reading the BMP image\n");
299 for(unsigned int i = 0; i < rowStride; i += 4)
301 unsigned char temp = pixelsPtr[i];
302 pixelsPtr[i] = pixelsPtr[i + 2];
303 pixelsPtr[i + 2] = temp;
308 // move past the padding.
309 if(fseek(fp, padding, SEEK_CUR))
311 DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32 padding\n");
319 * function to decode format BI_BITFIELDS & bpp = 16 & R:G:B = 5:6:5
320 * @param[in] fp The file to read from
321 * @param[out] pixels The pointer that we want to store bmp data in
322 * @param[in] width bmp width
323 * @param[in] height bmp height
324 * @param[in] offset offset from bmp header to bmp image data
325 * @param[in] topDown indicate image data is read from bottom or from top
326 * @return true, if decode successful, false otherwise
328 bool DecodeBF565(FILE* fp,
329 unsigned char* pixels,
335 if(fp == NULL || pixels == NULL)
337 DALI_LOG_ERROR("Error decoding RGB565 format\n");
340 if(fseek(fp, offset, SEEK_SET))
342 DALI_LOG_ERROR("Error seeking RGB565 data\n");
346 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
347 unsigned int rowStride = width * 2;
349 for(unsigned int i = 0; i < height; i++)
351 unsigned char* pixelsPtr = NULL;
354 // the data in the file is top down, and we store the data top down
355 pixelsPtr = pixels + (i * rowStride);
359 // the data in the file is bottom up, and we store the data top down
360 pixelsPtr = pixels + (((height - 1) - i) * rowStride);
362 if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
372 * function to decode format BI_BITFIELDS & bpp = 16 & R:G:B = 5:5:5
373 * @param[in] fp The file to read from
374 * @param[out] pixels The pointer that we want to store bmp data in
375 * @param[in] width bmp width
376 * @param[in] height bmp height
377 * @param[in] offset offset from bmp header to bmp image data
378 * @param[in] topDown indicate image data is read from bottom or from top
379 * @return true, if decode successful, false otherwise
381 bool DecodeBF555(FILE* fp,
382 unsigned char* pixels,
388 if(fp == NULL || pixels == NULL)
390 DALI_LOG_ERROR("Error decoding BMP_BITFIELDS555 format\n");
394 if(fseek(fp, offset, SEEK_SET))
396 DALI_LOG_ERROR("Error seeking BMP_BITFIELDS555 data\n");
400 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
402 std::vector<char> raw(width * height * 2);
403 unsigned int rawStride = width * 2;
404 unsigned int rowStride = width * 3;
407 for(unsigned int j = 0; j < height; j++)
409 rawPtr = &raw[0] + (j * rawStride);
410 if(fread(rawPtr, 1, rawStride, fp) != rawStride)
416 for(unsigned int yPos = 0; yPos < height; yPos++)
418 unsigned char* pixelsPtr = NULL;
421 // the data in the file is top down, and we store the data top down
422 pixelsPtr = pixels + (yPos * rowStride);
426 // the data in the file is bottom up, and we store the data top down
427 pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
430 for(unsigned int k = 0; k < width; k++)
432 int index = yPos * rawStride + 2 * k;
433 pixelsPtr[3 * k] = ((raw[index + 1] >> 2) & 0x1F) * 0xFF / 0x1F;
434 pixelsPtr[3 * k + 1] = (((raw[index + 1] & 0x03) << 3) | (raw[index] >> 5)) * 0xFF / 0x1F;
435 pixelsPtr[3 * k + 2] = (raw[index] & 0x1F) * 0xFF / 0x1F;
442 * function to decode format BI_RGB & bpp = 16 & R:G:B = 5:5:5
443 * @param[in] fp The file to read from
444 * @param[out] pixels The pointer that we want to store bmp data in
445 * @param[in] width bmp width
446 * @param[in] height bmp height
447 * @param[in] offset offset from bmp header to bmp image data
448 * @param[in] topDown indicate image data is read from bottom or from top
449 * @return true, if decode successful, false otherwise
451 bool DecodeRGB555(FILE* fp,
452 unsigned char* pixels,
458 if(fp == NULL || pixels == NULL)
460 DALI_LOG_ERROR("Error decoding BMP_RGB555 format\n");
463 if(fseek(fp, offset, SEEK_SET))
465 DALI_LOG_ERROR("Error seeking BMP_RGB555 data\n");
469 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
470 std::vector<char> raw(width * height * 2);
471 unsigned int rawStride = width * 2;
472 unsigned int rowStride = width * 3;
475 for(unsigned int j = 0; j < height; j++)
477 rawPtr = &raw[0] + (j * rawStride);
478 if(fread(rawPtr, 1, rawStride, fp) != rawStride)
483 for(unsigned int i = 0; i < height; i++)
485 unsigned char* pixelsPtr = NULL;
488 // the data in the file is top down, and we store the data top down
489 pixelsPtr = pixels + (i * rowStride);
493 // the data in the file is bottom up, and we store the data top down
494 pixelsPtr = pixels + (((height - 1) - i) * rowStride);
496 for(unsigned int k = 0; k < width; k++)
498 int index = i * rawStride + 2 * k;
499 pixelsPtr[3 * k] = ((raw[index + 1] >> 2) & 0x1F) * 0xFF / 0x1F;
500 pixelsPtr[3 * k + 1] = (((raw[index + 1] & 0x03) << 3) | (raw[index] >> 5)) * 0xFF / 0x1F;
501 pixelsPtr[3 * k + 2] = (raw[index] & 0x1F) * 0xFF / 0x1F;
508 * function to decode format BI_RGB & bpp = 1
509 * @param[in] fp The file to read from
510 * @param[out] pixels The pointer that we want to store bmp data in
511 * @param[in] width bmp width
512 * @param[in] height bmp height
513 * @param[in] offset offset from bmp header to bmp palette data
514 * @param[in] topDown indicate image data is read from bottom or from top
515 * @return true, if decode successful, false otherwise
517 bool DecodeRGB1(FILE* fp,
518 unsigned char* pixels,
524 if(fp == NULL || pixels == NULL)
526 DALI_LOG_ERROR("Error decoding BMP_RGB1 format\n");
529 if(fseek(fp, offset, SEEK_SET))
531 DALI_LOG_ERROR("Error seeking BMP_RGB1 data\n");
535 unsigned char colorTable[8] = {0};
537 unsigned int fillw = ((width & 63) != 0) ? width + 64 - (width & 63) : width;
538 std::vector<char> colorIndex(fillw * height);
539 unsigned int rowStride = fillw * 3; // RGB
541 if(fread(colorTable, 1, 8, fp) != 8)
546 for(unsigned int i = 0; i < fillw * height; i += 8)
548 if(fread(&cmd, 1, 1, fp) != 1)
553 colorIndex[i] = (cmd >> 7) & 0x01;
554 colorIndex[i + 1] = (cmd >> 6) & 0x01;
555 colorIndex[i + 2] = (cmd >> 5) & 0x01;
556 colorIndex[i + 3] = (cmd >> 4) & 0x01;
557 colorIndex[i + 4] = (cmd >> 3) & 0x01;
558 colorIndex[i + 5] = (cmd >> 2) & 0x01;
559 colorIndex[i + 6] = (cmd >> 1) & 0x01;
560 colorIndex[i + 7] = (cmd & 0x01);
563 for(unsigned int index = 0; index < height; index = index + 1)
565 unsigned char* pixelsPtr = NULL;
568 // the data in the file is top down, and we store the data top down
569 pixelsPtr = pixels + (index * rowStride);
573 // the data in the file is bottom up, and we store the data top down
574 pixelsPtr = pixels + (((height - 1) - index) * rowStride);
576 for(unsigned int j = 0; j < fillw; j++)
578 unsigned int ctIndex = 0;
579 if((fillw * index + j) < (fillw * height))
581 ctIndex = colorIndex[fillw * index + j];
587 // temp solution for PLM bug P130411-5268, there is one mono bmp that cause DecodeRGB1 API crash.
588 if(((3 * j + 2) < height * fillw * 3) && (ctIndex < 2))
590 pixelsPtr[3 * j] = colorTable[4 * ctIndex + 2];
591 pixelsPtr[3 * j + 1] = colorTable[4 * ctIndex + 1];
592 pixelsPtr[3 * j + 2] = colorTable[4 * ctIndex];
600 * function to decode format BI_RGB & bpp = 4
601 * @param[in] fp The file to read from
602 * @param[out] pixels The pointer that we want to store bmp data in
603 * @param[in] width bmp width
604 * @param[in] height bmp height
605 * @param[in] offset offset from bmp header to bmp palette data
606 * @param[in] topDown indicate image data is read from bottom or from top
607 * @return true, if decode successful, false otherwise
609 bool DecodeRGB4(FILE* fp,
610 unsigned char* pixels,
616 if(fp == NULL || pixels == NULL)
618 DALI_LOG_ERROR("Error decoding BMP_RGB4 format\n");
621 if(fseek(fp, offset, SEEK_SET))
623 DALI_LOG_ERROR("Error seeking BMP_RGB4 data\n");
629 unsigned int fillw = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
630 std::vector<char> colorIndex(fillw * height);
631 unsigned int rowStride = fillw * 3;
633 if(fread(colorTable, 1, 64, fp) != 64)
638 for(unsigned int i = 0; i < fillw * height; i += 2)
640 if(fread(&cmd, 1, 1, fp) != 1)
645 colorIndex[i] = cmd >> 4;
646 colorIndex[i + 1] = cmd & (0x0F);
648 unsigned int ctIndex = 0;
650 for(unsigned int index = 0; index < height; index = index + 1)
652 unsigned char* pixelsPtr = NULL;
655 // the data in the file is top down, and we store the data top down
656 pixelsPtr = pixels + (index * rowStride);
660 // the data in the file is bottom up, and we store the data top down
661 pixelsPtr = pixels + (((height - 1) - index) * rowStride);
663 for(unsigned int j = 0; j < fillw; j++)
665 ctIndex = colorIndex[fillw * index + j];
666 pixelsPtr[3 * j] = colorTable[4 * ctIndex + 2];
667 pixelsPtr[(3 * j + 1)] = colorTable[4 * ctIndex + 1];
668 pixelsPtr[(3 * j + 2)] = colorTable[4 * ctIndex];
676 * function to decode format BI_RGB & bpp = 8
677 * @param[in] fp The file to read from
678 * @param[out] pixels The pointer that we want to store bmp data in
679 * @param[in] width bmp width
680 * @param[in] height bmp height
681 * @param[in] offset offset from bmp header to bmp palette data
682 * @param[in] topDown indicate image data is read from bottom or from top
683 * @return true, if decode successful, false otherwise
685 bool DecodeRGB8(FILE* fp,
686 unsigned char* pixels,
692 if(fp == NULL || pixels == NULL)
694 DALI_LOG_ERROR("Error decoding BMP_RGB8 format\n");
697 if(fseek(fp, offset, SEEK_SET))
699 DALI_LOG_ERROR("Error seeking BMP_RGB8 data\n");
703 std::vector<char> colorTable(1024);
704 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
706 std::vector<char> colorIndex(width * height);
707 unsigned int rowStride = width * 3; //RGB8->RGB24
709 if(fread(&colorTable[0], 1, 1024, fp) != 1024)
713 for(unsigned int i = 0; i < width * height; i++)
715 if(fread(&cmd, 1, 1, fp) != 1)
722 unsigned int ctIndex = 0;
723 for(unsigned int index = 0; index < height; index = index + 1)
725 unsigned char* pixelsPtr = NULL;
728 // the data in the file is top down, and we store the data top down
729 pixelsPtr = pixels + (index * rowStride);
733 // the data in the file is bottom up, and we store the data top down
734 pixelsPtr = pixels + (((height - 1) - index) * rowStride);
736 for(unsigned int j = 0; j < width; j++)
738 ctIndex = colorIndex[width * index + j];
739 pixelsPtr[3 * j] = colorTable[4 * ctIndex + 2];
740 pixelsPtr[(3 * j + 1)] = colorTable[4 * ctIndex + 1];
741 pixelsPtr[(3 * j + 2)] = colorTable[4 * ctIndex];
748 * function to decode format BI_RLE4 & bpp = 4
749 * @param[in] fp The file to read from
750 * @param[out] pixels The pointer that we want to store bmp data in
751 * @param[in] width bmp width
752 * @param[in] height bmp height
753 * @param[in] offset offset from bmp header to bmp palette data
754 * @param[in] topDown indicate image data is read from bottom or from top
755 * @return true, if decode successful, false otherwise
757 bool DecodeRLE4(FILE* fp,
758 unsigned char* pixels,
764 if(fp == NULL || pixels == NULL)
766 DALI_LOG_ERROR("Error decoding BMP_RLE4 format\n");
769 unsigned char* pixelsPtr = pixels;
770 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
772 unsigned int cmdStride = 2;
774 std::vector<char> colorIndex(width * height >> 1);
775 std::vector<char> run;
780 width += (width & 1);
785 if(fseek(fp, offset, SEEK_SET))
787 DALI_LOG_ERROR("Error seeking BMP_RLE4 data\n");
791 if(fread(colorTable, 1, 64, fp) != 64)
796 while((x >> 1) + y * width < width * height)
802 if(fread(cmd, 1, cmdStride, fp) != cmdStride)
806 if(cmd[0] == 0) // ESCAPE
810 case 1: //end of bitmap
813 case 0: // end of line
818 if(fread(cmd, 1, cmdStride, fp) != cmdStride)
820 DALI_LOG_ERROR("Error reading the BMP image\n");
823 dx = cmd[0] & (0xFF);
824 dy = cmd[1] & (0xFF);
829 // decode a literal run
830 unsigned int length = cmd[1] & (0xFF);
831 //size of run, which is word aligned
832 unsigned int bytesize = length;
833 bytesize += (bytesize & 1);
835 bytesize += (bytesize & 1);
836 run.resize(bytesize);
837 if(fread(&run[0], 1, bytesize, fp) != bytesize)
839 DALI_LOG_ERROR("Error reading the BMP image\n");
844 length += (length & 1);
846 for(unsigned int i = 0; i < length; i += 1)
848 colorIndex[(x >> 1) + width * (height - y - 1) + i] = run[i];
853 for(unsigned int i = 0; i < length; i++)
855 if((i & 1) == 0) //copy high to low
857 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((run[i >> 1] & 0xF0) >> 4);
859 else //copy low to high
861 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((run[i >> 1] & 0x0F) << 4);
865 x += cmd[1] & (0xFF);
871 unsigned int length = cmd[0] & (0xFF);
874 length += (length & 1);
876 for(unsigned int i = 0; i < length; i++)
878 colorIndex[(height - y - 1) * width + i + (x >> 1)] = cmd[1];
883 for(unsigned int i = 0; i < length; i++)
887 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((cmd[1] & 0xF0) >> 4);
891 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((cmd[1] & 0x0F) << 4);
895 x += cmd[0] & (0xFF);
901 for(unsigned int index = 0; index < (width * height); index = index + 1)
903 ctIndexHigh = colorIndex[index] >> 4;
904 ctIndexLow = colorIndex[index] & (0x0F);
905 pixelsPtr[6 * index] = colorTable[4 * ctIndexHigh + 2];
906 pixelsPtr[6 * index + 1] = colorTable[4 * ctIndexHigh + 1];
907 pixelsPtr[6 * index + 2] = colorTable[4 * ctIndexHigh];
908 pixelsPtr[6 * index + 3] = colorTable[4 * ctIndexLow + 2];
909 pixelsPtr[6 * index + 4] = colorTable[4 * ctIndexLow + 1];
910 pixelsPtr[6 * index + 5] = colorTable[4 * ctIndexLow];
916 * function to decode format BI_RLE8 & bpp = 8
917 * @param[in] fp The file to read from
918 * @param[out] pixels The pointer that we want to store bmp data in
919 * @param[in] width bmp width
920 * @param[in] height bmp height
921 * @param[in] offset offset from bmp header to bmp palette data
922 * @param[in] topDown indicate image data is read from bottom or from top
923 * @return true, if decode successful, false otherwise
925 bool DecodeRLE8(FILE* fp,
926 unsigned char* pixels,
932 if(fp == NULL || pixels == NULL)
934 DALI_LOG_ERROR("Error decoding BMP_RLE8 format\n");
937 unsigned char* pixelsPtr = pixels;
940 unsigned int cmdStride = 2;
942 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
943 std::vector<char> colorTable(1024);
945 std::vector<char> colorIndex(width * height);
947 if(fseek(fp, offset, SEEK_SET))
949 DALI_LOG_ERROR("Error seeking BMP_RLE8 data\n");
953 if(fread(&colorTable[0], 1, 1024, fp) != 1024)
961 unsigned int length = 0;
962 unsigned int copylength = 0;
963 std::vector<char> run;
964 while((x + y * width) < width * height)
970 if(fread(cmd, 1, cmdStride, fp) != cmdStride)
975 if(cmd[0] == 0) //ESCAPE
979 case 1: // end of bitmap
982 case 0: // end of line
987 if(fread(cmd, 1, cmdStride, fp) != cmdStride)
989 DALI_LOG_ERROR("Error reading the BMP image\n");
992 dx = cmd[0] & (0xFF);
993 dy = cmd[1] & (0xFF);
998 //decode a literal run
999 length = cmd[1] & (0xFF);
1000 copylength = length;
1001 //absolute mode must be word-aligned
1002 length += (length & 1);
1004 if(fread(&run[0], 1, length, fp) != length)
1006 DALI_LOG_ERROR("Error reading the BMP image\n");
1010 for(unsigned int i = 0; i < length; i += 1)
1012 colorIndex[x + width * (height - y - 1) + i] = run[i];
1017 } // end if cmd[0] ==
1020 length = cmd[0] & (0xFF);
1021 for(unsigned int i = 0; i < length; i++)
1023 colorIndex[(height - y - 1) * width + x] = cmd[1];
1029 for(unsigned int index = 0; index < width * height; index = index + 1)
1031 ctIndex = colorIndex[index];
1032 pixelsPtr[3 * index] = colorTable[4 * ctIndex + 2];
1033 pixelsPtr[3 * index + 1] = colorTable[4 * ctIndex + 1];
1034 pixelsPtr[3 * index + 2] = colorTable[4 * ctIndex];
1039 } // unnamed namespace
1041 bool LoadBmpHeader(const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height)
1043 BmpFileHeader fileHeader;
1044 BmpInfoHeader infoHeader;
1046 bool ret = LoadBmpHeader(input.file, width, height, fileHeader, infoHeader);
1051 bool LoadBitmapFromBmp(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap)
1053 //DALI_ASSERT_DEBUG( bitmap.GetPackedPixelsProfile() != 0 && "Need a packed pixel bitmap to load into." );
1054 FILE* const fp = input.file;
1057 DALI_LOG_ERROR("Error loading bitmap\n");
1060 BmpFormat customizedFormat = BMP_NOTEXIST;
1061 BmpFileHeader fileHeader;
1062 BmpInfoHeader infoHeader;
1064 // Load the header info
1065 unsigned int width, height;
1067 if(!LoadBmpHeader(fp, width, height, fileHeader, infoHeader))
1072 Pixel::Format pixelFormat = Pixel::RGB888;
1073 switch(infoHeader.compression)
1076 switch(infoHeader.bitsPerPixel)
1079 pixelFormat = Pixel::BGR8888;
1083 if(fileHeader.offset == FileHeaderOffsetOfRGB24V5) //0x8A
1085 customizedFormat = BMP_RGB24V5;
1089 pixelFormat = Pixel::RGB888;
1094 customizedFormat = BMP_RGB555;
1098 customizedFormat = BMP_RGB8;
1102 customizedFormat = BMP_RGB4;
1106 customizedFormat = BMP_RGB1;
1109 DALI_LOG_WARNING("%d bits per pixel not supported for BMP files\n", infoHeader.bitsPerPixel);
1115 if(infoHeader.bitsPerPixel == 8)
1117 customizedFormat = BMP_RLE8;
1123 if(infoHeader.bitsPerPixel == 4)
1125 customizedFormat = BMP_RLE4;
1129 case 3: // // BI_BITFIELDS
1131 if(infoHeader.bitsPerPixel == 16)
1133 if(fseek(fp, 14 + infoHeader.infoHeaderSize + 1, SEEK_SET))
1139 if(fread(&mask, 1, 1, fp) != 1)
1144 if((mask & 0x80) == MaskForBFRGB565) // mask is 0xF8
1146 pixelFormat = Pixel::RGB565;
1148 else if((mask & 0x80) == 0) // mask is 0x 7C
1150 customizedFormat = BMP_BITFIELDS555;
1157 else if(infoHeader.bitsPerPixel == 32)
1159 if(fileHeader.offset == FileHeaderOffsetOfBF32V4) // 0x7A
1161 customizedFormat = BMP_BITFIELDS32V4;
1165 customizedFormat = BMP_BITFIELDS32;
1171 DALI_LOG_WARNING("Compression not supported for BMP files\n");
1175 bool topDown = false;
1177 // if height is negative, bitmap data is top down
1178 if(infoHeader.height < 0)
1180 infoHeader.height = abs(infoHeader.height);
1181 height = infoHeader.height;
1185 unsigned int rowStride = infoHeader.width * (infoHeader.bitsPerPixel >> 3);
1187 // bitmaps row stride is padded to 4 bytes
1188 unsigned int padding = (rowStride % 4);
1191 padding = 4 - padding;
1194 int imageW = infoHeader.width;
1195 int pixelBufferW = infoHeader.width;
1196 int pixelBufferH = infoHeader.height;
1197 auto newPixelFormat = Pixel::Format::INVALID;
1199 switch(customizedFormat)
1206 case BMP_BITFIELDS555:
1208 pixelBufferW = ((imageW & 3) != 0) ? imageW + 4 - (imageW & 3) : imageW;
1209 pixelBufferH = abs(infoHeader.height);
1210 newPixelFormat = Pixel::RGB888;
1215 pixelBufferW = ((imageW & 63) != 0) ? imageW + 64 - (imageW & 63) : imageW;
1216 pixelBufferH = abs(infoHeader.height);
1217 newPixelFormat = Pixel::RGB888;
1220 case BMP_BITFIELDS32:
1221 case BMP_BITFIELDS32V4:
1223 pixelBufferH = abs(infoHeader.height);
1224 newPixelFormat = Pixel::RGB8888;
1229 newPixelFormat = Pixel::RGB888;
1233 if(pixelFormat == Pixel::RGB565)
1235 pixelBufferW = ((imageW & 3) != 0) ? imageW + 4 - (imageW & 3) : imageW;
1236 pixelBufferH = abs(infoHeader.height);
1237 newPixelFormat = Pixel::RGB565;
1241 pixelBufferW = infoHeader.width;
1242 pixelBufferH = infoHeader.height;
1243 newPixelFormat = pixelFormat;
1248 bitmap = Dali::Devel::PixelBuffer::New(pixelBufferW, pixelBufferH, newPixelFormat);
1249 auto pixels = bitmap.GetBuffer();
1251 // Read the raw bitmap data
1252 decltype(pixels) pixelsIterator = nullptr;
1254 bool decodeResult(false);
1255 switch(customizedFormat)
1259 decodeResult = DecodeRGB1(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1264 decodeResult = DecodeRGB4(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1269 decodeResult = DecodeRLE4(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1272 case BMP_BITFIELDS32:
1274 decodeResult = DecodeBF32(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
1277 case BMP_BITFIELDS555:
1279 decodeResult = DecodeBF555(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown);
1284 decodeResult = DecodeRGB555(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown);
1289 decodeResult = DecodeRGB8(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1294 decodeResult = DecodeRLE8(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1299 decodeResult = DecodeRGB24V5(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
1302 case BMP_BITFIELDS32V4:
1304 decodeResult = DecodeBF32V4(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
1309 if(pixelFormat == Pixel::RGB565)
1311 decodeResult = DecodeBF565(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown);
1315 for(unsigned int yPos = 0; yPos < height; yPos++)
1319 // the data in the file is top down, and we store the data top down
1320 pixelsIterator = pixels + (yPos * rowStride);
1324 // the data in the file is bottom up, and we store the data top down
1325 pixelsIterator = pixels + (((height - 1) - yPos) * rowStride);
1328 if(fread(pixelsIterator, 1, rowStride, fp) != rowStride)
1330 DALI_LOG_ERROR("Error reading the BMP image\n");
1334 // If 24 bit mode then swap Blue and Red pixels
1335 // BGR888 doesn't seem to be supported by dali-core
1336 if(infoHeader.bitsPerPixel == 24)
1338 for(unsigned int i = 0; i < rowStride; i += 3)
1340 unsigned char temp = pixelsIterator[i];
1341 pixelsIterator[i] = pixelsIterator[i + 2];
1342 pixelsIterator[i + 2] = temp;
1348 if(fseek(fp, padding, SEEK_CUR)) // move past the padding.
1350 DALI_LOG_ERROR("Error moving past BMP padding\n");
1354 decodeResult = true;
1368 } // namespace TizenPlatform