| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 PDFium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
| 6 | |
| 7 #include "core/src/fxcodec/lbmp/fx_bmp.h" | |
| 8 | |
| 9 #include <algorithm> | |
| 10 | |
| 11 namespace { | |
| 12 | |
| 13 const size_t kBmpCoreHeaderSize = 12; | |
| 14 const size_t kBmpInfoHeaderSize = 40; | |
| 15 | |
| 16 // TODO(thestig): Replace with FXDWORD_GET_LSBFIRST? | |
| 17 FX_DWORD GetDWord_LSBFirst(uint8_t* p) { | |
| 18 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); | |
| 19 } | |
| 20 | |
| 21 void SetDWord_LSBFirst(uint8_t* p, FX_DWORD v) { | |
| 22 p[0] = (uint8_t)v; | |
| 23 p[1] = (uint8_t)(v >> 8); | |
| 24 p[2] = (uint8_t)(v >> 16); | |
| 25 p[3] = (uint8_t)(v >> 24); | |
| 26 } | |
| 27 } // namespace | |
| 28 | |
| 29 FX_WORD GetWord_LSBFirst(uint8_t* p) { | |
| 30 return p[0] | (p[1] << 8); | |
| 31 } | |
| 32 void SetWord_LSBFirst(uint8_t* p, FX_WORD v) { | |
| 33 p[0] = (uint8_t)v; | |
| 34 p[1] = (uint8_t)(v >> 8); | |
| 35 } | |
| 36 void bmp_error(bmp_decompress_struct_p bmp_ptr, const FX_CHAR* err_msg) { | |
| 37 if (bmp_ptr && bmp_ptr->bmp_error_fn) { | |
| 38 bmp_ptr->bmp_error_fn(bmp_ptr, err_msg); | |
| 39 } | |
| 40 } | |
| 41 bmp_decompress_struct_p bmp_create_decompress() { | |
| 42 bmp_decompress_struct_p bmp_ptr = FX_Alloc(bmp_decompress_struct, 1); | |
| 43 if (bmp_ptr == NULL) { | |
| 44 return NULL; | |
| 45 } | |
| 46 FXSYS_memset(bmp_ptr, 0, sizeof(bmp_decompress_struct)); | |
| 47 bmp_ptr->decode_status = BMP_D_STATUS_HEADER; | |
| 48 bmp_ptr->bmp_header_ptr = FX_Alloc(BmpFileHeader, 1); | |
| 49 return bmp_ptr; | |
| 50 } | |
| 51 void bmp_destroy_decompress(bmp_decompress_struct_pp bmp_ptr_ptr) { | |
| 52 if (bmp_ptr_ptr == NULL || *bmp_ptr_ptr == NULL) { | |
| 53 return; | |
| 54 } | |
| 55 bmp_decompress_struct_p bmp_ptr = *bmp_ptr_ptr; | |
| 56 *bmp_ptr_ptr = NULL; | |
| 57 if (bmp_ptr->out_row_buffer) { | |
| 58 FX_Free(bmp_ptr->out_row_buffer); | |
| 59 } | |
| 60 FX_Free(bmp_ptr->pal_ptr); | |
| 61 FX_Free(bmp_ptr->bmp_header_ptr); | |
| 62 FX_Free(bmp_ptr); | |
| 63 } | |
| 64 int32_t bmp_read_header(bmp_decompress_struct_p bmp_ptr) { | |
| 65 if (bmp_ptr == NULL) { | |
| 66 return 0; | |
| 67 } | |
| 68 FX_DWORD skip_size_org = bmp_ptr->skip_size; | |
| 69 if (bmp_ptr->decode_status == BMP_D_STATUS_HEADER) { | |
| 70 ASSERT(sizeof(BmpFileHeader) == 14); | |
| 71 BmpFileHeader* bmp_header_ptr = NULL; | |
| 72 if (bmp_read_data(bmp_ptr, (uint8_t**)&bmp_header_ptr, 14) == NULL) { | |
| 73 return 2; | |
| 74 } | |
| 75 bmp_ptr->bmp_header_ptr->bfType = | |
| 76 GetWord_LSBFirst((uint8_t*)&bmp_header_ptr->bfType); | |
| 77 bmp_ptr->bmp_header_ptr->bfOffBits = | |
| 78 GetDWord_LSBFirst((uint8_t*)&bmp_header_ptr->bfOffBits); | |
| 79 bmp_ptr->data_size = GetDWord_LSBFirst((uint8_t*)&bmp_header_ptr->bfSize); | |
| 80 if (bmp_ptr->bmp_header_ptr->bfType != BMP_SIGNATURE) { | |
| 81 bmp_error(bmp_ptr, "Not A Bmp Image"); | |
| 82 return 0; | |
| 83 } | |
| 84 if (bmp_ptr->avail_in < sizeof(FX_DWORD)) { | |
| 85 bmp_ptr->skip_size = skip_size_org; | |
| 86 return 2; | |
| 87 } | |
| 88 bmp_ptr->img_ifh_size = | |
| 89 GetDWord_LSBFirst(bmp_ptr->next_in + bmp_ptr->skip_size); | |
| 90 bmp_ptr->pal_type = 0; | |
| 91 static_assert(sizeof(BmpCoreHeader) == kBmpCoreHeaderSize, | |
| 92 "BmpCoreHeader has wrong size"); | |
| 93 static_assert(sizeof(BmpInfoHeader) == kBmpInfoHeaderSize, | |
| 94 "BmpInfoHeader has wrong size"); | |
| 95 switch (bmp_ptr->img_ifh_size) { | |
| 96 case kBmpCoreHeaderSize: { | |
| 97 bmp_ptr->pal_type = 1; | |
| 98 BmpCoreHeaderPtr bmp_core_header_ptr = NULL; | |
| 99 if (bmp_read_data(bmp_ptr, (uint8_t**)&bmp_core_header_ptr, | |
| 100 bmp_ptr->img_ifh_size) == NULL) { | |
| 101 bmp_ptr->skip_size = skip_size_org; | |
| 102 return 2; | |
| 103 } | |
| 104 bmp_ptr->width = | |
| 105 GetWord_LSBFirst((uint8_t*)&bmp_core_header_ptr->bcWidth); | |
| 106 bmp_ptr->height = | |
| 107 GetWord_LSBFirst((uint8_t*)&bmp_core_header_ptr->bcHeight); | |
| 108 bmp_ptr->bitCounts = | |
| 109 GetWord_LSBFirst((uint8_t*)&bmp_core_header_ptr->bcBitCount); | |
| 110 bmp_ptr->compress_flag = BMP_RGB; | |
| 111 bmp_ptr->imgTB_flag = FALSE; | |
| 112 } break; | |
| 113 case kBmpInfoHeaderSize: { | |
| 114 BmpInfoHeaderPtr bmp_info_header_ptr = NULL; | |
| 115 if (bmp_read_data(bmp_ptr, (uint8_t**)&bmp_info_header_ptr, | |
| 116 bmp_ptr->img_ifh_size) == NULL) { | |
| 117 bmp_ptr->skip_size = skip_size_org; | |
| 118 return 2; | |
| 119 } | |
| 120 bmp_ptr->width = | |
| 121 GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biWidth); | |
| 122 bmp_ptr->height = | |
| 123 GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biHeight); | |
| 124 bmp_ptr->bitCounts = | |
| 125 GetWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biBitCount); | |
| 126 bmp_ptr->compress_flag = | |
| 127 GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biCompression); | |
| 128 bmp_ptr->color_used = | |
| 129 GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biClrUsed); | |
| 130 bmp_ptr->dpi_x = (int32_t)GetDWord_LSBFirst( | |
| 131 (uint8_t*)&bmp_info_header_ptr->biXPelsPerMeter); | |
| 132 bmp_ptr->dpi_y = (int32_t)GetDWord_LSBFirst( | |
| 133 (uint8_t*)&bmp_info_header_ptr->biYPelsPerMeter); | |
| 134 if (bmp_ptr->height < 0) { | |
| 135 bmp_ptr->height = -bmp_ptr->height; | |
| 136 bmp_ptr->imgTB_flag = TRUE; | |
| 137 } | |
| 138 } break; | |
| 139 default: { | |
| 140 if (bmp_ptr->img_ifh_size > | |
| 141 std::min(kBmpInfoHeaderSize, sizeof(BmpInfoHeader))) { | |
| 142 BmpInfoHeaderPtr bmp_info_header_ptr = NULL; | |
| 143 if (bmp_read_data(bmp_ptr, (uint8_t**)&bmp_info_header_ptr, | |
| 144 bmp_ptr->img_ifh_size) == NULL) { | |
| 145 bmp_ptr->skip_size = skip_size_org; | |
| 146 return 2; | |
| 147 } | |
| 148 FX_WORD biPlanes; | |
| 149 bmp_ptr->width = | |
| 150 GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biWidth); | |
| 151 bmp_ptr->height = | |
| 152 GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biHeight); | |
| 153 bmp_ptr->bitCounts = | |
| 154 GetWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biBitCount); | |
| 155 bmp_ptr->compress_flag = | |
| 156 GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biCompression); | |
| 157 bmp_ptr->color_used = | |
| 158 GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biClrUsed); | |
| 159 biPlanes = GetWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biPlanes); | |
| 160 bmp_ptr->dpi_x = GetDWord_LSBFirst( | |
| 161 (uint8_t*)&bmp_info_header_ptr->biXPelsPerMeter); | |
| 162 bmp_ptr->dpi_y = GetDWord_LSBFirst( | |
| 163 (uint8_t*)&bmp_info_header_ptr->biYPelsPerMeter); | |
| 164 if (bmp_ptr->height < 0) { | |
| 165 bmp_ptr->height = -bmp_ptr->height; | |
| 166 bmp_ptr->imgTB_flag = TRUE; | |
| 167 } | |
| 168 if (bmp_ptr->compress_flag == BMP_RGB && biPlanes == 1 && | |
| 169 bmp_ptr->color_used == 0) { | |
| 170 break; | |
| 171 } | |
| 172 } | |
| 173 bmp_error(bmp_ptr, "Unsupported Bmp File"); | |
| 174 return 0; | |
| 175 } | |
| 176 } | |
| 177 ASSERT(bmp_ptr->width > 0); | |
| 178 ASSERT(bmp_ptr->compress_flag <= BMP_BITFIELDS); | |
| 179 switch (bmp_ptr->bitCounts) { | |
| 180 case 1: | |
| 181 case 4: | |
| 182 case 8: | |
| 183 case 16: | |
| 184 case 24: { | |
| 185 if (bmp_ptr->color_used > ((FX_DWORD)1) << bmp_ptr->bitCounts) { | |
| 186 bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); | |
| 187 return 0; | |
| 188 } | |
| 189 } | |
| 190 case 32: { | |
| 191 if (bmp_ptr->width <= 0 || bmp_ptr->compress_flag > BMP_BITFIELDS) { | |
| 192 bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); | |
| 193 return 0; | |
| 194 } | |
| 195 } break; | |
| 196 default: | |
| 197 bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); | |
| 198 return 0; | |
| 199 } | |
| 200 bmp_ptr->src_row_bytes = BMP_WIDTHBYTES(bmp_ptr->width, bmp_ptr->bitCounts); | |
| 201 switch (bmp_ptr->bitCounts) { | |
| 202 case 1: | |
| 203 case 4: | |
| 204 case 8: | |
| 205 bmp_ptr->out_row_bytes = BMP_WIDTHBYTES(bmp_ptr->width, 8); | |
| 206 bmp_ptr->components = 1; | |
| 207 break; | |
| 208 case 16: | |
| 209 case 24: | |
| 210 bmp_ptr->out_row_bytes = BMP_WIDTHBYTES(bmp_ptr->width, 24); | |
| 211 bmp_ptr->components = 3; | |
| 212 break; | |
| 213 case 32: | |
| 214 bmp_ptr->out_row_bytes = bmp_ptr->src_row_bytes; | |
| 215 bmp_ptr->components = 4; | |
| 216 break; | |
| 217 } | |
| 218 FX_Free(bmp_ptr->out_row_buffer); | |
| 219 bmp_ptr->out_row_buffer = FX_Alloc(uint8_t, bmp_ptr->out_row_bytes); | |
| 220 FXSYS_memset(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes); | |
| 221 bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_PAL); | |
| 222 } | |
| 223 if (bmp_ptr->decode_status == BMP_D_STATUS_PAL) { | |
| 224 skip_size_org = bmp_ptr->skip_size; | |
| 225 if (bmp_ptr->compress_flag == BMP_BITFIELDS) { | |
| 226 if (bmp_ptr->bitCounts != 16 && bmp_ptr->bitCounts != 32) { | |
| 227 bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); | |
| 228 return 0; | |
| 229 } | |
| 230 FX_DWORD* mask; | |
| 231 if (bmp_read_data(bmp_ptr, (uint8_t**)&mask, 3 * sizeof(FX_DWORD)) == | |
| 232 NULL) { | |
| 233 bmp_ptr->skip_size = skip_size_org; | |
| 234 return 2; | |
| 235 } | |
| 236 bmp_ptr->mask_red = GetDWord_LSBFirst((uint8_t*)&mask[0]); | |
| 237 bmp_ptr->mask_green = GetDWord_LSBFirst((uint8_t*)&mask[1]); | |
| 238 bmp_ptr->mask_blue = GetDWord_LSBFirst((uint8_t*)&mask[2]); | |
| 239 if (bmp_ptr->mask_red & bmp_ptr->mask_green || | |
| 240 bmp_ptr->mask_red & bmp_ptr->mask_blue || | |
| 241 bmp_ptr->mask_green & bmp_ptr->mask_blue) { | |
| 242 bmp_error(bmp_ptr, "The Bitfield Bmp File Is Corrupt"); | |
| 243 return 0; | |
| 244 } | |
| 245 if (bmp_ptr->bmp_header_ptr->bfOffBits < 26 + bmp_ptr->img_ifh_size) { | |
| 246 bmp_ptr->bmp_header_ptr->bfOffBits = 26 + bmp_ptr->img_ifh_size; | |
| 247 } | |
| 248 bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA_PRE); | |
| 249 return 1; | |
| 250 } else if (bmp_ptr->bitCounts == 16) { | |
| 251 bmp_ptr->mask_red = 0x7C00; | |
| 252 bmp_ptr->mask_green = 0x03E0; | |
| 253 bmp_ptr->mask_blue = 0x001F; | |
| 254 } | |
| 255 bmp_ptr->pal_num = 0; | |
| 256 if (bmp_ptr->bitCounts < 16) { | |
| 257 bmp_ptr->pal_num = 1 << bmp_ptr->bitCounts; | |
| 258 if (bmp_ptr->color_used != 0) { | |
| 259 bmp_ptr->pal_num = bmp_ptr->color_used; | |
| 260 } | |
| 261 uint8_t* src_pal_ptr = NULL; | |
| 262 FX_DWORD src_pal_size = bmp_ptr->pal_num * (bmp_ptr->pal_type ? 3 : 4); | |
| 263 if (bmp_read_data(bmp_ptr, (uint8_t**)&src_pal_ptr, src_pal_size) == | |
| 264 NULL) { | |
| 265 bmp_ptr->skip_size = skip_size_org; | |
| 266 return 2; | |
| 267 } | |
| 268 FX_Free(bmp_ptr->pal_ptr); | |
| 269 bmp_ptr->pal_ptr = FX_Alloc(FX_DWORD, bmp_ptr->pal_num); | |
| 270 int32_t src_pal_index = 0; | |
| 271 if (bmp_ptr->pal_type == BMP_PAL_OLD) { | |
| 272 while (src_pal_index < bmp_ptr->pal_num) { | |
| 273 bmp_ptr->pal_ptr[src_pal_index++] = BMP_PAL_ENCODE( | |
| 274 0x00, src_pal_ptr[2], src_pal_ptr[1], src_pal_ptr[0]); | |
| 275 src_pal_ptr += 3; | |
| 276 } | |
| 277 } else { | |
| 278 while (src_pal_index < bmp_ptr->pal_num) { | |
| 279 bmp_ptr->pal_ptr[src_pal_index++] = BMP_PAL_ENCODE( | |
| 280 src_pal_ptr[3], src_pal_ptr[2], src_pal_ptr[1], src_pal_ptr[0]); | |
| 281 src_pal_ptr += 4; | |
| 282 } | |
| 283 } | |
| 284 } | |
| 285 if (bmp_ptr->bmp_header_ptr->bfOffBits < | |
| 286 14 + bmp_ptr->img_ifh_size + | |
| 287 bmp_ptr->pal_num * (bmp_ptr->pal_type ? 3 : 4)) { | |
| 288 bmp_ptr->bmp_header_ptr->bfOffBits = | |
| 289 14 + bmp_ptr->img_ifh_size + | |
| 290 bmp_ptr->pal_num * (bmp_ptr->pal_type ? 3 : 4); | |
| 291 } | |
| 292 bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA_PRE); | |
| 293 } | |
| 294 return 1; | |
| 295 } | |
| 296 int32_t bmp_decode_image(bmp_decompress_struct_p bmp_ptr) { | |
| 297 if (bmp_ptr->decode_status == BMP_D_STATUS_DATA_PRE) { | |
| 298 bmp_ptr->avail_in = 0; | |
| 299 if (!bmp_ptr->bmp_get_data_position_fn( | |
| 300 bmp_ptr, bmp_ptr->bmp_header_ptr->bfOffBits)) { | |
| 301 bmp_ptr->decode_status = BMP_D_STATUS_TAIL; | |
| 302 bmp_error(bmp_ptr, "The Bmp File Is Corrupt, Unexpected Stream Offset"); | |
| 303 return 0; | |
| 304 } | |
| 305 bmp_ptr->row_num = 0; | |
| 306 bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA); | |
| 307 } | |
| 308 if (bmp_ptr->decode_status == BMP_D_STATUS_DATA) { | |
| 309 switch (bmp_ptr->compress_flag) { | |
| 310 case BMP_RGB: | |
| 311 case BMP_BITFIELDS: | |
| 312 return bmp_decode_rgb(bmp_ptr); | |
| 313 case BMP_RLE8: | |
| 314 return bmp_decode_rle8(bmp_ptr); | |
| 315 case BMP_RLE4: | |
| 316 return bmp_decode_rle4(bmp_ptr); | |
| 317 } | |
| 318 } | |
| 319 bmp_error(bmp_ptr, "Any Uncontrol Error"); | |
| 320 return 0; | |
| 321 } | |
| 322 int32_t bmp_decode_rgb(bmp_decompress_struct_p bmp_ptr) { | |
| 323 uint8_t* row_buf = bmp_ptr->out_row_buffer; | |
| 324 uint8_t* des_buf = NULL; | |
| 325 while (bmp_ptr->row_num < bmp_ptr->height) { | |
| 326 if (bmp_read_data(bmp_ptr, &des_buf, bmp_ptr->src_row_bytes) == NULL) { | |
| 327 return 2; | |
| 328 } | |
| 329 bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA); | |
| 330 switch (bmp_ptr->bitCounts) { | |
| 331 case 1: { | |
| 332 for (int32_t col = 0; col < bmp_ptr->width; col++) { | |
| 333 *row_buf++ = des_buf[col >> 3] & (0x80 >> (col % 8)) ? 0x01 : 0x00; | |
| 334 } | |
| 335 } break; | |
| 336 case 4: { | |
| 337 for (int32_t col = 0; col < bmp_ptr->width; col++) { | |
| 338 *row_buf++ = (col & 0x01) ? (des_buf[col >> 1] & 0x0F) | |
| 339 : ((des_buf[col >> 1] & 0xF0) >> 4); | |
| 340 } | |
| 341 } break; | |
| 342 case 16: { | |
| 343 FX_WORD* buf = (FX_WORD*)des_buf; | |
| 344 uint8_t blue_bits = 0; | |
| 345 uint8_t green_bits = 0; | |
| 346 uint8_t red_bits = 0; | |
| 347 for (int32_t i = 0; i < 16; i++) { | |
| 348 if ((bmp_ptr->mask_blue >> i) & 0x01) { | |
| 349 blue_bits++; | |
| 350 } | |
| 351 if ((bmp_ptr->mask_green >> i) & 0x01) { | |
| 352 green_bits++; | |
| 353 } | |
| 354 if ((bmp_ptr->mask_red >> i) & 0x01) { | |
| 355 red_bits++; | |
| 356 } | |
| 357 } | |
| 358 green_bits += blue_bits; | |
| 359 red_bits += green_bits; | |
| 360 blue_bits = 8 - blue_bits; | |
| 361 green_bits -= 8; | |
| 362 red_bits -= 8; | |
| 363 for (int32_t col = 0; col < bmp_ptr->width; col++) { | |
| 364 *buf = GetWord_LSBFirst((uint8_t*)buf); | |
| 365 *row_buf++ = (uint8_t)((*buf & bmp_ptr->mask_blue) << blue_bits); | |
| 366 *row_buf++ = (uint8_t)((*buf & bmp_ptr->mask_green) >> green_bits); | |
| 367 *row_buf++ = (uint8_t)((*buf++ & bmp_ptr->mask_red) >> red_bits); | |
| 368 } | |
| 369 } break; | |
| 370 case 8: | |
| 371 case 24: | |
| 372 case 32: | |
| 373 FXSYS_memcpy(bmp_ptr->out_row_buffer, des_buf, bmp_ptr->src_row_bytes); | |
| 374 break; | |
| 375 } | |
| 376 row_buf = bmp_ptr->out_row_buffer; | |
| 377 bmp_ptr->bmp_get_row_fn(bmp_ptr, | |
| 378 bmp_ptr->imgTB_flag | |
| 379 ? bmp_ptr->row_num++ | |
| 380 : (bmp_ptr->height - 1 - bmp_ptr->row_num++), | |
| 381 bmp_ptr->out_row_buffer); | |
| 382 } | |
| 383 bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL); | |
| 384 return 1; | |
| 385 } | |
| 386 int32_t bmp_decode_rle8(bmp_decompress_struct_p bmp_ptr) { | |
| 387 uint8_t* first_byte_ptr = NULL; | |
| 388 uint8_t* second_byte_ptr = NULL; | |
| 389 bmp_ptr->col_num = 0; | |
| 390 while (TRUE) { | |
| 391 FX_DWORD skip_size_org = bmp_ptr->skip_size; | |
| 392 if (bmp_read_data(bmp_ptr, &first_byte_ptr, 1) == NULL) { | |
| 393 return 2; | |
| 394 } | |
| 395 switch (*first_byte_ptr) { | |
| 396 case RLE_MARKER: { | |
| 397 if (bmp_read_data(bmp_ptr, &first_byte_ptr, 1) == NULL) { | |
| 398 bmp_ptr->skip_size = skip_size_org; | |
| 399 return 2; | |
| 400 } | |
| 401 switch (*first_byte_ptr) { | |
| 402 case RLE_EOL: { | |
| 403 if (bmp_ptr->row_num >= bmp_ptr->height) { | |
| 404 bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL); | |
| 405 bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); | |
| 406 return 0; | |
| 407 } | |
| 408 bmp_ptr->bmp_get_row_fn( | |
| 409 bmp_ptr, bmp_ptr->imgTB_flag | |
| 410 ? bmp_ptr->row_num++ | |
| 411 : (bmp_ptr->height - 1 - bmp_ptr->row_num++), | |
| 412 bmp_ptr->out_row_buffer); | |
| 413 bmp_ptr->col_num = 0; | |
| 414 FXSYS_memset(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes); | |
| 415 bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA); | |
| 416 continue; | |
| 417 } | |
| 418 case RLE_EOI: { | |
| 419 if (bmp_ptr->row_num < bmp_ptr->height) { | |
| 420 bmp_ptr->bmp_get_row_fn( | |
| 421 bmp_ptr, bmp_ptr->imgTB_flag | |
| 422 ? bmp_ptr->row_num++ | |
| 423 : (bmp_ptr->height - 1 - bmp_ptr->row_num++), | |
| 424 bmp_ptr->out_row_buffer); | |
| 425 } | |
| 426 bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL); | |
| 427 return 1; | |
| 428 } | |
| 429 case RLE_DELTA: { | |
| 430 uint8_t* delta_ptr; | |
| 431 if (bmp_read_data(bmp_ptr, &delta_ptr, 2) == NULL) { | |
| 432 bmp_ptr->skip_size = skip_size_org; | |
| 433 return 2; | |
| 434 } | |
| 435 bmp_ptr->col_num += (int32_t)delta_ptr[0]; | |
| 436 int32_t bmp_row_num_next = bmp_ptr->row_num + (int32_t)delta_ptr[1]; | |
| 437 if (bmp_ptr->col_num >= bmp_ptr->out_row_bytes || | |
| 438 bmp_row_num_next >= bmp_ptr->height) { | |
| 439 bmp_error(bmp_ptr, "The Bmp File Is Corrupt Or Not Supported"); | |
| 440 return 0; | |
| 441 } | |
| 442 while (bmp_ptr->row_num < bmp_row_num_next) { | |
| 443 FXSYS_memset(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes); | |
| 444 bmp_ptr->bmp_get_row_fn( | |
| 445 bmp_ptr, bmp_ptr->imgTB_flag | |
| 446 ? bmp_ptr->row_num++ | |
| 447 : (bmp_ptr->height - 1 - bmp_ptr->row_num++), | |
| 448 bmp_ptr->out_row_buffer); | |
| 449 } | |
| 450 } break; | |
| 451 default: { | |
| 452 if ((int32_t)(*first_byte_ptr) > | |
| 453 bmp_ptr->src_row_bytes - bmp_ptr->col_num) { | |
| 454 bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); | |
| 455 return 0; | |
| 456 } | |
| 457 if (bmp_read_data(bmp_ptr, &second_byte_ptr, | |
| 458 *first_byte_ptr & 1 ? *first_byte_ptr + 1 | |
| 459 : *first_byte_ptr) == NULL) { | |
| 460 bmp_ptr->skip_size = skip_size_org; | |
| 461 return 2; | |
| 462 } | |
| 463 FXSYS_memcpy(bmp_ptr->out_row_buffer + bmp_ptr->col_num, | |
| 464 second_byte_ptr, *first_byte_ptr); | |
| 465 bmp_ptr->col_num += (int32_t)(*first_byte_ptr); | |
| 466 } | |
| 467 } | |
| 468 } break; | |
| 469 default: { | |
| 470 if (bmp_read_data(bmp_ptr, &second_byte_ptr, 1) == NULL) { | |
| 471 bmp_ptr->skip_size = skip_size_org; | |
| 472 return 2; | |
| 473 } | |
| 474 if ((int32_t)(*first_byte_ptr) > | |
| 475 bmp_ptr->src_row_bytes - bmp_ptr->col_num) { | |
| 476 bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); | |
| 477 return 0; | |
| 478 } | |
| 479 FXSYS_memset(bmp_ptr->out_row_buffer + bmp_ptr->col_num, | |
| 480 *second_byte_ptr, *first_byte_ptr); | |
| 481 bmp_ptr->col_num += (int32_t)(*first_byte_ptr); | |
| 482 } | |
| 483 } | |
| 484 } | |
| 485 bmp_error(bmp_ptr, "Any Uncontrol Error"); | |
| 486 return 0; | |
| 487 } | |
| 488 int32_t bmp_decode_rle4(bmp_decompress_struct_p bmp_ptr) { | |
| 489 uint8_t* first_byte_ptr = NULL; | |
| 490 uint8_t* second_byte_ptr = NULL; | |
| 491 bmp_ptr->col_num = 0; | |
| 492 while (TRUE) { | |
| 493 FX_DWORD skip_size_org = bmp_ptr->skip_size; | |
| 494 if (bmp_read_data(bmp_ptr, &first_byte_ptr, 1) == NULL) { | |
| 495 return 2; | |
| 496 } | |
| 497 switch (*first_byte_ptr) { | |
| 498 case RLE_MARKER: { | |
| 499 if (bmp_read_data(bmp_ptr, &first_byte_ptr, 1) == NULL) { | |
| 500 bmp_ptr->skip_size = skip_size_org; | |
| 501 return 2; | |
| 502 } | |
| 503 switch (*first_byte_ptr) { | |
| 504 case RLE_EOL: { | |
| 505 if (bmp_ptr->row_num >= bmp_ptr->height) { | |
| 506 bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL); | |
| 507 bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); | |
| 508 return 0; | |
| 509 } | |
| 510 bmp_ptr->bmp_get_row_fn( | |
| 511 bmp_ptr, bmp_ptr->imgTB_flag | |
| 512 ? bmp_ptr->row_num++ | |
| 513 : (bmp_ptr->height - 1 - bmp_ptr->row_num++), | |
| 514 bmp_ptr->out_row_buffer); | |
| 515 bmp_ptr->col_num = 0; | |
| 516 FXSYS_memset(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes); | |
| 517 bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA); | |
| 518 continue; | |
| 519 } | |
| 520 case RLE_EOI: { | |
| 521 if (bmp_ptr->row_num < bmp_ptr->height) { | |
| 522 bmp_ptr->bmp_get_row_fn( | |
| 523 bmp_ptr, bmp_ptr->imgTB_flag | |
| 524 ? bmp_ptr->row_num++ | |
| 525 : (bmp_ptr->height - 1 - bmp_ptr->row_num++), | |
| 526 bmp_ptr->out_row_buffer); | |
| 527 } | |
| 528 bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL); | |
| 529 return 1; | |
| 530 } | |
| 531 case RLE_DELTA: { | |
| 532 uint8_t* delta_ptr; | |
| 533 if (bmp_read_data(bmp_ptr, &delta_ptr, 2) == NULL) { | |
| 534 bmp_ptr->skip_size = skip_size_org; | |
| 535 return 2; | |
| 536 } | |
| 537 bmp_ptr->col_num += (int32_t)delta_ptr[0]; | |
| 538 int32_t bmp_row_num_next = bmp_ptr->row_num + (int32_t)delta_ptr[1]; | |
| 539 if (bmp_ptr->col_num >= bmp_ptr->out_row_bytes || | |
| 540 bmp_row_num_next >= bmp_ptr->height) { | |
| 541 bmp_error(bmp_ptr, "The Bmp File Is Corrupt Or Not Supported"); | |
| 542 return 0; | |
| 543 } | |
| 544 while (bmp_ptr->row_num < bmp_row_num_next) { | |
| 545 FXSYS_memset(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes); | |
| 546 bmp_ptr->bmp_get_row_fn( | |
| 547 bmp_ptr, bmp_ptr->imgTB_flag | |
| 548 ? bmp_ptr->row_num++ | |
| 549 : (bmp_ptr->height - 1 - bmp_ptr->row_num++), | |
| 550 bmp_ptr->out_row_buffer); | |
| 551 } | |
| 552 } break; | |
| 553 default: { | |
| 554 uint8_t size = (uint8_t)(((FX_WORD)(*first_byte_ptr) + 1) >> 1); | |
| 555 if ((int32_t)*first_byte_ptr >= | |
| 556 bmp_ptr->out_row_bytes - bmp_ptr->col_num) { | |
| 557 if (size + (bmp_ptr->col_num >> 1) > bmp_ptr->src_row_bytes) { | |
| 558 bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); | |
| 559 return 0; | |
| 560 } | |
| 561 *first_byte_ptr = bmp_ptr->out_row_bytes - bmp_ptr->col_num - 1; | |
| 562 } | |
| 563 if (bmp_read_data(bmp_ptr, &second_byte_ptr, | |
| 564 size & 1 ? size + 1 : size) == NULL) { | |
| 565 bmp_ptr->skip_size = skip_size_org; | |
| 566 return 2; | |
| 567 } | |
| 568 for (uint8_t i = 0; i < *first_byte_ptr; i++) { | |
| 569 if (i & 0x01) { | |
| 570 *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) = | |
| 571 (*second_byte_ptr++ & 0x0F); | |
| 572 } else { | |
| 573 *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) = | |
| 574 ((*second_byte_ptr & 0xF0) >> 4); | |
| 575 } | |
| 576 } | |
| 577 } | |
| 578 } | |
| 579 } break; | |
| 580 default: { | |
| 581 if (bmp_read_data(bmp_ptr, &second_byte_ptr, 1) == NULL) { | |
| 582 bmp_ptr->skip_size = skip_size_org; | |
| 583 return 2; | |
| 584 } | |
| 585 if ((int32_t)*first_byte_ptr > | |
| 586 bmp_ptr->out_row_bytes - bmp_ptr->col_num) { | |
| 587 uint8_t size = (uint8_t)(((FX_WORD)(*first_byte_ptr) + 1) >> 1); | |
| 588 if (size + (bmp_ptr->col_num >> 1) > bmp_ptr->src_row_bytes) { | |
| 589 bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); | |
| 590 return 0; | |
| 591 } | |
| 592 *first_byte_ptr = bmp_ptr->out_row_bytes - bmp_ptr->col_num - 1; | |
| 593 } | |
| 594 for (uint8_t i = 0; i < *first_byte_ptr; i++) { | |
| 595 if (i & 0x01) { | |
| 596 *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) = | |
| 597 (*second_byte_ptr & 0x0F); | |
| 598 } else { | |
| 599 *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) = | |
| 600 ((*second_byte_ptr & 0xF0) >> 4); | |
| 601 } | |
| 602 } | |
| 603 } | |
| 604 } | |
| 605 } | |
| 606 bmp_error(bmp_ptr, "Any Uncontrol Error"); | |
| 607 return 0; | |
| 608 } | |
| 609 uint8_t* bmp_read_data(bmp_decompress_struct_p bmp_ptr, | |
| 610 uint8_t** des_buf_pp, | |
| 611 FX_DWORD data_size) { | |
| 612 if (bmp_ptr == NULL || bmp_ptr->avail_in < bmp_ptr->skip_size + data_size) { | |
| 613 return NULL; | |
| 614 } | |
| 615 *des_buf_pp = bmp_ptr->next_in + bmp_ptr->skip_size; | |
| 616 bmp_ptr->skip_size += data_size; | |
| 617 return *des_buf_pp; | |
| 618 } | |
| 619 void bmp_save_decoding_status(bmp_decompress_struct_p bmp_ptr, int32_t status) { | |
| 620 bmp_ptr->decode_status = status; | |
| 621 bmp_ptr->next_in += bmp_ptr->skip_size; | |
| 622 bmp_ptr->avail_in -= bmp_ptr->skip_size; | |
| 623 bmp_ptr->skip_size = 0; | |
| 624 } | |
| 625 void bmp_input_buffer(bmp_decompress_struct_p bmp_ptr, | |
| 626 uint8_t* src_buf, | |
| 627 FX_DWORD src_size) { | |
| 628 bmp_ptr->next_in = src_buf; | |
| 629 bmp_ptr->avail_in = src_size; | |
| 630 bmp_ptr->skip_size = 0; | |
| 631 } | |
| 632 FX_DWORD bmp_get_avail_input(bmp_decompress_struct_p bmp_ptr, | |
| 633 uint8_t** avial_buf_ptr) { | |
| 634 if (avial_buf_ptr) { | |
| 635 *avial_buf_ptr = NULL; | |
| 636 if (bmp_ptr->avail_in > 0) { | |
| 637 *avial_buf_ptr = bmp_ptr->next_in; | |
| 638 } | |
| 639 } | |
| 640 return bmp_ptr->avail_in; | |
| 641 } | |
| 642 bmp_compress_struct_p bmp_create_compress() { | |
| 643 bmp_compress_struct_p bmp_ptr; | |
| 644 bmp_ptr = FX_Alloc(bmp_compress_struct, 1); | |
| 645 if (bmp_ptr) { | |
| 646 FXSYS_memset(bmp_ptr, 0, sizeof(bmp_compress_struct)); | |
| 647 } | |
| 648 return bmp_ptr; | |
| 649 } | |
| 650 void bmp_destroy_compress(bmp_compress_struct_p bmp_ptr) { | |
| 651 if (bmp_ptr) { | |
| 652 if (bmp_ptr->src_free && bmp_ptr->src_buf) { | |
| 653 FX_Free(bmp_ptr->src_buf); | |
| 654 } | |
| 655 FX_Free(bmp_ptr); | |
| 656 } | |
| 657 } | |
| 658 static void WriteFileHeader(BmpFileHeaderPtr head_ptr, uint8_t* dst_buf) { | |
| 659 FX_DWORD offset; | |
| 660 offset = 0; | |
| 661 SetWord_LSBFirst(&dst_buf[offset], head_ptr->bfType); | |
| 662 offset += 2; | |
| 663 SetDWord_LSBFirst(&dst_buf[offset], head_ptr->bfSize); | |
| 664 offset += 4; | |
| 665 SetWord_LSBFirst(&dst_buf[offset], head_ptr->bfReserved1); | |
| 666 offset += 2; | |
| 667 SetWord_LSBFirst(&dst_buf[offset], head_ptr->bfReserved2); | |
| 668 offset += 2; | |
| 669 SetDWord_LSBFirst(&dst_buf[offset], head_ptr->bfOffBits); | |
| 670 offset += 4; | |
| 671 } | |
| 672 static void WriteInfoHeader(BmpInfoHeaderPtr info_head_ptr, uint8_t* dst_buf) { | |
| 673 FX_DWORD offset; | |
| 674 offset = sizeof(BmpFileHeader); | |
| 675 SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biSize); | |
| 676 offset += 4; | |
| 677 SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biWidth); | |
| 678 offset += 4; | |
| 679 SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biHeight); | |
| 680 offset += 4; | |
| 681 SetWord_LSBFirst(&dst_buf[offset], info_head_ptr->biPlanes); | |
| 682 offset += 2; | |
| 683 SetWord_LSBFirst(&dst_buf[offset], info_head_ptr->biBitCount); | |
| 684 offset += 2; | |
| 685 SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biCompression); | |
| 686 offset += 4; | |
| 687 SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biSizeImage); | |
| 688 offset += 4; | |
| 689 SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biXPelsPerMeter); | |
| 690 offset += 4; | |
| 691 SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biYPelsPerMeter); | |
| 692 offset += 4; | |
| 693 SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biClrUsed); | |
| 694 offset += 4; | |
| 695 SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biClrImportant); | |
| 696 offset += 4; | |
| 697 } | |
| 698 static void bmp_encode_bitfields(bmp_compress_struct_p bmp_ptr, | |
| 699 uint8_t*& dst_buf, | |
| 700 FX_DWORD& dst_size) { | |
| 701 if (bmp_ptr->info_header.biBitCount != 16 && | |
| 702 bmp_ptr->info_header.biBitCount != 32) { | |
| 703 return; | |
| 704 } | |
| 705 FX_DWORD size, dst_pos, i; | |
| 706 size = bmp_ptr->src_pitch * bmp_ptr->src_row * | |
| 707 bmp_ptr->info_header.biBitCount / 16; | |
| 708 dst_pos = bmp_ptr->file_header.bfOffBits; | |
| 709 dst_size += size; | |
| 710 dst_buf = FX_Realloc(uint8_t, dst_buf, dst_size); | |
| 711 if (dst_buf == NULL) { | |
| 712 return; | |
| 713 } | |
| 714 FXSYS_memset(&dst_buf[dst_pos], 0, size); | |
| 715 FX_DWORD mask_red; | |
| 716 FX_DWORD mask_green; | |
| 717 FX_DWORD mask_blue; | |
| 718 mask_red = 0x7C00; | |
| 719 mask_green = 0x03E0; | |
| 720 mask_blue = 0x001F; | |
| 721 if (bmp_ptr->info_header.biCompression == BMP_BITFIELDS) { | |
| 722 if (bmp_ptr->bit_type == BMP_BIT_565) { | |
| 723 mask_red = 0xF800; | |
| 724 mask_green = 0x07E0; | |
| 725 mask_blue = 0x001F; | |
| 726 } | |
| 727 if (bmp_ptr->info_header.biBitCount == 32) { | |
| 728 mask_red = 0xFF0000; | |
| 729 mask_green = 0x00FF00; | |
| 730 mask_blue = 0x0000FF; | |
| 731 } | |
| 732 SetDWord_LSBFirst(&dst_buf[dst_pos], mask_red); | |
| 733 dst_pos += 4; | |
| 734 SetDWord_LSBFirst(&dst_buf[dst_pos], mask_green); | |
| 735 dst_pos += 4; | |
| 736 SetDWord_LSBFirst(&dst_buf[dst_pos], mask_blue); | |
| 737 dst_pos += 4; | |
| 738 bmp_ptr->file_header.bfOffBits = dst_pos; | |
| 739 } | |
| 740 uint8_t blue_bits = 0; | |
| 741 uint8_t green_bits = 0; | |
| 742 uint8_t red_bits = 0; | |
| 743 for (i = 0; i < bmp_ptr->info_header.biBitCount; i++) { | |
| 744 if ((mask_blue >> i) & 0x01) { | |
| 745 blue_bits++; | |
| 746 } | |
| 747 if ((mask_green >> i) & 0x01) { | |
| 748 green_bits++; | |
| 749 } | |
| 750 if ((mask_red >> i) & 0x01) { | |
| 751 red_bits++; | |
| 752 } | |
| 753 } | |
| 754 green_bits += blue_bits; | |
| 755 red_bits += green_bits; | |
| 756 blue_bits = 8 - blue_bits; | |
| 757 green_bits -= 8; | |
| 758 red_bits -= 8; | |
| 759 i = 0; | |
| 760 for (int32_t row_num = bmp_ptr->src_row - 1; row_num > -1; row_num--, i = 0) { | |
| 761 while (i < bmp_ptr->src_width * bmp_ptr->src_bpp / 8) { | |
| 762 uint8_t b = bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch + i++]; | |
| 763 uint8_t g = bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch + i++]; | |
| 764 uint8_t r = bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch + i++]; | |
| 765 if (bmp_ptr->src_bpp == 32) { | |
| 766 i++; | |
| 767 } | |
| 768 FX_DWORD pix_val = 0; | |
| 769 pix_val |= (b >> blue_bits) & mask_blue; | |
| 770 pix_val |= (g << green_bits) & mask_green; | |
| 771 pix_val |= (r << red_bits) & mask_red; | |
| 772 if (bmp_ptr->info_header.biBitCount == 16) { | |
| 773 SetWord_LSBFirst(&dst_buf[dst_pos], pix_val); | |
| 774 dst_pos += 2; | |
| 775 } else { | |
| 776 SetDWord_LSBFirst(&dst_buf[dst_pos], pix_val); | |
| 777 dst_pos += 4; | |
| 778 } | |
| 779 } | |
| 780 } | |
| 781 dst_size = dst_pos; | |
| 782 } | |
| 783 | |
| 784 static void bmp_encode_rgb(bmp_compress_struct_p bmp_ptr, | |
| 785 uint8_t*& dst_buf, | |
| 786 FX_DWORD& dst_size) { | |
| 787 if (bmp_ptr->info_header.biBitCount == 16) { | |
| 788 bmp_encode_bitfields(bmp_ptr, dst_buf, dst_size); | |
| 789 return; | |
| 790 } | |
| 791 FX_DWORD size, dst_pos; | |
| 792 FX_DWORD dst_pitch = | |
| 793 (bmp_ptr->src_width * bmp_ptr->info_header.biBitCount + 31) / 32 * 4; | |
| 794 size = dst_pitch * bmp_ptr->src_row; | |
| 795 dst_pos = bmp_ptr->file_header.bfOffBits; | |
| 796 dst_size += size; | |
| 797 dst_buf = FX_Realloc(uint8_t, dst_buf, dst_size); | |
| 798 if (dst_buf == NULL) { | |
| 799 return; | |
| 800 } | |
| 801 FXSYS_memset(&dst_buf[dst_pos], 0, size); | |
| 802 for (int32_t row_num = bmp_ptr->src_row - 1; row_num > -1; row_num--) { | |
| 803 FXSYS_memcpy(&dst_buf[dst_pos], | |
| 804 &bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch], | |
| 805 bmp_ptr->src_pitch); | |
| 806 dst_pos += dst_pitch; | |
| 807 } | |
| 808 dst_size = dst_pos; | |
| 809 } | |
| 810 static uint8_t bmp_rle8_search(const uint8_t* buf, int32_t len) { | |
| 811 uint8_t num; | |
| 812 num = 1; | |
| 813 while (num < len) { | |
| 814 if (buf[num - 1] != buf[num] || num == 0xFF) { | |
| 815 break; | |
| 816 } | |
| 817 num++; | |
| 818 } | |
| 819 return num; | |
| 820 } | |
| 821 static void bmp_encode_rle8(bmp_compress_struct_p bmp_ptr, | |
| 822 uint8_t*& dst_buf, | |
| 823 FX_DWORD& dst_size) { | |
| 824 FX_DWORD size, dst_pos, index; | |
| 825 uint8_t rle[2] = {0}; | |
| 826 size = bmp_ptr->src_pitch * bmp_ptr->src_row * 2; | |
| 827 dst_pos = bmp_ptr->file_header.bfOffBits; | |
| 828 dst_size += size; | |
| 829 dst_buf = FX_Realloc(uint8_t, dst_buf, dst_size); | |
| 830 if (dst_buf == NULL) { | |
| 831 return; | |
| 832 } | |
| 833 FXSYS_memset(&dst_buf[dst_pos], 0, size); | |
| 834 for (int32_t row_num = bmp_ptr->src_row - 1, i = 0; row_num > -1;) { | |
| 835 index = row_num * bmp_ptr->src_pitch; | |
| 836 rle[0] = bmp_rle8_search(&bmp_ptr->src_buf[index + i], size - index - i); | |
| 837 rle[1] = bmp_ptr->src_buf[index + i]; | |
| 838 if (i + rle[0] >= (int32_t)bmp_ptr->src_pitch) { | |
| 839 rle[0] = uint8_t(bmp_ptr->src_pitch - i); | |
| 840 if (rle[0]) { | |
| 841 dst_buf[dst_pos++] = rle[0]; | |
| 842 dst_buf[dst_pos++] = rle[1]; | |
| 843 } | |
| 844 dst_buf[dst_pos++] = RLE_MARKER; | |
| 845 dst_buf[dst_pos++] = RLE_EOL; | |
| 846 i = 0; | |
| 847 row_num--; | |
| 848 } else { | |
| 849 i += rle[0]; | |
| 850 dst_buf[dst_pos++] = rle[0]; | |
| 851 dst_buf[dst_pos++] = rle[1]; | |
| 852 } | |
| 853 } | |
| 854 dst_buf[dst_pos++] = RLE_MARKER; | |
| 855 dst_buf[dst_pos++] = RLE_EOI; | |
| 856 dst_size = dst_pos; | |
| 857 } | |
| 858 static uint8_t bmp_rle4_search(const uint8_t* buf, int32_t len) { | |
| 859 uint8_t num; | |
| 860 num = 2; | |
| 861 while (num < len) { | |
| 862 if (buf[num - 2] != buf[num] || num == 0xFF) { | |
| 863 break; | |
| 864 } | |
| 865 num++; | |
| 866 } | |
| 867 return num; | |
| 868 } | |
| 869 static void bmp_encode_rle4(bmp_compress_struct_p bmp_ptr, | |
| 870 uint8_t*& dst_buf, | |
| 871 FX_DWORD& dst_size) { | |
| 872 FX_DWORD size, dst_pos, index; | |
| 873 uint8_t rle[2] = {0}; | |
| 874 size = bmp_ptr->src_pitch * bmp_ptr->src_row; | |
| 875 dst_pos = bmp_ptr->file_header.bfOffBits; | |
| 876 dst_size += size; | |
| 877 dst_buf = FX_Realloc(uint8_t, dst_buf, dst_size); | |
| 878 if (dst_buf == NULL) { | |
| 879 return; | |
| 880 } | |
| 881 FXSYS_memset(&dst_buf[dst_pos], 0, size); | |
| 882 for (int32_t row_num = bmp_ptr->src_row - 1, i = 0; row_num > -1; | |
| 883 rle[1] = 0) { | |
| 884 index = row_num * bmp_ptr->src_pitch; | |
| 885 rle[0] = bmp_rle4_search(&bmp_ptr->src_buf[index + i], size - index - i); | |
| 886 rle[1] |= (bmp_ptr->src_buf[index + i] & 0x0f) << 4; | |
| 887 rle[1] |= bmp_ptr->src_buf[index + i + 1] & 0x0f; | |
| 888 if (i + rle[0] >= (int32_t)bmp_ptr->src_pitch) { | |
| 889 rle[0] = uint8_t(bmp_ptr->src_pitch - i); | |
| 890 if (rle[0]) { | |
| 891 dst_buf[dst_pos++] = rle[0]; | |
| 892 dst_buf[dst_pos++] = rle[1]; | |
| 893 } | |
| 894 dst_buf[dst_pos++] = RLE_MARKER; | |
| 895 dst_buf[dst_pos++] = RLE_EOL; | |
| 896 i = 0; | |
| 897 row_num--; | |
| 898 } else { | |
| 899 i += rle[0]; | |
| 900 dst_buf[dst_pos++] = rle[0]; | |
| 901 dst_buf[dst_pos++] = rle[1]; | |
| 902 } | |
| 903 } | |
| 904 dst_buf[dst_pos++] = RLE_MARKER; | |
| 905 dst_buf[dst_pos++] = RLE_EOI; | |
| 906 dst_size = dst_pos; | |
| 907 } | |
| 908 FX_BOOL bmp_encode_image(bmp_compress_struct_p bmp_ptr, | |
| 909 uint8_t*& dst_buf, | |
| 910 FX_DWORD& dst_size) { | |
| 911 FX_DWORD head_size = sizeof(BmpFileHeader) + sizeof(BmpInfoHeader); | |
| 912 FX_DWORD pal_size = sizeof(FX_DWORD) * bmp_ptr->pal_num; | |
| 913 if (bmp_ptr->info_header.biClrUsed > 0 && | |
| 914 bmp_ptr->info_header.biClrUsed < bmp_ptr->pal_num) { | |
| 915 pal_size = sizeof(FX_DWORD) * bmp_ptr->info_header.biClrUsed; | |
| 916 } | |
| 917 dst_size = head_size + sizeof(FX_DWORD) * bmp_ptr->pal_num; | |
| 918 dst_buf = FX_TryAlloc(uint8_t, dst_size); | |
| 919 if (dst_buf == NULL) { | |
| 920 return FALSE; | |
| 921 } | |
| 922 FXSYS_memset(dst_buf, 0, dst_size); | |
| 923 bmp_ptr->file_header.bfOffBits = head_size; | |
| 924 if (bmp_ptr->pal_ptr && pal_size) { | |
| 925 FXSYS_memcpy(&dst_buf[head_size], bmp_ptr->pal_ptr, pal_size); | |
| 926 bmp_ptr->file_header.bfOffBits += pal_size; | |
| 927 } | |
| 928 WriteInfoHeader(&bmp_ptr->info_header, dst_buf); | |
| 929 switch (bmp_ptr->info_header.biCompression) { | |
| 930 case BMP_RGB: | |
| 931 bmp_encode_rgb(bmp_ptr, dst_buf, dst_size); | |
| 932 break; | |
| 933 case BMP_BITFIELDS: | |
| 934 bmp_encode_bitfields(bmp_ptr, dst_buf, dst_size); | |
| 935 break; | |
| 936 case BMP_RLE8: | |
| 937 bmp_encode_rle8(bmp_ptr, dst_buf, dst_size); | |
| 938 break; | |
| 939 case BMP_RLE4: | |
| 940 bmp_encode_rle4(bmp_ptr, dst_buf, dst_size); | |
| 941 break; | |
| 942 default: | |
| 943 break; | |
| 944 } | |
| 945 bmp_ptr->file_header.bfSize = dst_size; | |
| 946 WriteFileHeader(&bmp_ptr->file_header, dst_buf); | |
| 947 return TRUE; | |
| 948 } | |
| OLD | NEW |