2 * Copyright (c) 2022 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(DALI_UNLIKELY(fread(&header, 1, readLength, fp) != readLength))
93 bool LoadBmpHeader(FILE* fp, unsigned int& width, unsigned int& height, BmpFileHeader& fileHeader, BmpInfoHeader& infoHeader)
95 if(DALI_UNLIKELY(!ReadHeader(fp, fileHeader)))
97 DALI_LOG_ERROR("File header read failed\n");
101 if(DALI_UNLIKELY(!ReadHeader(fp, infoHeader)))
103 DALI_LOG_ERROR("Info header read failed\n");
107 width = infoHeader.width;
108 height = abs(infoHeader.height);
110 if(DALI_UNLIKELY(infoHeader.width == 0))
112 DALI_LOG_ERROR("Invalid header size\n");
120 * function to decode format BI_RGB & bpp = 24 & bmp version5.
121 * @param[in] fp The file to read from
122 * @param[out] pixels The pointer that we want to store bmp data in
123 * @param[in] width bmp width
124 * @param[in] height bmp height
125 * @param[in] offset offset from bmp header to bmp image data
126 * @param[in] topDown indicate image data is read from bottom or from top
127 * @param[in] padding padded to a u_int32 boundary for each line
128 * @return true, if decode successful, false otherwise
130 bool DecodeRGB24V5(FILE* fp,
131 unsigned char* pixels,
136 unsigned int rowStride,
137 unsigned int padding)
139 if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
141 DALI_LOG_ERROR("Error decoding BMP_RGB24V5 format\n");
144 if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
146 DALI_LOG_ERROR("Error seeking BMP_RGB24V5 data\n");
150 for(std::uint32_t yPos = 0; yPos < height; ++yPos)
152 std::uint8_t* pixelsPtr = NULL;
155 pixelsPtr = pixels + (yPos * rowStride);
159 pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
161 if(DALI_UNLIKELY(fread(pixelsPtr, 1, rowStride, fp) != rowStride))
163 DALI_LOG_ERROR("Error reading the BMP image\n");
166 for(std::uint32_t i = 0; i < rowStride; i += 3)
168 std::uint8_t temp = pixelsPtr[i];
169 pixelsPtr[i] = pixelsPtr[i + 2];
170 pixelsPtr[i + 2] = temp;
175 // move past the padding.
176 if(DALI_UNLIKELY(fseek(fp, padding, SEEK_CUR)))
178 DALI_LOG_ERROR("Error moving past BMP_RGB24V5 padding\n");
186 * function to decode format BI_BITFIELDS & bpp = 32 & bmp version4.
187 * @param[in] fp The file to read from
188 * @param[out] pixels The pointer that we want to store bmp data in
189 * @param[in] width bmp width
190 * @param[in] height bmp height
191 * @param[in] offset offset from bmp header to bmp image data
192 * @param[in] topDown indicate image data is read from bottom or from top
193 * @param[in] rowStride bits span for each line
194 * @param[in] padding padded to a u_int32 boundary for each line
195 * @return true, if decode successful, false otherwise
197 bool DecodeBF32V4(FILE* fp,
198 unsigned char* pixels,
203 unsigned int rowStride,
204 unsigned int padding)
206 if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
208 DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32V4 format\n");
211 if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
213 DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32V4 data\n");
217 for(std::uint32_t yPos = 0; yPos < height; ++yPos)
219 std::uint8_t* pixelsPtr = NULL;
222 pixelsPtr = pixels + (yPos * rowStride);
226 pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
228 if(DALI_UNLIKELY(fread(pixelsPtr, 1, rowStride, fp) != rowStride))
230 DALI_LOG_ERROR("Error reading the BMP image\n");
233 for(std::uint32_t i = 0; i < rowStride; i += 4)
235 std::uint8_t temp = pixelsPtr[i];
236 pixelsPtr[i] = pixelsPtr[i + 2];
237 pixelsPtr[i + 2] = temp;
241 // move past the padding.
242 if(DALI_UNLIKELY(fseek(fp, padding, SEEK_CUR)))
244 DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32V4 padding\n");
252 * function to decode format BI_BITFIELDS & bpp = 32
253 * @param[in] fp The file to read from
254 * @param[out] pixels The pointer that we want to store bmp data in
255 * @param[in] width bmp width
256 * @param[in] height bmp height
257 * @param[in] offset offset from bmp header to bmp image data
258 * @param[in] topDown indicate image data is read from bottom or from top
259 * @param[in] rowStride bits span for each line
260 * @param[in] padding padded to a u_int32 boundary for each line
261 * @return true, if decode successful, false otherwise
263 bool DecodeBF32(FILE* fp,
264 unsigned char* pixels,
269 unsigned int rowStride,
270 unsigned int padding)
272 if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
274 DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32 format\n");
277 if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
279 DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32 data\n");
283 for(std::uint32_t yPos = 0; yPos < height; ++yPos)
285 std::uint8_t* pixelsPtr;
288 // the data in the file is top down, and we store the data top down
289 pixelsPtr = pixels + (yPos * rowStride);
293 // the data in the file is bottom up, and we store the data top down
294 pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
297 if(DALI_UNLIKELY(fread(pixelsPtr, 1, rowStride, fp) != rowStride))
299 DALI_LOG_ERROR("Error reading the BMP image\n");
302 for(std::uint32_t i = 0; i < rowStride; i += 4)
304 std::uint8_t temp = pixelsPtr[i];
305 pixelsPtr[i] = pixelsPtr[i + 2];
306 pixelsPtr[i + 2] = temp;
311 // move past the padding.
312 if(DALI_UNLIKELY(fseek(fp, padding, SEEK_CUR)))
314 DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32 padding\n");
322 * function to decode format BI_BITFIELDS & bpp = 16 & R:G:B = 5:6:5
323 * @param[in] fp The file to read from
324 * @param[out] pixels The pointer that we want to store bmp data in
325 * @param[in] width bmp width
326 * @param[in] height bmp height
327 * @param[in] offset offset from bmp header to bmp image data
328 * @param[in] topDown indicate image data is read from bottom or from top
329 * @return true, if decode successful, false otherwise
331 bool DecodeBF565(FILE* fp,
332 unsigned char* pixels,
338 if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
340 DALI_LOG_ERROR("Error decoding RGB565 format\n");
343 if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
345 DALI_LOG_ERROR("Error seeking RGB565 data\n");
349 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
350 std::uint32_t rowStride = width * 2;
352 for(std::uint32_t i = 0; i < height; ++i)
354 std::uint8_t* pixelsPtr = NULL;
357 // the data in the file is top down, and we store the data top down
358 pixelsPtr = pixels + (i * rowStride);
362 // the data in the file is bottom up, and we store the data top down
363 pixelsPtr = pixels + (((height - 1) - i) * rowStride);
365 if(DALI_UNLIKELY(fread(pixelsPtr, 1, rowStride, fp) != rowStride))
375 * function to decode format BI_BITFIELDS & bpp = 16 & R:G:B = 5:5:5
376 * @param[in] fp The file to read from
377 * @param[out] pixels The pointer that we want to store bmp data in
378 * @param[in] width bmp width
379 * @param[in] height bmp height
380 * @param[in] offset offset from bmp header to bmp image data
381 * @param[in] topDown indicate image data is read from bottom or from top
382 * @return true, if decode successful, false otherwise
384 bool DecodeBF555(FILE* fp,
385 unsigned char* pixels,
391 if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
393 DALI_LOG_ERROR("Error decoding BMP_BITFIELDS555 format\n");
397 if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
399 DALI_LOG_ERROR("Error seeking BMP_BITFIELDS555 data\n");
403 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
405 std::vector<std::uint8_t> raw(width * height * 2);
406 std::uint32_t rawStride = width * 2;
407 std::uint32_t rowStride = width * 3;
409 std::uint8_t* rawPtr = NULL;
410 for(std::uint32_t j = 0; j < height; ++j)
412 rawPtr = &raw[0] + (j * rawStride);
413 if(DALI_UNLIKELY(fread(rawPtr, 1, rawStride, fp) != rawStride))
419 for(std::uint32_t yPos = 0; yPos < height; ++yPos)
421 std::uint8_t* pixelsPtr = NULL;
424 // the data in the file is top down, and we store the data top down
425 pixelsPtr = pixels + (yPos * rowStride);
429 // the data in the file is bottom up, and we store the data top down
430 pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
433 for(std::uint32_t k = 0; k < width; ++k)
435 std::uint32_t index = yPos * rawStride + 2 * k;
436 pixelsPtr[3 * k] = ((raw[index + 1] >> 2) & 0x1F) * 0xFF / 0x1F;
437 pixelsPtr[3 * k + 1] = (((raw[index + 1] & 0x03) << 3) | (raw[index] >> 5)) * 0xFF / 0x1F;
438 pixelsPtr[3 * k + 2] = (raw[index] & 0x1F) * 0xFF / 0x1F;
445 * function to decode format BI_RGB & bpp = 16 & R:G:B = 5:5:5
446 * @param[in] fp The file to read from
447 * @param[out] pixels The pointer that we want to store bmp data in
448 * @param[in] width bmp width
449 * @param[in] height bmp height
450 * @param[in] offset offset from bmp header to bmp image data
451 * @param[in] topDown indicate image data is read from bottom or from top
452 * @return true, if decode successful, false otherwise
454 bool DecodeRGB555(FILE* fp,
455 unsigned char* pixels,
461 if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
463 DALI_LOG_ERROR("Error decoding BMP_RGB555 format\n");
466 if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
468 DALI_LOG_ERROR("Error seeking BMP_RGB555 data\n");
472 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
473 std::vector<std::uint8_t> raw(width * height * 2);
474 std::uint32_t rawStride = width * 2;
475 std::uint32_t rowStride = width * 3;
477 std::uint8_t* rawPtr = NULL;
478 for(std::uint32_t j = 0; j < height; ++j)
480 rawPtr = &raw[0] + (j * rawStride);
481 if(DALI_UNLIKELY(fread(rawPtr, 1, rawStride, fp) != rawStride))
486 for(std::uint32_t i = 0; i < height; ++i)
488 std::uint8_t* pixelsPtr = NULL;
491 // the data in the file is top down, and we store the data top down
492 pixelsPtr = pixels + (i * rowStride);
496 // the data in the file is bottom up, and we store the data top down
497 pixelsPtr = pixels + (((height - 1) - i) * rowStride);
499 for(std::uint32_t k = 0; k < width; ++k)
501 std::uint32_t index = i * rawStride + 2 * k;
502 pixelsPtr[3 * k] = ((raw[index + 1] >> 2) & 0x1F) * 0xFF / 0x1F;
503 pixelsPtr[3 * k + 1] = (((raw[index + 1] & 0x03) << 3) | (raw[index] >> 5)) * 0xFF / 0x1F;
504 pixelsPtr[3 * k + 2] = (raw[index] & 0x1F) * 0xFF / 0x1F;
511 * function to decode format BI_RGB & bpp = 1
512 * @param[in] fp The file to read from
513 * @param[out] pixels The pointer that we want to store bmp data in
514 * @param[in] width bmp width
515 * @param[in] height bmp height
516 * @param[in] offset offset from bmp header to bmp palette data
517 * @param[in] topDown indicate image data is read from bottom or from top
518 * @return true, if decode successful, false otherwise
520 bool DecodeRGB1(FILE* fp,
521 unsigned char* pixels,
527 if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
529 DALI_LOG_ERROR("Error decoding BMP_RGB1 format\n");
532 if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
534 DALI_LOG_ERROR("Error seeking BMP_RGB1 data\n");
538 std::uint8_t colorTable[8] = {0};
540 std::uint32_t fillw = ((width & 63) != 0) ? width + 64 - (width & 63) : width;
541 std::vector<std::uint8_t> colorIndex(fillw * height);
542 std::uint32_t rowStride = fillw * 3; // RGB
544 if(DALI_UNLIKELY(fread(colorTable, 1, 8, fp) != 8))
549 for(std::uint32_t i = 0; i < fillw * height; i += 8)
551 if(DALI_UNLIKELY(fread(&cmd, 1, 1, fp) != 1))
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);
566 for(std::uint32_t index = 0; index < height; ++index)
568 std::uint8_t* pixelsPtr = NULL;
571 // the data in the file is top down, and we store the data top down
572 pixelsPtr = pixels + (index * rowStride);
576 // the data in the file is bottom up, and we store the data top down
577 pixelsPtr = pixels + (((height - 1) - index) * rowStride);
579 for(std::uint32_t j = 0; j < fillw; ++j)
581 std::uint32_t ctIndex = 0;
582 if((fillw * index + j) < (fillw * height))
584 ctIndex = colorIndex[fillw * index + j];
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))
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];
603 * function to decode format BI_RGB & bpp = 4
604 * @param[in] fp The file to read from
605 * @param[out] pixels The pointer that we want to store bmp data in
606 * @param[in] width bmp width
607 * @param[in] height bmp height
608 * @param[in] offset offset from bmp header to bmp palette data
609 * @param[in] topDown indicate image data is read from bottom or from top
610 * @return true, if decode successful, false otherwise
612 bool DecodeRGB4(FILE* fp,
613 unsigned char* pixels,
619 if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
621 DALI_LOG_ERROR("Error decoding BMP_RGB4 format\n");
624 if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
626 DALI_LOG_ERROR("Error seeking BMP_RGB4 data\n");
630 std::uint8_t colorTable[64];
632 std::uint32_t fillw = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
633 std::vector<std::uint8_t> colorIndex(fillw * height);
634 std::uint32_t rowStride = fillw * 3;
636 if(DALI_UNLIKELY(fread(colorTable, 1, 64, fp) != 64))
641 for(std::uint32_t i = 0; i < fillw * height; i += 2)
643 if(DALI_UNLIKELY(fread(&cmd, 1, 1, fp) != 1))
648 colorIndex[i] = cmd >> 4;
649 colorIndex[i + 1] = cmd & (0x0F);
651 std::uint32_t ctIndex = 0;
653 for(std::uint32_t index = 0; index < height; ++index)
655 std::uint8_t* pixelsPtr = NULL;
658 // the data in the file is top down, and we store the data top down
659 pixelsPtr = pixels + (index * rowStride);
663 // the data in the file is bottom up, and we store the data top down
664 pixelsPtr = pixels + (((height - 1) - index) * rowStride);
666 for(std::uint32_t j = 0; j < fillw; ++j)
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];
679 * function to decode format BI_RGB & bpp = 8
680 * @param[in] fp The file to read from
681 * @param[out] pixels The pointer that we want to store bmp data in
682 * @param[in] width bmp width
683 * @param[in] height bmp height
684 * @param[in] offset offset from bmp header to bmp palette data
685 * @param[in] topDown indicate image data is read from bottom or from top
686 * @return true, if decode successful, false otherwise
688 bool DecodeRGB8(FILE* fp,
689 unsigned char* pixels,
695 if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
697 DALI_LOG_ERROR("Error decoding BMP_RGB8 format\n");
700 if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
702 DALI_LOG_ERROR("Error seeking BMP_RGB8 data\n");
706 std::vector<std::uint8_t> colorTable(1024);
707 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
708 std::vector<std::uint8_t> colorIndex(width * height);
709 std::uint32_t rowStride = width * 3; //RGB8->RGB24
711 if(DALI_UNLIKELY(fread(&colorTable[0], 1, 1024, fp) != 1024))
715 if(DALI_UNLIKELY(fread(&colorIndex[0], 1, width * height, fp) != width * height))
719 std::uint8_t ctIndex = 0;
720 for(std::uint32_t index = 0; index < height; ++index)
722 std::uint8_t* pixelsPtr = NULL;
725 // the data in the file is top down, and we store the data top down
726 pixelsPtr = pixels + (index * rowStride);
730 // the data in the file is bottom up, and we store the data top down
731 pixelsPtr = pixels + (((height - 1) - index) * rowStride);
733 for(std::uint32_t j = 0; j < width; ++j)
735 ctIndex = colorIndex[width * index + j];
736 pixelsPtr[3 * j] = colorTable[4 * ctIndex + 2];
737 pixelsPtr[(3 * j + 1)] = colorTable[4 * ctIndex + 1];
738 pixelsPtr[(3 * j + 2)] = colorTable[4 * ctIndex];
745 * function to decode format BI_RLE4 & bpp = 4
746 * @param[in] fp The file to read from
747 * @param[out] pixels The pointer that we want to store bmp data in
748 * @param[in] width bmp width
749 * @param[in] height bmp height
750 * @param[in] offset offset from bmp header to bmp palette data
751 * @param[in] topDown indicate image data is read from bottom or from top
752 * @return true, if decode successful, false otherwise
754 bool DecodeRLE4(FILE* fp,
755 unsigned char* pixels,
761 if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
763 DALI_LOG_ERROR("Error decoding BMP_RLE4 format\n");
766 std::uint8_t* pixelsPtr = pixels;
767 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
769 std::uint32_t cmdStride = 2;
770 std::uint8_t colorTable[64];
771 std::vector<std::uint8_t> colorIndex(width * height >> 1);
772 std::vector<std::uint8_t> run;
775 std::uint32_t dx = 0;
776 std::uint32_t dy = 0;
777 width += (width & 1);
782 if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
784 DALI_LOG_ERROR("Error seeking BMP_RLE4 data\n");
788 if(DALI_UNLIKELY(fread(colorTable, 1, 64, fp) != 64))
793 while((x >> 1) + y * width < width * height)
799 if(DALI_UNLIKELY(fread(cmd, 1, cmdStride, fp) != cmdStride))
803 if(cmd[0] == 0) // ESCAPE
807 case 1: //end of bitmap
810 case 0: // end of line
815 if(DALI_UNLIKELY(fread(cmd, 1, cmdStride, fp) != cmdStride))
817 DALI_LOG_ERROR("Error reading the BMP image\n");
820 dx = cmd[0] & (0xFF);
821 dy = cmd[1] & (0xFF);
826 // decode a literal run
827 std::uint32_t length = cmd[1] & (0xFF);
828 //size of run, which is word aligned
829 std::uint32_t bytesize = length;
830 bytesize += (bytesize & 1);
832 bytesize += (bytesize & 1);
833 run.resize(bytesize);
834 if(DALI_UNLIKELY(fread(&run[0], 1, bytesize, fp) != bytesize))
836 DALI_LOG_ERROR("Error reading the BMP image\n");
841 length += (length & 1);
843 for(std::uint32_t i = 0; i < length; ++i)
845 colorIndex[(x >> 1) + width * (height - y - 1) + i] = run[i];
850 for(std::uint32_t i = 0; i < length; ++i)
852 if((i & 1) == 0) //copy high to low
854 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((run[i >> 1] & 0xF0) >> 4);
856 else //copy low to high
858 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((run[i >> 1] & 0x0F) << 4);
862 x += cmd[1] & (0xFF);
868 std::uint32_t length = cmd[0] & (0xFF);
871 length += (length & 1);
873 for(std::uint32_t i = 0; i < length; ++i)
875 colorIndex[(height - y - 1) * width + i + (x >> 1)] = cmd[1];
880 for(std::uint32_t i = 0; i < length; ++i)
884 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((cmd[1] & 0xF0) >> 4);
888 colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((cmd[1] & 0x0F) << 4);
892 x += cmd[0] & (0xFF);
896 std::uint32_t ctIndexHigh = 0;
897 std::uint32_t ctIndexLow = 0;
898 for(std::uint32_t index = 0; index < (width * height); ++index)
900 ctIndexHigh = colorIndex[index] >> 4;
901 ctIndexLow = colorIndex[index] & (0x0F);
902 pixelsPtr[6 * index] = colorTable[4 * ctIndexHigh + 2];
903 pixelsPtr[6 * index + 1] = colorTable[4 * ctIndexHigh + 1];
904 pixelsPtr[6 * index + 2] = colorTable[4 * ctIndexHigh];
905 pixelsPtr[6 * index + 3] = colorTable[4 * ctIndexLow + 2];
906 pixelsPtr[6 * index + 4] = colorTable[4 * ctIndexLow + 1];
907 pixelsPtr[6 * index + 5] = colorTable[4 * ctIndexLow];
913 * function to decode format BI_RLE8 & bpp = 8
914 * @param[in] fp The file to read from
915 * @param[out] pixels The pointer that we want to store bmp data in
916 * @param[in] width bmp width
917 * @param[in] height bmp height
918 * @param[in] offset offset from bmp header to bmp palette data
919 * @param[in] topDown indicate image data is read from bottom or from top
920 * @return true, if decode successful, false otherwise
922 bool DecodeRLE8(FILE* fp,
923 unsigned char* pixels,
929 if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
931 DALI_LOG_ERROR("Error decoding BMP_RLE8 format\n");
934 std::uint8_t* pixelsPtr = pixels;
937 std::uint32_t cmdStride = 2;
939 width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
940 std::vector<std::uint8_t> colorTable(1024);
942 std::vector<std::uint8_t> colorIndex(width * height);
944 if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
946 DALI_LOG_ERROR("Error seeking BMP_RLE8 data\n");
950 if(DALI_UNLIKELY(fread(&colorTable[0], 1, 1024, fp) != 1024))
955 std::uint32_t dx = 0;
956 std::uint32_t dy = 0;
958 std::uint32_t length = 0;
959 std::uint32_t copylength = 0;
960 std::vector<std::uint8_t> run;
961 while((x + y * width) < width * height)
963 if(DALI_UNLIKELY(finish))
967 if(DALI_UNLIKELY(fread(cmd, 1, cmdStride, fp) != cmdStride))
972 if(cmd[0] == 0) //ESCAPE
976 case 1: // end of bitmap
979 case 0: // end of line
984 if(DALI_UNLIKELY(fread(cmd, 1, cmdStride, fp) != cmdStride))
986 DALI_LOG_ERROR("Error reading the BMP image\n");
989 dx = cmd[0] & (0xFF);
990 dy = cmd[1] & (0xFF);
995 //decode a literal run
996 length = cmd[1] & (0xFF);
998 //absolute mode must be word-aligned
999 length += (length & 1);
1001 if(DALI_UNLIKELY(fread(&run[0], 1, length, fp) != length))
1003 DALI_LOG_ERROR("Error reading the BMP image\n");
1007 for(std::uint32_t i = 0; i < length; ++i)
1009 colorIndex[x + width * (height - y - 1) + i] = run[i];
1014 } // end if cmd[0] ==
1017 length = cmd[0] & (0xFF);
1018 for(std::uint32_t i = 0; i < length; ++i)
1020 colorIndex[(height - y - 1) * width + x] = cmd[1];
1025 std::uint32_t ctIndex = 0;
1026 for(std::uint32_t index = 0; index < width * height; ++index)
1028 ctIndex = colorIndex[index];
1029 pixelsPtr[3 * index] = colorTable[4 * ctIndex + 2];
1030 pixelsPtr[3 * index + 1] = colorTable[4 * ctIndex + 1];
1031 pixelsPtr[3 * index + 2] = colorTable[4 * ctIndex];
1036 } // unnamed namespace
1038 bool LoadBmpHeader(const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height)
1040 BmpFileHeader fileHeader;
1041 BmpInfoHeader infoHeader;
1043 bool ret = LoadBmpHeader(input.file, width, height, fileHeader, infoHeader);
1048 bool LoadBitmapFromBmp(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap)
1050 //DALI_ASSERT_DEBUG( bitmap.GetPackedPixelsProfile() != 0 && "Need a packed pixel bitmap to load into." );
1051 FILE* const fp = input.file;
1052 if(DALI_UNLIKELY(fp == NULL))
1054 DALI_LOG_ERROR("Error loading bitmap\n");
1057 BmpFormat customizedFormat = BMP_NOTEXIST;
1058 BmpFileHeader fileHeader;
1059 BmpInfoHeader infoHeader;
1061 // Load the header info
1062 unsigned int width, height;
1064 if(DALI_UNLIKELY(!LoadBmpHeader(fp, width, height, fileHeader, infoHeader)))
1069 Pixel::Format pixelFormat = Pixel::RGB888;
1070 switch(infoHeader.compression)
1074 switch(infoHeader.bitsPerPixel)
1078 pixelFormat = Pixel::RGBA8888;
1084 if(fileHeader.offset == FileHeaderOffsetOfRGB24V5) //0x8A
1086 customizedFormat = BMP_RGB24V5;
1090 pixelFormat = Pixel::RGB888;
1097 customizedFormat = BMP_RGB555;
1103 customizedFormat = BMP_RGB8;
1109 customizedFormat = BMP_RGB4;
1115 customizedFormat = BMP_RGB1;
1121 DALI_LOG_ERROR("%d bits per pixel not supported for BMP files\n", infoHeader.bitsPerPixel);
1129 if(infoHeader.bitsPerPixel == 8)
1131 customizedFormat = BMP_RLE8;
1137 if(infoHeader.bitsPerPixel == 4)
1139 customizedFormat = BMP_RLE4;
1143 case 3: // // BI_BITFIELDS
1145 if(infoHeader.bitsPerPixel == 16)
1147 if(DALI_UNLIKELY(fseek(fp, 14 + infoHeader.infoHeaderSize + 1, SEEK_SET)))
1153 if(DALI_UNLIKELY(fread(&mask, 1, 1, fp) != 1))
1158 if((mask & 0x80) == MaskForBFRGB565) // mask is 0xF8
1160 pixelFormat = Pixel::RGB565;
1162 else if((mask & 0x80) == 0) // mask is 0x 7C
1164 customizedFormat = BMP_BITFIELDS555;
1171 else if(infoHeader.bitsPerPixel == 32)
1173 if(fileHeader.offset == FileHeaderOffsetOfBF32V4) // 0x7A
1175 customizedFormat = BMP_BITFIELDS32V4;
1179 customizedFormat = BMP_BITFIELDS32;
1186 DALI_LOG_ERROR("Compression not supported for BMP files\n");
1191 bool topDown = false;
1193 // if height is negative, bitmap data is top down
1194 if(infoHeader.height < 0)
1196 infoHeader.height = abs(infoHeader.height);
1197 height = infoHeader.height;
1201 unsigned int rowStride = infoHeader.width * (infoHeader.bitsPerPixel >> 3);
1203 // bitmaps row stride is padded to 4 bytes
1204 unsigned int padding = (rowStride % 4);
1207 padding = 4 - padding;
1210 int imageW = infoHeader.width;
1211 int pixelBufferW = infoHeader.width;
1212 int pixelBufferH = infoHeader.height;
1213 auto newPixelFormat = Pixel::Format::INVALID;
1215 switch(customizedFormat)
1222 case BMP_BITFIELDS555:
1224 pixelBufferW = ((imageW & 3) != 0) ? imageW + 4 - (imageW & 3) : imageW;
1225 pixelBufferH = abs(infoHeader.height);
1226 newPixelFormat = Pixel::RGB888;
1231 pixelBufferW = ((imageW & 63) != 0) ? imageW + 64 - (imageW & 63) : imageW;
1232 pixelBufferH = abs(infoHeader.height);
1233 newPixelFormat = Pixel::RGB888;
1236 case BMP_BITFIELDS32:
1237 case BMP_BITFIELDS32V4:
1239 pixelBufferH = abs(infoHeader.height);
1240 newPixelFormat = Pixel::RGBA8888;
1245 newPixelFormat = Pixel::RGB888;
1250 if(pixelFormat == Pixel::RGB565)
1252 pixelBufferW = ((imageW & 3) != 0) ? imageW + 4 - (imageW & 3) : imageW;
1253 pixelBufferH = abs(infoHeader.height);
1254 newPixelFormat = Pixel::RGB565;
1258 pixelBufferW = infoHeader.width;
1259 pixelBufferH = infoHeader.height;
1260 newPixelFormat = pixelFormat;
1266 bitmap = Dali::Devel::PixelBuffer::New(pixelBufferW, pixelBufferH, newPixelFormat);
1267 auto pixels = bitmap.GetBuffer();
1269 // Read the raw bitmap data
1270 decltype(pixels) pixelsIterator = nullptr;
1272 bool decodeResult(false);
1273 switch(customizedFormat)
1277 decodeResult = DecodeRGB1(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1282 decodeResult = DecodeRGB4(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1287 decodeResult = DecodeRLE4(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1290 case BMP_BITFIELDS32:
1292 decodeResult = DecodeBF32(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
1295 case BMP_BITFIELDS555:
1297 decodeResult = DecodeBF555(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown);
1302 decodeResult = DecodeRGB555(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown);
1307 decodeResult = DecodeRGB8(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1312 decodeResult = DecodeRLE8(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
1317 decodeResult = DecodeRGB24V5(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
1320 case BMP_BITFIELDS32V4:
1322 decodeResult = DecodeBF32V4(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
1327 if(pixelFormat == Pixel::RGB565)
1329 decodeResult = DecodeBF565(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown);
1333 for(unsigned int yPos = 0; yPos < height; yPos++)
1337 // the data in the file is top down, and we store the data top down
1338 pixelsIterator = pixels + (yPos * rowStride);
1342 // the data in the file is bottom up, and we store the data top down
1343 pixelsIterator = pixels + (((height - 1) - yPos) * rowStride);
1346 if(DALI_UNLIKELY(fread(pixelsIterator, 1, rowStride, fp) != rowStride))
1348 DALI_LOG_ERROR("Error reading the BMP image\n");
1352 // If 32 bit mode then swap Blue and Red pixels. And Alpha pixels must be ignored.
1353 // Reference : https://users.cs.fiu.edu/~czhang/teaching/cop4225/project_files/bitmap_format.htm
1354 // ... if the compression field of the bitmap is set to bi_rgb, ... the high byte in each dword is not used.
1355 // RGB8888 format doesn't seem to be supported by graphics-api
1356 if(infoHeader.bitsPerPixel == 32)
1358 for(uint32_t i = 0; i < rowStride; i += 4)
1360 uint8_t temp = pixelsIterator[i];
1361 pixelsIterator[i] = pixelsIterator[i + 2];
1362 pixelsIterator[i + 2] = temp;
1363 pixelsIterator[i + 3] = 255u;
1367 // If 24 bit mode then swap Blue and Red pixels
1368 // BGR888 doesn't seem to be supported by dali-core
1369 if(infoHeader.bitsPerPixel == 24)
1371 for(uint32_t i = 0; i < rowStride; i += 3)
1373 uint8_t temp = pixelsIterator[i];
1374 pixelsIterator[i] = pixelsIterator[i + 2];
1375 pixelsIterator[i + 2] = temp;
1381 if(DALI_UNLIKELY(fseek(fp, padding, SEEK_CUR))) // move past the padding.
1383 DALI_LOG_ERROR("Error moving past BMP padding\n");
1387 decodeResult = true;
1393 if(DALI_UNLIKELY(!decodeResult))
1395 DALI_LOG_ERROR("Decoding failed\n");
1402 } // namespace TizenPlatform