| 186 | } |
| 187 | |
| 188 | Error ImageLoaderICO::load_embedded_image(const IconEntry &p_icon_entry, Ref<Image> p_image, const Vector<uint8_t> &p_data, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) { |
| 189 | ERR_FAIL_COND_V_MSG(p_data.is_empty(), ERR_INVALID_DATA, "ImageLoaderICO: Empty image data."); |
| 190 | |
| 191 | // Check if it's PNG (modern ICO files often use PNG) |
| 192 | if (p_data.size() >= 8) { |
| 193 | bool is_png = true; |
| 194 | for (int i = 0; i < 8; i++) { |
| 195 | if (p_data[i] != PNG_SIGNATURE[i]) { |
| 196 | is_png = false; |
| 197 | break; |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | if (is_png) { |
| 202 | Error err = p_image->load_png_from_buffer(p_data); |
| 203 | if (err == OK && !p_image->is_empty()) { |
| 204 | if (p_scale != 1.0 && p_scale > 0.0) { |
| 205 | int new_width = MAX(1, Math::round(p_image->get_width() * p_scale)); |
| 206 | int new_height = MAX(1, Math::round(p_image->get_height() * p_scale)); |
| 207 | p_image->resize(new_width, new_height, Image::INTERPOLATE_LANCZOS); |
| 208 | } |
| 209 | if (p_flags & FLAG_FORCE_LINEAR) { |
| 210 | p_image->srgb_to_linear(); |
| 211 | } |
| 212 | return OK; |
| 213 | } |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | // If it's not PNG, assume it's BMP (ICO spec only allows PNG or BMP) |
| 218 | // Embedded BMP data excludes the BITMAPFILEHEADER, so we need to construct it |
| 219 | if (p_data.size() < BITMAP_INFO_HEADER_MIN_SIZE) { |
| 220 | ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "ImageLoaderICO: Embedded image data is too small to be a valid BMP."); |
| 221 | } |
| 222 | |
| 223 | // Read BITMAPINFOHEADER to get header size and calculate color table |
| 224 | // The embedded BMP data starts with BITMAPINFOHEADER (no BITMAPFILEHEADER) |
| 225 | |
| 226 | bmp_header_s bmp_header; |
| 227 | |
| 228 | Error err = parse_after_file_header(p_data, bmp_header); |
| 229 | ERR_FAIL_COND_V_MSG(err != OK, err, "ImageLoaderICO: Failed to parse the BMP info header."); |
| 230 | |
| 231 | uint32_t info_header_size = bmp_header.bmp_info_header.bmp_header_size; |
| 232 | ERR_FAIL_COND_V_MSG(info_header_size < BITMAP_INFO_HEADER_MIN_SIZE, ERR_FILE_CORRUPT, |
| 233 | "ImageLoaderICO: Invalid BITMAPINFOHEADER size in embedded BMP data."); |
| 234 | |
| 235 | uint16_t bits_per_pixel = bmp_header.bmp_info_header.bmp_bit_count; |
| 236 | uint32_t color_table_size = 0; |
| 237 | if (bits_per_pixel <= 8) { |
| 238 | // Support 256 colors max, 4 bytes per color |
| 239 | color_table_size = (1 << bits_per_pixel) * 4; |
| 240 | } |
| 241 | |
| 242 | bmp_header.bmp_file_header.bmp_signature = BITMAP_SIGNATURE; |
| 243 | bmp_header.bmp_file_header.bmp_file_size = BITMAP_FILE_HEADER_SIZE + p_data.size(); |
| 244 | bmp_header.bmp_file_header.bmp_file_padding = 0; |
| 245 | bmp_header.bmp_file_header.bmp_file_offset = BITMAP_FILE_HEADER_SIZE + info_header_size + color_table_size; |
nothing calls this directly
no test coverage detected