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
48 int bins[100] = {};
49 for(unsigned i= 0; i < image.size(); i++)
50 {
51 Color color= image(i);
52 float g= color.r + color.g + color.b;
53
54 int b= (g - gmin) * 100 / (gmax - gmin);
55 if(b >= 99) b= 99;
56 if(b < 0) b= 0;
57 bins[b]++;
58 }
59
60 float saturation= 0;
61 float qbins= 0;
62 for(unsigned i= 0; i < 100; i++)
63 {
64 qbins= qbins + float(bins[i]) / float(image.size());
65 if(qbins > .75f)
66 return gmin + float(i+1) / 100 * (gmax - gmin);
67 }
68
69 return gmax;
70}
71
72Image tone( const Image& image, const float saturation )
73{
74 Image tmp(image.width(), image.height());
75
76 float k= 1 / std::pow(saturation, 1 / 2.2f);
77 for(unsigned i= 0; i < image.size(); i++)
78 {
79 Color color= image(i);
80 if(std::isnan(color.r) || std::isnan(color.g) || std::isnan(color.b))
81 // marque les pixels pourris avec une couleur improbable...
82 color= Color(1, 0, 1);
83 else
84 // sinon transformation rgb -> srgb
85 color= k * srgb(color);
86
87 tmp(i)= Color(color, 1);
88 }
89
90 return tmp;
91}
92
93
94Image mipmap( const Image& image )
95{
96 unsigned w= std::max(unsigned(1), image.width() / 2);
97 unsigned h= std::max(unsigned(1), image.height() / 2);
98
99 Image tmp(w, h);
100
101 for(unsigned py= 0; py < h; py++)
102 for(unsigned px= 0; px < w; px++)
103 {
104 unsigned x= 2*px;
105 unsigned y= 2*py;
106 tmp(px, py)= (image(x, y) + image(x +1, y) + image(x +1, y +1) + image(x, y +1)) / 4;
107 }
108
109 return tmp;
110}
111
112Image flipY( const Image& image )
113{
114 // flip de l'image : origine en haut a gauche
115 Image flip(image.width(), image.height());
116
117 for(unsigned y= 0; y < image.height(); y++)
118 for(unsigned x= 0; x < image.width(); x++)
119 {
120 unsigned s= image.offset(x, y);
121 unsigned d= flip.offset(x, flip.height() - y -1);
122
123 flip(d)= image(s);
124 }
125
126 return flip;
127}
128
129Image flipX( const Image& image )
130{
131 Image flip(image.width(), image.height());
132
133 for(unsigned y= 0; y < image.height(); y++)
134 for(unsigned x= 0; x < image.width(); x++)
135 {
136 unsigned s= image.offset(x, y);
137 unsigned d= flip.offset(flip.width() -x -1, y);
138
139 flip(d)= image(s);
140 }
141
142 return flip;
143}
144
145Image copy( const Image& image, const unsigned xmin, const unsigned ymin, const unsigned width, const unsigned height )
146{
147 Image copy(width, height);
148
149 for(unsigned y= 0; y < height; y++)
150 for(unsigned x= 0; x < width; x++)
151 {
152 unsigned s= image.offset(xmin+x, ymin+y);
153 unsigned d= copy.offset(x, y);
154
155 copy(d)= image(s);
156 }
157
158 return copy;
159}
160
161
162unsigned read_image_size( const char *filename )
163{
164 int w, h, c;
165 if(!stbi_info(filename, &w, &h, &c))
166 return 0;
167
168 return sizeof(Color)*w*h;
169}
170
171Image read_image( const char *filename, const bool flipY )
172{
173 stbi_ldr_to_hdr_scale(1);
174 stbi_ldr_to_hdr_gamma(1);
175 stbi_set_flip_vertically_on_load(flipY);
176
177 int width, height, channels;
178 float *data= stbi_loadf(filename, &width, &height, &channels, 4);
179 if(!data)
180 {
181 printf("[error] loading '%s'...\n", filename);
182 return {};
183 }
184
185 Image image(width, height);
186 for(unsigned i= 0, offset= 0; i < image.size(); i++, offset+= 4)
187 image(i)= Color( data[offset], data[offset + 1], data[offset + 2], data[offset + 3]);
188
189 stbi_image_free(data);
190 return image;
191}
192
193Image read_image_hdr( const char *filename, const bool flipY )
194{
195 return read_image(filename, flipY );
196}
197
198
199inline float clamp( const float x, const float min, const float max )
200{
201 if(x < min) return min;
202 else if(x > max) return max;
203 else return x;
204}
205
206bool write_image_png( const Image& image, const char *filename, const bool flipY )
207{
208 if(image.size() == 0)
209 return false;
210
211 std::vector<unsigned char> tmp(image.width()*image.height()*4);
212 for(unsigned i= 0, offset= 0; i < image.size(); i++, offset+= 4)
213 {
214 Color pixel= image(i) * 255;
215 tmp[offset ]= clamp(pixel.r, 0, 255);
216 tmp[offset +1]= clamp(pixel.g, 0, 255);
217 tmp[offset +2]= clamp(pixel.b, 0, 255);
218 tmp[offset +3]= clamp(pixel.a, 0, 255);
219 }
220
221 stbi_flip_vertically_on_write(flipY);
222 return stbi_write_png(filename, image.width(), image.height(), 4, tmp.data(), image.width() * 4) != 0;
223}
224
225bool write_image( const Image& image, const char *filename, const bool flipY )
226{
227 return write_image_png(image, filename, flipY );
228}
229
230bool write_image_bmp( const Image& image, const char *filename, const bool flipY )
231{
232 if(image.size() == 0)
233 return false;
234
235 std::vector<unsigned char> tmp(image.width()*image.height()*4);
236 for(unsigned i= 0, offset= 0; i < image.size(); i++, offset+= 4)
237 {
238 Color pixel= image(i) * 255;
239 tmp[offset ]= clamp(pixel.r, 0, 255);
240 tmp[offset +1]= clamp(pixel.g, 0, 255);
241 tmp[offset +2]= clamp(pixel.b, 0, 255);
242 tmp[offset +3]= clamp(pixel.a, 0, 255);
243 }
244
245 stbi_flip_vertically_on_write(flipY);
246 return stbi_write_bmp(filename, image.width(), image.height(), 4, tmp.data()) != 0;
247}
248
249bool write_image_hdr( const Image& image, const char *filename, const bool flipY )
250{
251 if(image.size() == 0)
252 return false;
253
254 stbi_flip_vertically_on_write(flipY);
255 return stbi_write_hdr(filename, image.width(), image.height(), 4, image.data()) != 0;
256}
257
258bool write_image_preview( const Image& image, const char *filename, const bool flipY )
259{
260 if(image.size() == 0)
261 return false;
262
263 Image tmp= tone(image, range(image));
264 return write_image_png(tmp, filename, flipY);
265}
266
267
268ImageData image_data( unsigned char *data,const int width, const int height, const int channels )
269{
270 int n= std::max(3, channels);
271 ImageData image(width, height, n);
272
273 if(channels == 4)
274 {
275 for(int i= 0; i < width*height*4; i+= 4)
276 {
277 image.pixels[i]= data[i];
278 image.pixels[i+1]= data[i+1];
279 image.pixels[i+2]= data[i+2];
280 image.pixels[i+3]= data[i+3];
281 }
282 }
283 else if(channels == 3)
284 {
285 for(int i= 0; i < width*height*3; i+= 3)
286 {
287 image.pixels[i]= data[i];
288 image.pixels[i+1]= data[i+1];
289 image.pixels[i+2]= data[i+2];
290 }
291 }
292 else
293 {
294 int k= 0;
295 for(int i= 0; i < width*height*3; i+= 3)
296 {
297 unsigned char r= 0;
298 unsigned char g= 0;
299 unsigned char b= 0;
300
301 if(n >= 1) { r= data[k++]; g= r; b= r; } // rgb= rrr
302 if(n >= 2) { g= data[k++]; b= 0; } // rgb= rg0
303 if(n >= 3) { b= data[k++]; } // rgb
304
305 image.pixels[i]= r;
306 image.pixels[i+1]= g;
307 image.pixels[i+2]= b;
308 }
309 }
310
311 stbi_image_free(data);
312 return image;
313}
314
315ImageData read_image_data( const void *buffer, const unsigned size, const bool flipY )
316{
317 stbi_set_flip_vertically_on_load(flipY);
318
319 int width, height, channels;
320 unsigned char *data= stbi_load_from_memory((const unsigned char *) buffer, size, &width, &height, &channels, 0);
321 if(!data)
322 {
323 printf("[error] reading buffer image...\n");
324 return {};
325 }
326
327 return image_data(data, width, height, channels);
328}
329
330ImageData read_image_data( const char *filename, const bool flipY )
331{
332 stbi_set_flip_vertically_on_load(flipY);
333
334 int width, height, channels;
335 unsigned char *data= stbi_load(filename, &width, &height, &channels, 0);
336 if(!data)
337 {
338 printf("[error] loading '%s'...\n", filename);
339 return {};
340 }
341
342 return image_data(data, width, height, channels);
343}
344
345
346int write_image_data( ImageData& image, const char *filename, const bool flipY )
347{
348 if(image.size != 1)
349 {
350 printf("[error] writing color image '%s'... not an 8 bits image.\n", filename);
351 return -1;
352 }
353
354 stbi_flip_vertically_on_write(flipY);
355
356 int code= 0;
357 if(std::string(filename).rfind(".png") != std::string::npos)
358 code= stbi_write_png(filename, image.width, image.height, image.channels, image.pixels.data(), image.width * image.channels) != 0;
359 else if(std::string(filename).rfind(".bmp") != std::string::npos)
360 code= stbi_write_bmp(filename, image.width, image.height, image.channels, image.pixels.data()) != 0;
361
362 else
363 {
364 printf("[error] writing color image '%s'... not a .png / .bmp image.\n", filename);
365 return -1;
366 }
367
368 if(code > 0)
369 return 0;
370
371 printf("[error] writing color image '%s'...\n", filename);
372 return -1;
373}
374
375
376ImageData flipY( const ImageData& image )
377{
378 // flip de l'image : origine en haut a gauche
379 ImageData flip(image.width, image.height, image.channels);
380
381 for(unsigned y= 0; y < image.height; y++)
382 for(unsigned x= 0; x < image.width; x++)
383 {
384 unsigned s= image.offset(x, y);
385 unsigned d= flip.offset(x, flip.height - y -1);
386
387 for(unsigned i= 0; i < image.channels; i++)
388 flip.pixels[d +i]= image.pixels[s +i];
389 }
390
391 return flip;
392}
393
394ImageData flipX( const ImageData& image )
395{
396 ImageData flip(image.width, image.height, image.channels);
397
398 for(unsigned y= 0; y < image.height; y++)
399 for(unsigned x= 0; x < image.width; x++)
400 {
401 unsigned s= image.offset(x, y);
402 unsigned d= flip.offset(flip.width -x -1, y);
403
404 for(unsigned i= 0; i < image.channels; i++)
405 flip.pixels[d +i]= image.pixels[s +i];
406 }
407
408 return flip;
409}
410
411ImageData copy( const ImageData& image, const unsigned xmin, const unsigned ymin, const unsigned width, const unsigned height )
412{
413 ImageData copy(width, height, image.channels);
414
415 for(unsigned y= 0; y < height; y++)
416 for(unsigned x= 0; x < width; x++)
417 {
418 unsigned s= image.offset(xmin +x, ymin +y);
419 unsigned d= copy.offset(x, y);
420
421 for(unsigned i= 0; i < image.channels; i++)
422 copy.pixels[d +i]= image.pixels[s +i];
423 }
424
425 return copy;
426}
427
428ImageData mimap( const ImageData& image )
429{
430 unsigned w= std::max(unsigned(1), image.width / 2);
431 unsigned h= std::max(unsigned(1), image.height / 2);
432
433 ImageData tmp(w, h, image.channels);
434
435 for(unsigned py= 0; py < h; py++)
436 for(unsigned px= 0; px < w; px++)
437 {
438 unsigned x= 2*px;
439 unsigned y= 2*py;
440 unsigned d= tmp.offset(px, py);
441
442 for(unsigned i= 0; i < image.channels; i++)
443 tmp.pixels[d +i]= (
444 image.pixels[image.offset(x, y) +i]
445 + image.pixels[image.offset(x+1, y) +i]
446 + image.pixels[image.offset(x, y+1) +i]
447 + image.pixels[image.offset(x+1, y+1) +i] ) / 4;
448 }
449
450 return tmp;
451}
452
453int miplevels( const int width, const int height )
454{
455 int w= width;
456 int h= height;
457 int levels= 1;
458 while(w > 1 || h > 1)
459 {
460 w= std::max(1, w / 2);
461 h= std::max(1, h / 2);
462 levels= levels + 1;
463 }
464
465 return levels;
466}
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:206
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:258
bool write_image_hdr(const Image &image, const char *filename, const bool flipY)
enregistre une image au format .hdr
Definition image_io.cpp:249
unsigned read_image_size(const char *filename)
renvoie la taille en octets de l'image chargee. ou 0 si erreur.
Definition image_io.cpp:162
bool write_image_bmp(const Image &image, const char *filename, const bool flipY)
enregistre une image au format .bmp
Definition image_io.cpp:230
Image mipmap(const Image &image)
reduit une image.
Definition image_io.cpp:94
Image flipY(const Image &image)
retourne l'image
Definition image_io.cpp:112
Image flipX(const Image &image)
retourne l'image
Definition image_io.cpp:129
Image read_image(const char *filename, const bool flipY)
Definition image_io.cpp:171
int write_image_data(ImageData &image, const char *filename, const bool flipY)
enregistre des donnees dans un fichier png.
Definition image_io.cpp:346
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:315
bool write_image(const Image &image, const char *filename, const bool flipY)
enregistre une image au format .png
Definition image_io.cpp:225
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:145
int miplevels(const int width, const int height)
renvoie le nombre de mipmap d'une image width x height.
Definition image_io.cpp:453
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:53