22 ImageViewer( std::vector<const char *>& filenames ) :
App(1024, 640), m_filenames()
24 for(
unsigned i= 0; i < filenames.size(); i++)
25 m_filenames.push_back(filenames[i]);
28 void range(
const Image& image )
33 for(
int y= 0; y < image.
height(); y++)
34 for(
int x= 0; x < image.
width(); x++)
36 Color color= image(x, y);
37 float y= color.r + color.g + color.b;
42 for(
int y= 0; y < image.
height(); y++)
43 for(
int x= 0; x < image.
width(); x++)
45 Color color= image(x, y);
46 float y= color.r + color.g + color.b;
47 int b= (y - ymin) * 100.f / (ymax - ymin);
53 printf(
"range [%f..%f]\n", ymin, ymax);
59 for(
int i= 0; i < 100; i++)
63 m_saturation= ymin + (float) i / 100.f * (ymax - ymin);
64 m_saturation_step= m_saturation / 40.f;
65 m_saturation_max= ymax;
69 qbins= qbins + (float) bins[i] / (m_width * m_height);
74 Image tone(
const Image& image,
const float saturation,
const float gamma )
78 float invg= 1 / gamma;
79 float k= 1 / std::pow(saturation, invg);
80 for(
unsigned i= 0; i < image.
size(); i++)
82 Color color= image(i);
83 if(std::isnan(color.r) || std::isnan(color.g) || std::isnan(color.b))
85 color=
Color(1, 0, 1);
88 color=
Color(k * std::pow(color.r, invg), k * std::pow(color.g, invg), k * std::pow(color.b, invg));
90 tmp(i)=
Color(color, 1);
100 for(
unsigned i= 0; i < image.
size(); i++)
102 Color color= image(i);
103 float g= (color.r + color.b + color.b) / 3;
112 void title(
const int index )
115 sprintf(tmp,
"buffer %02d: %s", index, m_filenames[index].c_str());
116 SDL_SetWindowTitle(m_window, tmp);
119 Image read(
const char *filename )
137 for(
unsigned i= 0; i < m_filenames.size(); i++)
139 printf(
"loading buffer %u...\n", i);
141 Image image= read(m_filenames[i].c_str());
142 if(image.
size() == 0)
145 m_images.push_back(image);
146 m_times.push_back(timestamp(m_filenames[i].c_str()));
150 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
151 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
167 SDL_SetWindowSize(m_window, m_width, m_height);
169 glGenVertexArrays(1, &m_vao);
170 glBindVertexArray(m_vao);
185 m_saturation_step= 1;
186 m_saturation_max= 1000;
188 m_reference_index= -1;
193 range(m_images.front());
199 glGenSamplers(1, &m_sampler_nearest);
200 glSamplerParameteri(m_sampler_nearest, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
201 glSamplerParameteri(m_sampler_nearest, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
202 glSamplerParameteri(m_sampler_nearest, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
203 glSamplerParameteri(m_sampler_nearest, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
207 glBindVertexArray(0);
208 glBindTexture(GL_TEXTURE_2D, 0);
210 glDisable(GL_DEPTH_TEST);
211 glDisable(GL_CULL_FACE);
217 glDeleteVertexArrays(1, &m_vao);
218 glDeleteTextures(m_textures.size(), m_textures.data());
228 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
233 reload_program(m_program,
smart_path(
"data/shaders/tonemap.glsl") );
240 m_index= (m_index -1 + m_textures.size()) % m_textures.size();
248 m_index= (m_index +1 + m_textures.size()) % m_textures.size();
254 static float last_time= 0;
258 size_t time= timestamp(m_filenames[m_index].c_str());
259 if(time != m_times[m_index])
262 printf(
"reload image '%s'...\n", m_filenames[m_index].c_str());
264 Image image= read(m_filenames[m_index].c_str());
267 m_times[m_index]= time;
268 m_images[m_index]= image;
271 glBindTexture(GL_TEXTURE_2D, m_textures[m_index]);
272 glTexImage2D(GL_TEXTURE_2D, 0,
274 GL_RGBA, GL_FLOAT, image.
data());
276 glGenerateMipmap(GL_TEXTURE_2D);
288 if(filename && filename[0])
292 Image image= read(filename);
295 m_images.push_back( image );
296 m_filenames.push_back( filename );
297 m_times.push_back( timestamp(filename) );
300 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
301 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
305 printf(
"index %d\n", m_index);
306 for(
unsigned i= 0; i < m_filenames.size(); i++)
307 printf(
"images[%d] '%s'\n", i, m_filenames[i].c_str());
316 unsigned int bmouse= SDL_GetMouseState(&xmouse, &ymouse);
318 glBindVertexArray(m_vao);
319 glUseProgram(m_program);
324 sampler= m_sampler_nearest;
327 if(m_reference_index == -1)
328 program_use_texture(m_program,
"image_next", 1, m_textures[(m_index +1) % m_textures.size()], sampler);
333 if(bmouse & SDL_BUTTON(1))
346 if(bmouse & SDL_BUTTON(3))
351 m_zoom= m_zoom + float(wheel.y) / 4.f;
352 if(m_zoom < .1f) m_zoom= .1f;
353 if(m_zoom > 10.f) m_zoom= 10.f;
358 if(bmouse & SDL_BUTTON(3))
367 m_graph= (m_graph +1) % 2;
374 glDrawArrays(GL_TRIANGLES, 0, 3);
382 std::string file= m_filenames[m_index];
383 size_t ext= file.rfind(
".");
384 if(ext != std::string::npos)
385 file= file.substr(0, ext) +
"-tone.png";
387 printf(
"writing '%s'...\n", file.c_str());
392 value(m_widgets,
"saturation", m_saturation, 0.f, m_saturation_max*10, m_saturation_step);
393 value(m_widgets,
"compression", m_compression, .1f, 10.f, .1f);
396 button(m_widgets,
"reset", reset);
397 if(reset) range(m_images[m_index]);
400 button(m_widgets,
"reload", reload);
403 Image image= read(m_filenames[m_index].c_str());
405 m_images[m_index]= image;
406 m_times[m_index]= timestamp(m_filenames[m_index].c_str());
409 glBindTexture(GL_TEXTURE_2D, m_textures[m_index]);
410 glTexImage2D(GL_TEXTURE_2D, 0,
412 GL_RGBA, GL_FLOAT, image.
data());
414 glGenerateMipmap(GL_TEXTURE_2D);
418 int reference= (m_index == m_reference_index) ? 1 : 0;
419 if(
button(m_widgets,
"reference", reference))
421 if(reference) m_reference_index= m_index;
422 else m_reference_index= -1;
426 button(m_widgets,
"export all", export_all);
429 #pragma omp parallel for
430 for(
unsigned i= 0; i < m_images.size(); i++)
434 image= tone(gray(m_images[i]), m_saturation, m_compression);
436 image= tone(m_images[i], m_saturation, m_compression);
439 sprintf(filename,
"%s-tone.png", m_filenames[i].c_str());
440 printf(
"exporting '%s'...\n", filename);
449 float x= px / float(
window_width()) * m_images[m_index].width();
450 float y= py / float(
window_height()) * m_images[m_index].height();
451 Color pixel= m_images[m_index](x, y);
452 label(m_widgets,
"pixel %d %d: %f %f %f",
int(x),
int(y), pixel.r, pixel.g, pixel.b);
456 button(m_widgets,
"R", m_red);
457 button(m_widgets,
"G", m_green);
458 button(m_widgets,
"B", m_blue);
459 button(m_widgets,
"A", m_alpha);
460 button(m_widgets,
"gray", m_gray);
461 button(m_widgets,
"smooth", m_smooth);
463 if(m_reference_index != -1)
464 button(m_widgets,
"diff to reference", m_difference);
469 button(m_widgets,
"select image...", list);
473 for(
unsigned i= 0; i < m_filenames.size(); i++)
476 sprintf(tmp,
"[%u] %s", i, m_filenames[i].c_str());
477 select(m_widgets, tmp, i, m_index);
492 printf(
"screenshot %d...\n", calls);
499 m_filenames.erase(m_filenames.begin() + m_index);
500 m_times.erase(m_times.begin() + m_index);
501 m_images.erase(m_images.begin() + m_index);
502 m_textures.erase(m_textures.begin() + m_index);
503 if(m_reference_index == m_index)
504 m_reference_index= -1;
506 if(m_textures.empty())
509 m_index= m_index % int(m_textures.size());
520 std::vector<std::string> m_filenames;
521 std::vector<size_t> m_times;
522 std::vector<Image> m_images;
523 std::vector<GLuint> m_textures;
524 int m_width, m_height;
528 GLuint m_sampler_nearest;
530 int m_red, m_green, m_blue, m_alpha, m_gray;
536 float m_saturation_step;
537 float m_saturation_max;
541 int m_reference_index;
546 int main(
int argc,
char **argv )
550 printf(
"usage: %s image.[bmp|png|jpg|tga|hdr]\n", argv[0]);
554 std::vector<const char *> options(argv +1, argv + argc);
App(const int width, const int height, const int major=3, const int minor=3, const int samples=0)
constructeur, dimensions de la fenetre et version d'openGL.
representation d'une image.
int height() const
renvoie la hauteur de l'image.
const void * data() const
renvoie un pointeur sur le stockage des couleurs des pixels.
unsigned size() const
renvoie le nombre de pixels de l'image.
int width() const
renvoie la largeur de l'image.
void begin(Widgets &w)
debut de la description des elements de l'interface graphique.
Widgets create_widgets()
cree une interface graphique. a detruire avec release_widgets( ).
void release_widgets(Widgets &w)
detruit l'interface graphique.
bool button(Widgets &w, const char *text, int &status)
void label(Widgets &w, const char *format,...)
cree un texte. meme fonctionnement que printf().
void clear_drop_events()
desactive drag/drop.
int window_height()
renvoie la hauteur de la fenetre de l'application.
bool value(Widgets &w, const char *label, int &value, const int value_min, const int value_max, const int value_step)
valeur editable par increment.
void clear_key_state(const SDL_Keycode key)
desactive une touche du clavier.
void printf(Text &text, const int px, const int py, const char *format,...)
affiche un texte a la position x, y. meme utilisation que printf().
const std::vector< std::string > & drop_events()
drag/drop. recupere tous les fichiers.
bool select(Widgets &w, const char *text, const int option, int &status)
void end(Widgets &w)
termine la description des elements de l'interface graphique.
int key_state(const SDL_Keycode key)
renvoie l'etat d'une touche du clavier. cf la doc SDL2 pour les codes.
void begin_line(Widgets &w)
place les prochains elements sur une nouvelle ligne.
SDL_MouseWheelEvent wheel_event()
renvoie le dernier evenement. etat de la molette de la souris / glisser sur le pad.
int window_width()
renvoie la largeur de la fenetre de l'application.
const char * smart_path(const char *filename)
renvoie le chemin(path) vers le fichier 'filename' apres l'avoir cherche dans un repertoire standard....
float global_time()
renvoie le temps ecoule depuis le lancement de l'application, en millisecondes.
int write_image(const Image &image, const char *filename)
enregistre une image dans un fichier png.
Image read_image(const char *filename)
Point max(const Point &a, const Point &b)
renvoie la plus grande composante de chaque point. x, y, z= max(a.x, b.x), max(a.y,...
GLuint make_texture(const int unit, const int width, const int height, const GLenum texel_type, const GLenum data_format, const GLenum data_type)
creation de textures filtrables / mipmaps
int screenshot(const char *filename)
enregistre le contenu de la fenetre dans un fichier. doit etre de type .png / .bmp
GLuint read_program(const char *filename, const char *definitions)
void program_uniform(const GLuint program, const char *uniform, const std::vector< unsigned > &v)
affecte un tableau de valeurs a un uniform du shader program.
int program_print_errors(const GLuint program)
affiche les erreurs de compilation.
int release_program(const GLuint program)
detruit les shaders et le program.
void program_use_texture(const GLuint program, const char *uniform, const int unit, const GLuint texture, const GLuint sampler)
configure le pipeline et le shader program pour utiliser une texture, et des parametres de filtrage,...
Image read_image_pfm(const char *filename)
charge une image a partir d'un fichier .pfm.
bool is_pfm_image(const char *filename)
renvoie vrai si le nom de fichier se termine par .pfm.
bool is_hdr_image(const char *filename)
renvoie vrai si le nom de fichier se termine par .hdr.
Image read_image_hdr(const char *filename)
representation d'une couleur (rgba) transparente ou opaque.
int init()
a deriver pour creer les objets openGL. renvoie -1 pour indiquer une erreur, 0 sinon.
int quit()
a deriver pour detruire les objets openGL. renvoie -1 pour indiquer une erreur, 0 sinon.
int render()
a deriver pour afficher les objets. renvoie 1 pour continuer, 0 pour fermer l'application.
vecteur generique, utilitaire.