1 /*
2 Based on zlib license - see http://www.gzip.org/zlib/zlib_license.html
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19
20 "Philip D. Bober" <wildfire1138@mchsi.com>
21 */
22
23 /**
24 * 4/17/04 - IMG_SavePNG & IMG_SavePNG_RW - Philip D. Bober
25 * 11/08/2004 - Compr fix, levels -1,1-7 now work - Tyler Montbriand
26 */
27 #include <stdlib.h>
28 #include <png.h>
29 #include <zlib.h>
30 #include "write_png.h"
31
32 #ifndef png_voidp
33 #define png_voidp voidp
34 #endif
35
Pygame_SDL2_SavePNG(const char * file,SDL_Surface * surf,int compression)36 int Pygame_SDL2_SavePNG(const char *file, SDL_Surface *surf,int compression){
37 SDL_RWops *fp;
38 int ret;
39
40 fp=SDL_RWFromFile(file,"wb");
41
42 if( fp == NULL ) {
43 return (-1);
44 }
45
46 ret=Pygame_SDL2_SavePNG_RW(fp,surf,compression);
47 SDL_RWclose(fp);
48 return ret;
49 }
50
png_write_data(png_structp png_ptr,png_bytep data,png_size_t length)51 static void png_write_data(png_structp png_ptr,png_bytep data, png_size_t length){
52 SDL_RWops *rp = (SDL_RWops*) png_get_io_ptr(png_ptr);
53 SDL_RWwrite(rp,data,1,length);
54 }
55
Pygame_SDL2_SavePNG_RW(SDL_RWops * src,SDL_Surface * surf,int compression)56 int Pygame_SDL2_SavePNG_RW(SDL_RWops *src, SDL_Surface *surf,int compression){
57 png_structp png_ptr;
58 png_infop info_ptr;
59 SDL_PixelFormat *fmt=NULL;
60 SDL_Surface *tempsurf=NULL;
61 int ret;
62 int i;
63 png_colorp palette;
64 Uint8 *palette_alpha=NULL;
65 png_byte **row_pointers=NULL;
66 unsigned int target_format;
67
68 png_ptr=NULL;info_ptr=NULL;palette=NULL;ret=-1;
69
70 if( !src || !surf) {
71 goto savedone2; /* Nothing to do. */
72 }
73
74 row_pointers=(png_byte **)malloc(surf->h * sizeof(png_byte*));
75 if (!row_pointers) {
76 SDL_SetError("Couldn't allocate memory for rowpointers");
77 goto savedone2;
78 }
79
80 png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL);
81 if (!png_ptr){
82 SDL_SetError("Couldn't allocate memory for PNG file version: " PNG_LIBPNG_VER_STRING);
83 goto savedone2;
84 }
85 info_ptr= png_create_info_struct(png_ptr);
86 if (!info_ptr){
87 SDL_SetError("Couldn't allocate image information for PNG file");
88 goto savedone;
89 }
90 /* setup custom writer functions */
91 png_set_write_fn(png_ptr,(png_voidp)src,png_write_data,NULL);
92
93 if (setjmp(png_jmpbuf(png_ptr))){
94 SDL_SetError("Unknown error writing PNG");
95 goto savedone;
96 }
97
98 if(compression>Z_BEST_COMPRESSION)
99 compression=Z_BEST_COMPRESSION;
100
101 if(compression == Z_NO_COMPRESSION) // No compression
102 {
103 png_set_filter(png_ptr,0,PNG_FILTER_NONE);
104 png_set_compression_level(png_ptr,Z_NO_COMPRESSION);
105 }
106 else if(compression<0) // Default compression
107 png_set_compression_level(png_ptr,Z_DEFAULT_COMPRESSION);
108 else
109 png_set_compression_level(png_ptr,compression);
110
111 fmt=surf->format;
112
113 if (fmt->Amask) {
114 png_set_IHDR(png_ptr,info_ptr,
115 surf->w,surf->h,8,PNG_COLOR_TYPE_RGB_ALPHA,
116 PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,
117 PNG_FILTER_TYPE_DEFAULT);
118 } else {
119 png_set_IHDR(png_ptr,info_ptr,
120 surf->w,surf->h,8,PNG_COLOR_TYPE_RGB,
121 PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,
122 PNG_FILTER_TYPE_DEFAULT);
123 }
124
125 png_write_info(png_ptr, info_ptr);
126
127 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
128 if (fmt->Amask) {
129 target_format = SDL_PIXELFORMAT_ABGR8888;
130 } else {
131 target_format = SDL_PIXELFORMAT_BGR888;
132 }
133 #else
134 if (fmt->Amask) {
135 target_format = SDL_PIXELFORMAT_RGBA8888;
136 } else {
137 target_format = SDL_PIXELFORMAT_RGB888;
138 }
139 #endif
140
141 if (surf->format->format != target_format) {
142 tempsurf = SDL_ConvertSurfaceFormat(surf, target_format, 0);
143 surf = tempsurf;
144
145 if (!tempsurf){
146 SDL_SetError("Couldn't allocate temp surface");
147 goto savedone;
148 }
149 }
150
151 for(i=0;i < surf->h;i++){
152 row_pointers[i]= ((png_byte*) surf->pixels) + i * surf->pitch;
153 }
154
155 png_write_image(png_ptr, row_pointers);
156
157 if (tempsurf) {
158 SDL_FreeSurface(tempsurf);
159 }
160
161 png_write_end(png_ptr, NULL);
162
163 ret=0; /* got here, so nothing went wrong. YAY! */
164
165 savedone: /* clean up and return */
166 png_destroy_write_struct(&png_ptr,&info_ptr);
167
168 savedone2:
169 if (palette) {
170 free(palette);
171 }
172 if (palette_alpha) {
173 free(palette_alpha);
174 }
175 if (row_pointers) {
176 free(row_pointers);
177 }
178 return ret;
179 }
180