gKit2 light
Loading...
Searching...
No Matches
image_io.cpp
1
2#include <cfloat>
3#include <string>
4
5#include "color.h"
6#include "image.h"
7#include "image_io.h"
8
9#define STB_IMAGE_IMPLEMENTATION
10#include "stb_image.h"
11
12#define STB_IMAGE_WRITE_IMPLEMENTATION
13#include "stb_image_write.h"
14
15Image srgb( const Image& image )
16{
17 Image tmp(image.width(), image.height());
18
19 for(unsigned i= 0; i < image.size(); i++)
20 tmp(i)= srgb(image(i));
21
22 return tmp;
23}
24
25Image linear( const Image& image )
26{
27 Image tmp(image.width(), image.height());
28
29 for(unsigned i= 0; i < image.size(); i++)
30 tmp(i)= linear(image(i));
31
32 return tmp;
33}
34
35float range( const Image& image )
36{
37 float gmin= FLT_MAX;
38 float gmax= 0;
39 for(unsigned i= 0; i < image.size(); i++)
40 {
41 Color color= image(i);
42 float g= color.r + color.g + color.b;
43
44 if(g < gmin) gmin= g;
45 if(g > gmax) gmax= g;
46 }
47
49 int bins[100] = {};
50 for(unsigned i= 0; i < image.size(); i++)
51 {
52 Color color= image(i);
53 float g= color.r + color.g + color.b;
54
55 int b= (g - gmin) * 100 / (gmax - gmin);
56 if(b >= 99) b= 99;
57 if(b < 0) b= 0;
58 bins[b]++;
59 }
60
61 float saturation= 0;
62 float qbins= 0;
63 for(unsigned i= 0; i < 100; i++)
64 {
65 qbins= qbins + float(bins[i]) / float(image.size());
66 if(qbins > .75f)
67 return gmin + float(i+1) / 100 * (gmax - gmin);
68 }
69
70 return gmax;
71}
72
73Image tone( const Image& image, const float saturation )
74{
75 Image tmp(image.width(), image.height());
76
77 float k= 1 / std::pow(saturation, 1 / 2.2f);
78 for(unsigned i= 0; i < image.size(); i++)
79 {
80 Color color= image(i);
81 if(std::isnan(color.r) || std::isnan(color.g) || std::isnan(color.b))
82 // marque les pixels pourris avec une couleur improbable...
83 color= Color(1, 0, 1);
84 else
85 // sinon transformation rgb -> srgb
86 color= k * srgb(color);
87
88 tmp(i)= Color(color, 1);
89 }
90
91 return tmp;
92}
93
94
95Image mipmap( const Image& image )
96{
97 unsigned w= std::max(unsigned(1), image.width() / 2);
98 unsigned h= std::max(unsigned(1), image.height() / 2);
99
100 Image tmp(w, h);
101
102 for(unsigned py= 0; py < h; py++)
103 for(unsigned px= 0; px < w; px++)
104 {
105 unsigned x= 2*px;
106 unsigned y= 2*py;
107 tmp(px, py)= (image(x, y) + image(x +1, y) + image(x +1, y +1) + image(x, y +1)) / 4;
108 }
109
110 return tmp;
111}
112
113Image flipY( const Image& image )
114{
115 // flip de l'image : origine en haut a gauche
116 Image flip(image.width(), image.height());
117
118 for(unsigned y= 0; y < image.height(); y++)
119 for(unsigned x= 0; x < image.width(); x++)
120 {
121 unsigned s= image.offset(x, y);
122 unsigned d= flip.offset(x, flip.height() - y -1);
123
124 flip(d)= image(s);
125 }
126
127 return flip;
128}
129
130Image flipX( const Image& image )
131{
132 Image flip(image.width(), image.height());
133
134 for(unsigned y= 0; y < image.height(); y++)
135 for(unsigned x= 0; x < image.width(); x++)
136 {
137 unsigned s= image.offset(x, y);
138 unsigned d= flip.offset(flip.width() -x -1, y);
139
140 flip(d)= image(s);
141 }
142
143 return flip;
144}
145
146Image copy( const Image& image, const unsigned xmin, const unsigned ymin, const unsigned width, const unsigned height )
147{
148 Image copy(width, height);
149
150 for(unsigned y= 0; y < height; y++)
151 for(unsigned x= 0; x < width; x++)
152 {
153 unsigned s= image.offset(xmin+x, ymin+y);
154 unsigned d= copy.offset(x, y);
155
156 copy(d)= image(s);
157 }
158
159 return copy;
160}
161
162Image& blit( Image& image, const unsigned xmin, const unsigned ymin, const Image& pixels )
163{
164 if(image.size() == 0)
165 return image;
166 if(pixels.size() == 0)
167 return image;
168
169 unsigned xmax= std::min( image.width(), xmin + pixels.width() );
170 unsigned ymax= std::min( image.height(), ymin + pixels.height() );
171 unsigned w= xmax - xmin;
172 unsigned h= ymax - ymin;
173
174 for(unsigned y= 0; y < h; y++)
175 for(unsigned x= 0; x < w; x++)
176 image(x + xmin, y + ymin)= pixels(x, y);
177
178 return image;
179}
180
181
182unsigned read_image_size( const char *filename )
183{
184 int w, h, c;
185 if(!stbi_info(filename, &w, &h, &c))
186 return 0;
187
188 return sizeof(Color)*w*h;
189}
190
191Image read_image( const char *filename, const bool flipY )
192{
193 stbi_ldr_to_hdr_scale(1);
194 stbi_ldr_to_hdr_gamma(1);
195 stbi_set_flip_vertically_on_load(flipY);
196
197 int width, height, channels;
198 float *data= stbi_loadf(filename, &width, &height, &channels, 4);
199 if(!data)
200 {
201 printf("[error] loading '%s'...\n", filename);
202 return {};
203 }
204
205 Image image(width, height);
206 for(unsigned i= 0, offset= 0; i < image.size(); i++, offset+= 4)
207 image(i)= Color( data[offset], data[offset + 1], data[offset + 2], data[offset + 3]);
208
209 stbi_image_free(data);
210 return image;
211}
212
213Image read_image_hdr( const char *filename, const bool flipY )
214{
215 return read_image(filename, flipY );
216}
217
218
219inline float clamp( const float x, const float min, const float max )
220{
221 if(x < min) return min;
222 else if(x > max) return max;
223 else return x;
224}
225
226bool write_image_png( const Image& image, const char *filename, const bool flipY )
227{
228 if(image.size() == 0)
229 return false;
230
231 std::vector<unsigned char> tmp(image.width()*image.height()*4);
232 for(unsigned i= 0, offset= 0; i < image.size(); i++, offset+= 4)
233 {
234 Color pixel= image(i) * 255;
235 tmp[offset ]= clamp(pixel.r, 0, 255);
236 tmp[offset +1]= clamp(pixel.g, 0, 255);
237 tmp[offset +2]= clamp(pixel.b, 0, 255);
238 tmp[offset +3]= clamp(pixel.a, 0, 255);
239 }
240
241 stbi_flip_vertically_on_write(flipY);
242 return stbi_write_png(filename, image.width(), image.height(), 4, tmp.data(), image.width() * 4) != 0;
243}
244
245bool write_image( const Image& image, const char *filename, const bool flipY )
246{
247 return write_image_png(image, filename, flipY );
248}
249
250bool write_image_bmp( const Image& image, const char *filename, const bool flipY )
251{
252 if(image.size() == 0)
253 return false;
254
255 std::vector<unsigned char> tmp(image.width()*image.height()*4);
256 for(unsigned i= 0, offset= 0; i < image.size(); i++, offset+= 4)
257 {
258 Color pixel= image(i) * 255;
259 tmp[offset ]= clamp(pixel.r, 0, 255);
260 tmp[offset +1]= clamp(pixel.g, 0, 255);
261 tmp[offset +2]= clamp(pixel.b, 0, 255);
262 tmp[offset +3]= clamp(pixel.a, 0, 255);
263 }
264
265 stbi_flip_vertically_on_write(flipY);
266 return stbi_write_bmp(filename, image.width(), image.height(), 4, tmp.data()) != 0;
267}
268
269bool write_image_hdr( const Image& image, const char *filename, const bool flipY )
270{
271 if(image.size() == 0)
272 return false;
273
274 stbi_flip_vertically_on_write(flipY);
275 return stbi_write_hdr(filename, image.width(), image.height(), 4, image.data()) != 0;
276}
277
278bool write_image_preview( const Image& image, const char *filename, const bool flipY )
279{
280 if(image.size() == 0)
281 return false;
282
283 Image tmp= tone(image, range(image));
284 return write_image_png(tmp, filename, flipY);
285}
286
287
288ImageData image_data( unsigned char *data,const int width, const int height, const int channels )
289{
290 int n= std::max(3, channels);
291 ImageData image(width, height, n);
292
293 if(channels == 4)
294 {
295 for(int i= 0; i < width*height*4; i+= 4)
296 {
297 image.pixels[i]= data[i];
298 image.pixels[i+1]= data[i+1];
299 image.pixels[i+2]= data[i+2];
300 image.pixels[i+3]= data[i+3];
301 }
302 }
303 else if(channels == 3)
304 {
305 for(int i= 0; i < width*height*3; i+= 3)
306 {
307 image.pixels[i]= data[i];
308 image.pixels[i+1]= data[i+1];
309 image.pixels[i+2]= data[i+2];
310 }
311 }
312 else
313 {
314 int k= 0;
315 for(int i= 0; i < width*height*3; i+= 3)
316 {
317 unsigned char r= 0;
318 unsigned char g= 0;
319 unsigned char b= 0;
320
321 if(n >= 1) { r= data[k++]; g= r; b= r; } // rgb= rrr
322 if(n >= 2) { g= data[k++]; b= 0; } // rgb= rg0
323 if(n >= 3) { b= data[k++]; } // rgb
324
325 image.pixels[i]= r;
326 image.pixels[i+1]= g;
327 image.pixels[i+2]= b;
328 }
329 }
330
331 stbi_image_free(data);
332 return image;
333}
334
335ImageData read_image_data( const void *buffer, const unsigned size, const bool flipY )
336{
337 stbi_set_flip_vertically_on_load(flipY);
338
339 int width, height, channels;
340 unsigned char *data= stbi_load_from_memory((const unsigned char *) buffer, size, &width, &height, &channels, 0);
341 if(!data)
342 {
343 printf("[error] reading buffer image...\n");
344 return {};
345 }
346
347 return image_data(data, width, height, channels);
348}
349
350ImageData read_image_data( const char *filename, const bool flipY )
351{
352 stbi_set_flip_vertically_on_load(flipY);
353
354 int width, height, channels;
355 unsigned char *data= stbi_load(filename, &width, &height, &channels, 0);
356 if(!data)
357 {
358 printf("[error] loading '%s'...\n", filename);
359 return {};
360 }
361
362 return image_data(data, width, height, channels);
363}
364
365
366int write_image_data( const ImageData& image, const char *filename, const bool flipY )
367{
368 if(image.size != 1)
369 {
370 printf("[error] writing color image '%s'... not an 8 bits image.\n", filename);
371 return -1;
372 }
373
374 stbi_flip_vertically_on_write(flipY);
375
376 int code= 0;
377 if(std::string(filename).rfind(".png") != std::string::npos)
378 code= stbi_write_png(filename, image.width, image.height, image.channels, image.pixels.data(), image.width * image.channels) != 0;
379 else if(std::string(filename).rfind(".bmp") != std::string::npos)
380 code= stbi_write_bmp(filename, image.width, image.height, image.channels, image.pixels.data()) != 0;
381
382 else
383 {
384 printf("[error] writing color image '%s'... not a .png / .bmp image.\n", filename);
385 return -1;
386 }
387
388 if(code > 0)
389 return 0;
390
391 printf("[error] writing color image '%s'...\n", filename);
392 return -1;
393}
394
395
396
397ImageData srgb( const ImageData& image )
398{
399 ImageData tmp(image.width, image.height, image.channels);
400
401 for(unsigned i= 0; i < image.pixels.size(); i+= image.channels)
402 {
403 Color pixel= srgb( Color( image.pixels[i], image.pixels[i+1], image.pixels[i+2], (image.channels > 3) ? image.pixels[i+3] : 255 ) / 255 );
404
405 tmp.pixels[i]= clamp(pixel.r * 255, 0, 255);
406 tmp.pixels[i +1]= clamp(pixel.g * 255, 0, 255);
407 tmp.pixels[i +2]= clamp(pixel.b * 255, 0, 255);
408 if(image.channels > 3)
409 tmp.pixels[i +3]= clamp(pixel.a * 255, 0, 255);
410 }
411
412 return tmp;
413}
414
416{
417 ImageData tmp(image.width, image.height, image.channels);
418
419 for(unsigned i= 0; i < image.pixels.size(); i+= image.channels)
420 {
421 Color pixel= linear( Color( image.pixels[i], image.pixels[i+1], image.pixels[i+2], (image.channels > 3) ? image.pixels[i+3] : 255 ) / 255 );
422
423 tmp.pixels[i]= clamp(pixel.r * 255, 0, 255);
424 tmp.pixels[i +1]= clamp(pixel.g * 255, 0, 255);
425 tmp.pixels[i +2]= clamp(pixel.b * 255, 0, 255);
426 if(image.channels > 3)
427 tmp.pixels[i +3]= clamp(pixel.a * 255, 0, 255);
428 }
429
430 return tmp;
431}
432
433ImageData flipY( const ImageData& image )
434{
435 // flip de l'image : origine en haut a gauche
436 ImageData flip(image.width, image.height, image.channels);
437
438 for(unsigned y= 0; y < image.height; y++)
439 for(unsigned x= 0; x < image.width; x++)
440 {
441 unsigned s= image.offset(x, y);
442 unsigned d= flip.offset(x, flip.height - y -1);
443
444 for(unsigned i= 0; i < image.channels; i++)
445 flip.pixels[d +i]= image.pixels[s +i];
446 }
447
448 return flip;
449}
450
451ImageData flipX( const ImageData& image )
452{
453 ImageData flip(image.width, image.height, image.channels);
454
455 for(unsigned y= 0; y < image.height; y++)
456 for(unsigned x= 0; x < image.width; x++)
457 {
458 unsigned s= image.offset(x, y);
459 unsigned d= flip.offset(flip.width -x -1, y);
460
461 for(unsigned i= 0; i < image.channels; i++)
462 flip.pixels[d +i]= image.pixels[s +i];
463 }
464
465 return flip;
466}
467
468ImageData copy( const ImageData& image, const unsigned xmin, const unsigned ymin, const unsigned width, const unsigned height )
469{
470 ImageData copy(width, height, image.channels);
471
472 for(unsigned y= 0; y < height; y++)
473 for(unsigned x= 0; x < width; x++)
474 {
475 unsigned s= image.offset(xmin +x, ymin +y);
476 unsigned d= copy.offset(x, y);
477
478 for(unsigned i= 0; i < image.channels; i++)
479 copy.pixels[d +i]= image.pixels[s +i];
480 }
481
482 return copy;
483}
484
485
486ImageData& blit( ImageData& image, const unsigned xmin, const unsigned ymin, const ImageData& pixels )
487{
488 if(image.pixels.size() == 0)
489 return image;
490 if(pixels.pixels.size() == 0)
491 return image;
492 if(image.channels != pixels.channels)
493 return image;
494
495 unsigned xmax= std::min( image.width, xmin + pixels.width );
496 unsigned ymax= std::min( image.height, ymin + pixels.height );
497 unsigned w= xmax - xmin;
498 unsigned h= ymax - ymin;
499
500 for(unsigned y= 0; y < h; y++)
501 for(unsigned x= 0; x < w; x++)
502 {
503 unsigned char *dst= image.pixels.data() + image.offset(x + xmin, y + ymin);
504 const unsigned char *src= pixels.pixels.data() + pixels.offset(x, y);
505 for(unsigned i= 0; i < pixels.channels; i++)
506 dst[i]= src[i];
507 }
508
509 return image;
510}
511
513{
514 unsigned w= std::max(unsigned(1), image.width / 2);
515 unsigned h= std::max(unsigned(1), image.height / 2);
516
517 ImageData tmp(w, h, image.channels);
518
519 for(unsigned py= 0; py < h; py++)
520 for(unsigned px= 0; px < w; px++)
521 {
522 unsigned x= 2*px;
523 unsigned y= 2*py;
524 unsigned d= tmp.offset(px, py);
525
526 for(unsigned i= 0; i < image.channels; i++)
527 tmp.pixels[d +i]= (
528 image.pixels[image.offset(x, y) +i]
529 + image.pixels[image.offset(x+1, y) +i]
530 + image.pixels[image.offset(x, y+1) +i]
531 + image.pixels[image.offset(x+1, y+1) +i] ) / 4;
532 }
533
534 return tmp;
535}
536
537int miplevels( const int width, const int height )
538{
539 int w= width;
540 int h= height;
541 int levels= 1;
542 while(w > 1 || h > 1)
543 {
544 w= std::max(1, w / 2);
545 h= std::max(1, h / 2);
546 levels= levels + 1;
547 }
548
549 return levels;
550}
representation d'une image.
Definition image.h:21
unsigned width() const
renvoie la largeur de l'image.
Definition image.h:100
unsigned height() const
renvoie la hauteur de l'image.
Definition image.h:102
unsigned offset(const int x, const int y) const
Definition image.h:108
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().
Definition text.cpp:140
bool write_image_png(const Image &image, const char *filename, const bool flipY)
enregistre une image au format .png
Definition image_io.cpp:226
bool write_image_preview(const Image &image, const char *filename, const bool flipY)
raccourci pour write_image_png(tone(image, range(image)), "image.png")
Definition image_io.cpp:278
bool write_image_hdr(const Image &image, const char *filename, const bool flipY)
enregistre une image au format .hdr
Definition image_io.cpp:269
unsigned read_image_size(const char *filename)
renvoie la taille en octets de l'image chargee. ou 0 si erreur.
Definition image_io.cpp:182
bool write_image_bmp(const Image &image, const char *filename, const bool flipY)
enregistre une image au format .bmp
Definition image_io.cpp:250
Image & blit(Image &image, const unsigned xmin, const unsigned ymin, const Image &pixels)
remplace un bout d'image par une autre. copie l'image pixels dans image [xmin, xmin+pixels....
Definition image_io.cpp:162
Image mipmap(const Image &image)
reduit une image.
Definition image_io.cpp:95
Image flipY(const Image &image)
retourne l'image
Definition image_io.cpp:113
Image flipX(const Image &image)
retourne l'image
Definition image_io.cpp:130
Image read_image(const char *filename, const bool flipY)
Definition image_io.cpp:191
float clamp(const float x, const float min, const float max)
renvoie une valeur comprise entre a et b.
Definition image_io.cpp:219
int write_image_data(const ImageData &image, const char *filename, const bool flipY)
enregistre des donnees dans un fichier png.
Definition image_io.cpp:366
Image linear(const Image &image)
transformation couleur : srgb vers rgb lineaire
Definition image_io.cpp:25
ImageData read_image_data(const void *buffer, const unsigned size, const bool flipY)
charge les donnees d'un fichier png stocke en memoire. renvoie une image initialisee par defaut en ca...
Definition image_io.cpp:335
bool write_image(const Image &image, const char *filename, const bool flipY)
enregistre une image au format .png
Definition image_io.cpp:245
Image copy(const Image &image, const unsigned xmin, const unsigned ymin, const unsigned width, const unsigned height)
renvoie un bloc de l'image
Definition image_io.cpp:146
int miplevels(const int width, const int height)
renvoie le nombre de mipmap d'une image width x height.
Definition image_io.cpp:537
Image srgb(const Image &image)
transformation couleur : rgb lineaire vers srgb
Definition image_io.cpp:15
Point max(const Point &a, const Point &b)
renvoie la plus grande composante de chaque point { max(a.x, b.x), max(a.y, b.y), max(a....
Definition vec.cpp:35
Point min(const Point &a, const Point &b)
renvoie la plus petite composante de chaque point { min(a.x, b.x), min(a.y, b.y), min(a....
Definition vec.cpp:30
representation d'une couleur (rgba) transparente ou opaque.
Definition color.h:14
stockage temporaire des donnees d'une image.
Definition image_io.h:55