/// <summary> /// Reverses the filtering process done on the decompressed /// datastream to get the unfiltered datastream. /// </summary> /// <param name="filter_type">The type of filtering process done on the section of data.</param> private byte[] unfilter_scanline(Filter_Types filter_type, byte[] filtered_scanline_bytes, byte[] previous_scanline_bytes) { byte[] result = null; switch (filter_type) { case (Filter_Types.SUB): result = unfilter_sub_scanline(filtered_scanline_bytes); break; case (Filter_Types.UP): result = unfilter_up_scanline(filtered_scanline_bytes, previous_scanline_bytes); break; case (Filter_Types.AVERAGE): result = unfilter_avg_scanline(filtered_scanline_bytes, previous_scanline_bytes); break; case (Filter_Types.PAETH): result = unfilter_paeth_scanline(filtered_scanline_bytes, previous_scanline_bytes); break; default: result = new byte[filtered_scanline_bytes.Length - 1]; for (int i = 1; i < filtered_scanline_bytes.Length; i++) { result[i - 1] = filtered_scanline_bytes[i]; } break; } return(result); }
/// <summary> /// Reverses the filtering of the bytes passed in. /// Assumes that the bytes are a one-dimensional array of all of /// the bytes of data. This means that one scanline comes after /// another, and this method uses the stored height/width fields /// of the PNG file decoded to determine when a new scanline is /// reached. Also assumes that the PNG file is valid. /// </summary> /// <param name="decompressed_datastream">The decompressed datastream to be unfiltered.</param> /// <returns>An array of bytes that contains the unfiltered, decompressed datastream's bytes.</returns> private byte[] unfilter_datastream(byte[] decompressed_datastream) { if (!is_valid_png || decompressed_datastream == null) { return(null); } List <byte> unfiltered_bytes = new List <byte>(); // process the first scanline byte[] previous_scanline = new byte[width_p * pixel_width_p + 1]; byte[] current_scanline = new byte[width_p * pixel_width_p + 1]; int byte_index = 0; Filter_Types filter_type = (Filter_Types)decompressed_datastream[byte_index++]; current_scanline[0] = decompressed_datastream_p[0]; // specially handle the first scanline (no previous scanline) and add results to // the unfiltered bytes list for (; byte_index < width_p * pixel_width_p + 1;) { current_scanline[byte_index] = decompressed_datastream[byte_index]; ++byte_index; } byte_index = 0; previous_scanline = unfilter_scanline(filter_type, current_scanline, previous_scanline); foreach (byte scanline_byte in previous_scanline) { unfiltered_bytes.Add(scanline_byte); } // unfilter the other scanlines, and add them to the list for (int i = 1; i < height_p; i++) { int scanline_length = (int)width_p * pixel_width + 1; int first_bit_index = (scanline_length) * i; current_scanline[0] = decompressed_datastream[first_bit_index + byte_index++]; filter_type = (Filter_Types)current_scanline[0]; for (; byte_index < scanline_length;) { current_scanline[byte_index] = decompressed_datastream[first_bit_index + byte_index]; ++byte_index; } previous_scanline = unfilter_scanline(filter_type, current_scanline, previous_scanline); foreach (byte scanline_byte in previous_scanline) { unfiltered_bytes.Add(scanline_byte); } byte_index = 0; } return(unfiltered_bytes.ToArray()); }