Pixel Access

Getting the value of a pixel

Uint32 getpixel(SDL_Surface *surface, int x, int y)
{
    int bpp = surface->format->BytesPerPixel;
    /* Here p is the address to the pixel we want to retrieve */
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp) {
    case 1:
        return *p;
        break;

    case 2:
        return *(Uint16 *)p;
        break;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
            return p[0] << 16 | p[1] << 8 | p[2];
        else
            return p[0] | p[1] << 8 | p[2] << 16;
        break;

    case 4:
        return *(Uint32 *)p;
        break;

    default:
        return 0;       /* shouldn't happen, but avoids warnings */
    }
}

Setting the value of a pixel

void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
    int bpp = surface->format->BytesPerPixel;
    /* Here p is the address to the pixel we want to set */
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp) {
    case 1:
        *p = pixel;
        break;

    case 2:
        *(Uint16 *)p = pixel;
        break;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
            p[0] = (pixel >> 16) & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = pixel & 0xff;
        } else {
            p[0] = pixel & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = (pixel >> 16) & 0xff;
        }
        break;

    case 4:
        *(Uint32 *)p = pixel;
        break;
    }
}

Comments

These functions are designed to work with any pixel depth supported by SDL. You must lock the surface using SDL_LockSurface before using them. Note that pixel manipulations are very inefficient on hardware surfaces.

The "Uint32" value returned from getpixel() can be broken into RGB values using SDL_GetRGB or SDL_GetRGBA. A Uint32 to send to putpixel() can be assembled from RGB values using SDL_MapRGB or SDL_MapRGBA, for example: putpixel(surf, x, y, SDL_MapRGB(surf->format, r, g, b));

Note: On my computer (I can't verify on others), surface->format->BytesPerPixel does NOT return 1,2 or 3 but 8,16 or 24... Thus, these examples don't work... [JD - "BytesPerPixel should be 1-4, BitsPerPixel should be 8-32"] You just have to modify this line :

- Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
+ Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp / 8;

Note: The above changes are not correct. I'm not sure about the BytesPerPixel problem since that should always return 1, 2, 3, or 4 (8 bit depth = 1 byte per pixel, etc.), but if you are having a problem with this, changing the above lines will only break both functions because those lines have nothing to do with determining the bit depth. The change should be on this line:

- int bpp = surface->format->BytesPerPixel;
+ int bpp = surface->format->BytesPerPixel / 8;

Note: for 16 bits the line could also be:

because pitch gives the number of BYTES per surface scanline, and because x, in this case, needs no multiplier since the pointer cast produces moves through two bytes of memory for every integer change of x.


CategoryExamples

Pixel_Access (last edited 2010-03-30 12:48:09 by bl9-76-246)