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.
19 #include <dali/internal/imaging/common/loader-wbmp.h>
27 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
28 #include <dali/integration-api/debug.h>
32 namespace TizenPlatform
36 #if defined(DEBUG_ENABLED)
37 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_LOADER_WBMP");
40 // TODO : We need to determine it in dali-common.h or something else. Currently, we set this value in code level.
41 #define DALI_BYTE_ORDER_BIG_ENDIAN 0
43 #define IMG_MAX_SIZE 65536
45 #define IMG_TOO_BIG(w, h) \
46 ((((unsigned long long)w) * ((unsigned long long)h)) >= \
47 ((1ULL << (29)) - 2048))
49 //extract multiple bytes integer , and saved in *data
50 int extractMultiByteInteger(unsigned int* data, const std::uint8_t* const& map, size_t length, size_t* position)
52 // the header field contains an image type indentifier of multi-byte length(TypeField), an octet of general header info(FixHeaderField)
53 //, a multi-byte width field(Width) and a multi-byte height field(Height) and so on.
54 // The actual organisation of the image data depends on the image type
55 // for Ext Headers flag (7th bit), 1 = More will follow, 0 = Last octet
56 // so in the for loop, if(buf & 0x80 == 0), loop will be exited
57 int targetMultiByteInteger = 0, readBufCount;
60 for(readBufCount = 0;;)
62 // readBufCount means the count that fetched data from map
63 // extractMultiByteInteger() is to fetch wbmp type , width, and height
64 // for wbmp type, when readBufCount == 1, buf = 0x00, it will exit the loop
65 // for width, it have 4 bytes, so when readBufCount == 4, it must exit the loop
66 // for general width and height, if(buf & 0x80) == 0, then the next byte does not need to fetch again
67 // first step, readBufCount = 1 , read int(4 bytes) to buf, if buf & 0x80 !=0, the buf need to continue to fetch
68 // second step, readBufCount = 2, read next( 4 bytes) to buf, if buf & 0x80 == 0, then assigned the buf to target
69 if(DALI_UNLIKELY((readBufCount++) == 4))
73 if(DALI_UNLIKELY(*position > length))
77 buf = map[(*position)++];
78 targetMultiByteInteger = (targetMultiByteInteger << 7) | (buf & 0x7f);
82 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "position: %d, readBufCount: %d\n", *position, readBufCount);
86 *data = targetMultiByteInteger;
90 // Calculate 4bit integer into 4byte integer
91 constexpr std::uint32_t Calculate4BitTo4Byte(const std::uint8_t& input)
93 std::uint32_t output = 0;
94 #if DALI_BYTE_ORDER_BIG_ENDIAN
95 output |= static_cast<std::uint32_t>(input & 0x08) << 21;
96 output |= static_cast<std::uint32_t>(input & 0x04) << 14;
97 output |= static_cast<std::uint32_t>(input & 0x02) << 7;
98 output |= static_cast<std::uint32_t>(input & 0x01);
100 output |= static_cast<std::uint32_t>(input & 0x08) >> 3;
101 output |= static_cast<std::uint32_t>(input & 0x04) << 6;
102 output |= static_cast<std::uint32_t>(input & 0x02) << 15;
103 output |= static_cast<std::uint32_t>(input & 0x01) << 24;
105 return output * 0xff;
109 * @brief Calculation result bit-->byte table in compile.
110 * Required memory = 16 * 4byte = 64byte
113 constexpr std::uint32_t cachedCalculation4BitTo4ByteTable[16] = {
114 Calculate4BitTo4Byte(0x00), Calculate4BitTo4Byte(0x01), Calculate4BitTo4Byte(0x02), Calculate4BitTo4Byte(0x03),
115 Calculate4BitTo4Byte(0x04), Calculate4BitTo4Byte(0x05), Calculate4BitTo4Byte(0x06), Calculate4BitTo4Byte(0x07),
116 Calculate4BitTo4Byte(0x08), Calculate4BitTo4Byte(0x09), Calculate4BitTo4Byte(0x0a), Calculate4BitTo4Byte(0x0b),
117 Calculate4BitTo4Byte(0x0c), Calculate4BitTo4Byte(0x0d), Calculate4BitTo4Byte(0x0e), Calculate4BitTo4Byte(0x0f)};
119 } // end unnamed namespace
121 bool LoadBitmapFromWbmp(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap)
123 FILE* const fp = input.file;
124 if(DALI_UNLIKELY(fp == NULL))
126 DALI_LOG_ERROR("Error loading bitmap\n");
129 Dali::Vector<unsigned char> map;
134 std::uint32_t lineByteLength;
136 if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END)))
138 DALI_LOG_ERROR("Error seeking WBMP data\n");
141 long positionIndicator = ftell(fp);
143 unsigned int fsize(0u);
144 if(positionIndicator > -1L)
146 fsize = static_cast<unsigned int>(positionIndicator);
149 if(DALI_UNLIKELY(0u == fsize))
151 DALI_LOG_ERROR("Error: filesize is 0!\n");
155 if(DALI_UNLIKELY(fseek(fp, 0, SEEK_SET)))
157 DALI_LOG_ERROR("Error seeking WBMP data\n");
160 if(DALI_UNLIKELY(fsize <= 4))
162 DALI_LOG_ERROR("Error: WBMP Raw Data Not Found!\n");
165 if(DALI_UNLIKELY(fsize > 4096 * 4096 * 4))
167 DALI_LOG_ERROR("Error: WBMP size is too large!\n");
170 map.ResizeUninitialized(fsize);
172 if(DALI_UNLIKELY(fread(&map[0], 1, fsize, fp) != fsize))
174 DALI_LOG_WARNING("image file read opeation error!\n");
178 const std::uint8_t* const inputBufferPtr = &map[0];
180 if(DALI_UNLIKELY(extractMultiByteInteger(&type, inputBufferPtr, fsize, &position) < 0))
185 position++; /* skipping one byte */
187 if(DALI_UNLIKELY(extractMultiByteInteger(&w, inputBufferPtr, fsize, &position) < 0))
191 if(DALI_UNLIKELY(extractMultiByteInteger(&h, inputBufferPtr, fsize, &position) < 0))
195 if(DALI_UNLIKELY(type != 0))
197 DALI_LOG_ERROR("Unknown Format!\n");
201 if(DALI_UNLIKELY((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE)))
206 lineByteLength = (w + 7) >> 3;
207 // fsize was wrong! Load failed.
208 if(DALI_UNLIKELY(position + h * lineByteLength > fsize))
210 DALI_LOG_ERROR("Pixel infomation is bigger than file size! (%u + %u * %u > %u)\n", static_cast<std::uint32_t>(position), h, lineByteLength, fsize);
214 // w >= 1 and h >= 1. So we can assume that outputPixels is not null.
215 auto outputPixels = (bitmap = Dali::Devel::PixelBuffer::New(w, h, Pixel::L8)).GetBuffer();
219 * std::uint8_t* line = NULL;
220 * std::uint32_t cur = 0, x, y;
221 * for(y = 0; y < h; y++)
223 * line = &map[0] + position;
224 * position += lineByteLength;
225 * for(x = 0; x < w; x++)
228 * int offset = 1 << (0x07 - (x & 0x07));
229 * if(line[idx] & offset)
231 * outputPixels[cur] = 0xff; //0xffffffff;
235 * outputPixels[cur] = 0x00; //0xff000000;
243 const std::uint8_t* inputPixels = inputBufferPtr + position;
244 const std::uint32_t lineBitLengthWithoutPadding = (w >> 3) << 3;
246 for(std::uint32_t y = 0; y < h; ++y)
249 if((reinterpret_cast<std::ptrdiff_t>(outputPixels) & (sizeof(std::uint32_t) - 1)) == 0)
251 for(; x < lineBitLengthWithoutPadding; x += 8)
253 // memset whole 8 bits
254 // outputPixels filled 4 bytes in one operation.
255 // cachedCalculation4BitTo4ByteTable calculated in compile-time.
256 *(reinterpret_cast<std::uint32_t*>(outputPixels + 0)) = cachedCalculation4BitTo4ByteTable[((*inputPixels) >> 4) & 0x0f];
257 *(reinterpret_cast<std::uint32_t*>(outputPixels + 4)) = cachedCalculation4BitTo4ByteTable[(*inputPixels) & 0x0f];
263 // memset linePadding bits naive.
266 const std::uint8_t offset = (0x07 - (x & 0x07));
267 *outputPixels = ((*inputPixels) >> offset) & 1 ? 0xff : 0x00;
280 bool LoadWbmpHeader(const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height)
282 FILE* const fp = input.file;
283 if(DALI_UNLIKELY(fp == NULL))
285 DALI_LOG_ERROR("Error loading bitmap\n");
288 Dali::Vector<unsigned char> map;
293 if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END)))
295 DALI_LOG_ERROR("Error seeking WBMP data\n");
298 long positionIndicator = ftell(fp);
300 unsigned int fsize(0u);
301 if(positionIndicator > -1L)
303 fsize = static_cast<unsigned int>(positionIndicator);
306 if(DALI_UNLIKELY(0u == fsize))
311 if(DALI_UNLIKELY(fseek(fp, 0, SEEK_SET)))
313 DALI_LOG_ERROR("Error seeking WBMP data\n");
316 if(DALI_UNLIKELY(fsize <= 4))
318 DALI_LOG_ERROR("Error: WBMP Raw Data Not Found!\n");
322 // type(1 byte) + fixedheader(1 byte) + width(uint) + height(uint)
323 unsigned int headerSize = 1 + 1 + 4 + 4; // 8 + 8 + 32 + 32;
324 headerSize = std::min(headerSize, fsize);
326 map.ResizeUninitialized(headerSize);
327 if(DALI_UNLIKELY(fread(&map[0], 1, headerSize, fp) != headerSize))
329 DALI_LOG_WARNING("image file read opeation error!\n");
333 const std::uint8_t* const inputBufferPtr = &map[0];
335 if(DALI_UNLIKELY(extractMultiByteInteger(&type, inputBufferPtr, headerSize, &position) < 0))
337 DALI_LOG_ERROR("Error: unable to read type!\n");
340 position++; /* skipping one byte */
341 if(DALI_UNLIKELY(type != 0))
343 DALI_LOG_ERROR("Error: unknown format!\n");
346 if(DALI_UNLIKELY(extractMultiByteInteger(&w, inputBufferPtr, headerSize, &position) < 0))
348 DALI_LOG_ERROR("Error: can not read width!\n");
351 if(DALI_UNLIKELY(extractMultiByteInteger(&h, inputBufferPtr, headerSize, &position) < 0))
353 DALI_LOG_ERROR("Error: can not read height!\n");
357 if(DALI_UNLIKELY((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE)))
359 DALI_LOG_ERROR("Error: file size is not supported!\n");
368 } // namespace TizenPlatform