[v1.0.0] Teinte, Saturation, Luminosité

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
This commit is contained in:
Geoffrey Frogeye 2014-05-22 20:14:36 +02:00
parent 386ff0b51b
commit 82a60fccf9
9 changed files with 264 additions and 122 deletions

View file

@ -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) sexé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)

View file

@ -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

View file

@ -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;
}
}
void actualiserDimensionsEcran() {
SDL_Init(SDL_INIT_VIDEO);
const SDL_VideoInfo *info = SDL_GetVideoInfo();
ecranX = info->current_w;
ecranY = info->current_h;
SDL_Quit();
}

View file

@ -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;

View file

@ -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;

View file

@ -27,6 +27,7 @@ int main(int argc, char *args[]) {
code = procederCommande(decoupe, image);
} else {
actualiserDimensionsEcran();
afficherImage(image);
boucleDeCommandes(image);
code = 0;

View file

@ -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;
}

View file

@ -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,

View file

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