Rust Library for a custom animated image file format that I created for my a fun "TV Head" cosplay project. It is also the project that I'm gonna be using for my undergraduate thesis. Yes, I know it is a strange name, it will probably be changed in the future.
[Video that shows "prototipo file" working] (old C++ Code)
- Pixels are stored in a Color table called Palletes, just like gif files.
- The way of indexing a color from a color table changes depending on how many colors there are. So if the pallete contains only 2 colors, indexes will be stored in 1 bit, if it contains 4 colors, it will be stored in 2 bits. it will increase bit by bit, like: 3 bits, 4 bits, 5 bits, 6 bits... 1 byte and 2 bits, it just goes until it hits 4 bytes, then it stops. In this way it will be guaranteed it will only spend the necessary.
This is just an example it might be changed in the future!!!
//This is a RON representation of how the still image works, THIS ONE HAS BETTER DETAILS
//same as QOI Run! If the current pixel is the same as the before it will check every pixel in front of it to check if it is still the same. Then it will register how much times it repeated
//RUN(times_repeated)
//LZSS(OFFSET, LENGTH) //USE THIS ONE TO MAKE FRAMES STOP
//It will copy the last pixel and change its value according to the specified rules.
//DIFF(difference_red, difference_green, difference_blue)
//HASH(Index) //THIS NEEDS a way to put them in an array in a fastest way!!!
File(
header: "VAF"
width: 0x0015,
height: 0x0001,
// If this is true then "frames" will be an array of struct Frame, when its not it will have just one element.
is_animated: false,
// If this is true, then a pixel will take 4 bytes instead of only 3 bytes.
has_alpha_channel: true,
//how many times the height and the width is divided. The size of the chunk.
//2 bytes
//can divide a screen by 4 times, resulting into 8 different chunk by row or column.
//Maximum capacity of chunks is: 64 chunks
chunks_x: 0b00,// 1
chunks_y: 0b00,// 1
//In this case the image is SO small it only contains 1 chunk
//As there is only 4 different colours there's no need to spend more than 2 bits for each index.
//stored in a 5 bit space as this represent the quantity of bits in a 4 byte space (32).
//https://en.wikipedia.org/wiki/Color_depth
colors_quantity: 0b00010// as there will always be a color, 0b0 must represent 1 instead of 0.
pallete: [
Color{r: 0xFF, g: 0x00, b: 0x95, a: 0xFF},
Color{r: 0x00, g: 0xB9, b: 0xF2, a: 0xFF},
Color{r: 0xFA, g: 0xD5, b: 0x00, a: 0xFF},
Color{r: 0x00, g: 0x00, b: 0x00, a: 0x00}
]
is_animated: false,
frames:[
Frame{.
chunks: [
Chunk{
index: 0 // First chunk 1 byte
pallet_id : 0
pixels: [Hash(0b11), Hash(0b00), Hash(0b01), Hash(0b10),
LZSS(0100, 1101)] //
}
],
},
]
)
//This is a RON representation of how the animated file works.
File(
...
is_animated: true,
...
frames:[
Frame{
chunks: [
Chunk{
pallet_id : 0
pixels: [Hash(0b11), Hash(0b00), Hash(0b01), Hash(0b10),
LZSS(0100, 1101)]
}
],
//The delay is in a hundreth of a second
delay_frame_end: 100
},
Frame{
chunks: [
Chunk{
pallet_id : 0
pixels: [Hash(0b00), Hash(0b01), Hash(0b10), Hash(0b11),
LZSS(0100, 1101)]
}
],
delay_frame_end: 100
},
Frame{
chunks: [
Chunk{
pallet_id : 0
pixels: [Hash(0b01), Hash(0b10), Hash(0b11), Hash(0b00),
LZSS(0100, 1101)]
}
],
delay_frame_end: 100
},
Frame{
chunks: [
Chunk{
pallet_id : 0
pixels: [Hash(0b10), Hash(0b11), Hash(0b00), Hash(0b01),
LZSS(0100, 1101)]
}
],
delay_frame_end: 100
}
chunks_x: 1, //4 bytes
chunks_y: 1, //4 bytes
]
)
Byte Size | Content | Meaning | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
3 | 56 41 46 (ASCII for VAF) | Header | ||||||||
2 | Ex: 0x0438 (1080) | Image Width | ||||||||
2 | Ex: 0x02D0 (720) | Image Height | ||||||||
1 |
|
Global configuration | ||||||||
... | Palettes | |||||||||
... | Chunks |
Byte Size | Content | Meaning | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
3 | 56 41 46 (ASCII for VAF) | Header | ||||||||
2 | Ex: 0x0438 (1080) | Image Width | ||||||||
2 | Ex: 0x02D0 (720) | Image Height | ||||||||
1 |
|
Global configuration |
This is repeated a lot throughout the file.
3 bit for color quantity
https://en.wikipedia.org/wiki/GIF#True_color
Existem alguns problemas com esse método:
- O número de chunks precisa ter o mesmo número de cores na paleta? R: Não, elas devem variar de forma independente, ou seja, algumas chunks podem ter mais ou menos cores independendo das outras.
- Como saber o número ideal de chunks em uma imagem qualquer? R: As chunks poderiam começar por um número pré-definido e se subdividirem em chunks menores caso o numero de cores em uma certa chunk exceda o limite de 65,535 cores (2 Bytes)
- Uma paleta de uma chunk deve repetir mais de uma vez em caso de repetição extrema? R:SIM! Paletas devem possuir seus proprios identificadores.
As paletas serão declaradas individualmente das chunks de exibição, pois dessa forma haverá garantia que todas as chunks terão acesso a todas as paletas de cores.
- As chunks são REALMENTE necessárias se a ideia é usar menos do que 4 bytes? R: Em partes, sim! pois uma foto pode haver MUUUITAS cores de um lado e poucas do outro lado
Inspiration:
- https://bitbeamcannon.com/nes-graphical-specs/
- https://en.wikipedia.org/wiki/GIF
- https://en.wikipedia.org/wiki/PNG
- https://youtu.be/EFUYNoFRHQI?t=1416 (How PNG Works: Compromising Speed for Quality)
- https://en.wikipedia.org/wiki/QOI_(image_format)