Fade in does not work when PNG file has transpare nt background

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

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

For example, it works for PNG 1, but PNG 2 will get a white background. I
haven’t find a figure out how to find color key of PNG 2 automatically and let
both PNG 1 and PNG 2 work.

[PNG 1] http://bone.twbbs.org.tw/png1.png
[PNG 2] http://bone.twbbs.org.tw/png2.png

======== 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;
}

// Set Color Key of image.
uint colorkey = image.format.colorkey;
SDL_SetColorKey (image, SDL_SRCCOLORKEY|SDL_RLEACCEL, colorkey);

// 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);
    
    SDL_Surface * temp = SDL_DisplayFormat(image);
    SDL_BlitSurface (temp, &rect, screen, &rect2);

    SDL_Flip(screen);
}

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

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?

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

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

But it is still a little bit slow I think.=====================================================================
private uint findColorKey (SDL_Surface * surface)
{
// Calcuate how many pixels we have
int length = surface.w * surface.h;

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

        // 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) {
            return SDL_MapRGBA (surface.format, red, green, 
                                blue, alpha);
        }
    }

    return 0;
}

=========================================================================

Thanks for all of your reply.

My ultimate goal is do animation with layer supported, here is a example I
made (click mouse buttons will move the girl image around and fade out,
click again it will fade in and move around again).

[Example] http://simplesdl.googlecode.com/files/simplesdl.zip
(Windows executable file is located at Examples folder)

Because I don’t have much knowledge about image processing, so I’m not sure
would over blit work in this case, but I would take a look at it and Spring
proeject when I got time.

Currently, I just reblit everything in correct order when main window is
refreshed, it’s not the best solution I think, but at least it works fine and
performance is acceptable on my AMD Sempron 2800/512M computer.

Here is what I do when I try to figure out what color of the transparent
background in PNG/GIF image.

It works on most case listed at http://entropymine.com/jason/testbed/pngtrans/,
except T9/T10 which transparent is totally ignored, and G7/G8 which has strange
color on it but in fact it should be gray.

BTW, I found that image marked as binary transparency seems has colorkey flag on.

Finally, I’m a little confusing about how to handle 24-bit per pixel image.

The code getPixel() I listed below definitely not correct when it processing an
24-bit per pixel image, because it offset two bytes at a single iteration,
but it should offset 3 bytes, I haven’t figure out how to handle 24-bit
image like this yet.

But since the colorkey flag is on, so it will not call findColorKey()
and getPixel(), so it won’t crash.

Even it got called, it just not go through all pixels and maybe get
incorrect pixel value, harmless also.

The following is the algorithm I tried to find out color key.================================================================
if (SDL_SRCCOLORKEY flag is on) {
SDL_SetColorKey (color key in SDL_PixelFormat);
} else if (SDL_SRCALPHA flag is on) {
// Go over all pixels in image until find a transparent pixel,
// and return the RGBA value that the pixel have.
colorkey = findColorKey ();

if (colorkey is found) {
    SDL_SetColorKey (colorkey);
}

}

================ Find Color Key ================================
// Note: ref uint colorkey means the parameter colorkey is pass
// by reference.
/******************************************************

  • Find Color of Transparent Background
  • This method will scan through image to find a pixel
  • that mask as transparent, and return the color of
  • it.
  • Params
  • surface = The surface of image.
    
  • color   = The color key will be stored here. 
    
  • Returns:
  • Did we find a color key?
    

******************************************************/
private bool findColorKey (SDL_Surface * surface, ref uint colorkey)
{
// Calcuate how many pixels we have
int length = surface.w * surface.h;
bool found = false;
Stdout.format (“bytes:{}”, surface.format.BytesPerPixel).newline;

// Go through all pixels.
for (int i = 0; i < length; i++) {

    // Get current pixel data from image.
    ulong pixel = getPixel (surface, i);

    // 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) {
        found = true;
        colorkey = SDL_MapRGBA (surface.format, red, green, 
                                blue, alpha);
    }
}

return found;

}

==================== Get Pixel =================================
/*********************************************************

  • Get a pixel in image.
  • Params:
  • surface = SDL_Surface pointer of image.
    
  • offset  = How many pixel offset from first pixel
    
  • Returns:
  • The pixel value in 64 bit unsigned integer.
    

********************************************************/
private ulong getPixel (SDL_Surface * surface, ulong offset)
{
ulong pixel;
int bytesPerPixel = surface.format.BytesPerPixel;

SDL_LockSurface(surface);

// Just in case that someone pass in a non 32-bit RGBA PNG file,
// this would prevent program from crash.
switch (bytesPerPixel) {
    //! A normal 8-bit PNG would match this.
    case 1:
        pixel = *(cast(ubyte *) surface.pixels + offset);
        break;

    //! A normal 16-bit PNG would match this.
    case 2:
        pixel = *(cast(ushort *) surface.pixels + offset);
        break;

    //! 24-bit PNG would match this.
    //! This will not go through all pixels.
    case 3:
        pixel = *(cast(ushort *) surface.pixels + offset);
        break;

    //! A normal 32-bit PNG would match this.
    case 4:
        pixel = *(cast(uint *) surface.pixels + offset);
        break;

    //! Even a 64-bit PNG would not match this.
    //! The bytesPerPixel will be 4.
    case 8:
        pixel = *(cast(long *) surface.pixels + offset);
        break;

    default:
        pixel = *(cast(ubyte *) surface.pixels + offset);
}
SDL_UnlockSurface(surface);

return pixel;

}