| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*  image_loader_bmp.cpp                                                 */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*                       This file is part of:                           */ | 
					
						
							|  |  |  | /*                           GODOT ENGINE                                */ | 
					
						
							|  |  |  | /*                      https://godotengine.org                          */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2020-01-01 11:16:22 +01:00
										 |  |  | /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */ | 
					
						
							|  |  |  | /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */ | 
					
						
							| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* Permission is hereby granted, free of charge, to any person obtaining */ | 
					
						
							|  |  |  | /* a copy of this software and associated documentation files (the       */ | 
					
						
							|  |  |  | /* "Software"), to deal in the Software without restriction, including   */ | 
					
						
							|  |  |  | /* without limitation the rights to use, copy, modify, merge, publish,   */ | 
					
						
							|  |  |  | /* distribute, sublicense, and/or sell copies of the Software, and to    */ | 
					
						
							|  |  |  | /* permit persons to whom the Software is furnished to do so, subject to */ | 
					
						
							|  |  |  | /* the following conditions:                                             */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* The above copyright notice and this permission notice shall be        */ | 
					
						
							|  |  |  | /* included in all copies or substantial portions of the Software.       */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ | 
					
						
							|  |  |  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ | 
					
						
							|  |  |  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ | 
					
						
							|  |  |  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ | 
					
						
							|  |  |  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ | 
					
						
							|  |  |  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ | 
					
						
							|  |  |  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "image_loader_bmp.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image, | 
					
						
							|  |  |  | 		const uint8_t *p_buffer, | 
					
						
							|  |  |  | 		const uint8_t *p_color_buffer, | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 		const uint32_t color_table_size, | 
					
						
							| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | 		const bmp_header_s &p_header) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Error err = OK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (p_buffer == NULL) | 
					
						
							|  |  |  | 		err = FAILED; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (err == OK) { | 
					
						
							|  |  |  | 		size_t index = 0; | 
					
						
							| 
									
										
										
										
											2018-10-03 16:13:34 +02:00
										 |  |  | 		size_t width = (size_t)p_header.bmp_info_header.bmp_width; | 
					
						
							|  |  |  | 		size_t height = (size_t)p_header.bmp_info_header.bmp_height; | 
					
						
							|  |  |  | 		size_t bits_per_pixel = (size_t)p_header.bmp_info_header.bmp_bit_count; | 
					
						
							| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 		// Check whether we can load it
 | 
					
						
							| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 		if (bits_per_pixel == 1) { | 
					
						
							|  |  |  | 			// Requires bit unpacking...
 | 
					
						
							|  |  |  | 			ERR_FAIL_COND_V(width % 8 != 0, ERR_UNAVAILABLE); | 
					
						
							|  |  |  | 			ERR_FAIL_COND_V(height % 8 != 0, ERR_UNAVAILABLE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} else if (bits_per_pixel == 4) { | 
					
						
							|  |  |  | 			// Requires bit unpacking...
 | 
					
						
							|  |  |  | 			ERR_FAIL_COND_V(width % 2 != 0, ERR_UNAVAILABLE); | 
					
						
							|  |  |  | 			ERR_FAIL_COND_V(height % 2 != 0, ERR_UNAVAILABLE); | 
					
						
							| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 		} else if (bits_per_pixel == 16) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ERR_FAIL_V(ERR_UNAVAILABLE); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 		// Image data (might be indexed)
 | 
					
						
							|  |  |  | 		PoolVector<uint8_t> data; | 
					
						
							|  |  |  | 		int data_len = 0; | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 		if (bits_per_pixel <= 8) { // indexed
 | 
					
						
							|  |  |  | 			data_len = width * height; | 
					
						
							|  |  |  | 		} else { // color
 | 
					
						
							|  |  |  | 			data_len = width * height * 4; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ERR_FAIL_COND_V(data_len == 0, ERR_BUG); | 
					
						
							|  |  |  | 		err = data.resize(data_len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		PoolVector<uint8_t>::Write data_w = data.write(); | 
					
						
							|  |  |  | 		uint8_t *write_buffer = data_w.ptr(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		const uint32_t width_bytes = width * bits_per_pixel / 8; | 
					
						
							|  |  |  | 		const uint32_t line_width = (width_bytes + 3) & ~3; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// The actual data traversal is determined by
 | 
					
						
							|  |  |  | 		// the data width in case of 8/4/1 bit images
 | 
					
						
							|  |  |  | 		const uint32_t w = bits_per_pixel >= 24 ? width : width_bytes; | 
					
						
							|  |  |  | 		const uint8_t *line = p_buffer + (line_width * (height - 1)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (uint64_t i = 0; i < height; i++) { | 
					
						
							|  |  |  | 			const uint8_t *line_ptr = line; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for (unsigned int j = 0; j < w; j++) { | 
					
						
							|  |  |  | 				switch (bits_per_pixel) { | 
					
						
							|  |  |  | 					case 1: { | 
					
						
							|  |  |  | 						uint8_t color_index = *line_ptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						write_buffer[index + 0] = (color_index >> 7) & 1; | 
					
						
							|  |  |  | 						write_buffer[index + 1] = (color_index >> 6) & 1; | 
					
						
							|  |  |  | 						write_buffer[index + 2] = (color_index >> 5) & 1; | 
					
						
							|  |  |  | 						write_buffer[index + 3] = (color_index >> 4) & 1; | 
					
						
							|  |  |  | 						write_buffer[index + 4] = (color_index >> 3) & 1; | 
					
						
							|  |  |  | 						write_buffer[index + 5] = (color_index >> 2) & 1; | 
					
						
							|  |  |  | 						write_buffer[index + 6] = (color_index >> 1) & 1; | 
					
						
							|  |  |  | 						write_buffer[index + 7] = (color_index >> 0) & 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						index += 8; | 
					
						
							|  |  |  | 						line_ptr += 1; | 
					
						
							|  |  |  | 					} break; | 
					
						
							|  |  |  | 					case 4: { | 
					
						
							|  |  |  | 						uint8_t color_index = *line_ptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						write_buffer[index + 0] = (color_index >> 4) & 0x0f; | 
					
						
							|  |  |  | 						write_buffer[index + 1] = color_index & 0x0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						index += 2; | 
					
						
							|  |  |  | 						line_ptr += 1; | 
					
						
							|  |  |  | 					} break; | 
					
						
							|  |  |  | 					case 8: { | 
					
						
							|  |  |  | 						uint8_t color_index = *line_ptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						write_buffer[index] = color_index; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						index += 1; | 
					
						
							|  |  |  | 						line_ptr += 1; | 
					
						
							|  |  |  | 					} break; | 
					
						
							|  |  |  | 					case 24: { | 
					
						
							|  |  |  | 						uint32_t color = *((uint32_t *)line_ptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						write_buffer[index + 2] = color & 0xff; | 
					
						
							|  |  |  | 						write_buffer[index + 1] = (color >> 8) & 0xff; | 
					
						
							|  |  |  | 						write_buffer[index + 0] = (color >> 16) & 0xff; | 
					
						
							|  |  |  | 						write_buffer[index + 3] = 0xff; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						index += 4; | 
					
						
							|  |  |  | 						line_ptr += 3; | 
					
						
							|  |  |  | 					} break; | 
					
						
							|  |  |  | 					case 32: { | 
					
						
							|  |  |  | 						uint32_t color = *((uint32_t *)line_ptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						write_buffer[index + 2] = color & 0xff; | 
					
						
							|  |  |  | 						write_buffer[index + 1] = (color >> 8) & 0xff; | 
					
						
							|  |  |  | 						write_buffer[index + 0] = (color >> 16) & 0xff; | 
					
						
							|  |  |  | 						write_buffer[index + 3] = color >> 24; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						index += 4; | 
					
						
							|  |  |  | 						line_ptr += 4; | 
					
						
							|  |  |  | 					} break; | 
					
						
							| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 			line -= line_width; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 		if (p_color_buffer == NULL || color_table_size == 0) { // regular pixels
 | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 			p_image->create(width, height, 0, Image::FORMAT_RGBA8, data); | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 		} else { // data is in indexed format, extend it
 | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 			// Palette data
 | 
					
						
							|  |  |  | 			PoolVector<uint8_t> palette_data; | 
					
						
							|  |  |  | 			palette_data.resize(color_table_size * 4); | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 			PoolVector<uint8_t>::Write palette_data_w = palette_data.write(); | 
					
						
							|  |  |  | 			uint8_t *pal = palette_data_w.ptr(); | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 			const uint8_t *cb = p_color_buffer; | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 			for (unsigned int i = 0; i < color_table_size; ++i) { | 
					
						
							|  |  |  | 				uint32_t color = *((uint32_t *)cb); | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 				pal[i * 4 + 0] = (color >> 16) & 0xff; | 
					
						
							|  |  |  | 				pal[i * 4 + 1] = (color >> 8) & 0xff; | 
					
						
							|  |  |  | 				pal[i * 4 + 2] = (color)&0xff; | 
					
						
							|  |  |  | 				pal[i * 4 + 3] = 0xff; | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 				cb += 4; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// Extend palette to image
 | 
					
						
							|  |  |  | 			PoolVector<uint8_t> extended_data; | 
					
						
							|  |  |  | 			extended_data.resize(data.size() * 4); | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 			PoolVector<uint8_t>::Write ex_w = extended_data.write(); | 
					
						
							|  |  |  | 			uint8_t *dest = ex_w.ptr(); | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 			const int num_pixels = width * height; | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 			for (int i = 0; i < num_pixels; i++) { | 
					
						
							|  |  |  | 				dest[0] = pal[write_buffer[i] * 4 + 0]; | 
					
						
							|  |  |  | 				dest[1] = pal[write_buffer[i] * 4 + 1]; | 
					
						
							|  |  |  | 				dest[2] = pal[write_buffer[i] * 4 + 2]; | 
					
						
							|  |  |  | 				dest[3] = pal[write_buffer[i] * 4 + 3]; | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 				dest += 4; | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-09-22 18:45:08 +02:00
										 |  |  | 			p_image->create(width, height, 0, Image::FORMAT_RGBA8, extended_data); | 
					
						
							| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f, | 
					
						
							|  |  |  | 		bool p_force_linear, float p_scale) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bmp_header_s bmp_header; | 
					
						
							|  |  |  | 	Error err = ERR_INVALID_DATA; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-22 15:10:18 +01:00
										 |  |  | 	// A valid bmp file should always at least have a
 | 
					
						
							|  |  |  | 	// file header and a minimal info header
 | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 	if (f->get_len() > BITMAP_FILE_HEADER_SIZE + BITMAP_INFO_HEADER_MIN_SIZE) { | 
					
						
							| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | 		// File Header
 | 
					
						
							|  |  |  | 		bmp_header.bmp_file_header.bmp_signature = f->get_16(); | 
					
						
							|  |  |  | 		if (bmp_header.bmp_file_header.bmp_signature == BITMAP_SIGNATURE) { | 
					
						
							|  |  |  | 			bmp_header.bmp_file_header.bmp_file_size = f->get_32(); | 
					
						
							|  |  |  | 			bmp_header.bmp_file_header.bmp_file_padding = f->get_32(); | 
					
						
							|  |  |  | 			bmp_header.bmp_file_header.bmp_file_offset = f->get_32(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Info Header
 | 
					
						
							|  |  |  | 			bmp_header.bmp_info_header.bmp_header_size = f->get_32(); | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 			ERR_FAIL_COND_V(bmp_header.bmp_info_header.bmp_header_size < BITMAP_INFO_HEADER_MIN_SIZE, ERR_FILE_CORRUPT); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | 			bmp_header.bmp_info_header.bmp_width = f->get_32(); | 
					
						
							|  |  |  | 			bmp_header.bmp_info_header.bmp_height = f->get_32(); | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | 			bmp_header.bmp_info_header.bmp_planes = f->get_16(); | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 			ERR_FAIL_COND_V(bmp_header.bmp_info_header.bmp_planes != 1, ERR_FILE_CORRUPT); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | 			bmp_header.bmp_info_header.bmp_bit_count = f->get_16(); | 
					
						
							|  |  |  | 			bmp_header.bmp_info_header.bmp_compression = f->get_32(); | 
					
						
							|  |  |  | 			bmp_header.bmp_info_header.bmp_size_image = f->get_32(); | 
					
						
							|  |  |  | 			bmp_header.bmp_info_header.bmp_pixels_per_meter_x = f->get_32(); | 
					
						
							|  |  |  | 			bmp_header.bmp_info_header.bmp_pixels_per_meter_y = f->get_32(); | 
					
						
							|  |  |  | 			bmp_header.bmp_info_header.bmp_colors_used = f->get_32(); | 
					
						
							|  |  |  | 			bmp_header.bmp_info_header.bmp_important_colors = f->get_32(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-17 20:28:35 +03:00
										 |  |  | 			switch (bmp_header.bmp_info_header.bmp_compression) { | 
					
						
							|  |  |  | 				case BI_RLE8: | 
					
						
							|  |  |  | 				case BI_RLE4: | 
					
						
							|  |  |  | 				case BI_CMYKRLE8: | 
					
						
							|  |  |  | 				case BI_CMYKRLE4: { | 
					
						
							|  |  |  | 					// Stop parsing
 | 
					
						
							| 
									
										
										
										
											2019-08-11 10:49:53 +02:00
										 |  |  | 					String bmp_path = f->get_path(); | 
					
						
							| 
									
										
										
										
											2019-07-17 20:28:35 +03:00
										 |  |  | 					f->close(); | 
					
						
							| 
									
										
										
										
											2019-08-11 10:49:53 +02:00
										 |  |  | 					ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Compressed BMP files are not supported: " + bmp_path + "."); | 
					
						
							| 
									
										
										
										
											2019-07-17 20:28:35 +03:00
										 |  |  | 				} break; | 
					
						
							| 
									
										
										
										
											2018-12-22 15:10:18 +01:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 			// Don't rely on sizeof(bmp_file_header) as structure padding
 | 
					
						
							|  |  |  | 			// adds 2 bytes offset leading to misaligned color table reading
 | 
					
						
							|  |  |  | 			uint32_t ct_offset = BITMAP_FILE_HEADER_SIZE + | 
					
						
							|  |  |  | 								 bmp_header.bmp_info_header.bmp_header_size; | 
					
						
							|  |  |  | 			f->seek(ct_offset); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			uint32_t color_table_size = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// bmp_colors_used may report 0 despite having a color table
 | 
					
						
							|  |  |  | 			// for 4 and 1 bit images, so don't rely on this information
 | 
					
						
							|  |  |  | 			if (bmp_header.bmp_info_header.bmp_bit_count <= 8) { | 
					
						
							|  |  |  | 				// Support 256 colors max
 | 
					
						
							|  |  |  | 				color_table_size = 1 << bmp_header.bmp_info_header.bmp_bit_count; | 
					
						
							| 
									
										
										
										
											2019-07-17 01:43:33 +03:00
										 |  |  | 				ERR_FAIL_COND_V(color_table_size == 0, ERR_BUG); | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			PoolVector<uint8_t> bmp_color_table; | 
					
						
							| 
									
										
										
										
											2019-06-20 16:59:48 +02:00
										 |  |  | 			// Color table is usually 4 bytes per color -> [B][G][R][0]
 | 
					
						
							| 
									
										
										
										
											2019-06-26 15:08:25 +02:00
										 |  |  | 			bmp_color_table.resize(color_table_size * 4); | 
					
						
							| 
									
										
										
										
											2019-06-20 16:59:48 +02:00
										 |  |  | 			PoolVector<uint8_t>::Write bmp_color_table_w = bmp_color_table.write(); | 
					
						
							|  |  |  | 			f->get_buffer(bmp_color_table_w.ptr(), color_table_size * 4); | 
					
						
							| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			f->seek(bmp_header.bmp_file_header.bmp_file_offset); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			uint32_t bmp_buffer_size = (bmp_header.bmp_file_header.bmp_file_size - | 
					
						
							|  |  |  | 										bmp_header.bmp_file_header.bmp_file_offset); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			PoolVector<uint8_t> bmp_buffer; | 
					
						
							|  |  |  | 			err = bmp_buffer.resize(bmp_buffer_size); | 
					
						
							|  |  |  | 			if (err == OK) { | 
					
						
							|  |  |  | 				PoolVector<uint8_t>::Write bmp_buffer_w = bmp_buffer.write(); | 
					
						
							|  |  |  | 				f->get_buffer(bmp_buffer_w.ptr(), bmp_buffer_size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				PoolVector<uint8_t>::Read bmp_buffer_r = bmp_buffer.read(); | 
					
						
							|  |  |  | 				PoolVector<uint8_t>::Read bmp_color_table_r = bmp_color_table.read(); | 
					
						
							|  |  |  | 				err = convert_to_image(p_image, bmp_buffer_r.ptr(), | 
					
						
							| 
									
										
										
										
											2019-04-21 15:49:49 +03:00
										 |  |  | 						bmp_color_table_r.ptr(), color_table_size, bmp_header); | 
					
						
							| 
									
										
										
										
											2018-04-30 01:25:46 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			f->close(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ImageLoaderBMP::get_recognized_extensions( | 
					
						
							|  |  |  | 		List<String> *p_extensions) const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p_extensions->push_back("bmp"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ImageLoaderBMP::ImageLoaderBMP() {} |