From 68b61139b8b4390f42f5ebf12fe93248239138fd Mon Sep 17 00:00:00 2001 From: Geoffrey Frogeye Date: Mon, 19 May 2014 17:37:00 +0200 Subject: [PATCH] Avancement sur l'ouverture et la fermeture de fichiers (demi-commit) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contient les travaux de la séance du 19/05/2014 ainsi que de précédents travaux * traitementImage.cpp * Ajout de la détection de l'en-tête et de ses informations dans la fonction ouvrir() * Ajout de la fonction sauver() (non-fonctionelle) * Mise en commentaire de la fonction trait() pour le moment * Correction des fonctions cercle(), disque() et redimensionner() (non-testées) * Ajout d'un fichier utilitaires.cpp * Fonction presentation() qui montre un joli ASCII art * Déplacement de imageDefaut() * Déplacement de chaineVersXXX() * testing.cpp * Ajout d'un dossier tests avec différentes images de test * Ajout d'instructions pour tester l'ouverture et la sauvegarde de fichiers --- .gitattributes | 15 +- src/analyserCommande.cpp | 16 -- src/main.cpp | 60 +------- src/testing.cpp | 30 ++-- src/traitementImage.cpp | 311 ++++++++++++++++++++++++++------------- src/utilitaires.cpp | 82 +++++++++++ tests/.gitignore | 3 + tests/PikachuP1.pbm | Bin 0 -> 4202 bytes tests/PikachuP2.pgm | Bin 0 -> 16189 bytes tests/PikachuP3.ppm | Bin 0 -> 46840 bytes tests/PikachuP4.pbm | Bin 0 -> 560 bytes tests/PikachuP5.pgm | Bin 0 -> 4148 bytes tests/PikachuP6.ppm | Bin 0 -> 12340 bytes 13 files changed, 329 insertions(+), 188 deletions(-) create mode 100644 src/utilitaires.cpp create mode 100644 tests/.gitignore create mode 100644 tests/PikachuP1.pbm create mode 100644 tests/PikachuP2.pgm create mode 100644 tests/PikachuP3.ppm create mode 100644 tests/PikachuP4.pbm create mode 100644 tests/PikachuP5.pgm create mode 100644 tests/PikachuP6.ppm diff --git a/.gitattributes b/.gitattributes index 412eeda..705c150 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12,11 +12,16 @@ # Standard to msysgit *.doc diff=astextplain *.DOC diff=astextplain -*.docx diff=astextplain -*.DOCX diff=astextplain -*.dot diff=astextplain -*.DOT diff=astextplain -*.pdf diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain + +# Personalisé +*.pbm binary +*.pgm binary +*.ppm binary \ No newline at end of file diff --git a/src/analyserCommande.cpp b/src/analyserCommande.cpp index 1cc4d7c..0e07d3c 100644 --- a/src/analyserCommande.cpp +++ b/src/analyserCommande.cpp @@ -2,22 +2,6 @@ #include #include -int chaineVersEntier(string chaine, int &entier) { - entier = atoi(chaine.c_str()); - if (entier == 0 && chaine != "0") { - return 1; - } - return 0; -} - -int chaineVersFlottant(string chaine, float &flottant) { - flottant = atof(chaine.c_str()); - if (flottant == 0 && chaine != "0") { - return 1; - } - return 0; -} - void afficherImage(Image image) { int x, y, r, v, b, dimensionX = image.g_dimensionX(), dimensionY = image.g_dimensionY(), typeComposantes = image.g_typeComposantes(); diff --git a/src/main.cpp b/src/main.cpp index 1089307..ddac7b8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,75 +4,19 @@ using namespace std; #include "affichageFenetre.cpp" #include "image.h" +#include "utilitaires.cpp" #include "traitementImage.cpp" #include "analyserCommande.cpp" #define NOMBREOR 1.61803398875 -Image imageDefaut() { - int dimY = 256, dimX = dimY * NOMBREOR, maxComposante = 255; - Image imageRoue(dimX, dimY, maxComposante, PILG_RVB); - Pixel pointRoue = imageRoue.g_pixelVide(); - int x, y, step; - float substep, lum; - for (x = 0; x < dimX; x++) { - for (y = 0; y < dimY; y++) { - step = (x * 6.0) / dimX; - substep = (x - step * (dimX / 6.0)) / (dimX / 6.0) * maxComposante; - lum = 1 - ((float) y) / dimY; - switch (step) { - case 0: - pointRoue.r = maxComposante; - pointRoue.v = substep; - pointRoue.b = 0; - break; - case 1: - pointRoue.r = maxComposante - substep; - pointRoue.v = maxComposante; - pointRoue.b = 0; - break; - case 2: - pointRoue.r = 0; - pointRoue.v = maxComposante; - pointRoue.b = substep; - break; - case 3: - pointRoue.r = 0; - pointRoue.v = maxComposante - substep; - pointRoue.b = maxComposante; - break; - case 4: - pointRoue.r = substep; - pointRoue.v = 0; - pointRoue.b = maxComposante; - break; - case 5: - pointRoue.r = maxComposante; - pointRoue.v = 0; - pointRoue.b = maxComposante - substep; - break; - default: - pointRoue.r = pointRoue.v = pointRoue.b = 0; - } - - // Dégradé vers le noir - pointRoue.r = pointRoue.r * lum; - pointRoue.v = pointRoue.v * lum; - pointRoue.b = pointRoue.b * lum; - - imageRoue.s_pixel(x, y, pointRoue); - } - } - return imageRoue; -} - int main(int argc, char *args[]) { #if defined(WIN32) // Permet de refaire fonctionner cout et cerr sous Windows après démarrage de SDL freopen("CON", "w", stdout); freopen("CON", "w", stderr); #endif - cout << "PILG" << endl; // Message d'entrée et de test + presentation(); Image image = imageDefaut(); diff --git a/src/testing.cpp b/src/testing.cpp index 8ab10fc..b799e3f 100644 --- a/src/testing.cpp +++ b/src/testing.cpp @@ -5,6 +5,7 @@ using namespace std; #include "affichageFenetre.cpp" #include "image.h" +#include "utilitaires.cpp" #include "traitementImage.cpp" #include "analyserCommande.cpp" @@ -104,19 +105,29 @@ int main(int argc, char *args[]) { freopen("CON", "w", stderr); #endif - cout << "PILG - Test" << endl; // Message d'entrée et de test - - // Image image = genererRoue(256, 128, 255); + presentation(); #define DIMENSIONS 256 + Image imageOriginale = genererRoue(DIMENSIONS*2, DIMENSIONS, 255); + // Image imageoriginale; // Tester si ça marche - Image imageOriginale = genererRoue(DIMENSIONS, DIMENSIONS, 255); - Image image = imageOriginale.g_vide(); - for (float i = 0; i < 2 * PI; i += 0.1) { - pivoter(imageOriginale, image, DIMENSIONS/2, DIMENSIONS/2, i); - afficherImage(image); - } + // // Roue + // Image image = imageOriginale.g_vide(); + // for (float i = 0; i < 2 * PI; i += 0.1) { + // pivoter(imageOriginale, image, DIMENSIONS/2, DIMENSIONS/2, i); + // afficherImage(image); + // } + // Ouvrir fichier + // cout << ouvrir(imageOriginale, "tests/PikachuP6.ppm") << endl; + + afficherImage(imageOriginale); + attendreFenetre(); + + // pivoter(imageOriginale, imageOriginale, imageOriginale.g_dimensionX()/2, imageOriginale.g_dimensionY()/2, 0.5); + // attendreFenetre(); + + cout << sauver(imageOriginale, "tests/Sauvegardé.ppm", true, "Ceci est un commentaire") << endl; // // Neige en dégradé // for (int i; i < 300; i++) { @@ -157,6 +168,7 @@ int main(int argc, char *args[]) { // } // cout << "Éxecution du programme terminée. Vous pouvez quitter la fenêtre." << endl; + fermerFenetre(); return 0; diff --git a/src/traitementImage.cpp b/src/traitementImage.cpp index 5c64c31..2a06fec 100644 --- a/src/traitementImage.cpp +++ b/src/traitementImage.cpp @@ -1,8 +1,11 @@ #include +#include #define PI 3.14159265359 #define MAXCOMPOSANTEDEFAUT 255 +typedef enum {PILG_TYPE, PILG_DIMENSIONS, PILG_MAXCOMPOSANTE, PILG_IMAGE} PILG_OuvrirEtape; + // Gestion de fichiers int creer(Image &sortie, unsigned int dimensionX, unsigned int dimensionY, unsigned int maxComposante, PILG_Comp typeComposantes) { // Créer une image de dimensions X et Y sortie = *new Image(dimensionX, dimensionY, maxComposante, typeComposantes); @@ -10,13 +13,174 @@ int creer(Image &sortie, unsigned int dimensionX, unsigned int dimensionY, unsig } int ouvrir(Image &sortie, string nomFichier) { // Ouvrir une image existante à partir du nom du fichier ***Geoffrey + // Ouverture du fichier + ifstream streamFichier(nomFichier.c_str(), ios::in); + if (streamFichier) { + // Calcul de la taille (en octets) du fichier + streamFichier.seekg(0, ios::end); + int tailleFichier (streamFichier.tellg()); - return 1; + // Stockage du fichier dans une chaîne + streamFichier.seekg(0, ios::beg); + char *caracteres = new char [tailleFichier]; + streamFichier.read(caracteres, tailleFichier); + string fichier_caracteres(caracteres); + delete[] caracteres; + streamFichier.close(); + + // Variables d'informations + PILG_OuvrirEtape ouvrirEtape(PILG_TYPE); + bool ASCII(false); + int dimensionX; + int dimensionY; + int maxComposante; + PILG_Comp typeComposantes; + + // Variables de traitement du fichier + string element(""); + int x(0); + int y(0); + string pixelASCII; + int RVBcomposante(0); // Composante actuelle pour RVB + + for (int c(0); c < tailleFichier; c++) { + if (ouvrirEtape != PILG_IMAGE) { + if (fichier_caracteres[c] == (char) 0x0a) { // En cas de nouvel élément + if (element[0] != '#') { // Si c'est un commentaire, on passe à l'élément suivant + switch (ouvrirEtape) { + case PILG_TYPE: + if (element.length() == 2 && element[0] == 'P') { + switch (element[1]) { + case '1': + case '4': + typeComposantes = PILG_BIN; + break; + case '2': + case '5': + typeComposantes = PILG_NIV; + break; + case '3': + case '6': + typeComposantes = PILG_RVB; + break; + default: + return 3; + break; + } + switch (element[1]) { + case '1': + case '2': + case '3': + ASCII = true; + break; + case '4': + case '5': + case '6': + ASCII = false; + break; + default: + return 3; + break; + } + } else { + return 3; + } + + ouvrirEtape = PILG_DIMENSIONS; +#if DEBUG + cout << "Type de fichier : " << element << " (" << ((typeComposantes == 0) ? "Noir et Blanc" : ((typeComposantes == 1) ? "Niveaux de gris" : "Rouge / Vert / Bleu")) << ", " << (ASCII ? "ASCII" : "Brut") << ")" << endl; +#endif + break; + + case PILG_DIMENSIONS: { + bool espaceDepasse(false); + string dimensionXchaine(""); + string dimensionYchaine(""); + for (int j(0); j < element.size(); j++) { + if (element[j] == ' ') { + espaceDepasse = true; + } else if (espaceDepasse) { + dimensionXchaine += element[j]; + } else { + dimensionYchaine += element[j]; + } + } + chaineVersEntier(dimensionXchaine, dimensionX); + chaineVersEntier(dimensionYchaine, dimensionY); + if (!espaceDepasse || dimensionX == 0 || dimensionY == 0) { + return 5; + } +#if DEBUG + cout << "Dimensions : " << dimensionX << " px / " << dimensionY << "px" << endl; +#endif + if (typeComposantes == PILG_BIN) { + ouvrirEtape = PILG_IMAGE; + } else { + ouvrirEtape = PILG_MAXCOMPOSANTE; + } + } + break; + case PILG_MAXCOMPOSANTE: + chaineVersEntier(element, maxComposante); +#if DEBUG + cout << "Maximum de composante" << ((typeComposantes == 2) ? "s" : "") << " : " << maxComposante << endl; +#endif + ouvrirEtape = PILG_IMAGE; + break; + + default: + return 4; + break; + } + element = ""; + if (ouvrirEtape == PILG_IMAGE) { + sortie = *new Image(dimensionX, dimensionY, maxComposante, typeComposantes); + } + } + } else { + element += fichier_caracteres[c]; + } + } else { + // ... + } + } + } else { + return 1; + } +#if DEBUG + cout << endl << endl; +#endif + + return 0; } int sauver(Image entree, string nomFichier, bool ASCII, string commentaire) { // Sauvegarder l'image obtenue dans un nouveau fichier - - return 1; + ofstream fichier(nomFichier.c_str(), ios::out | ios::trunc); +#define FICHIER_SEPARATEUR (char) 0x0a + if (entree.g_typeComposantes() == PILG_RVB && ASCII) { + fichier << "P6"; + } else { + return 1; + } + fichier << FICHIER_SEPARATEUR; + // if (commentaire) { + // fichier << "#" << commentaire << FICHIER_SEPARATEUR; + // } + fichier << entree.g_dimensionX() << " " << entree.g_dimensionY() << FICHIER_SEPARATEUR; + + if (entree.g_typeComposantes() != PILG_BIN) { + fichier << entree.g_maxComposante() << FICHIER_SEPARATEUR;; + } + Pixel pixel; + for (int x = 0; x <= entree.g_dimensionX(); x++) { + for (int y = 0; y <= entree.g_dimensionY(); y++) { + if (entree.g_typeComposantes() == PILG_RVB && ASCII) { + fichier << pixel.r << FICHIER_SEPARATEUR << pixel.v << FICHIER_SEPARATEUR << pixel.b << FICHIER_SEPARATEUR; + } + } + } + fichier.close(); + return 0; } int importer(Image entree, Image &sortie, string nomFichier, int x, int y) { @@ -34,105 +198,52 @@ int importer(Image entree, Image &sortie, string nomFichier, int x, int y) { // Couleur -int rvbVersTsl(Pixel entree, Pixel &sortie) { - TSLcouleur tslcouleur; - float r = (float) entree.r/entree.maxComposante; - float v = (float) entree.v/entree.maxComposante; - float b = (float) entree.b/entree.maxComposante; - - float min = (r < v < b ? || (v < r && v < b ? b b || v)); - float max = (r > v > b ? || (v > r && v > b ? b b || v)); - float s, h, l; - if max == min - s = 0 - h = Number.NaN - else - s = if l < 0.5 then (max - min) / (max + min) else (max - min) / (2 - max - min) - - if r == max then h = (g - b) / (max - min) - else if (g == max) then h = 2 + (b - r) / (max - min) - else if (b == max) then h = 4 + (r - g) / (max - min) - - h *= 60; - h += 360 if h < 0 - [h,s,l] -} int teinte(Image entree, Image &sortie, float teinte) { // Change la teinte de l'image - for (int x=0, x = image.g_DimensionX(), x++) { - for (int y=0, y = image.g_DimensionY(), y++) { - rvbVersTsl(); - g_pixel(x, y); - - } - } -return 1; + // for (int x = 0, x = image.g_DimensionX(), x++) { + // for (int y = 0, y = image.g_DimensionY(), y++) { + // rvbVersTsl(); + // g_pixel(x, y); + + // } + // } + // return 1; } int saturation(Image entree, Image &sortie, float saturation) { // Sature l'image - // Pour x = image.g_DimensionX() - // Pour y = image.g_DimensionY() - // Ajouter la variable saturation à chaque valeur de chaque pixel - // Ne pas dépasser le seuil limite MaxComposante !!! - // Fin Pour - // Fin Pour + // Utilisation de la méthode TSL return 1; } int luminosite(Image entree, Image &sortie, float luminosite) { // Augmente la luminosité de l'image - // Pour x=0 à x=image.g_DimensionX() - // Pour y=0 à y=image.g_DimensionY() - // si image.g_typeComposante=1 - // pixel = image.g_pixel(x,y); - // pixel.g = luminosite*10+pixel.g; - // image.s_pixel(x, y, pixel); - // sinon si image.g_typeComposante=2 - // pixel = image.g_pixel(x,y); - // pixel.r = luminosite*10+pixel.r; - // pixel.v = luminosite*10+pixel.v; - // pixel.b = luminosite*10+pixel.b; - // image.s_pixel(x, y, pixel); - // Fin si - // Fin Pour - // Fin Pour + // Utilisation de la méthode TSL return 1; } int contraste(Image entree, Image &sortie, float contraste) { // Accentue les contrastes de l'image - // pour x=0 à x=image.g_dimensionX() - // pour y=0 à y=image.g_DimensionY() - // si image.g_typeComposante=1 - // pixel = image.g_pixel(x,y); - // pixel.g = contraste*pixel.g; - // if pixel.g > Image.g_maxComposante - // pixel.g = Image.g_maxComposante - // end if - // End If - // Fin Pour - // Fin Pour - - + // À voir return 1; } // Dessin int trait(Image entree, Image &sortie, int x1, int y1, int x2, int y2, Pixel couleur) { // Dessine un trait d'un point (x1,y1) à un point (x2,y2) - int x, y, dx, dy; - float e, e(1,0), e(0,1) ; // valeur d’erreur et incréments - dy = y2 - y1 ; - dx = x2 - x1 ; - y = y1 ; // rangée initiale - e = 0,0 ; // valeur d’erreur initiale - e(1,0) = dy / dx ; - e(0,1) = -1.0 ; - for (x = x1, x = x2, x++) { - sortie.s_pixel(x, y, couleur); - if ((e = e + e(1,0)) >= 0,5) { // erreur pour le pixel suivant de même rangée - y = y + 1 ; // choisir plutôt le pixel suivant dans la rangée supérieure - e = e + e(0,1) ; // ajuste l’erreur commise dans cette nouvelle rangée - } - } + // int x, y, dx, dy; + // float e, e(1, 0), e(0, 1) ; // valeur d’erreur et incréments + // dy = y2 - y1 ; + // dx = x2 - x1 ; + // y = y1 ; // rangée initiale + // e = 0, 0 ; // valeur d’erreur initiale + // e(1, 0) = dy / dx ; + // e(0, 1) = -1.0 ; + // for (x = x1; x <= x2; x++) { + // sortie.s_pixel(x, y, couleur); + // if ((e = e + e(1, 0)) >= 0, 5) { // erreur pour le pixel suivant de même rangée + // y = y + 1 ; // choisir plutôt le pixel suivant dans la rangée supérieure + // e = e + e(0, 1) ; // ajuste l’erreur commise dans cette nouvelle rangée + // } + // } + // return 0; return 1; } @@ -148,28 +259,28 @@ int rectangle(Image entree, Image &sortie, int x1, int y1, int x2, int y2, Pixel } int cercle(Image entree, Image &sortie, int x0, int y0, int r, Pixel couleur) { - sortie=entree; - for (int x=0, x=image.g_dimensionX(), x++) { - for (int y=0, y=image.g_dimensionY(), y++) { - if (sqrt(pow(x-x0, 2) + pow(y-y0, 2)) == r) { + sortie = entree; + for (int x = 0; x <= entree.g_dimensionX(); x++) { + for (int y = 0; y <= entree.g_dimensionY(); y++) { + if (sqrt(pow(x - x0, 2) + pow(y - y0, 2)) == r) { sortie.s_pixel(x, y, couleur); } } } - return 1; + return 0; } -int disque(Image entree, Image &sortie, int x, int y, int r, Pixel couleur) { - - sortie=entree; - for (int x=0, x=image.g_dimensionX(), x++) { - for (int y=0, y=image.g_dimensionY(), y++) { - if (sqrt(pow(x-x0, 2) + pow(y-y0, 2)) <= r) { +int disque(Image entree, Image &sortie, int x0, int y0, int r, Pixel couleur) { + + sortie = entree; + for (int x = 0; x <= entree.g_dimensionX(); x++) { + for (int y = 0; y <= entree.g_dimensionY(); y++) { + if (sqrt(pow(x - x0, 2) + pow(y - y0, 2)) <= r) { sortie.s_pixel(x, y, couleur); } } } - return 1; + return 0; } // Geométrie @@ -209,15 +320,15 @@ int retourner(Image entree, Image &sortie, int rotation) { int redimensionner(Image entree, Image &sortie, int x1, int x2, int y1, int y2) { - sortie = *new Image(x2-x1, y2-y1, entree.g_maxComposante(), entree.g_typeComposantes()); + sortie = *new Image(x2 - x1, y2 - y1, entree.g_maxComposante(), entree.g_typeComposantes()); Pixel pixel = entree.g_pixelVide(); - for (int x = x1, x <= x2, x++) { - for (int y = y1, y <= y2, y++) { - entree.g_pixel(x+x1, y+y1, pixel); + for (int x = x1; x <= x2; x++) { + for (int y = y1; y <= y2; y++) { + entree.g_pixel(x + x1, y + y1, pixel); sortie.s_pixel(x, y, pixel); } } - return 1; + return 0; } // Modification couleur diff --git a/src/utilitaires.cpp b/src/utilitaires.cpp new file mode 100644 index 0000000..7334fbc --- /dev/null +++ b/src/utilitaires.cpp @@ -0,0 +1,82 @@ +#define NOMBREOR 1.61803398875 + +void presentation() { + cout << " ____ ___ _ ____ " << endl + << "| _ \\|_ _|| | / ___|" << endl + << "| |_) || | | | | | _ " << endl + << "| __/ | | | |___| |_| |" << endl + << "|_| |___||_____|\\____|" << endl; +} + +Image imageDefaut() { + int dimY = 256, dimX = dimY * NOMBREOR, maxComposante = 255; + Image imageRoue(dimX, dimY, maxComposante, PILG_RVB); + Pixel pointRoue = imageRoue.g_pixelVide(); + int x, y, step; + float substep, lum; + for (x = 0; x < dimX; x++) { + for (y = 0; y < dimY; y++) { + step = (x * 6.0) / dimX; + substep = (x - step * (dimX / 6.0)) / (dimX / 6.0) * maxComposante; + lum = 1 - ((float) y) / dimY; + switch (step) { + case 0: + pointRoue.r = maxComposante; + pointRoue.v = substep; + pointRoue.b = 0; + break; + case 1: + pointRoue.r = maxComposante - substep; + pointRoue.v = maxComposante; + pointRoue.b = 0; + break; + case 2: + pointRoue.r = 0; + pointRoue.v = maxComposante; + pointRoue.b = substep; + break; + case 3: + pointRoue.r = 0; + pointRoue.v = maxComposante - substep; + pointRoue.b = maxComposante; + break; + case 4: + pointRoue.r = substep; + pointRoue.v = 0; + pointRoue.b = maxComposante; + break; + case 5: + pointRoue.r = maxComposante; + pointRoue.v = 0; + pointRoue.b = maxComposante - substep; + break; + default: + pointRoue.r = pointRoue.v = pointRoue.b = 0; + } + + // Dégradé vers le noir + pointRoue.r = pointRoue.r * lum; + pointRoue.v = pointRoue.v * lum; + pointRoue.b = pointRoue.b * lum; + + imageRoue.s_pixel(x, y, pointRoue); + } + } + return imageRoue; +} + +int chaineVersEntier(string chaine, int &entier) { + entier = atoi(chaine.c_str()); + if (entier == 0 && chaine != "0") { + return 1; + } + return 0; +} + +int chaineVersFlottant(string chaine, float &flottant) { + flottant = atof(chaine.c_str()); + if (flottant == 0 && chaine != "0") { + return 1; + } + return 0; +} diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..dd84e96 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!Pikachu* \ No newline at end of file diff --git a/tests/PikachuP1.pbm b/tests/PikachuP1.pbm new file mode 100644 index 0000000000000000000000000000000000000000..87871e56097fcfa088524c33514dc72ffb54080b GIT binary patch literal 4202 zcmeHHO-lno488BK81OC~kRH5=sCcNBBL0IO3ZhW`|CoAzbbomJ+8@*F{`h(Lcu)B zq{?r~g4$x4QiGwQ8T8zhDG#1`x>svu>Z3)% zNh@VGm{Nu}ERTSUZo*iN=aCQ52B;2X)n)@C?fRhrjn5+;vA785V`TbJh_Yr?7OuHj zCRDHq!*ZsqpG7+xnw&eORR6+71Y4M+b579ag=+|np+bW;P3Z(j3QmCCN%vz!KUo(R z;K!rP@N^51Js`H(o1R)M(4r%mKA%^yRS2qy1SsB7IFX42@H-ov`Hx{huIX@#D`a3% z4<|AMQcVNBelgS8+p7XRLUn0!IGf=Bm4X#Chb438@7KU)91w)A3Lsj)8GbLd$n>Vd IvHv@pZ;gZ!(f|Me literal 0 HcmV?d00001 diff --git a/tests/PikachuP2.pgm b/tests/PikachuP2.pgm new file mode 100644 index 0000000000000000000000000000000000000000..e0b39bf18fc02a18093da2dc8aad9122def5310d GIT binary patch literal 16189 zcmeI3!EW0y42JJ{3In?jb&_V;Zo{w*J9G<*VQoIU-O1|Y)w#x-dG#5ddH zc~wQA;Sq?l2f(ioe=j9A#lCLeuiAZEdJBx0%MqCX2Q;5FJT(>VX76K&ILe}u?di)* zc9UEX;1e^?&@W6%=vfLYCoV~EhovQDhJz5Z?{<>{(#m1WnPWLVpzQawL6XQB)4B$0 zzVLHgnsW~0!$~;L&Z2N-@uGmk7$MVPk;*Y=$Zwwu%C-(|hcWQ2H?#-pGi(nWCP^yW zUFrpcb0DB!q+avtzSaA*H=J5&YF^Vsye zd3S{Gf^#A9Be+VyRQvqkAz{)n=Ny00z|qi_F~A&)TR5zlQ;gQQFk>aG#26)=@};?R z`ktE}midP0ea>CDWDN{xpNU(TrRGR%gvNkAf+H(r-pc2xG2vi|+y+nZX-bykk(1oi z98D07!garno|5YOM}t}l<6=#TfId8=+{shACdYMK&P$j%0e==)9khgNym47ndTdOe zmX!etvBqe3_t);0>IZD?gX^nz)EKcP) zK*@l^x^9Q`JHRsYXj1?}`MYVC-P8)g_dXj1H69BpukL;i1G~=Ws z|Eu7I_W>K|4kmjmq6d9&;x9}s?4!l<=a{@~R%r&@qO3#rm9R^Yv275$$oa+K-ECiK-ECiz!VMq2NyXy5dZ)H literal 0 HcmV?d00001 diff --git a/tests/PikachuP3.ppm b/tests/PikachuP3.ppm new file mode 100644 index 0000000000000000000000000000000000000000..b6715f08735a84975d8243269ce6321e1ebdbea0 GIT binary patch literal 46840 zcmeI4&2HQ_6ovPCiUGP0tntKgyDN&O=pu;`6n%p%0u(Kf_We=G9-ebGy5f*SNfE6B zWa1NwKlkV36-O5Gbl?1N_~rAjKmYOR^G}E0e*f@vc>4I^@c!#x|9$y(`18xRf4~0o z_o02$HV>!6!>KvGeXEaRAO^&M7!U(uKn#chF(3xSfEW-1Vn7Ut0Wly3#DEwO17bi7 zhygJm2E>3E5CdXB42Xf58E7Axi$8ixLvN|pe@^9l>IH?UE+wh zpC{1{P6J_xE$4a9w%vdRZ|5Q1YX-1AJ~oec{TBlsH4-bbhq7rK`vrO-*7Q_sm7U4^ z_!&r$UYFoCc(t)XB2P^!Yn#7w{#4=LI|dEn6?l@lErLO@ha6bZyjmvv3so2 z6PK$yzRx3H6nLMBWX=Z#Y{y~?NstZ8Z6@5`N%c+CmQvpDlo#IP3d|aN(I$MgRnA)l zOiWhITw-(kr_fB+X)jd0H1lpqB{Iv4IEyvGxvp}-wf$cpjvOc+jLZ9C@oUY$GJ?v?V!8o2gFmekqWgMweBP57#s7hX#NyHhh z0br@=i1))96!w>Rfo6A-tw7A!QMm^9VeE_^d?RKX+!4UH06cz1Mx+8p_LmPgWQe(< zV%D%o5Uj24S{TWGi)Nm1Qn`lFIV#6knoYH+16#N;&1C}v#mFMs%nuM|h`p3WXY&Rm zw;lWUsJem`e$rY;(b~)nY#hdu^JEhpLrk<1uQGy}rq2b$mgiw!J4D|d`#(2i2Y8#Y z%#L%FRG1M?KfoCvJ^yUq^)C~3@NyL>x|ERbWJ72i7V;J^X%ncCgfXiD1?GXdi7Mur ziukdO%49P-^G%rIR5RhVF(bY>1F?b&##wy*1lv#!?jFDmm_c7SaTPWOt%*8TR9ye@RKP;5q?vIQ-qk^IJ5SCgY=~mV7|}C>2~NzUSqMbU~?>N zRHW-X5che@Cwej3mg61xiqv{ZP01Y+Jqy;DBqElBmNUbvln|&-y@-P|9vje2l*Z1PUPI86W%h!Q(;$HGXgo+QG{5V^~#|0^icWF}xRW@c-N zhRxico^raeX(y#@YpIhxWi3E d5CdXB42S_SAO^&M7!U(uKn#chG4R?L_#al%FvtJ^ literal 0 HcmV?d00001 diff --git a/tests/PikachuP4.pbm b/tests/PikachuP4.pbm new file mode 100644 index 0000000000000000000000000000000000000000..ca06c16cf40bc76a7c9adce0c3ea214d74864d27 GIT binary patch literal 560 zcmc)Eu}T9$5C-5mP6%F+q>J4x*jNdHBLSNrqGAzq1W9d^A|NW!Mi4J=;Op4s-oQt2 z^8{Il;Du9v|JlnU2-)VFe{W}Q(j?k9C&Sa@tHJQdoL}@)lV0}C+2rPNJT;^7^kH&$ zYubnHsFRpZ63N!j^=1Prb*%y?JvDR!pNjx9Ey}X;1-}}lJ1@N1(#jqytgJlK_k|6< zIp=j@Yu=TMY4`z`u`>XiPM~W)33yU>fkJI%0QkNKEaz4vX4FNP@kv|sjj~^#sXuJ< x^K>ERFH1w3ZzNI!%2_4y$~Dn@ZPWK&_B(%nA6vDN?=*du(0}J24mAJM`2&veg~tE@ literal 0 HcmV?d00001 diff --git a/tests/PikachuP5.pgm b/tests/PikachuP5.pgm new file mode 100644 index 0000000000000000000000000000000000000000..ce9386c8dd7164043c3b8ca343a6e90a89319cb4 GIT binary patch literal 4148 zcmeH|J#O4E5QY1#cmx4~+dvMyF46@-Vz_X!Fb27Sfi;jHz{x3iAD)JX*fyQ=-jI|i ziIQk+7c3jn-1**{8Itm0zkAbseEjr5zCONh?(QEB&Ed;K^ZEJvpQo4R+tbVM=U+dY z>$lgt+neV0X7_Ht-*uO9>A-)|0b|Z9#GEMr{wxJ^JRZ*xAipe7ksSrRD|Hd@ns)3v zV!Zb=-a5z3klWVz7~s^vsA^`>t zeyjNKJ4kC!9H1gjx)Sd?aZ0OzW?t{j4B$E9=d`sem1xB(z?MPG$vE1gqm!*Xz=DcZ zo4;JbKl`2Z8gD(Q#GB)U5A-ahOkX@MdgNpNeF1^S!S*{D7?$F^Wzm?!Xj_D90Rz1v zV15u|*Su$?ZQEW2UhAf}j->{gR*m6>8`$%RCZ1r-OMGXp5I79j!yg6kK4+uMV^_w! zSDX!yj9&1UlVA+yx+2EyQzjsiUx{=Ga$?0!1pq}I;#|5UP=+ZI;^H|)e3;aK879tL zogUPHr4{{6xov#`Mg)_j zOn1zAwx#vFd*mWr0>*mAjNzGmz!4Z38S%6ot3mibt?Sj}(-ophE}U>qLUY}Plu0DLZysq9| zUVpy&^szd6bhJD@u1=4ak55jPf97j;V0K`3V0K`3V0K`3U=I#FXs$gZo+zdG87HbY zb{X?ajGcb(`M`d^xel>~$WI?5wxCoV_qP+Vh5BZ3^K-#W?{Ws-?CO}FY^5?k@Va~O z|N6deoZHwIJ+f`(Y?-8l;k#~u$m4R8Bgo9vQhJnEIYUX&e3iNoe*-=Ryc|eic76rl zRtuIy+pV=${G-@gm_#j59TG7x<4I=p2syWD6G52Pmh505Sb3Ofg<98NZ{5uY4qn2n z$4GuJ@M;rp*MteVA2&av+=8$fr#~?HzO2bbXy8QL<`;Zda&2y2ec()bsxxw%>^2ds zDzE$RST-hfT3Av-hhJv;ctpXgx~^k@{ok2Ck}K!9{NyLC2_v?($n{%ElO_B)IcvLa z+)jUVcuZ*KC@87`MC8BA$(&sMYP@UJPSiYrR6?R6gvRrH>_YnYV!>@5R>idKwLt-e}JVOujO)C-k(dDIwN8%L>oeqBj?-uke@Hk})o%pws zYf{H%`WD0wL;DuAkn0tms|5tt@Pkp9!TiFAUF>9z0m7b=+zlozM5=OqFXU>0(py{5 zdC=J2$UVY?$C-(!Xm}DN2jq<;k>1t`1XS=a>e!931~am^?$y4$KbB4$KZ5q62>cwQNWf literal 0 HcmV?d00001