Best way to read an arbitrary pixel from an arbitrary color

depth?
Content-Type: text/plain; charset=“iso-8859-1”

I’ve spent the better part of the evening trying to wade through the
different masks in the pixel format structure trying to solve the
folowing problem. Hopefully someone on this list is feeling generous
and can think a little straighter than me right now.

Problem: I want to read an arbitrary pixel from x,y into a the
following struct.

struct {
Uint8 r;
Uint8 g;
Uint8 b;
} color;

I would like the function to be able to read the value regardless of
the target surfaces color depth and bit distribution. (works in 16 bit
5-5-5, 16 bit 5-6-5, 24 bit etc etc, anything but 8 bit (I’m not using
any palettized surfaces now)). I know this can be done with the
surface->format->Xloss/Xshift/Xmask family of masks. The only problem
is I can’t figure out the right order to use them in to get it to come
out right.

I’d be happy if someone could at least tell me what example code to
wade through to figure it out.

Phoenix Kokido
members.xoom.com/kokido
@Wes_PooleDate: Wed, 05 Jan 2000 03:00:41 +0000

Phoenix Kokido wrote:

I’ve spent the better part of the evening trying to wade through the
different masks in the pixel format structure trying to solve the
folowing problem. Hopefully someone on this list is feeling generous
and can think a little straighter than me right now.

Problem: I want to read an arbitrary pixel from x,y into a the
following struct.

struct {
Uint8 r;
Uint8 g;
Uint8 b;
} color;

This may be overly simplistic, but I've done this by combining an SDL

example (I think it came with the demos package with SDL 0.8?), which
gets a pixel, and a pair of macros straight from the SDL which I
converted into a function for ease of use, which disassemble the R, G,
and B values. I’m not sure how it handles different 16-bit encodings
etc., but you can give it a try…

/****** This functino just grabs data for one raw pixel from a surface
******/

Uint32 get_pixel(SDL_Surface *surface, Sint32 Xcoord, Sint32 Ycoord)
{
Uint8 r, g, b;
Uint8 *bits;
Uint8 bytespp;
Uint32 pixel;

/* Set the number of bytes per pixel to calculate the pixel offset… */
bytespp = surface->format->BytesPerPixel;

/*calculate the offset (pointer) to the screen->pixels array
 * screen->pitch must be the x of the screen times bytes per pixel
 */
bits = ((Uint8 *)surface->pixels) + Ycoord*surface->pitch +

Xcoord*bytespp;

/* We may now get the pixel */
switch(bytespp)
  {
  case 1:
    (Uint8) pixel = *((Uint8 *) bits);
    break;

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

  case 3: /* odd case, create offsets from screen data */
    r = *((bits) + surface->format->Rshift / 8);
    g = *((bits) + surface->format->Gshift / 8);
    b = *((bits) + surface->format->Bshift / 8);

    pixel = (r >> surface->format->Rshift) & 0xFF;
    pixel = (g >> surface->format->Gshift) & 0xFF;
    pixel = (b >> surface->format->Bshift) & 0xFF;
    break;

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

return pixel;
} /* get_pixel() */

/*******************************************************/

void DISEMBLE_RGB(void *inpixel, Uint8 bpp, SDL_PixelFormat *fmt, Uint8
*r, Uint8 *g, Uint8 *b)
{
Uint32 pixel;

    switch (bpp) {                                                  
            case 2:                                                
                    pixel = *((Uint16

*)(inpixel));
RGB_FROM_PIXEL(pixel, fmt, r, g, b);
break;

            case 3:                                                 
                    *r = *(((Uint8

*)inpixel)+fmt->Rshift/8);
*g = *(((Uint8
*)inpixel)+fmt->Gshift/8);
*b = *(((Uint8
*)inpixel)+fmt->Bshift/8);
// pixel = (*r << fmt->Rshift) | (*g <<
fmt->Gshift) | (*b << fmt->Bshift);
break;

            case 4:                                                 
                    pixel = *((Uint32

*)(inpixel));
RGB_FROM_PIXEL(pixel, fmt, r, g, b);
break;
}

}

/* Load pixel of the specified format from a buffer and get its R-G-B
values */
void RGB_FROM_PIXEL(Uint32 pixel, SDL_PixelFormat *fmt, Uint8 *r, Uint8
*g, Uint8 *b)
{
*r = (((pixel&fmt->Rmask)>>fmt->Rshift)<Rloss);
*g = (((pixel&fmt->Gmask)>>fmt->Gshift)<Gloss);
*b = (((pixel&fmt->Bmask)>>fmt->Bshift)<Bloss);
}

/*****************************************************/

Hey, I never said it was pretty...Call get_pixel, then disemble_RGB. 

To be more efficient, just find the macros in the SDL header files,
include them, and use the macros. I suspect that the last function,
RGB_FROM_PIXEL, is the one you’re probably most interested in…

Nathan Yawn
@Nathan_A_Yawn

The easiest way to do this will be to just use the SDL function provided
for the purpose: SDL_GetRGB. Rather than writing your own function to
extract the red, green, and blue components. I believe Sam has finally
made it part of the official API though it wasn’t for a long time
(though it was hiding in the source ever since I started using SDL). It
might not even be documented yet.–

| Rafael R. Sevilla @Rafael_R_Sevilla |
| Instrumentation, Robotics, and Control Laboratory |

College of Engineering, University of the Philippines, Diliman