f | import sys | f | import sys |
| | | |
n | def read_input_data(): | n | def read_bmp_data(): |
| return sys.stdin.buffer.read() | | return sys.stdin.buffer.read() |
| | | |
n | def validate_header(data): | n | def validate_bmp_header(data): |
| if len(data) < 14: | | if len(data) < 14: |
n | return 'Invalid file size' | n | return 'Incorrect size' |
| if data[:2] != b'BM': | | if data[:2] != b'BM': |
| return 'Not a Windows BMP' | | return 'Not a Windows BMP' |
n | total_size = int.from_bytes(data[2:6], 'little') | n | file_size = int.from_bytes(data[2:6], 'little') |
| if total_size != len(data): | | if file_size != len(data): |
| return 'Incorrect size' | | return 'Incorrect size' |
| if len(data) < 18: | | if len(data) < 18: |
n | return 'Incomplete BMP header' | n | return 'Incorrect size' |
| return total_size | | return file_size |
| | | |
n | def analyze_dib_header(data, start_offset): | n | def parse_dib_header(data, offset): |
| dib_size = int.from_bytes(data[start_offset:start_offset + 4], 'litt | | header_size = int.from_bytes(data[offset:offset + 4], 'little') |
| le') | | |
| valid_sizes = [12, 16, 40, 52, 56, 64, 108, 124] | | valid_sizes = [12, 16, 40, 52, 56, 64, 108, 124] |
n | if dib_size not in valid_sizes: | n | if header_size not in valid_sizes: |
| return ('Incorrect header size', None, None, None, None, None) | | return ('Incorrect header size', None, None, None, None, None) |
n | dib_end = start_offset + dib_size | n | end_offset = offset + header_size |
| if len(data) < dib_end: | | if len(data) < end_offset: |
| return ('Incomplete DIB header', None, None, None, None, None) | | return ('Incorrect size', None, None, None, None, None) |
| if dib_size == 12: | | if header_size == 12: |
| img_width = int.from_bytes(data[start_offset + 4:start_offset + | | width = int.from_bytes(data[offset + 4:offset + 6], 'little') |
| 6], 'little') | | |
| img_height = int.from_bytes(data[start_offset + 6:start_offset + | | height = int.from_bytes(data[offset + 6:offset + 8], 'little') |
| 8], 'little') | | |
| bpp = int.from_bytes(data[start_offset + 10:start_offset + 12], | | bpp = int.from_bytes(data[offset + 10:offset + 12], 'little') |
| 'little') | | |
| compression = 0 | | compression = 0 |
n | img_size = 0 | n | image_size = 0 |
| elif dib_size == 16: | | elif header_size == 16: |
| img_width = int.from_bytes(data[start_offset + 4:start_offset + | | width = int.from_bytes(data[offset + 4:offset + 6], 'little', si |
| 6], 'little', signed=True) | | gned=True) |
| img_height = int.from_bytes(data[start_offset + 6:start_offset + | | height = int.from_bytes(data[offset + 6:offset + 8], 'little', s |
| 8], 'little', signed=True) | | igned=True) |
| bpp = int.from_bytes(data[start_offset + 10:start_offset + 12], | | bpp = int.from_bytes(data[offset + 10:offset + 12], 'little') |
| 'little') | | |
| compression = int.from_bytes(data[start_offset + 12:start_offset | | compression = int.from_bytes(data[offset + 12:offset + 16], 'lit |
| + 16], 'little') | | tle') |
| img_size = 0 | | image_size = 0 |
| else: | | else: |
n | img_width = int.from_bytes(data[start_offset + 4:start_offset + | n | width = int.from_bytes(data[offset + 4:offset + 8], 'little', si |
| 8], 'little', signed=True) | | gned=True) |
| img_height = int.from_bytes(data[start_offset + 8:start_offset + | | height = int.from_bytes(data[offset + 8:offset + 12], 'little', |
| 12], 'little', signed=True) | | signed=True) |
| bpp = int.from_bytes(data[start_offset + 14:start_offset + 16], | | bpp = int.from_bytes(data[offset + 14:offset + 16], 'little') |
| 'little') | | |
| compression = int.from_bytes(data[start_offset + 16:start_offset | | compression = int.from_bytes(data[offset + 16:offset + 20], 'lit |
| + 20], 'little') | | tle') |
| img_size = int.from_bytes(data[start_offset + 20:start_offset + | | image_size = int.from_bytes(data[offset + 20:offset + 24], 'litt |
| 24], 'little') | | le') |
| return (None, img_width, img_height, bpp, compression, img_size) | | return (None, width, height, bpp, compression, image_size) |
| | | |
n | def compute_image_size(width, height, bits_per_pixel): | n | def calculate_image_size(width, height, bpp): |
| absolute_width = abs(width) | | abs_width = abs(width) |
| absolute_height = abs(height) | | abs_height = abs(height) |
| bits_in_row = absolute_width * bits_per_pixel | | bits_per_row = abs_width * bpp |
| bytes_in_row = (bits_in_row + 7) // 8 | | bytes_per_row = (bits_per_row + 7) // 8 |
| row_padding = (4 - bytes_in_row % 4) % 4 | | padding = (4 - bytes_per_row % 4) % 4 |
| total_row_size = bytes_in_row + row_padding | | total_row_bytes = bytes_per_row + padding |
| return (absolute_width, absolute_height, total_row_size * absolute_h | | return (abs_width, abs_height, total_row_bytes * abs_height) |
| eight) | | |
| | | |
n | def resolve_placeholder(img_size_actual, img_size_expected): | n | def determine_placeholder(actual_size, expected_size): |
| if img_size_actual == img_size_expected + 2: | | if actual_size == expected_size + 2: |
| return 2 | | return 2 |
n | if img_size_actual in {0, img_size_expected}: | n | if actual_size in {0, expected_size}: |
| return 0 | | return 0 |
| return None | | return None |
| if __name__ == '__main__': | | if __name__ == '__main__': |
n | bmp_content = read_input_data() | n | bmp_data = read_bmp_data() |
| header_validation = validate_header(bmp_content) | | file_validation = validate_bmp_header(bmp_data) |
| if isinstance(header_validation, str): | | if isinstance(file_validation, str): |
| print(header_validation) | | print(file_validation) |
| sys.exit(0) | | sys.exit(0) |
n | err_msg, img_w, img_h, bpp, compress, img_size = analyze_dib_header( | n | error, width, height, bits_per_pixel, compression_method, image_size |
| bmp_content, 14) | | = parse_dib_header(bmp_data, 14) |
| if err_msg: | | if error: |
| print(err_msg) | | print(error) |
| sys.exit(0) | | sys.exit(0) |
n | width_abs, height_abs, computed_size = compute_image_size(img_w, img | n | width_abs, height_abs, calculated_size = calculate_image_size(width, |
| _h, bpp) | | height, bits_per_pixel) |
| placeholder_result = resolve_placeholder(img_size, computed_size) | | placeholder_size = determine_placeholder(image_size, calculated_size |
| | | ) |
| if placeholder_result is None: | | if placeholder_size is None: |
| print('Incorrect image size') | | print('Incorrect image size') |
| sys.exit(0) | | sys.exit(0) |
t | print(f'{width_abs} {height_abs} {bpp} {compress} {placeholder_resul | t | print(f'{width_abs} {height_abs} {bits_per_pixel} {compression_metho |
| t}') | | d} {placeholder_size}') |