The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
savepng.cpp
Go to the documentation of this file.
1 /*
2  * SDL_SavePNG -- libpng-based SDL_Surface writer.
3  *
4  * This code is free software, available under zlib/libpng license.
5  * http://www.libpng.org/pub/png/src/libpng-LICENSE.txt
6  */
7 #include <SDL.h>
8 #include <png.h>
9 
10 #include "savepng.h"
11 
12 #pragma GCC diagnostic ignored "-Wold-style-cast"
13 
14 #define SAVEPNG_SUCCESS 0
15 #define SAVEPNG_ERROR -1
16 
17 #define USE_ROW_POINTERS
18 
19 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
20 #define rmask 0xFF000000
21 #define gmask 0x00FF0000
22 #define bmask 0x0000FF00
23 #define amask 0x000000FF
24 #else
25 #define rmask 0x000000FF
26 #define gmask 0x0000FF00
27 #define bmask 0x00FF0000
28 #define amask 0xFF000000
29 #endif
30 
31 #include <cstdlib>
32 
33 /* libpng callbacks */
34 static void png_error_SDL(png_structp /*ctx*/, png_const_charp str)
35 {
36  SDL_SetError("libpng: %s\n", str);
37 }
38 static void png_write_SDL(png_structp png_ptr, png_bytep data, png_size_t length)
39 {
40  SDL_RWops *rw = static_cast<SDL_RWops*>(png_get_io_ptr(png_ptr));
41  SDL_RWwrite(rw, data, sizeof(png_byte), length);
42 }
43 
44 SDL_Surface *SDL_PNGFormatAlpha(SDL_Surface *src)
45 {
46  SDL_Surface *surf;
47  SDL_Rect rect = { 0 , 0 , 0 , 0 };
48 
49  /* NO-OP for images < 32bpp and 32bpp images that already have Alpha channel */
50  if (src->format->BitsPerPixel <= 24 || src->format->Amask) {
51  src->refcount++;
52  return src;
53  }
54 
55  /* Convert 32bpp alpha-less image to 24bpp alpha-less image */
56  rect.w = src->w;
57  rect.h = src->h;
58  surf = SDL_CreateRGBSurface(src->flags, src->w, src->h, 24,
59  src->format->Rmask, src->format->Gmask, src->format->Bmask, 0);
60  SDL_LowerBlit(src, &rect, surf, &rect);
61 
62  return surf;
63 }
64 
65 int SDL_SavePNG_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
66 {
67  png_structp png_ptr;
68  png_infop info_ptr;
69  png_colorp pal_ptr;
70  SDL_Palette *pal;
71  int i, colortype;
72 #ifdef USE_ROW_POINTERS
73  png_bytep *row_pointers;
74 #endif
75  /* Initialize and do basic error checking */
76  if (!dst)
77  {
78  SDL_SetError("Argument 2 to SDL_SavePNG_RW can't be nullptr, expecting SDL_RWops*\n");
79  return (SAVEPNG_ERROR);
80  }
81  if (!surface)
82  {
83  SDL_SetError("Argument 1 to SDL_SavePNG_RW can't be nullptr, expecting SDL_Surface*\n");
84  if (freedst) SDL_RWclose(dst);
85  return (SAVEPNG_ERROR);
86  }
87  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, png_error_SDL, nullptr); /* err_ptr, err_fn, warn_fn */
88  if (!png_ptr)
89  {
90  SDL_SetError("Unable to png_create_write_struct on %s\n", PNG_LIBPNG_VER_STRING);
91  if (freedst) SDL_RWclose(dst);
92  return (SAVEPNG_ERROR);
93  }
94  info_ptr = png_create_info_struct(png_ptr);
95  if (!info_ptr)
96  {
97  SDL_SetError("Unable to png_create_info_struct\n");
98  png_destroy_write_struct(&png_ptr, nullptr);
99  if (freedst) SDL_RWclose(dst);
100  return (SAVEPNG_ERROR);
101  }
102  if (setjmp(png_jmpbuf(png_ptr))) /* All other errors, see also "png_error_SDL" */
103  {
104  png_destroy_write_struct(&png_ptr, &info_ptr);
105  if (freedst) SDL_RWclose(dst);
106  return (SAVEPNG_ERROR);
107  }
108 
109  /* Setup our RWops writer */
110  png_set_write_fn(png_ptr, dst, png_write_SDL, nullptr); /* w_ptr, write_fn, flush_fn */
111 
112  /* Prepare chunks */
113  colortype = PNG_COLOR_MASK_COLOR;
114  if (surface->format->BytesPerPixel > 0
115  && surface->format->BytesPerPixel <= 8
116  && (pal = surface->format->palette))
117  {
118  colortype |= PNG_COLOR_MASK_PALETTE;
119  pal_ptr = static_cast<png_colorp>(malloc(pal->ncolors * sizeof(png_color)));
120  for (i = 0; i < pal->ncolors; i++) {
121  pal_ptr[i].red = pal->colors[i].r;
122  pal_ptr[i].green = pal->colors[i].g;
123  pal_ptr[i].blue = pal->colors[i].b;
124  }
125  png_set_PLTE(png_ptr, info_ptr, pal_ptr, pal->ncolors);
126  free(pal_ptr);
127  }
128  else if (surface->format->BytesPerPixel > 3 || surface->format->Amask)
129  colortype |= PNG_COLOR_MASK_ALPHA;
130 
131  png_set_IHDR(png_ptr, info_ptr, surface->w, surface->h, 8, colortype,
132  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
133 
134 // png_set_packing(png_ptr);
135 
136  /* Allow BGR surfaces */
137  if (surface->format->Rmask == bmask
138  && surface->format->Gmask == gmask
139  && surface->format->Bmask == rmask)
140  png_set_bgr(png_ptr);
141 
142  /* Write everything */
143  png_write_info(png_ptr, info_ptr);
144 #ifdef USE_ROW_POINTERS
145  row_pointers = static_cast<png_bytep*> (malloc(sizeof(png_bytep)*surface->h));
146  for (i = 0; i < surface->h; i++)
147  row_pointers[i] = static_cast<png_bytep>(static_cast<Uint8*>(surface->pixels)) + i * surface->pitch;
148  png_write_image(png_ptr, row_pointers);
149  free(row_pointers);
150 #else
151  for (i = 0; i < surface->h; i++)
152  png_write_row(png_ptr, (png_bytep)(Uint8*)surface->pixels + i * surface->pitch);
153 #endif
154  png_write_end(png_ptr, info_ptr);
155 
156  /* Done */
157  png_destroy_write_struct(&png_ptr, &info_ptr);
158  if (freedst) SDL_RWclose(dst);
159  return (SAVEPNG_SUCCESS);
160 }
#define SAVEPNG_SUCCESS
Definition: savepng.cpp:14
static void png_write_SDL(png_structp png_ptr, png_bytep data, png_size_t length)
Definition: savepng.cpp:38
#define bmask
Definition: savepng.cpp:22
#define gmask
Definition: savepng.cpp:21
GLenum src
Definition: glew.h:2392
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
#define rmask
Definition: savepng.cpp:20
GLuint GLsizei GLsizei * length
Definition: glew.h:1793
static void png_error_SDL(png_structp, png_const_charp str)
Definition: savepng.cpp:34
SDL_Surface * SDL_PNGFormatAlpha(SDL_Surface *src)
Definition: savepng.cpp:44
GLenum GLenum dst
Definition: glew.h:2392
#define SAVEPNG_ERROR
Definition: savepng.cpp:15
int SDL_SavePNG_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
Definition: savepng.cpp:65
surf
Definition: filter.cpp:143
size_t i
Definition: function.cpp:1057