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)
}