File: IMG_SavePNG.c

package info (click to toggle)
enigma 1.20-dfsg.1-2
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 64,620 kB
  • ctags: 16,428
  • sloc: xml: 153,614; cpp: 63,581; ansic: 31,088; sh: 4,825; makefile: 1,858; yacc: 288; perl: 84; sed: 16
file content (151 lines) | stat: -rw-r--r-- 5,085 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include "SDL.h"
#include "IMG_SavePNG.h"
#include "png.h"
#include <stdlib.h>
#include <setjmp.h>

#define IMG_SetError(a) SDL_SetError(a)

/* Save a PNG type image to an SDL datasource */
static void png_write_data(png_structp ctx, png_bytep area, png_size_t size)
{
	SDL_RWops *src;
	
	src = (SDL_RWops *)png_get_io_ptr(ctx);
	SDL_RWwrite(src, area, size, 1);
}

static void png_io_flush(png_structp ctx)
{
	SDL_RWops *src;
	
	src = (SDL_RWops *)png_get_io_ptr(ctx);
	/* how do I flush src? */
}

static int png_colortype_from_surface(SDL_Surface *surface)
{
	int colortype = PNG_COLOR_MASK_COLOR; /* grayscale not supported */
	
	if (surface->format->palette)
		colortype |= PNG_COLOR_MASK_PALETTE;
	else if (surface->format->Amask)
		colortype |= PNG_COLOR_MASK_ALPHA;
	
	return colortype;
}

static void png_user_warn(png_structp ctx, png_const_charp str)
{
	fprintf(stderr, "libpng: warning: %s\n", str);
}

static void png_user_error(png_structp ctx, png_const_charp str)
{
	fprintf(stderr, "libpng: error: %s\n", str);
}



int IMG_SavePNG_RW(SDL_Surface *face, SDL_RWops *src) {
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
	const int rmask = 0x00ff0000;
	const int gmask = 0x0000ff00;
	const int bmask = 0x000000ff;
	const int amask = 0x00000000;
#else
    const int rmask = 0x000000ff;
	const int gmask = 0x0000ff00;
	const int bmask = 0x00ff0000;
	const int amask = 0x00000000;
#endif

	int          result  = -1;
	SDL_Surface *surface = SDL_CreateRGBSurface(SDL_SWSURFACE, face->w, face->h, 24,
                                                rmask, gmask, bmask, amask);

    if (surface) {
		png_structp png_ptr;

        SDL_BlitSurface(face, NULL, surface, NULL);
        SDL_LockSurface(surface);

        png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, png_user_error, png_user_warn);
        if (!png_ptr) {
            IMG_SetError("Couldn't allocate memory for PNG file");
        }
        else {
            /* Allocate/initialize the image information data.  REQUIRED */
            png_infop info_ptr = png_create_info_struct(png_ptr);
            if (!info_ptr) {
                IMG_SetError("Couldn't create image information for PNG file");
            }
            else {
                png_bytep *row_pointers = 0;

                /* Set error handling. */
                if (setjmp(png_jmpbuf(png_ptr))) {
                    IMG_SetError("Error writing the PNG file");
                }
                else {
					int colortype;
                    png_set_write_fn(png_ptr, src, png_write_data, png_io_flush);
                    /* Set the image information here.  Width and height are up to 2^31,
                     * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
                     * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
                     * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
                     * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
                     * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
                     * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
                     */
                    colortype = png_colortype_from_surface(surface);
                    png_set_IHDR(png_ptr, info_ptr, surface->w, surface->h, 8,
                                 colortype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
	
                    /* Write the file header information.  REQUIRED */
                    png_write_info(png_ptr, info_ptr);
	
                    /* pack pixels into bytes */
                    png_set_packing(png_ptr);

                    /* Create the array of pointers to image data */
                    row_pointers = (png_bytep*) malloc(sizeof(png_bytep)*surface->h);
                    if (!row_pointers) {
                        IMG_SetError("Couldn't allocate PNG row pointers");
                    }
                    else {
                        int i;
                        for (i = 0; i < surface->h; i++)
                            row_pointers[i] = (png_bytep)(Uint8 *)surface->pixels + i*surface->pitch;

                        /* write out the entire image data in one call */
                        png_write_image(png_ptr, row_pointers);
                        png_write_end(png_ptr, info_ptr);
                        result = 0; /* success! */
                    }
                }
                if (row_pointers)
                    free(row_pointers);
                
                png_destroy_info_struct(png_ptr, &info_ptr);
            }
            png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
        }

        SDL_UnlockSurface(surface);
        SDL_FreeSurface(surface);
    }

    return result;
}

int IMG_SavePNG(SDL_Surface *surface, const char *file)
{
    SDL_RWops *out = SDL_RWFromFile(file, "wb");
    int ret;
    if(!out)
		return -1;
    ret = IMG_SavePNG_RW(surface, out);
    SDL_RWclose(out);
    return ret;
}