From 82a60fccf9d022307b77f843a87011e1ef701960 Mon Sep 17 00:00:00 2001 From: Geoffrey Frogeye Date: Thu, 22 May 2014 20:14:36 +0200 Subject: [PATCH] =?UTF-8?q?[v1.0.0]=20Teinte,=20Saturation,=20Luminosit?= =?UTF-8?q?=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Passage en v1.0.0 finale (il faut bien, à un moment...). * Traitement image & commandes * Ajout de la fonction teinte * Ajout de la fonction saturation * Ajout de la fonction luminosité * Utilitaires * Ajout de conversions RVB→TSL & TSL→RVB pour les fonctions teinte, saturation et luminosité * L'image par défaut est désormais générée à partir de teinte et luminosité * Affichage de la fenêtre * La taille de l'écran est récupérable * L'échelle est désormais variable et est calculée selon les dimensions de l'écran --- README.md | 2 +- TODO.md | 7 +- src/affichageFenetre.cpp | 28 +++++-- src/analyserCommande.cpp | 65 +++++++++------ src/image.h | 4 +- src/main.cpp | 1 + src/testing.cpp | 45 +++++++--- src/traitementImage.cpp | 59 ++++++++++--- src/utilitaires.cpp | 175 ++++++++++++++++++++++++++------------- 9 files changed, 264 insertions(+), 122 deletions(-) diff --git a/README.md b/README.md index 57eea39..3614e9b 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Nos noms complets et le nom du lycée sont masqués pour des raisons d'intimité ###Le programme Ce programme est un éditeur basique d'images [PBM/PGM/PPM](http://fr.wikipedia.org/wiki/Portable_pixmap) s’exécutant en ligne de commande. -*Version :* Alpha +*Version :* v1.0.0 *Status :* [![Build Status](https://travis-ci.org/GeoffreyFrogeye/PILG.svg?branch=master)](https://travis-ci.org/GeoffreyFrogeye/PILG) diff --git a/TODO.md b/TODO.md index 5c7a95c..d2b3aa2 100644 --- a/TODO.md +++ b/TODO.md @@ -30,9 +30,9 @@ * Annuler * Refaire * Couleur **D** - * Teinte **D** - * Saturation **D** - * Luminosité **D** + * Teinte **C** + * Saturation **C** + * Luminosité **C** * Contraste * Dessin **C** * Trait **C** @@ -48,7 +48,6 @@ * Binaire **C** * Niveaux de gris **C** * Couleur **C** - * Aide * Documentation diff --git a/src/affichageFenetre.cpp b/src/affichageFenetre.cpp index 4b13e5d..f2f9d59 100644 --- a/src/affichageFenetre.cpp +++ b/src/affichageFenetre.cpp @@ -3,6 +3,8 @@ int fenetreDimensionX; // Stocke les dimensions X de la fenêtre int fenetreDimensionY; // Stocke les dimensions Y de la fenêtre +int ecranX = 1024; +int ecranY = 1080; bool fenetreOuverte = false; SDL_Surface *fenetreEcran; SDL_Surface *fenetreImage; @@ -11,16 +13,16 @@ SDL_Surface *fenetreImage; void definirPixel(SDL_Surface *surface, int x, int y, Uint32 pixel) { int nbOctetsParPixel = surface->format->BytesPerPixel; Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * nbOctetsParPixel; - + switch (nbOctetsParPixel) { case 1: *p = pixel; break; - + case 2: *(Uint16 *)p = pixel; break; - + case 3: if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { p[0] = (pixel >> 16) & 0xff; @@ -31,16 +33,16 @@ void definirPixel(SDL_Surface *surface, int x, int y, Uint32 pixel) { p[1] = (pixel >> 8) & 0xff; p[2] = (pixel >> 16) & 0xff; } - + break; - + case 4: *(Uint32 *)p = pixel; break; } } -void setNomFenetre(std::string nom) { // Change le nom de la fenêtre +void s_nomFenetre(std::string nom) { // Change le nom de la fenêtre SDL_WM_SetCaption(nom.c_str(), NULL); } @@ -68,7 +70,7 @@ void afficherFenetre() { void attendreFenetre() { SDL_Event evenement; - + do { SDL_WaitEvent(&evenement); } while (evenement.type != SDL_QUIT && @@ -93,7 +95,15 @@ void ouvrirFenetre(int dimensionX, int dimensionY, fenetreImage = SDL_CreateRGBSurface(SDL_HWSURFACE, fenetreDimensionX, fenetreDimensionY, 32, 0, 0, 0, 0); SDL_FillRect(fenetreImage, NULL, SDL_MapRGB(fenetreEcran->format, 0, 0, 0)); - setNomFenetre(nom); + s_nomFenetre(nom); SDL_LockSurface(fenetreImage); fenetreOuverte = true; -} \ No newline at end of file +} + +void actualiserDimensionsEcran() { + SDL_Init(SDL_INIT_VIDEO); + const SDL_VideoInfo *info = SDL_GetVideoInfo(); + ecranX = info->current_w; + ecranY = info->current_h; + SDL_Quit(); +} diff --git a/src/analyserCommande.cpp b/src/analyserCommande.cpp index 1e48048..079ed61 100644 --- a/src/analyserCommande.cpp +++ b/src/analyserCommande.cpp @@ -316,30 +316,43 @@ int executerCommande(Commande commande, Image &image) { // } else { // return 2; // } - // } else if (commande.fonction == "teinte") { - // if (argumentPresent(commande, "v1")) { - // if (teinte(image, image, commande.v1)) { - // return 3; - // } - // } else { - // return 2; - // } - // } else if (commande.fonction == "saturation") { - // if (argumentPresent(commande, "v1")) { - // if (saturation(image, image, commande.v1)) { - // return 3; - // } - // } else { - // return 2; - // } - // } else if (commande.fonction == "luminosite") { - // if (argumentPresent(commande, "v1")) { - // if (luminosite(image, image, commande.v1)) { - // return 3; - // } - // } else { - // return 2; - // } + } else if (commande.fonction == "teinte") { + if (image.g_typeComposantes() == PILG_RVB) { + if (argumentPresent(commande, "v1")) { + if (teinte(image, image, commande.v1)) { + return 3; + } + } else { + return 2; + } + } else { + return 11; + } + } else if (commande.fonction == "saturation") { + if (image.g_typeComposantes() == PILG_RVB) { + if (argumentPresent(commande, "v1")) { + if (saturation(image, image, commande.v1)) { + return 3; + } + } else { + return 2; + } + } else { + return 11; + } + } else if (commande.fonction == "luminosite") { + if (image.g_typeComposantes() == PILG_RVB) { + if (argumentPresent(commande, "v1")) { + if (luminosite(image, image, commande.v1)) { + return 3; + } + } else { + return 2; + } + } else { + return 11; + } + // } else if (commande.fonction == "contraste") { // if (argumentPresent(commande, "v1")) { // if (contraste(image, image, commande.v1)) { @@ -524,6 +537,10 @@ int procederCommande(vector< string > decoupe, Image &image) { messageErreur("La composante donnée n'est pas valide"); break; + case 11: + messageErreur("Il est nécessaire d'avoir une image en mode RVB pour executer cette commande"); + break; + default: messageErreur("Impossible d'analyser la commande"); break; diff --git a/src/image.h b/src/image.h index bfc4511..8f59e23 100644 --- a/src/image.h +++ b/src/image.h @@ -2,7 +2,7 @@ typedef enum {PILG_BIN, PILG_NIV, PILG_RVB} PILG_Comp; -typedef struct Pixel { +typedef struct { PILG_Comp typeComposantes; int maxComposante; int r; @@ -30,7 +30,7 @@ public: // Validateurs bool v_pixel(Pixel pixel) const; bool v_dimensions(int x, int y) const; - + private: // Variables int m_dimensionX; diff --git a/src/main.cpp b/src/main.cpp index 852901d..c7cbded 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,6 +27,7 @@ int main(int argc, char *args[]) { code = procederCommande(decoupe, image); } else { + actualiserDimensionsEcran(); afficherImage(image); boucleDeCommandes(image); code = 0; diff --git a/src/testing.cpp b/src/testing.cpp index 8eb15cf..d42b433 100644 --- a/src/testing.cpp +++ b/src/testing.cpp @@ -120,6 +120,9 @@ int appliquer(Image &image, string nomFichier, bool ASCII) { ouvrir(image, "tests/" + nomFichier); Pixel pixel; image.g_pixel(image.g_dimensionX() / 2, image.g_dimensionY() / 2, pixel); + // teinte(image, image, 180); + // saturation(image, image, 0.3); + // luminosite(image, image, -0.5); // trait(image, image, image.g_dimensionX() / 4, image.g_dimensionY() / 4, // image.g_dimensionX() - image.g_dimensionX() / 4, // image.g_dimensionY() - image.g_dimensionY() / 4, pixel); @@ -147,25 +150,43 @@ int main(int argc, char *args[]) { #endif presentation(); cout << "Éxecution des instructions dans testing.cpp." << endl << endl; -#define DIMENSIONS 50 - Image image1 = genererRoue(DIMENSIONS * 2, DIMENSIONS, 255); - Image image2 = genererRoue(DIMENSIONS * 2, DIMENSIONS, 255); - // Image image1; // Tester si ça marche + actualiserDimensionsEcran(); +#define DIMENSIONS 255 + // Image image1 = genererRoue(DIMENSIONS, DIMENSIONS, 255); + Image image1 = imageDefaut(); + // Image image = image1.g_vide(); + // ouvrir(image1, "tests/PikachuP6.ppm"); + // Image image2 = genererRoue(DIMENSIONS * 2, DIMENSIONS, 255); // afficherImage(image1); // attendreFenetre(); + // Ouvrir fichier + // appliquer(image1, "PikachuP1.pbm", true); + // appliquer(image1, "PikachuP2.pgm", true); + // appliquer(image1, "PikachuP3.ppm", true); + // appliquer(image1, "PikachuP4.pbm", false); + // appliquer(image1, "PikachuP5.pgm", false); + // appliquer(image1, "PikachuP6.ppm", false); + // // Chronomètre + // int tempsDepart = clock(); + // journal << "Temps d'execution: " << (float)(clock() - tempsDepart) / 1000000 << + // "s" << endl; + // // Afficher différentes tailles de fenêtre + // for (int i = 500; i < 1200; i += 10) { + // image1 = genererRoue(i * 2, i, 255); + // afficherImage(image1); + // // attendreFenetre(); + // } // // Roue // Image image = image1.g_vide(); // for (float i = 0; i < 2 * PI; i += 0.1) { // pivoter(image1, image, DIMENSIONS/2, DIMENSIONS/2, i); // afficherImage(image); // } - // Ouvrir fichier - appliquer(image1, "PikachuP1.pbm", true); - appliquer(image1, "PikachuP2.pgm", true); - appliquer(image1, "PikachuP3.ppm", true); - appliquer(image1, "PikachuP4.pbm", false); - appliquer(image1, "PikachuP5.pgm", false); - appliquer(image1, "PikachuP6.ppm", false); + // // Roue des couleurs + // for (float i = -1; i <= 1; i += 0.01) { + // teinte(image1, image, i); + // afficherImage(image); + // } // // Neige en dégradé // for (int i; i < 300; i++) { // afficherImage(genererBruit(200, 200)); @@ -202,7 +223,7 @@ int main(int argc, char *args[]) { // afficherFenetre(); // } // cout << "Éxecution du programme terminée. Vous pouvez quitter la fenêtre." << endl; - fermerFenetre(); + // fermerFenetre(); journal.close(); return 0; } diff --git a/src/traitementImage.cpp b/src/traitementImage.cpp index 8a8e876..0ee3e6d 100644 --- a/src/traitementImage.cpp +++ b/src/traitementImage.cpp @@ -369,28 +369,63 @@ int importer(Image entree, Image &sortie, string nomFichier, int x, int y) { // Couleur - 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; + sortie = entree.g_vide(); + Pixel pixel; + TSL tsl; + + for (int x = 0; x < sortie.g_dimensionX(); x++) { + for (int y = 0; y < sortie.g_dimensionY(); y++) { + entree.g_pixel(x, y, pixel); + rvb2tsl(pixel, tsl); + tsl.t += teinte; + tsl2rvb(tsl, pixel); + sortie.s_pixel(x, y, pixel); + } + } + + return 0; } int saturation(Image entree, Image &sortie, float saturation) { // Sature l'image - // Utilisation de la méthode TSL - return 1; + sortie = entree.g_vide(); + Pixel pixel; + TSL tsl; + + for (int x = 0; x < sortie.g_dimensionX(); x++) { + for (int y = 0; y < sortie.g_dimensionY(); y++) { + entree.g_pixel(x, y, pixel); + rvb2tsl(pixel, tsl); + tsl.s += saturation; + tsl.s = tsl.s > 1 ? 1 : (tsl.s < 0 ? 0 : tsl.s); + tsl2rvb(tsl, pixel); + sortie.s_pixel(x, y, pixel); + } + } + + return 0; } int luminosite(Image entree, Image &sortie, float luminosite) { // Augmente la luminosité de l'image - // Utilisation de la méthode TSL - return 1; + sortie = entree.g_vide(); + Pixel pixel; + TSL tsl; + + for (int x = 0; x < sortie.g_dimensionX(); x++) { + for (int y = 0; y < sortie.g_dimensionY(); y++) { + entree.g_pixel(x, y, pixel); + rvb2tsl(pixel, tsl); + tsl.l += luminosite; + tsl.l = tsl.l > 1 ? 1 : (tsl.l < 0 ? 0 : tsl.l); + tsl2rvb(tsl, pixel); + sortie.s_pixel(x, y, pixel); + } + } + + return 0; } int contraste(Image entree, Image &sortie, diff --git a/src/utilitaires.cpp b/src/utilitaires.cpp index 8500000..eb7e0f5 100644 --- a/src/utilitaires.cpp +++ b/src/utilitaires.cpp @@ -13,64 +13,112 @@ void presentation() { << "|_| |___| |_____| \\____|" << endl; } +typedef struct { + double t; + double s; + double l; +} TSL; + +int rvb2tsl(Pixel entree, TSL &sortie) { + double min, max, r = (float) entree.r / entree.maxComposante, + v = (float) entree.v / entree.maxComposante, + b = (float) entree.b / entree.maxComposante; + min = r < v ? r : v; + min = min < b ? min : b; + max = r > v ? r : v; + max = max > b ? max : b; + sortie.l = (max + min) / 2; + + if (max == min) { + sortie.s = 0; + sortie.t = NAN; + } else { + sortie.s = sortie.l < 0.5 ? (max - min) / (max + min) : (max - min) / + (2 - max - min); + } + + if (r == max) { + sortie.t = (v - b) / (max - min); + } else if (v == max) { + sortie.t = 2 + (b - r) / (max - min); + } else if (b == max) { + sortie.t = 4 + (r - v) / (max - min); + } + + sortie.t *= 60; + + if (sortie.t < 0) { + sortie.t += 360; + } + + return 0; +} + +int tsl2rvb(TSL entree, Pixel &sortie) { + double t3[3], c[3], t2, t1; + + while (entree.t < 0.0) { + entree.t += 360.0; + } + + while (entree.t > 360.0) { + entree.t += -360.0; + } + + if (entree.s == 0) { + fill_n(c, 3, entree.l * 255); + } else { + fill_n(t3, 3, 0); + fill_n(c, 3, 0); + t2 = entree.l < 0.5 ? entree.l * (1 + entree.s) : entree.l + entree.s - entree.l + * entree.s; + t1 = 2 * entree.l - t2; + entree.t /= 360; + t3[0] = entree.t + 1 / 3.0; + t3[1] = entree.t; + t3[2] = entree.t - 1 / 3.0; + + for (int i = 0; i <= 2; i++) { + if (t3[i] < 0) { + t3[i] += 1; + } + + if (t3[i] > 1) { + t3[i] -= 1; + } + + if (6 * t3[i] < 1) { + c[i] = t1 + (t2 - t1) * 6 * t3[i]; + } else if (2 * t3[i] < 1) { + c[i] = t2; + } else if (3 * t3[i] < 2) { + c[i] = t1 + (t2 - t1) * ((2 / 3.0) - t3[i]) * 6; + } else { + c[i] = t1; + } + } + + sortie.r = c[0] * sortie.maxComposante; + sortie.v = c[1] * sortie.maxComposante; + sortie.b = c[2] * sortie.maxComposante; + } + + return 0; +} + Image imageDefaut() { int dimY = 256, dimX = dimY * NOMBREOR, maxComposante = 255; Image imageRoue(dimX, dimY, maxComposante, PILG_RVB); + int x, y; + TSL tsl; Pixel pointRoue = imageRoue.g_pixelVide(); - int x, y, step; - float substep, lum; + tsl.s = 1; 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; + tsl.t = ((float) x / dimX) * 360; + tsl.l = 1 - ((float) y / dimY); + tsl2rvb(tsl, pointRoue); imageRoue.s_pixel(x, y, pointRoue); } } @@ -79,12 +127,23 @@ Image imageDefaut() { } void afficherImage(Image image) { -#define ECHELLE 1 - int x, y, r, v, b, eX, eY, dimensionX = image.g_dimensionX() * ECHELLE, - dimensionY = image.g_dimensionY() * ECHELLE, - typeComposantes = image.g_typeComposantes(); +#define MARGE 100 + int x, y, r, v, b, eX, eY, echelle, contenableX, contenableY, + dimensionX = image.g_dimensionX(), + dimensionY = image.g_dimensionY(), + typeComposantes = image.g_typeComposantes(); float ratio = (255.0 / image.g_maxComposante()); Pixel pixel; + // Calcul de l'échelle + contenableX = (ecranX - MARGE) / dimensionX; + contenableY = (ecranY - MARGE) / dimensionY; + echelle = (contenableX > contenableY ? contenableY : contenableX); + echelle = (echelle > 0 ? echelle : 1); + dimensionX = dimensionX * echelle; + dimensionY = dimensionY * echelle; + // journal << "Fenêtre: Image(" << image.g_dimensionX() << ";" << + // image.g_dimensionY() << "), Echelle(" << echelle << "), Fenetre(" << + // dimensionX << ";" << dimensionY << ")" << endl; if (fenetreOuverte && (dimensionX != fenetreDimensionX || dimensionY != fenetreDimensionY)) { @@ -113,9 +172,9 @@ void afficherImage(Image image) { break; } - for (eX = 0; eX < ECHELLE; eX++) { - for (eY = 0; eY < ECHELLE; eY++) { - pointFenetre(x * ECHELLE + eX, y * ECHELLE + eY, r, v, b); + for (eX = 0; eX < echelle; eX++) { + for (eY = 0; eY < echelle; eY++) { + pointFenetre(x * echelle + eX, y * echelle + eY, r, v, b); } } }