Fixed bug 2979 - SDL_ConvertSurface does not convert color keys consistently
authorSam Lantinga <slouken@libsdl.org>
Sat, 12 Aug 2017 16:59:00 -0700
changeset 11253ecc1f6b82d95
parent 11252 1017272c981f
child 11254 390de4b9f84f
Fixed bug 2979 - SDL_ConvertSurface does not convert color keys consistently

Edmund Horner

When a 16-bit "565 format" surface has a colour key set, it will blit with correct transparency. If, however, it has its colour key set then is converted to a 32-bit ARGB format surface, the colour key in the converted image will not necessarily be the same pixel value as the transparent pixels. It may not blit correctly, because the colour key does not match the right pixels.

In my case, with an image using 0xB54A for transparency, the colour key was converted to 180,170,82; but the corresponding pixels (with the same original value) were converted to 180,169,82. Blitting the converted image did not use transparency where expected.

I have attached a test case. The bug has been replicated on both x86_64 Linux (SDL 2.0.2), and 32-bit MS C++ 2010 on Windows (SDL 2.0.0).
src/video/SDL_surface.c
     1.1 --- a/src/video/SDL_surface.c	Sat Aug 12 16:48:46 2017 -0700
     1.2 +++ b/src/video/SDL_surface.c	Sat Aug 12 16:59:00 2017 -0700
     1.3 @@ -970,13 +970,32 @@
     1.4          }
     1.5  
     1.6          if (set_colorkey_by_color) {
     1.7 -            /* Set the colorkey by color, which needs to be unique */
     1.8 -            Uint8 keyR, keyG, keyB, keyA;
     1.9 +            SDL_Surface *tmp;
    1.10 +            SDL_Surface *tmp2;
    1.11 +            int converted_colorkey = 0;
    1.12  
    1.13 -            SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR,
    1.14 -                        &keyG, &keyB, &keyA);
    1.15 -            SDL_SetColorKey(convert, 1,
    1.16 -                            SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA));
    1.17 +            /* Create a dummy surface to get the colorkey converted */
    1.18 +            tmp = SDL_CreateRGBSurface(0, 1, 1,
    1.19 +                                   surface->format->BitsPerPixel, surface->format->Rmask,
    1.20 +                                   surface->format->Gmask, surface->format->Bmask,
    1.21 +                                   surface->format->Amask);
    1.22 +
    1.23 +            SDL_FillRect(tmp, NULL, surface->map->info.colorkey);
    1.24 +
    1.25 +            tmp->map->info.flags &= ~SDL_COPY_COLORKEY;
    1.26 +
    1.27 +            /* Convertion of the colorkey */
    1.28 +            tmp2 = SDL_ConvertSurface(tmp, format, 0);
    1.29 +
    1.30 +            /* Get the converted colorkey */
    1.31 +            memcpy(&converted_colorkey, tmp2->pixels, tmp2->format->BytesPerPixel);
    1.32 +
    1.33 +            SDL_FreeSurface(tmp);
    1.34 +            SDL_FreeSurface(tmp2);
    1.35 +
    1.36 +            /* Set the converted colorkey on the new surface */
    1.37 +            SDL_SetColorKey(convert, 1, converted_colorkey);
    1.38 +
    1.39              /* This is needed when converting for 3D texture upload */
    1.40              SDL_ConvertColorkeyToAlpha(convert);
    1.41          }