# QOI (format d'image)

Le QOI (Quite OK Image) est un format de compression d'images sans perte de 24 bits (8 bits par couleur RVB) ou 32 bits (8 bits par couleur avec le canal alpha de 8 bits RGBA), inventé par Dominic Szablewski et annoncé pour la première fois le 24 novembre 2021.

## Description

L'objectif visé était de créer une méthode de compression d'image sans perte open source, plus rapide et plus facile à mettre en œuvre que PNG. Une vidéo YouTube tierce en anglais explique comment la compression PNG et QOI est effectuée. Les chiffres spécifiés dans l'annonce et la vidéo revendiquent un encodage 20 à 50 fois plus rapide et une vitesse de décodage 3 à 4 fois plus rapide par rapport au PNG, avec des tailles compressées à peine plus lourdes que celles de PNG. Le format appartient au domaine public (CC0).

## Support logiciel et langage

QOI est pris en charge nativement par ImageMagick, IrfanView (à partir de la version 4.60), et FFmpeg (à partir de la version 5.1).
Des plugins créés par la communauté sont disponibles dans GIMP, Paint. NET et XnViewMP.
Il existe également des implémentations pour divers langages tels que Rust, Python, Java, C++, C# et bien d'autres. Une liste complète peut être trouvée sur le référentiel GitHub du projet.

## Format de fichier
### Entête

Un fichier QOI se compose d'un en-tête de 14 octets, suivi d'un nombre quelconque de "morceaux" de données et d'un marqueur de fin de 8 octets.
Les champs espace colorimétrique et canal sont purement informatifs. Ils ne changent pas la façon dont les blocs de données sont encodés.

### Encodage

Les images sont encodées ligne par ligne, de gauche à droite, de haut en bas. Le décodeur et l'encodeur commencent par {r: 0, g: 0, b: 0, a: 255} comme valeur de pixel précédente. Une image est complète lorsque tous les pixels spécifiés par width * height ont été couverts. Les pixels sont encodés comme :
* Codage de longueur d'exécution du pixel précédent ( QOI_OP_RUN )
* un index dans le tableau des pixels vus précédemment ( QOI_OP_INDEX )
* une différence par rapport à la valeur de pixel précédente dans r,g,b ( QOI_OP_DIFF ou QOI_OP_LUMA )
* Valeurs complètes r,g,b ou r,g,b,a ( QOI_OP_RGB ou QOI_OP_RGBA )
Les canaux de couleur sont supposés ne pas être prémultipliés avec le canal alpha (« alpha non prémultiplié »). Un array[64] (initialisé à zéro) de valeurs de pixel vues précédemment est maintenu par l'encodeur et le décodeur. Chaque pixel vu par l'encodeur et le décodeur est placé dans ce tableau à la position formée par une fonction de hachage de la valeur de couleur.
Dans l'encodeur, si la valeur de pixel à l'index correspond au pixel actuel, cette position d'index est écrite dans le flux sous la forme QOI_OP_INDEX . La fonction de hachage de l'index est :
Chaque bloc commence par une balise de 2 ou 8 bits, suivie d'un certain nombre de bits de données. La longueur en bits des morceaux est divisible par 8 - c'est-à-dire que tous les morceaux sont alignés sur les octets. Toutes les valeurs codées dans ces bits de données ont le bit le plus significatif à gauche. Les balises 8 bits ont priorité sur les balises 2 bits. Un décodeur doit d'abord vérifier la présence d'une étiquette de 8 bits. La fin du flux d'octets est marquée par 7 octets 0x00 suivis d'un seul octet 0x01 .
Les morceaux possibles sont :
La valeur alpha reste inchangée par rapport au pixel précédent.
Un encodeur valide ne doit pas émettre 2 blocs QOI_OP_INDEX consécutifs ou plus vers le même index. QOI_OP_RUN doit être utilisé à la place.
La différence avec les valeurs de canal actuelles utilise une opération de bouclage, donc 1 - 2 donnera 255, tandis que 255 + 1 donnera 0.
Les valeurs sont stockées sous forme d'entiers non signés avec un biais de 2. Par exemple − 2 est stocké sous la forme 0 ( b00 ). 1 est stocké en tant que 3 ( b11 ). La valeur alpha reste inchangée par rapport au pixel précédent.
Le canal vert est utilisé pour indiquer le sens général du changement et est codé sur 6 bits. Les canaux rouge et bleu (dr et db) fondent leurs diffs sur la différence du canal vert. C'est-à-dire :
La différence avec les valeurs de canal actuelles utilise une opération de bouclage, donc 10 - 13 donnera 253, tandis que 250 + 7 donnera 1.
Les valeurs sont stockées sous forme d'entiers non signés avec un biais de 32 pour le canal vert et un biais de 8 pour le canal rouge et bleu. La valeur alpha reste inchangée par rapport au pixel précédent.
La longueur d'exécution est stockée avec un biais de − 1. Notez que les longueurs d'exécution 63 et 64 ( b111110 et b111111 ) sont illégales car elles sont occupées par les QOI_OP_RGB et QOI_OP_RGBA.