Skip to content

Commit c996880

Browse files
committed
Save non-alpha pngs as RGB not RGBA
1 parent b9cf035 commit c996880

File tree

1 file changed

+53
-7
lines changed

1 file changed

+53
-7
lines changed

src/IMG_png.c

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -766,15 +766,61 @@ static int IMG_SavePNG_RW_miniz(SDL_Surface *surface, SDL_RWops *dst)
766766
return IMG_SetError("Passed NULL dst");
767767
}
768768

769-
if (surface->format->format == png_format) {
770-
png = tdefl_write_image_to_png_file_in_memory(surface->pixels, surface->w, surface->h, surface->format->BytesPerPixel, surface->pitch, &size);
771-
} else {
772-
SDL_Surface *cvt = SDL_ConvertSurfaceFormat(surface, png_format, 0);
773-
if (cvt) {
774-
png = tdefl_write_image_to_png_file_in_memory(cvt->pixels, cvt->w, cvt->h, cvt->format->BytesPerPixel, cvt->pitch, &size);
775-
SDL_FreeSurface(cvt);
769+
/* miniz only supports RGB and RGBA, it does not support palette.
770+
* So we:
771+
* - pick RGBA if surface has per-pixel alpha or if a palette entry has alpha.
772+
* - pick RGB in all other cases.
773+
* Just like the libpng implementation, global alpha and colorkey gets
774+
* ignored here for consistency.
775+
*/
776+
int do_rgba = SDL_ISPIXELFORMAT_ALPHA(surface->format->format);
777+
if (!do_rgba && SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
778+
SDL_Palette *pal = surface->format->palette;
779+
if (pal) {
780+
for (int i = 0; i < pal->ncolors; i++) {
781+
if (pal->colors[i].a != 255) {
782+
do_rgba = 1;
783+
break;
784+
}
785+
}
776786
}
777787
}
788+
789+
Uint32 cvt_fmt = do_rgba ? png_format : SDL_PIXELFORMAT_RGB24;
790+
SDL_Surface *cvt = NULL;
791+
Uint8 *pixels = surface->pixels;
792+
int bpp = surface->format->BytesPerPixel;
793+
int pitch = surface->pitch;
794+
if (surface->format->format != cvt_fmt) {
795+
cvt = SDL_ConvertSurfaceFormat(surface, cvt_fmt, 0);
796+
pixels = cvt ? cvt->pixels : NULL;
797+
bpp = cvt ? cvt->format->BytesPerPixel : 0;
798+
pitch = cvt ? cvt->pitch : 0;
799+
}
800+
if (pixels) {
801+
int w = surface->w;
802+
int h = surface->h;
803+
int tightened_pitch = bpp * w;
804+
if (pitch != tightened_pitch) {
805+
/* There is extra padding that we need to get rid of, if we don't
806+
* do this the miniz backend is going to generate corrupt PNGs */
807+
Uint8 *tightened_pixels = SDL_malloc(tightened_pitch * h);
808+
if (tightened_pixels) {
809+
for (int y = 0; y < h; y++) {
810+
memcpy(tightened_pixels + y * tightened_pitch, pixels + y * pitch, tightened_pitch);
811+
}
812+
png = tdefl_write_image_to_png_file_in_memory(tightened_pixels, w, h, bpp, tightened_pitch, &size);
813+
SDL_free(tightened_pixels);
814+
}
815+
}
816+
else {
817+
png = tdefl_write_image_to_png_file_in_memory(pixels, w, h, bpp, pitch, &size);
818+
}
819+
}
820+
if (cvt) {
821+
SDL_FreeSurface(cvt);
822+
}
823+
778824
if (png) {
779825
if (SDL_RWwrite(dst, png, size, 1)) {
780826
result = 0;

0 commit comments

Comments
 (0)