def parse_ffdb(bytes_array: BytesArray, image_info: ImageInfo): # таблицы квантования ff_db_indexes = bytes_array.find_all_pairs("ff", "db") if ff_db_indexes == -1: raise BadMarkerException header_size = 3 zig_zag = ZigZag() for ff_db_index in ff_db_indexes: ff_db_index += SECTION_TITLE_SIZE header = bytes_array[ff_db_index:ff_db_index + header_size] ff_db_size = int(header[0] + header[1], 16) ff_db_data = bytes_array[ff_db_index:ff_db_index + ff_db_size] ff_db_data_index = 0 values_length = int(ff_db_data[ff_db_data_index + 2][0], 16) if values_length != 0: raise BadQuantizationValuesLength quantization_table_id = int(ff_db_data[ff_db_data_index + 2][1], 16) quantization_table_index = ff_db_data_index + 3 quantization_arr = ff_db_data[quantization_table_index:] quantization_table = zig_zag.zig_zag_order(quantization_arr) image_info.add_quantization_table( QuantizationTable(quantization_table_id, quantization_table))
def parse_ffda(bytes_array: BytesArray, image_info: ImageInfo): # start of scan ffda_data = bytes_array.read_from_one_pair_to_other("ffda", "ffd9") header_length = int( ffda_data[2] + ffda_data[3], 16 ) # в первых ьдвух байтах длина только для заголовочной части а не для всей секции ffda_header_data = ffda_data[SECTION_TITLE_SIZE:header_length] ffda_header_index = 0 amount_of_components = int(ffda_header_data[ffda_header_index + 2], 16) if amount_of_components != 3: raise BadComponentsAmountException components_index = ffda_header_index + 3 for i in range(0, amount_of_components): component_id = int(ffda_header_data[components_index], 16) dc_table_id = int(ffda_header_data[components_index + 1][1]) ac_table_id = int(ffda_header_data[components_index + 1][0]) component = image_info.get_component_by_id(component_id) component.dc_haff_table_id = dc_table_id component.ac_haff_table_id = ac_table_id components_index += 2 # берем данные и переводим в двоичную строку(0111010...) coded_data = ffda_data[(header_length + 2):] coded_data_binary = hex_to_binary(coded_data) parse_channels(image_info, coded_data_binary)
def quantization(image_info: ImageInfo): for comp in image_info.components: quantization_table_id = comp.quantization_table_id quantization_table = image_info.get_quantization_table_by_id( quantization_table_id) for i, block in enumerate(comp.array_of_blocks): comp.array_of_blocks[i] = multiply_2d_matrixes( block, quantization_table.table)
def parse_channels(image_info: ImageInfo, coded_data_binary: str): y_comp_index = 1 cb_comp_index = 2 cr_comp_index = 3 y_component = image_info.get_component_by_id(y_comp_index) cb_component = image_info.get_component_by_id(cb_comp_index) cr_component = image_info.get_component_by_id(cr_comp_index) arr_for_index = [0] y_amount, cb_amount, cr_amount = 0, 0, 0 counter = 0 try: while y_amount < y_component.blocks_amount and\ cb_amount < cb_component.blocks_amount and cr_amount < cr_component.blocks_amount: for i in range(0, y_component.k_ratio): if y_amount >= y_component.blocks_amount: break parse_channel(coded_data_binary, y_component, image_info, arr_for_index) y_amount += 1 counter += 1 for j in range(0, cb_component.k_ratio): if cb_amount >= cb_component.blocks_amount: break parse_channel(coded_data_binary, cb_component, image_info, arr_for_index) for k in range(0, cr_component.k_ratio): if cr_amount >= cr_component.blocks_amount: break parse_channel(coded_data_binary, cr_component, image_info, arr_for_index) except EndException: pass length_of_data = len(coded_data_binary) length_index = arr_for_index[0] if arr_for_index[0] != len(coded_data_binary) - 1: print("length_of_data: " + str(length_of_data) + " length_index: " + str(length_index)) for comp in image_info.components: comp.substract_dc()
def parse_ffc0(bytes_array: BytesArray, image_info: ImageInfo): # Информация о картинке(р - ры) ff_c0_index = bytes_array.find_pair("ff", "c0") if ff_c0_index == -1: ff_c0_index = bytes_array.find_pair("ff", "c2") # raise NotBaseMethodOfCodingException header_index = ff_c0_index + SECTION_TITLE_SIZE ff_db_size = int(bytes_array[header_index] + bytes_array[header_index + 1], 16) ff_c0_data = bytes_array[header_index:header_index + ff_db_size] ff_db_data_index = 0 channel_dimension = int(ff_c0_data[ff_db_data_index + 2], 16) if channel_dimension != 8: raise BadDimensionException image_size_index = ff_db_data_index + 3 image_height = int( ff_c0_data[image_size_index] + ff_c0_data[image_size_index + 1], 16) image_width = int( ff_c0_data[image_size_index + 2] + ff_c0_data[image_size_index + 3], 16) image_info.width = image_width image_info.height = image_height channels_amount_index = ff_db_data_index + 7 channels_amount = int(ff_c0_data[channels_amount_index], 16) if channels_amount != 3: raise BadChannelsAmountException image_info.channels_amount = channels_amount channel_data_size = 3 channel_info_index = channels_amount_index + 1 max_horizontal_thinning = 0 max_vertical_thinning = 0 for i in range(0, channels_amount): channel_data = ff_c0_data[channel_info_index:channel_info_index + channel_data_size] component_id = int(channel_data[0], 16) horizontal_thinning = int(channel_data[1][0], 16) vertical_thinning = int(channel_data[1][1], 16) k_ratio = 1 if component_id == 1: k_ratio = horizontal_thinning * vertical_thinning max_horizontal_thinning = horizontal_thinning max_vertical_thinning = vertical_thinning horizontal_thinning = max_horizontal_thinning // horizontal_thinning vertical_thinning = max_vertical_thinning // vertical_thinning quantization_table_id = int(channel_data[2], 16) image_info.add_component( Component(component_id, horizontal_thinning, vertical_thinning, quantization_table_id, image_info.width, image_info.height, k_ratio)) channel_info_index += 3 image_info.set_new_size()
def parse_fffe(bytes_array: BytesArray, image_info: ImageInfo): # комментарий ff_ee_start = 2 if bytes_array[ff_ee_start] + bytes_array[ff_ee_start + 1] != 'fffe' \ or bytes_array[ff_ee_start] + bytes_array[ff_ee_start + 1] != 'ffe0': # raise BadMarkerException pass ff_ee_header_size = 2 comment = bytes_array.read_n_bytes(ff_ee_start + SECTION_TITLE_SIZE, ff_ee_header_size) comment = comment[2:] image_info.comment = comment
def y_cb_cr_to_rgb(image_info: ImageInfo): y_comp_index = 1 cb_comp_index = 2 cr_comp_index = 3 y_component = image_info.get_component_by_id(y_comp_index) cb_component = image_info.get_component_by_id(cb_comp_index) cr_component = image_info.get_component_by_id(cr_comp_index) rgb_components_array = [] if y_component.k_ratio == 4 and cb_component.k_ratio == 1 and cr_component.k_ratio == 1: convert_by_blocks(y_component, cb_component, cr_component, rgb_components_array, 1) elif y_component.k_ratio == 1 and cb_component.k_ratio == 1 and cr_component.k_ratio == 1: for i in range(0, y_component.blocks_amount): rgb_component = convert_ycbcr_to_rgb( y_component.array_of_blocks[i], cb_component.array_of_blocks[i], cr_component.array_of_blocks[i], 0, 2) rgb_components_array.append(rgb_component) else: raise BadComponentsAmountException return rgb_components_array
def merge_rgb_blocks(rgb_components_array: [], image_info: ImageInfo): y_comp_index = 1 y_component = image_info.get_component_by_id(y_comp_index) m_cols = 0 m_rows = 0 if y_component.k_ratio == 4: m_cols = int(y_component.horizontal_blocks / (y_component.k_ratio / 2)) m_rows = int(y_component.vertical_blocks / (y_component.k_ratio / 2)) elif y_component.k_ratio == 1: m_cols = int(y_component.horizontal_blocks) m_rows = int(y_component.vertical_blocks) rows = [] for i in range(0, m_rows): #filling one row of matrixes one_row = [] for j in range(0, m_cols): first = rgb_components_array.pop(0) one_row.append(first) while len(one_row) > 1: first = one_row.pop(0) second = one_row.pop(0) first_second_conc = append_right(first, second) new_arr = [] new_arr.append(first_second_conc) for mass in one_row: new_arr.append(mass) one_row = new_arr rows.append(one_row[0]) result_matrix = rows while len(result_matrix) > 1: first = result_matrix.pop(0) second = result_matrix.pop(0) first_second_conc = append_down(first, second) new_arr = [] new_arr.append(first_second_conc) for mass in result_matrix: new_arr.append(mass) result_matrix = new_arr result_matrix = np.asarray(result_matrix[0], dtype=np.uint8) return result_matrix
def decode_image(file_name: str) -> (): with open(file_name, "rb") as f: img = f.read() bytes_array = BytesArray(img) image_info = ImageInfo() # для результата parse_ffd8(bytes_array) parse_fffe(bytes_array, image_info) parse_ffdb(bytes_array, image_info) parse_ffc0(bytes_array, image_info) parse_ffc4(bytes_array, image_info) parse_ffda(bytes_array, image_info) quantization(image_info) i_dct(image_info) rgb_components_array = y_cb_cr_to_rgb(image_info) result_matrix = merge_rgb_blocks(rgb_components_array, image_info) result_matrix = cut_image(result_matrix) return result_matrix, image_info
parse_ffc4(bytes_array, image_info) parse_ffda(bytes_array, image_info) quantization(image_info) i_dct(image_info) rgb_components_array = y_cb_cr_to_rgb(image_info) result_matrix = merge_rgb_blocks(rgb_components_array, image_info) result_matrix = cut_image(result_matrix) return result_matrix, image_info if __name__ == "__main__": cur_path = os.path.dirname(__file__) with open(cur_path + "/images/vodopad.jpg", "rb") as f: img = f.read() bytes_array = BytesArray(img) image_info = ImageInfo() # для результата parse_ffd8(bytes_array) parse_fffe(bytes_array, image_info) parse_ffdb(bytes_array, image_info) parse_ffc0(bytes_array, image_info) parse_ffc4(bytes_array, image_info) parse_ffda(bytes_array, image_info) quantization(image_info) i_dct(image_info) rgb_components_array = y_cb_cr_to_rgb(image_info) result_matrix = merge_rgb_blocks(rgb_components_array, image_info) result_matrix = cut_image(result_matrix) imshow(result_matrix) plt.show()