Fade in does not work when PNG file has transparent background

I would like to write a program that fade in a PNG file in main SDL screen with
a background image.

Currently it works fine when PNG file has non-transparent background, but when
PNG file has transparent background, nothing happens.

I have tried lots combination of
SDL_DisplayFormat/SDL_DisplayFormatAlpha/SDL_BlitSurface, but I can’t get both
kind PNG file work correctly.

The following is my source code (It’s written in D Programming Language, but it
looks like C a lot and SDL API is same), where should I check?

================== Start of Source Code ========================
module fade;

import derelict.sdl.sdl;
import derelict.sdl.image;

import tango.io.Stdout;

void main ()
{
DerelictSDL.load();
DerelictSDLImage.load();

if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) {
    Stdout ("Error init.").newline;
}

SDL_Surface * screen = SDL_SetVideoMode (800,600,32,SDL_HWSURFACE);
SDL_Surface * background = IMG_Load ("../image/background.jpg");
SDL_Surface * image = IMG_Load ("../image/image.png");

if (image is null ) {
    Stdout ("Error").newline;
}

// Copy a blank screen.
SDL_Surface * back = SDL_DisplayFormatAlpha(screen);

// Place Position
SDL_Rect rect2;
rect2.x = 100;
rect2.y = 100;

// Place Size
SDL_Rect rect;
rect.w = image.w;
rect.h = image.h;

// Fade in
for (int i = 0; i < 255; i = i+5) {
    // Clear screen.
    SDL_BlitSurface (background, null, screen, null);

    // Set alpha for PNG image
    SDL_SetAlpha (image, SDL_SRCALPHA, i);
    
    /*************************************************************
     * Works fine when PNG file has no transparent background,
     * but when PNG file has transparent background, nothing
     * happend.
     ************************************************************/
    //! SDL_Surface * temp = SDL_DisplayFormatAlpha(image);
    //! SDL_BlitSurface (temp, &rect, screen, &rect2);

    /*************************************************************
     * Both PNG file fade in normally, but the transparent 
     * background in PNG will become white.
     ************************************************************/
    //! SDL_Surface * temp = SDL_DisplayFormat(image);
    //! SDL_BlitSurface (temp, &rect, screen, &rect2);

    /*************************************************************
     * Works fine when PNG file has no transparent background,
     * but when PNG file has transparent background, nothing
     * happend.*
     * PS:Seems slower.
     ************************************************************/
    //! SDL_BlitSurface (image, &rect, screen, &rect2);

    SDL_Flip(screen);
}

}
================== End of Source Code ========================

Brian Hsu <brianhsu.hsu at gmail.com> wrote:

OK, I got it work correctly for both kind PNG file, but I would like
know is this right way to do this?

first off, sdl 1.2 can’t have both, per surface and per pixel alpha, so
you have to pick one of those features. colorkeying is something
different and has nothing to do with alpha blending.

And it seems only work when transparent background PNG file has
correct metadata about color key (I’m not sure about this).

i don’t think pngs have colorkey information (had a quick look at the
wikipedia site), at least RGB pngs don’t. palette pngs are different
though (alpha per palette entry). nevertheless, i never saw SDL_image
set the colorkey for me in the loaded surfaces, so you will have to do
this for each surface.

best regards …
clemens

Clemens Kirchgatterer <clemens 1541.org> writes:

Brian Hsu <brianhsu.hsu gmail.com> wrote:

OK, I got it work correctly for both kind PNG file, but I would like
know is this right way to do this?

first off, sdl 1.2 can’t have both, per surface and per pixel alpha, so
you have to pick one of those features. colorkeying is something
different and has nothing to do with alpha blending.

Sorry that I’m not familiar with image processing, so I’m not totally
understand.

But the following is what I think what I want to do (my goal is fade in
a png or gif image, in the mean time if it has transparent background,
it should work), I would like to know are these correct?

1.PNG’s alpha channel is per pixel, so SDL_SetAlpha() would do nothing.

2.Colorkey is a technique that remove a certain color and made it looks
transparent background, it is used in GIF transparent background image.

3.SDL_DisplayFromat() would remove alpha channel, and SDL_SetAlpha() will
affect the returning surface.

4.But with correct color key set, the surface returning by SDL_DisplayFormat()
will remove the color specified by color key, so it just look like has a
transparent background.

5.So I first checked is SDL_SRCCOLORKEY or SDL_SRCALPHA set to determine what
kind of transparent background I’m processing.

6.If SDL_SRCCOLORKEY is set, then I get the color key from SDL_PixelFormat
in the image surface and set it using SDL_SetColorKey(), so I get a
transparent background image and could fade in it.

It works fine with GIF file, but when I process transparent background
PNG file, I run in to trouble and I’m not sure what I do is right or wrong.

7.If SDL_SRCALPHA is set, then I get Amask from SDL_PixelFormat in the image.

Here is the problem, what exactly Amask is? In my knowledge, it should be a
transparent mask, which means if bit and a pixel and Amask, then the value
is the alpha value for that pixel.

But when I blit some PNG file without alpha channel, I found that the background
maybe white or black.

So I have to figure out what color the transparent background is, and set it
as a color key.

Of course I could scan thorough all pixels and when it is mark as
transparent(alpha value is 0), I could use example listed at bottom of
SDL_PixelFormatl API document to figure out what color it is.

But this would be very slow, so is there any method I could quickly figure out
what the PNG transparent background color is?

If you fade to/from black, you could simply blit the image and then blit
a transparent black box overtop.

SDL_gfx has a blit-helper which sets the alpha channel byte to a
particular value. You could use that routine or derive your own function
which uses the existing alpha in the PNG as a saturation value (i.e.
A=myA if A<myA). This definitely “burns” a lot of memory bandwidth if
used in a display loop. :wink:

–AS

Brian Hsu wrote:

I would like to write a program that fade in a PNG file in main SDL screen with
a background image.

-------------- next part --------------
A non-text attachment was scrubbed…
Name: aschiffler.vcf
Type: text/x-vcard
Size: 135 bytes
Desc: not available
URL: http://lists.libsdl.org/pipermail/sdl-libsdl.org/attachments/20080525/e4bf9bcf/attachment.vcf

Brian Hsu <brianhsu.hsu at gmail.com> wrote:

But the following is what I think what I want to do (my goal is fade
in a png or gif image, in the mean time if it has transparent
background, it should work), I would like to know are these correct?

1.PNG’s alpha channel is per pixel, so SDL_SetAlpha() would do
nothing.

correct.

2.Colorkey is a technique that remove a certain color and made it
looks transparent background, it is used in GIF transparent
background image.

correct.

3.SDL_DisplayFromat() would remove alpha channel, and SDL_SetAlpha()
will affect the returning surface.

correct.

4.But with correct color key set, the surface returning by
SDL_DisplayFormat() will remove the color specified by color key, so
it just look like has a transparent background.

correct.

5.So I first checked is SDL_SRCCOLORKEY or SDL_SRCALPHA set to
determine what kind of transparent background I’m processing.

6.If SDL_SRCCOLORKEY is set, then I get the color key from
SDL_PixelFormat in the image surface and set it using SDL_SetColorKey
(), so I get a transparent background image and could fade in it.

It works fine with GIF file, but when I process transparent
background PNG file, I run in to trouble and I’m not sure what I do
is right or wrong.

i bet the problem is that. gif does have the information, what colorkey
it has, but png does not. png does not support colorkeying by itself.
so when loading an image with SDL_image it will set the colorkey in the
returned surface for gifs but not for pngs.

for pngs you have to know the colorkey in advance and set it after you
have loaded the image. one common technique is to use one corner pixel
to determine the colorkey. but this only works if you can agree on that
prerequisit.

7.If SDL_SRCALPHA is set, then I get Amask from SDL_PixelFormat in
the image.

correct.

Here is the problem, what exactly Amask is? In my knowledge, it
should be a transparent mask, which means if bit and a pixel and
Amask, then the value is the alpha value for that pixel.

the amask is the position and width of the alpha information within
each pixel data.

But when I blit some PNG file without alpha channel, I found that the
background maybe white or black.

whatever the background was when the image was created.

So I have to figure out what color the transparent background is, and
set it as a color key.

you have to know - you cant really figure it out from the RGB png. you
can make educated guesses, though. (see above)

Of course I could scan thorough all pixels and when it is mark as
transparent(alpha value is 0), I could use example listed at bottom of
SDL_PixelFormatl API document to figure out what color it is.

this would be also be possible, but only with RGBA pngs.

But this would be very slow, so is there any method I could quickly
figure out what the PNG transparent background color is?

besides what i have described above, i don’t think so.

good luck and best regards …
clemens

Brian Hsu <brianhsu.hsu at gmail.com> wrote:

OK, here is what I do in order to figure out the background color.

remember this will only work for 32bit pngs but not for 24bit pngs.

The performance seems acceptable when I tested with an 800x600 PNG
file without any transparent pixel.

worst case.

But it is still a little bit slow I think.

depends on where in the surface the first transparent pixel is.

mind the bugs in your code:

private uint findColorKey (SDL_Surface * surface)
{
    // Calcuate how many pixels we have
    int length = surface.w * surface.h;

lock the surface here before entering the loop.

      SDL_LockSurface(surface);
    // Go through all pixels.
    for (int i = 0; i < length; i++) {
        
        uint pixel = *(cast(uint *)surface.pixels + i);
        //SDL_LockSurface(surface);

why another lock? if you meant to write SDL_UnlockSurface() you should
move the unlock further down, when you are done accessing pixel data.

        // Get RGBA of current pixel
        ubyte red, blue, green, alpha;
        SDL_GetRGBA (pixel, surface.format, &red, &green, 
                     &blue, &alpha);

        // If this is transparent pixel, return the 
        // current color as color key.
        if (alpha == 0) {
              SDL_UnlockSurface(surface);
            return SDL_MapRGBA (surface.format, red, green, 
                                blue, alpha);
        }
    }
      SDL_UnlockSurface(surface);
    return 0;
}

also it is better to return the colorkey by reference parameter and use
the return value as indicater for not having found a transparent pixel,
otherwise you can not distinguish between a valid colorkey BLACK and no
colorkey found.

regards …
clemens

Hey,

If you need to combine per-pixel alpha and per-surface alpha, you have
to do it yourself (sadly…). You can take a look at Sprig
(http://pubpages.unh.edu/~jmb97/sprig.html). It has a blitter that
can handle that and a bunch of blending modes, but it’s as slow as
software gets.

Colorkey just won’t cut it if you have alpha values other than 0 and
255. Colorkey transparency is only on/off. I thought the colorkey was
automatically set by SDL_DisplayFormat (or Alpha)… Well, if you
definitely know that your pngs have only full transparency and full
opacity, then I would suggest that you choose the colorkey. Make a new
surface that is SDL_FillRect’ed with your colorkey, then blit your png
to it (with SDL_SRCALPHA).

For fading, definitely go for the overblitting approach, like Andreas said.

Jonny D_________________________________________________________________
Make every e-mail and IM count. Join the i?m Initiative from Microsoft.
http://im.live.com/Messenger/IM/Join/Default.aspx?source=EML_WL_ MakeCount