I think that some people need a parser for tea leaves of PNG images, if you go into the technical parts, each PNG file consists of a 16-bit signature and chunks, there are many chunks, then they have the same thing:
1) Data size
2) Chunk name
3) Data
4) CRC
and according to my algorithm for finding chunks, which you see below, you can get all the chunks and their data.
The first chunk will always be IHDR in which the basic data of the PNG file will be drawn, namely: width, height, color depth, color type, compression method (always 0), filtering method (always 0), four-line scan. And the last chunk is IEND which has no data.
In order to get all the chunks you need to check every 4 bytes for the presence of a name, get the data size and using it + CRC key the second chunk with the same parameters will be sent, this is how I did it on haxe
public static function parseChunks(code:String):Array<Dynamic> { // Array to store parsed chunks var chunks = []; // Starting index for chunk scanning var currentIndex:Int = 16; // Array of known chunk names and their corresponding hexadecimal representations var chunkName:Array<String> = ["IDAT", "IEND", "IHDR", "PLTE", "bKGD", "cHRM", "gAMA", "hIST", "iCCP", "iTXt", "pHYs", "sBIT", "sPLT", "sRGB", "tEXt", "tRNS", "zTXt"]; var chunkHex:Array<String> = ["49444154", "49454E44", "49484452", "504C5445", "624B4744", "6348524D", "67414D41", "68495354", "69434350", "69545874", "70485973", "73424954", "73504C54", "73524742", "74455874", "74524E53", "7A545874"]; // Loop through the code to find and parse chunks while (currentIndex < code.length + 2) { // Extract 8 characters from the code as a test chunk var testChunk = code.substring(currentIndex, currentIndex + 8); // Check if the test chunk exists in the list of known chunk hexadecimal representations if (chunkHex.indexOf(testChunk) != -1){ // Calculate the size of data for the current chunk var dataSize = Std.parseInt("0x" + code.substring(currentIndex - 8, currentIndex )); // Get the type of the chunk based on its hexadecimal representation var type:String = Bytes.ofHex(testChunk).toString(); // Extract data for the current chunk var data = code.substring(currentIndex + 8, currentIndex + 8 + dataSize * 2); // Extract CRC for the current chunk var crc = code.substring(currentIndex + 8 + dataSize * 2, currentIndex + 16 + dataSize * 2); // Create an object to represent the current chunk and add it to the chunks array var object = { name: testChunk, type: type, dataSize: dataSize, data: data, crc: crc }; chunks.push(object); // Move the current index to the next chunk currentIndex += 16 + dataSize * 2; } else { // Move the current index by 2 if the test chunk is not found currentIndex += 2; } } return chunks; }
and on Rust
// Function to parse chunks from a PNG file fn read_chunks(code: String) -> Result<Vec<Chunk>, io::Error> { // Array to store parsed chunks let mut chunks: Vec<Chunk> = Vec::new(); // Starting index for chunk scanning let mut current_index: usize = 16; // Array of known chunk names and their corresponding hexadecimal representations let chunk_hex: Vec<&str> = vec![ "49444154", "49454E44", "49484452", "504C5445", "624B4744", "6348524D", "67414D41", "68495354", "69434350", "69545874", "70485973", "73424954", "73504C54", "73524742", "74455874", "74524E53", "7A545874" ]; // Loop through the code to find and parse chunks while (current_index as usize) < code.len() { // Extract 8 characters from the code as a test chunk let test_chunk = &code[current_index..current_index + 8]; // Check if the test chunk exists in the list of known chunk hexadecimal representations if let Some(_position) = chunk_hex.iter().position(|&s| s == test_chunk.to_string()) { // Calculate the size of data for the current chunk let hex_string = &code[current_index - 8..current_index]; let data_size: i128 = i128::from_str_radix(hex_string, 16).unwrap(); // Extract data for the current chunk let data = &code[current_index + 8..current_index + 8 + (data_size as usize) * 2]; // Extract CRC for the current chunk let crc = &code[current_index + 8 + (data_size as usize) * 2..current_index + 16 + (data_size as usize) * 2]; // Create a chunk object and add it to the chunks vector let chunk = Chunk { name: test_chunk.to_string(), data_size: data_size, data: data.to_string(), crc: crc.to_string(), }; chunks.push(chunk); // Move the current index to the next chunk current_index += 16 + current_index * 2; } else { // Move the current index by 2 if the test chunk is not found current_index += 2; } } Ok(chunks) }