Archived

This topic is now archived and is closed to further replies.

How to get a pixel from a surface?

This topic is 5794 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

I want to read a pixel in a surface so I can pass it's color to an array. How do I do that? I'm running in DX7 and C/C++; Edited by - s_cloudx on February 27, 2002 4:06:59 AM

Share on other sites
er, is it possible?

Share on other sites
You could use the GDI GetPixel method:
  HDC hdc;lpSurface->GetDC(&hdc);//Now you can access the hdc using all the standard GDI functions.//Access colour at 32,32COLORREF cr = GetPixel(hdc,32,32);//Remember to do this!lpSurface->ReleaseDC(hdc);

Should work. I have a feeling some fanatic is about to start flaming me about the evilness of using GDI functions though

---------------

I finally got it all together...
...and then forgot where I put it.

Share on other sites
AdmiralBinary, I thank you! that''s exactly what I was looking for. One last question. How do I extract the rgb of the resultant COLORREF? I''m kinda lost here.
(yes, getdc is slow but it''s on initialization anyways so it won''t matter. )

er, IndirectX, I said DX7. guess you missed that. oh well. thanks for the help anyways. :D

Share on other sites
Don''t bother with the GDI (yes, I''ll be that person... but only because there is a much simpler way). Lock the surface, then use either GetLockedArray or GetLockedPixel to get the pixel (use GetLockedArray if you are grabbing lots of pixels and GetLockedPixel if you are only getting one).

Then, use GetPixelFormat to decypher the pixels.

Don''t forget to unlock the surface once you are done.

Trying is the first step towards failure.

Share on other sites
Wow, I''m surprised no gave teh best answer yet. In DirectDraw all you do is:

Call IDirectDrawSurface7::Lock() on the surface, and make sure DDLOCK_SURFACEMEMORYPTR is one of the properties bitwise or''ed with the other DDLOCK properties. And then, after the call to lock if it succeeds, the DDSURFACEDESC structure will have the pointer to the memory surface stored in the lpSurface feild.

So in psuedo code it looks like(dont know how to use white boxes):

---------------------------------------------------------
surface->Lock(NULL, &ddsd,
DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
NULL);

DWORD * memory = (DWORD *)ddsd.lpSurface;

DWORD * pixel = memory[x + y* ddsd.lPitch]; //This gets a pixel colo
memory[x + y * ddsd.lPitch] = 0xFF00FF00; //Set toBlue in 32-bit mode
---------------------------------------------------------

Basically, ddsd.lpSurface is a void pointer that needs to be casted to another type - depending on the bit depth of the surface. It may be 16(WORD), 32(DWORD), or 8(BYTE) - 24 is DWORD but with 4 bits unused, I think.... I hope that shed some light. As soon as you get that pointer you can read or write to the surface memory as you wish.

--I hope you know what pitch is. If you dont then ask.

Share on other sites
quote:
One last question. How do I extract the rgb of the resultant COLORREF? I''m kinda lost here.

I think a couple of ppl have beat me to this one, but I think I do know an easier method

GetRValue(colour)
GetGValue(colour)
GetBValue(colour)

These are just bitshifting macros, but they look neater...
Hope this helps

---------------

I finally got it all together...
...and then forgot where I put it.

Share on other sites
ragonastick, according to my SDK, GetLockedPixel and GetLockedArray is visual-basic specific (I might be wrong). sorry

EbonySeraph, you''re right. that is (the way I look at it) much faster. Pitch, I think, is the "extra memory" in the graphic card per line that exceeds the width of the resolution. Correct me if I''m wrong.

I''ll check out all your answers later when I get back to my pc.

Share on other sites
Yeah, that would be the pitch.

"Ogun''s Laughter Is No Joke!!!" - Ogun Kills On The Right, A Nigerian Poem.

Share on other sites
Hmm. GetRValue, GetGValue and GetBValue doesn''t seem to work . I know that a certain pixel (e.g. 12,20) has a pixel of:

red-10
green-243
blue-0

yet, I seem to be getting wrong result. Can anyone help me?

Share on other sites
For non time critical stuff use GDI.

For ingame stuff use Lock(). Look it up in the DX docs.

Share on other sites
quote:
Original post by s_cloudx
Hmm. GetRValue, GetGValue and GetBValue doesn''t seem to work . I know that a certain pixel (e.g. 12,20) has a pixel of:

red-10
green-243
blue-0

yet, I seem to be getting wrong result. Can anyone help me?

If your prog is running in, say, 16bit colour, it''ll have to convert to get your the 32bit COLORREF containing 8bit values. A full white pixel in 16bit mode might contain (248, 252, 248) in 32bit mode.

Share on other sites
Maybe I should had been more specific.

On photoshop, I check the color of a pixel location (eg. 12,20). Photoshop says it has a color of

red-10
green-243
blue-0

But I get mixed result when I try to get the color. Can someone give me a code on how to get the right color, pls?

Share on other sites
typedef union
{
struct
{
BYTE b;
BYTE g;
BYTE r;
} rgb;

struct
{
BYTE r;
BYTE g;
BYTE b;
} bgr;
} TRIPLE, *LPTRIPLE;

LPWORD pWord;
LPTRIPLE pTriple;
LPDWORD pDword;
DWORD dwColor, dwRed, dwGreen, dwBlue;

hr = m_pBackSurface->Lock(NULL, &ddsd,
DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
NULL);

// 16 bits
pWord = (LPWORD)ddsd.lpSurface + ((ddsd.lPitch / 2) * y) + x;
dwColor = (DWORD)(*pWord);

// 24 bits
pTriple = (LPTRIPLE)ddsd.lpSurface + ((ddsd.lPitch / 3) * y) + x;
dwRed = (DWORD)pTriple->rgb.r;
dwGreen = (DWORD)pTriple->rgb.g;
dwBlue = (DWORD)pTriple->rgb.b;
dwColor = (dwRed << 16) | (dwGreen << 8) | (dwBlue);
// or
dwRed = (DWORD)pTriple->bgr.r;
dwGreen = (DWORD)pTriple->bgr.g;
dwBlue = (DWORD)pTriple->bgr.b;
dwColor = (dwRed) | (dwGreen << 8) | (dwBlue << 16);

// 32 bits
pDword = (LPDWORD)ddsd.lpSurface + ((ddsd.lPitch / 4) * y) + x;
dwColor = (DWORD)(*pDword);

hr = m_pBackSurface->Unlock(NULL);

Share on other sites
Anon: I might be missing something, but how can I extract the RGB in 16-bit color? I''ll see later when I get home and try your code.

Share on other sites

// 16 bits
pWord = (LPWORD)ddsd.lpSurface + ((ddsd.lPitch / 2) * y) + x;
wColor = *pWord;

// 16 bits R5G5B5
wRed = (wColor & 0x7C00) >> 10;
wGreen = (wColor & 0x03E0) >> 5;
wBlue = (wColor & 0x001F);

// 16 bits R5G6B5
wRed = (wColor & 0xF800) >> 11;
wGreen = (wColor & 0x07E0) >> 5;
wBlue = (wColor & 0x001F);

Share on other sites
Anon, it still doesn''t work

R - 15
G - 30
B - 8

I''m expecting (i checked the color with photoshop):

R - 248
G - 240
B - 64

or, am I missing something? my guess would be that I''m getting the correct colors information but photoshop is giving me a different color format.

Kippesoep, I believed you were right. Maybe what I really need right now is to convert 16bit (or even 32bit) to 8bit. So, how do I do that?

Share on other sites
I''ll just throw a little something in here.
A little re-write of what I use in my 16 bit sprite library.

  USHORT *surf_ptr;USHORT colour;DDSURFACEDESC2  ddsd;ddsd.dwSize = sizeof(ddsd);if ( surface == NULL )     return;  // let''s get some surface info  surface -> GetSurfaceDesc( &ddsd );    ( surface ) -> Lock( NULL,                       &ddsd,                       DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,                       NULL);   surf_ptr = (USHORT *)ddsd.lpSurface;  ( surface ) -> Unlock(NULL);  colour = *(surf_ptr + ( y * ddsd.dwWidth ) + x );

Then extract colours using AP''s equations.
This assumes surface is made in system memory.

Guy

"Who lives in a pineapple under the sea ?"

Share on other sites
quote:
Original post by s_cloudx
or, am I missing something? my guess would be that I'm getting the correct colors information but photoshop is giving me a different color format.

Kippesoep, I believed you were right. Maybe what I really need right now is to convert 16bit (or even 32bit) to 8bit. So, how do I do that?

You're getting a different range. There are two ways to convert: the fast way and the accurate way.
First, the fast way:
16bit R5G5B5finalRed = wRed << 3;finalGreen = wGreen << 3;finalBlue = wBlue << 3;16bit R5G6B5finalRed = wRed << 3;finalGreen = wGreen << 2;finalBlue = wBlue << 3;

The accurate way:
16bit R5G5B5finalRed = wRed * 255 / 31;finalGreen = wGreen * 255 / 31;finalBlue = wBlue * 255 / 31;16bit R5G6B5finalRed = wRed * 255 / 31;finalGreen = wGreen * 255 / 63;finalBlue = wBlue * 255 / 63;

You could speed that up using two lookup tables (a total of 96 bytes):

    unsigned char table5bit [32];unsigned char table6bit [64];void initTables (){    int i;    for (i = 0; i < 32; i++) table5bit [i] = (unsigned char)(i * 255 / 31);    for (i = 0; i < 64; i++) table6bit [i] = (unsigned char)(i * 255 / 63);}

16bit R5G5B5finalRed = table5bit [wRed];finalGreen = table5bit [wGreen];finalBlue = table5bit [wBlue];16bit R5G6B5finalRed = table5bit [wRed];finalGreen = table6bit [wGreen];finalBlue = table5bit [wBlue];

[edited by - Kippesoep on March 15, 2002 1:27:16 PM]