gKit2 light
image_io.cpp
1 
2 #include <cstdio>
3 #include <string>
4 #include <algorithm>
5 #include <cmath>
6 
7 #ifdef GK_MACOS
8 #include <SDL2_image/SDL_image.h>
9 #include <SDL2_image/SDL_surface.h>
10 #else
11 #include <SDL2/SDL_image.h>
12 #include <SDL2/SDL_surface.h>
13 #endif
14 
15 #include "image_io.h"
16 
17 
18 Image read_image( const char *filename )
19 {
20  // importer le fichier en utilisant SDL_image
21  SDL_Surface *surface= IMG_Load(filename);
22  if(surface == NULL)
23  {
24  printf("[error] loading image '%s'... sdl_image failed.\n", filename);
25  return Image::error();
26  }
27 
28  // verifier le format, rgb ou rgba
29  const SDL_PixelFormat format= *surface->format;
30  int width= surface->w;
31  int height= surface->h;
32  int channels= format.BitsPerPixel / 8;
33 
34  printf("loading image '%s' %dx%d %d channels...\n", filename, width, height, channels);
35 
36  Image image(surface->w, surface->h);
37  // converti les donnees en pixel rgba, et retourne l'image, origine en bas a gauche.
38  if(format.BitsPerPixel == 32)
39  {
40  int py= 0;
41  for(int y= height -1; y >= 0; y--, py++)
42  {
43  Uint8 *pixel= (Uint8 *) surface->pixels + py * surface->pitch;
44 
45  for(int x= 0; x < width; x++)
46  {
47  Uint8 r= pixel[format.Rshift / 8];
48  Uint8 g= pixel[format.Gshift / 8];
49  Uint8 b= pixel[format.Bshift / 8];
50  Uint8 a= pixel[format.Ashift / 8];
51 
52  image(x, y)= Color((float) r / 255.f, (float) g / 255.f, (float) b / 255.f, (float) a / 255.f);
53  pixel= pixel + format.BytesPerPixel;
54  }
55  }
56  }
57 
58  else
59  {
60  int py= 0;
61  for(int y= height -1; y >= 0; y--, py++)
62  {
63  Uint8 *pixel= (Uint8 *) surface->pixels + py * surface->pitch;
64 
65  for(int x= 0; x < surface->w; x++)
66  {
67  Uint8 r= 0;
68  Uint8 g= 0;
69  Uint8 b= 0;
70  if(format.BitsPerPixel >= 8) { r= pixel[format.Rshift / 8]; g= r; b= r; } // rgb= rrr
71  if(format.BitsPerPixel >= 16) { g= pixel[format.Gshift / 8]; b= 0; } // rgb= rg0
72  if(format.BitsPerPixel >= 24) { b= pixel[format.Bshift / 8]; } // rgb
73 
74  image(x, y)= Color((float) r / 255.f, (float) g / 255.f, (float) b / 255.f);
75  pixel= pixel + format.BytesPerPixel;
76  }
77  }
78  }
79 
80  SDL_FreeSurface(surface);
81  return image;
82 }
83 
84 
85 int write_image( const Image& image, const char *filename )
86 {
87  if(std::string(filename).rfind(".png") == std::string::npos && std::string(filename).rfind(".bmp") == std::string::npos )
88  {
89  printf("[error] writing color image '%s'... not a .png / .bmp image.\n", filename);
90  return -1;
91  }
92 
93  // flip de l'image : Y inverse entre GL et BMP
94  std::vector<Uint8> flip(image.width() * image.height() * 4);
95 
96  int p= 0;
97  for(int y= 0; y < image.height(); y++)
98  for(int x= 0; x < image.width(); x++)
99  {
100  Color color= image(x, image.height() - y -1);
101  Uint8 r= (Uint8) std::min(std::floor(color.r * 255.f), 255.f);
102  Uint8 g= (Uint8) std::min(std::floor(color.g * 255.f), 255.f);
103  Uint8 b= (Uint8) std::min(std::floor(color.b * 255.f), 255.f);
104  Uint8 a= (Uint8) std::min(std::floor(color.a * 255.f), 255.f);
105 
106  flip[p]= r;
107  flip[p +1]= g;
108  flip[p +2]= b;
109  flip[p +3]= a;
110  p= p + 4;
111  }
112 
113  SDL_Surface *surface= SDL_CreateRGBSurfaceFrom((void *) &flip.front(), image.width(), image.height(),
114  32, image.width() * 4,
115 #if 0
116  0xFF000000,
117  0x00FF0000,
118  0x0000FF00,
119  0x000000FF
120 #else
121  0x000000FF,
122  0x0000FF00,
123  0x00FF0000,
124  0xFF000000
125 #endif
126  );
127 
128  int code= -1;
129  if(std::string(filename).rfind(".png") != std::string::npos)
130  code= IMG_SavePNG(surface, filename);
131  else if(std::string(filename).rfind(".bmp") != std::string::npos)
132  code= SDL_SaveBMP(surface, filename);
133 
134  SDL_FreeSurface(surface);
135  if(code < 0)
136  printf("[error] writing color image '%s'...\n%s\n", filename, SDL_GetError());
137  return code;
138 }
139 
140 
141 ImageData image_data( SDL_Surface *surface )
142 {
143  if(!surface)
144  {
145  //~ printf("loading image...\n");
146  return {};
147  }
148 
149  // verifier le format, rgb ou rgba
150  SDL_PixelFormat format= *surface->format;
151 
152  int width= surface->w;
153  int height= surface->h;
154  int channels= format.BitsPerPixel / 8;
155 
156  if(channels < 3) channels= 3;
157  ImageData image(width, height, channels);
158 
159  //~ printf("loading image %dx%d %d channels...\n", width, height, channels);
160 
161  // converti les donnees en pixel rgba, et retourne l'image, origine en bas a gauche.
162  if(format.BitsPerPixel == 32)
163  {
164  int py= 0;
165  for(int y= height -1; y >= 0; y--, py++)
166  {
167  Uint8 *pixel= (Uint8 *) surface->pixels + py * surface->pitch;
168 
169  for(int x= 0; x < width; x++)
170  {
171  Uint8 r= pixel[format.Rshift / 8];
172  Uint8 g= pixel[format.Gshift / 8];
173  Uint8 b= pixel[format.Bshift / 8];
174  Uint8 a= pixel[format.Ashift / 8];
175 
176  std::size_t offset= image.offset(x, y);
177  image.pixels[offset]= r;
178  image.pixels[offset +1]= g;
179  image.pixels[offset +2]= b;
180  image.pixels[offset +3]= a;
181  pixel= pixel + format.BytesPerPixel;
182  }
183  }
184  }
185 
186  else
187  {
188  int py= 0;
189  for(int y= height -1; y >= 0; y--, py++)
190  {
191  Uint8 *pixel= (Uint8 *) surface->pixels + py * surface->pitch;
192 
193  for(int x= 0; x < surface->w; x++)
194  {
195  Uint8 r= 0;
196  Uint8 g= 0;
197  Uint8 b= 0;
198 
199  if(format.BitsPerPixel >= 8) { r= pixel[format.Rshift / 8]; g= r; b= r; } // rgb= rrr
200  if(format.BitsPerPixel >= 16) { g= pixel[format.Gshift / 8]; b= 0; } // rgb= rg0
201  if(format.BitsPerPixel >= 24) { b= pixel[format.Bshift / 8]; } // rgb
202 
203  std::size_t offset= image.offset(x, y);
204  image.pixels[offset]= r;
205  image.pixels[offset +1]= g;
206  image.pixels[offset +2]= b;
207  pixel= pixel + format.BytesPerPixel;
208  }
209  }
210  }
211 
212  SDL_FreeSurface(surface);
213  return image;
214 }
215 
216 ImageData read_image_data( const char *filename )
217 {
218  // importer le fichier en utilisant SDL_image
219  SDL_Surface *surface= IMG_Load(filename);
220  if(surface == NULL)
221  {
222  printf("[error] loading image '%s'... sdl_image failed.\n%s\n", filename, SDL_GetError());
223  return ImageData();
224  }
225 
226  return image_data(surface);
227 }
228 
229 int write_image_data( ImageData& image, const char *filename )
230 {
231  if(std::string(filename).rfind(".png") == std::string::npos && std::string(filename).rfind(".bmp") == std::string::npos )
232  {
233  printf("[error] writing color image '%s'... not a .png / .bmp image.\n", filename);
234  return -1;
235  }
236 
237  if(image.size != 1)
238  {
239  printf("[error] writing color image '%s'... not an 8 bits image.\n", filename);
240  return -1;
241  }
242 
243  // flip de l'image : origine en bas a gauche
244  std::vector<Uint8> flip(image.width * image.height * 4);
245 
246  int p= 0;
247  for(int y= 0; y < image.height; y++)
248  for(int x= 0; x < image.width; x++)
249  {
250  std::size_t offset= image.offset(x, image.height - y -1);
251  Uint8 r= image.pixels[offset];
252  Uint8 g= image.pixels[offset +1];
253  Uint8 b= image.pixels[offset +2];
254  Uint8 a= 255;
255  if(image.channels > 3)
256  a= image.pixels[offset +3];
257 
258  flip[p]= r;
259  flip[p +1]= g;
260  flip[p +2]= b;
261  flip[p +3]= a;
262  p= p + 4;
263  }
264 
265  // construit la surface sdl
266  SDL_Surface *surface= SDL_CreateRGBSurfaceFrom((void *) &flip.front(), image.width, image.height,
267  32, image.width * 4,
268 #if 0
269  0xFF000000,
270  0x00FF0000,
271  0x0000FF00,
272  0x000000FF
273 #else
274  0x000000FF,
275  0x0000FF00,
276  0x00FF0000,
277  0xFF000000
278 #endif
279  );
280 
281  // enregistre le fichier
282  int code= -1;
283  if(std::string(filename).rfind(".png") != std::string::npos)
284  code= IMG_SavePNG(surface, filename);
285  else if(std::string(filename).rfind(".bmp") != std::string::npos)
286  code= SDL_SaveBMP(surface, filename);
287 
288  SDL_FreeSurface(surface);
289  if(code < 0)
290  printf("[error] writing color image '%s'...\n%s\n", filename, SDL_GetError());
291  return code;
292 }
293 
294 
295 Image flipY( const Image& image )
296 {
297  // flip de l'image : origine en haut a gauche
298  Image flip(image.width(), image.height());
299 
300  for(int y= 0; y < image.height(); y++)
301  for(int x= 0; x < image.width(); x++)
302  {
303  size_t s= image.offset(x, y);
304  size_t d= flip.offset(x, flip.height() - y -1);
305 
306  flip(d)= image(s);
307  }
308 
309  return flip;
310 }
311 
312 Image flipX( const Image& image )
313 {
314  Image flip(image.width(), image.height());
315 
316  for(int y= 0; y < image.height(); y++)
317  for(int x= 0; x < image.width(); x++)
318  {
319  size_t s= image.offset(x, y);
320  size_t d= flip.offset(flip.width() -x -1, y);
321 
322  flip(d)= image(s);
323  }
324 
325  return flip;
326 }
327 
328 Image copy( const Image& image, const int xmin, const int ymin, const int width, const int height )
329 {
330  Image copy(width, height);
331 
332  for(int y= 0; y < height; y++)
333  for(int x= 0; x < width; x++)
334  {
335  size_t s= image.offset(xmin+x, ymin+y);
336  size_t d= copy.offset(x, y);
337 
338  copy(d)= image(s);
339  }
340 
341  return copy;
342 }
343 
344 
345 ImageData flipY( const ImageData& image )
346 {
347  // flip de l'image : origine en haut a gauche
348  ImageData flip(image.width, image.height, image.channels);
349 
350  for(int y= 0; y < image.height; y++)
351  for(int x= 0; x < image.width; x++)
352  {
353  size_t s= image.offset(x, y);
354  size_t d= flip.offset(x, flip.height - y -1);
355 
356  for(int i= 0; i < image.channels; i++)
357  flip.pixels[d+i]= image.pixels[s+i];
358  }
359 
360  return flip;
361 }
362 
363 ImageData flipX( const ImageData& image )
364 {
365  ImageData flip(image.width, image.height, image.channels);
366 
367  for(int y= 0; y < image.height; y++)
368  for(int x= 0; x < image.width; x++)
369  {
370  size_t s= image.offset(x, y);
371  size_t d= flip.offset(flip.width -x -1, y);
372 
373  for(int i= 0; i < image.channels; i++)
374  flip.pixels[d+i]= image.pixels[s+i];
375  }
376 
377  return flip;
378 }
379 
380 ImageData copy( const ImageData& image, const int xmin, const int ymin, const int width, const int height )
381 {
382  ImageData copy(width, height, image.channels);
383 
384  for(int y= 0; y < height; y++)
385  for(int x= 0; x < width; x++)
386  {
387  size_t s= image.offset(xmin+x, ymin+y);
388  size_t d= copy.offset(x, y);
389 
390  for(int i= 0; i < image.channels; i++)
391  copy.pixels[d+i]= image.pixels[s+i];
392  }
393 
394  return copy;
395 }
396 
398 {
399  ImageData mip(std::max(1, image.width/2), std::max(1, image.height/2), image.channels);
400 
401  for(int y= 0; y < mip.height; y++)
402  for(int x= 0; x < mip.width; x++)
403  {
404  size_t d= mip.offset(x, y);
405  for(int i= 0; i < image.channels; i++)
406  mip.pixels[d+i]= (
407  image.pixels[image.offset(2*x, 2*y)+i]
408  + image.pixels[image.offset(2*x+1, 2*y)+i]
409  + image.pixels[image.offset(2*x, 2*y+1)+i]
410  + image.pixels[image.offset(2*x+1, 2*y+1)+i] ) / 4;
411  }
412 
413  return mip;
414 }
415 
416 Image downscale( const Image& image )
417 {
418  Image mip(std::max(1, image.width()/2), std::max(1, image.height()/2));
419 
420  for(int y= 0; y < mip.height(); y++)
421  for(int x= 0; x < mip.width(); x++)
422  mip(x, y)= (image(2*x, 2*y) + image(2*x+1, 2*y)
423  + image(2*x, 2*y+1) + image(2*x+1, 2*y+1)) / 4;
424 
425  return mip;
426 }
427 
428 
representation d'une image.
Definition: image.h:21
int height() const
renvoie la hauteur de l'image.
Definition: image.h:100
static Image & error()
Definition: image.h:126
unsigned offset(const int x, const int y) const
renvoie l'indice du pixel.
Definition: image.h:105
int width() const
renvoie la largeur de l'image.
Definition: image.h:98
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
ImageData read_image_data(const char *filename)
charge les donnees d'un fichier png. renvoie une image initialisee par defaut en cas d'echec.
Definition: image_io.cpp:216
int write_image_data(ImageData &image, const char *filename)
enregistre des donnees dans un fichier png.
Definition: image_io.cpp:229
ImageData image_data(SDL_Surface *surface)
converti une surface SDL en imageData, cf RWops pour charger les images deja en memoire.
Definition: image_io.cpp:141
int write_image(const Image &image, const char *filename)
enregistre une image dans un fichier png.
Definition: image_io.cpp:85
Image flipY(const Image &image)
retourne l'image
Definition: image_io.cpp:295
Image flipX(const Image &image)
retourne l'image
Definition: image_io.cpp:312
Image copy(const Image &image, const int xmin, const int ymin, const int width, const int height)
renvoie un bloc de l'image
Definition: image_io.cpp:328
ImageData downscale(const ImageData &image)
renvoie une image filtree plus petite.
Definition: image_io.cpp:397
Image read_image(const char *filename)
Definition: image_io.cpp:18
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,...
Definition: vec.cpp:35
Point min(const Point &a, const Point &b)
renvoie la plus petite composante de chaque point. x, y, z= min(a.x, b.x), min(a.y,...
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:38