1 /* SaveSurf: an example on how to save a SDLSurface in PNG
2 Copyright (C) 2006 Angelo "Encelo" Theodorou
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18 NOTE:
19
20 This program is part of "Mars, Land of No Mercy" SDL examples,
21 you can find other examples on http://marsnomercy.org
22 */
23
24 #include <stdlib.h>
25 #include <png.h>
26 #include <SDL.h>
27
28 enum pixelFormat {
29 RGBA_PIXEL_FORMAT = 0,
30 BGRA_PIXEL_FORMAT = 1
31 };
32
surface_pixel_format(SDL_Surface * surface)33 static enum pixelFormat surface_pixel_format(SDL_Surface *surface)
34 {
35 // This defines BGRA pixel format
36 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
37 int rmask = 0x00FF0000;
38 int gmask = 0x0000FF00;
39 int bmask = 0x000000FF;
40 //int amask = 0xFF000000;
41 #else
42 int rmask = 0x0000FF00;
43 int gmask = 0x00FF0000;
44 int bmask = 0xFF000000;
45 //int amask = 0x000000FF;
46 #endif
47
48 if ((surface->format->Rmask == rmask) && (surface->format->Gmask == gmask) && (surface->format->Bmask == bmask))
49 return BGRA_PIXEL_FORMAT;
50 else
51 return RGBA_PIXEL_FORMAT;
52 }
53
png_colortype_from_surface(SDL_Surface * surface)54 static int png_colortype_from_surface(SDL_Surface *surface)
55 {
56 int colortype = PNG_COLOR_MASK_COLOR; /* grayscale not supported */
57
58 if (surface->format->palette)
59 colortype |= PNG_COLOR_MASK_PALETTE;
60 else if (surface->format->Amask)
61 colortype |= PNG_COLOR_MASK_ALPHA;
62
63 return colortype;
64 }
65
66
png_user_warn(png_structp ctx,png_const_charp str)67 void png_user_warn(png_structp ctx, png_const_charp str)
68 {
69 fprintf(stderr, "libpng: warning: %s\n", str);
70 }
71
72
png_user_error(png_structp ctx,png_const_charp str)73 void png_user_error(png_structp ctx, png_const_charp str)
74 {
75 fprintf(stderr, "libpng: error: %s\n", str);
76 }
77
78
png_save_surface(const char * filename,SDL_Surface * surf)79 int png_save_surface(const char *filename, SDL_Surface *surf)
80 {
81 FILE *fp;
82 png_structp png_ptr;
83 png_infop info_ptr;
84 int i, colortype;
85 png_bytep *row_pointers;
86
87 /* Opening output file */
88 fp = fopen(filename, "wb");
89 if (fp == NULL) {
90 perror("fopen error");
91 return -1;
92 }
93
94 /* Initializing png structures and callbacks */
95 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
96 NULL, png_user_error, png_user_warn);
97 if (png_ptr == NULL) {
98 printf("png_create_write_struct error!\n");
99 fclose(fp);
100 return -1;
101 }
102
103 info_ptr = png_create_info_struct(png_ptr);
104 if (info_ptr == NULL) {
105 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
106 printf("png_create_info_struct error!\n");
107 fclose(fp);
108 return -1;
109 }
110
111 if (setjmp(png_jmpbuf(png_ptr))) {
112 png_destroy_write_struct(&png_ptr, &info_ptr);
113 fclose(fp);
114 return -1;
115 }
116
117 png_init_io(png_ptr, fp);
118
119 colortype = png_colortype_from_surface(surf);
120 png_set_IHDR(png_ptr, info_ptr, surf->w, surf->h, 8, colortype, PNG_INTERLACE_NONE,
121 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
122
123 /* Writing the image */
124 png_write_info(png_ptr, info_ptr);
125 png_set_packing(png_ptr);
126
127 /* If the surface image is in BGR mode, then ask libpng to swap red and blue channels */
128 if (surface_pixel_format(surf) == BGRA_PIXEL_FORMAT)
129 png_set_bgr(png_ptr);
130
131 /* Strip 4th byte */
132 if (surf->format->BytesPerPixel == 4 && !surf->format->Amask)
133 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
134
135 row_pointers = (png_bytep*) malloc(sizeof(png_bytep)*surf->h);
136 for (i = 0; i < surf->h; i++)
137 row_pointers[i] = (png_bytep)(Uint8 *)surf->pixels + i*surf->pitch;
138 png_write_image(png_ptr, row_pointers);
139 png_write_end(png_ptr, info_ptr);
140
141 /* Cleaning out... */
142 free(row_pointers);
143 png_destroy_write_struct(&png_ptr, &info_ptr);
144 fclose(fp);
145
146 return 0;
147 }
148