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 <SDL.h>
29 #include <png.h>
30 #include <zlib.h>
31 #include "IMG_savepng.h"
32
33 #ifndef png_voidp
34 #define png_voidp voidp
35 #endif
36
renpy_IMG_SavePNG(const char * file,SDL_Surface * surf,int compression)37 int renpy_IMG_SavePNG(const char *file, SDL_Surface *surf,int compression){
38 SDL_RWops *fp;
39 int ret;
40
41 fp=SDL_RWFromFile(file,"wb");
42
43 if( fp == NULL ) {
44 return (-1);
45 }
46
47 ret=renpy_IMG_SavePNG_RW(fp,surf,compression);
48 SDL_RWclose(fp);
49 return ret;
50 }
51
png_write_data(png_structp png_ptr,png_bytep data,png_size_t length)52 static void png_write_data(png_structp png_ptr,png_bytep data, png_size_t length){
53 SDL_RWops *rp = (SDL_RWops*) png_get_io_ptr(png_ptr);
54 SDL_RWwrite(rp,data,1,length);
55 }
56
renpy_IMG_SavePNG_RW(SDL_RWops * src,SDL_Surface * surf,int compression)57 int renpy_IMG_SavePNG_RW(SDL_RWops *src, SDL_Surface *surf,int compression){
58 png_structp png_ptr;
59 png_infop info_ptr;
60 SDL_PixelFormat *fmt=NULL;
61 SDL_Surface *tempsurf=NULL;
62 int ret;
63 unsigned int i;
64 png_colorp palette;
65 Uint8 *palette_alpha=NULL;
66 png_byte **row_pointers=NULL;
67 png_ptr=NULL;info_ptr=NULL;palette=NULL;ret=-1;
68
69 Uint32 target_format;
70
71 if( !src || !surf) {
72 goto savedone2; /* Nothing to do. */
73 }
74
75 row_pointers=(png_byte **)malloc(surf->h * sizeof(png_byte*));
76 if (!row_pointers) {
77 SDL_SetError("Couldn't allocate memory for rowpointers");
78 goto savedone2;
79 }
80
81 png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL);
82 if (!png_ptr){
83 SDL_SetError("Couldn't allocate memory for PNG file version: " PNG_LIBPNG_VER_STRING);
84 goto savedone2;
85 }
86 info_ptr= png_create_info_struct(png_ptr);
87 if (!info_ptr){
88 SDL_SetError("Couldn't allocate image information for PNG file");
89 goto savedone;
90 }
91 /* setup custom writer functions */
92 png_set_write_fn(png_ptr,(png_voidp)src,png_write_data,NULL);
93
94 if (setjmp(png_jmpbuf(png_ptr))){
95 SDL_SetError("Unknown error writing PNG");
96 goto savedone;
97 }
98
99 if(compression>Z_BEST_COMPRESSION)
100 compression=Z_BEST_COMPRESSION;
101
102 if(compression == Z_NO_COMPRESSION) // No compression
103 {
104 png_set_filter(png_ptr,0,PNG_FILTER_NONE);
105 png_set_compression_level(png_ptr,Z_NO_COMPRESSION);
106 }
107 else if(compression<0) // Default compression
108 png_set_compression_level(png_ptr,Z_DEFAULT_COMPRESSION);
109 else
110 png_set_compression_level(png_ptr,compression);
111
112 fmt=surf->format;
113
114 if (fmt->Amask) {
115 png_set_IHDR(png_ptr,info_ptr,
116 surf->w,surf->h,8,PNG_COLOR_TYPE_RGB_ALPHA,
117 PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,
118 PNG_FILTER_TYPE_DEFAULT);
119 } else {
120 png_set_IHDR(png_ptr,info_ptr,
121 surf->w,surf->h,8,PNG_COLOR_TYPE_RGB,
122 PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,
123 PNG_FILTER_TYPE_DEFAULT);
124 }
125
126 png_write_info(png_ptr, info_ptr);
127
128 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
129 if (fmt->Amask) {
130 target_format = SDL_PIXELFORMAT_ABGR8888;
131 } else {
132 target_format = SDL_PIXELFORMAT_BGR888;
133 }
134 #else
135 if (fmt->Amask) {
136 target_format = SDL_PIXELFORMAT_RGBA8888;
137 } else {
138 target_format = SDL_PIXELFORMAT_RGB888;
139 }
140 #endif
141
142 if (surf->format->format != target_format) {
143 tempsurf = SDL_ConvertSurfaceFormat(surf, target_format, 0);
144 surf = tempsurf;
145
146 if (!tempsurf){
147 SDL_SetError("Couldn't allocate temp surface");
148 goto savedone;
149 }
150 }
151
152 for(i=0;i < surf->h;i++){
153 row_pointers[i]= ((png_byte*) surf->pixels) + i * surf->pitch;
154 }
155
156 png_write_image(png_ptr, row_pointers);
157
158 if (tempsurf) {
159 SDL_FreeSurface(tempsurf);
160 }
161
162 png_write_end(png_ptr, NULL);
163
164 ret=0; /* got here, so nothing went wrong. YAY! */
165
166 savedone: /* clean up and return */
167 png_destroy_write_struct(&png_ptr,&info_ptr);
168
169 savedone2:
170 if (palette) {
171 free(palette);
172 }
173 if (palette_alpha) {
174 free(palette_alpha);
175 }
176 if (row_pointers) {
177 free(row_pointers);
178 }
179 return ret;
180 }
181