| 304 | } |
| 305 | |
| 306 | Error ImageLoaderICO::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) { |
| 307 | ERR_FAIL_COND_V_MSG(p_fileaccess.is_null(), ERR_INVALID_PARAMETER, "ImageLoaderICO: Invalid FileAccess."); |
| 308 | |
| 309 | // Read ICONDIR header |
| 310 | uint16_t reserved = p_fileaccess->get_16(); |
| 311 | ERR_FAIL_COND_V_MSG(reserved != 0, ERR_FILE_UNRECOGNIZED, "ImageLoaderICO: Invalid ICO file (reserved field should be 0)."); |
| 312 | |
| 313 | uint16_t icon_type = p_fileaccess->get_16(); |
| 314 | ERR_FAIL_COND_V_MSG(icon_type != 1, ERR_FILE_UNRECOGNIZED, "ImageLoaderICO: Invalid ICO file (type should be 1 for ICO)."); |
| 315 | |
| 316 | uint16_t icon_count = p_fileaccess->get_16(); |
| 317 | ERR_FAIL_COND_V_MSG(icon_count == 0, ERR_FILE_CORRUPT, "ImageLoaderICO: ICO file contains no images."); |
| 318 | |
| 319 | // Read all icon entries |
| 320 | Vector<IconEntry> entries; |
| 321 | entries.resize(icon_count); |
| 322 | |
| 323 | int best_index = -1; |
| 324 | int best_size = -1; |
| 325 | |
| 326 | for (uint16_t i = 0; i < icon_count; i++) { |
| 327 | IconEntry &entry = entries.write[i]; |
| 328 | entry.width = p_fileaccess->get_8(); |
| 329 | entry.height = p_fileaccess->get_8(); |
| 330 | entry.colors = p_fileaccess->get_8(); |
| 331 | entry.reserved = p_fileaccess->get_8(); |
| 332 | entry.planes = p_fileaccess->get_16(); |
| 333 | entry.bits_per_pixel = p_fileaccess->get_16(); |
| 334 | entry.image_size = p_fileaccess->get_32(); |
| 335 | entry.image_offset = p_fileaccess->get_32(); |
| 336 | |
| 337 | // Handle 0 width/height meaning 256 |
| 338 | uint16_t actual_width = (entry.width == 0) ? 256 : entry.width; |
| 339 | uint16_t actual_height = (entry.height == 0) ? 256 : entry.height; |
| 340 | |
| 341 | // Select best image: prefer larger images (ICO files typically contain multiple sizes) |
| 342 | int size = actual_width * actual_height; |
| 343 | if (best_index == -1 || size > best_size) { |
| 344 | best_index = i; |
| 345 | best_size = size; |
| 346 | } |
| 347 | } |
| 348 | |
| 349 | ERR_FAIL_COND_V_MSG(best_index == -1, ERR_FILE_CORRUPT, "ImageLoaderICO: Could not select an image from ICO file."); |
| 350 | |
| 351 | const IconEntry &selected_entry = entries[best_index]; |
| 352 | |
| 353 | // Read the selected image data |
| 354 | ERR_FAIL_COND_V_MSG(selected_entry.image_offset + selected_entry.image_size > (uint32_t)p_fileaccess->get_length(), |
| 355 | ERR_FILE_CORRUPT, "ImageLoaderICO: Image data offset exceeds file size."); |
| 356 | |
| 357 | Vector<uint8_t> image_data; |
| 358 | image_data.resize(selected_entry.image_size); |
| 359 | |
| 360 | uint64_t saved_pos = p_fileaccess->get_position(); |
| 361 | p_fileaccess->seek(selected_entry.image_offset); |
| 362 | p_fileaccess->get_buffer(image_data.ptrw(), selected_entry.image_size); |
| 363 | p_fileaccess->seek(saved_pos); |
no test coverage detected