Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion Groups
General
GeneralPortable MacsHardwareNetworking
Applications
Mac ApplicationsEudoraFirefox / MozillaInternet ExplorerOutlook ExpressMS OfficeEntourageExcelPowerPointWordVirtual PCMedia PlayerOther MS Products
Programming
Mac ProgrammingCodeWarriorPerl
Country Specific
Australian Mac GroupUK Mac Group

Mac Forum / Programming / Mac Programming / December 2005



Tip: Looking for answers? Try searching our database.

Back to getting pixel RGBColor values from a pixmap

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Don Bruder - 17 Dec 2005 20:18 GMT
A week or few ago, I asked about grabbing and/or stuffing a pixel's RGB
value out of/into a pixmap, and got information on Set|GetCPixel().
Great information. Quite useful. Also got advice that it was likely to
be too slow for my purpose (VMD) due to various steps involved in
handing it back to me. Unfortunately (and that isn't a criticism of the
advice... read on...) the advice was just as good as the information
that pointed me at Set|GetCPixel in the first place - it is indeed too
slow for my purposes, seeing as doing nothing more than using those two
routines as the core of a "brute force" copy from one 640x480 pixmap to
another, with no intervening pixel-processing involved, takes nearly 10
seconds. Actually being able to *DO* something with the pixels before
writing them to the output PixMap would be nice, since the whole point
of this exercise it to process the image so taht I can detect motion in
it...

To be more than just a "toy", I need it to be handling *AT LEAST* a
frame every 3-5 seconds, with 1 second or less between frames being much
better if I can somehow swing it.

So I obviously need a better way of "playing on the pixmaps".

Another factor:
Apparently, the method I've been using is creaming something in RAM, as
well as still being too slow to be all that useful. Without the "poking
around where I probably don't belong" code that accesses PixMaps
directly, the program runs flawlessly. With it, I get intermittent
quit-time or shortly post-quit-time crashes. I wonder if I've got a
problem calculating the index into the array of spource values? Doing
the math on "live" pixmaps verifies that the rowBytes value does indeed
match the expected value of 4 * HorizontalPixels, so it doesn't appear
that there's any "weirdness" in the layout of the pixel array. So I'm
stumped as to whats causing the crashes. (Even more stumped since they
aren't repeatable/predictable at a finer resolution than "it sometimes
crashes at or just after quitting when the pixmap accessing code is "in
play", but doesn't when it isn't)

Here's how I'm getting a pixel at the moment:

Note: This routine was designed, tested, and intended *ONLY* for use
with 32-bit direct color PixMaps as implemented for MacOS 9.1/Carbon.
Try using it for any other bit depth, or with an indexed color PixMap,
or with a PixMap that isn't part of an offscreen GWorld, or on MacOS X
(Classic MAY work, but I'm not equipped to test that idea) and I all but
guarantee it'll malfunction. Don't say I didn't warn ya!

RGBColor getpixel(GWorldPtr Source, int H, int V)
 {
   PixMapHandle  ThePixMapHandle = GetGWorldPixMap(Source);
   Ptr           BaseAddress = GetPixBaseAddr(ThePixMapHandle);
   long          RowBytes = GetPixRowBytes(ThePixMapHandle);
   long          Index = 0L;
   PixelStruct   ThePixel = {0, 0, 0, 0};
   PixelStruct   *PixelPtr = &ThePixel;
   RGBColor      ThePixelColor = {0, 0, 0};
   Rect          Bounds = {0,0,0,0};

   Locker(Source); // My conditional version of LockPixels()
   // Sanity-check the H/V values against Source's bounds Rect.
   // (Things get *REALLY* hairy if we trying playing outside it)
   if ((Bounds.left <= H) && (H <= Bounds.right) &&
       (Bounds.top <= V) && (V <= Bounds.bottom))
     {
       // H/V OK. "Fold" them into a linear index into the array of
       // 4 byte RGBColor values and use that to point to the desired
       // pixel's raw RGB value in the array.
       PixelPtr = (PixelStruct *)BaseAddress +
                                 (V * RowBytes) +
                                 (H * sizeof(PixelStruct));
     }
   else
     {
       // H and/or V is/are outside the bounds of this pixmap.
       // Function initialization has already pointed PixelPtr
       // at a known {0,0,0,0} PixelStruct, so just fall through
       // into the exit code to return it to the caller.
     }
   // Convert the pixel values pointed to by PixelPtr (Might be
   // {0,0,0,0} if H or V are out of range) into an RGBColor struct
   ThePixelColor.red   = PixelPtr->Red;
   ThePixelColor.green = PixelPtr->Green;
   ThePixelColor.blue  = PixelPtr->Blue;
   // We're all finished with the pixmap for now. Unlock it.
   Unlocker(Source);
   return ThePixelColor;
 }

The reverse operation, putpixel(), is quite similar, with the obvious
changes that are needed for writing a supplied value, rather than
reading and returning a result.

Obviously, there's a bunch of "gotta redo it every time" overhead -
Getting the handle to the pixmap, the (Un)LockPixels and H(un)Lock
operations, getting the bounds and baseAddr value - But if the pixmap is
kept "permanently locked" - something that the docs seem rather
"insistent" about when they say it isn't a good idea - doesn't that
invite problems with heap fragmentation? And if it's locked for each
access, then unlocked, the values have to be considered volatile between
calls, requiring a fresh cycle of "get PixMapHandle, lock it, get base
address and rowBytes values" before the next access can be done, blowing
performance out of the water.

Is it just me, or does this seem suspiciously like one of those classic
"damned if you do, damned if you don't" situations?

Is there a better way? Seems like there has to be, since programs like
Photoshop manage it, and at a much higher speed.

Signature

Don Bruder - dakidd@sonic.net - If your "From:" address isn't on my whitelist,
or the subject of the message doesn't contain the exact text "PopperAndShadow"
somewhere, any message sent to this address will go in the garbage without my
ever knowing it arrived. Sorry... <http://www.sonic.net/~dakidd> for more info

Reinder Verlinde - 17 Dec 2005 22:15 GMT
> Here's how I'm getting a pixel at the moment:
>
> Note: This routine was designed, tested, and intended *ONLY* for use
> with 32-bit direct color PixMaps as implemented for MacOS 9.1/Carbon.
> [...]
> RGBColor getpixel(GWorldPtr Source, int H, int V)

If you want this function to be fast, it probably is better to pass a
RGBColor * to this function. Otherwise, the compiler may copy the
RGBColor to return it.

>   {
>     PixMapHandle  ThePixMapHandle = GetGWorldPixMap(Source);
>     Ptr           BaseAddress = GetPixBaseAddr(ThePixMapHandle);
>     long          RowBytes = GetPixRowBytes(ThePixMapHandle);
>     long          Index = 0L;

Are you sure you need 'Index'? I can't see where you use it.

>     PixelStruct   ThePixel = {0, 0, 0, 0};
>     PixelStruct   *PixelPtr = &ThePixel;
>     RGBColor      ThePixelColor = {0, 0, 0};
>     Rect          Bounds = {0,0,0,0};

Is it me, or did you forget to initialize 'Bounds'?

>     Locker(Source); // My conditional version of LockPixels()
>     // Sanity-check the H/V values against Source's bounds Rect.
[quoted text clipped - 9 lines]
>                                   (H * sizeof(PixelStruct));
>       }

1. This probably does not matter in your case, but in general, you can
not be sure that Bounds.left and Bounds.top both are zero. For example,
you can have a 16x16 pixel GWorld with topleft at {30000,-20000}.

2. How large is an int on your system/compiler combination? If it is 2
bytes, that calculation could easily overflow, returning a PixelPtr that
points before the BaseAddress.

3. This code may be correct, but I would write an extra pair of
parentheses:
       PixelPtr = (PixelStruct *)(BaseAddress +
                                 (V * RowBytes) +
                                 (H * sizeof(PixelStruct)));
because I either:
- am too lazy to remember C operator precedence order
- rather spend my time on things that matter
- just prefer writing solid code

> [...]
> Obviously, there's a bunch of "gotta redo it every time" overhead -
> Getting the handle to the pixmap, the (Un)LockPixels and H(un)Lock
> operations, getting the bounds and baseAddr value - But if the pixmap is
> kept "permanently locked" - something that the docs seem rather
> "insistent" about when they say it isn't a good idea

Things may get bad when you keep a pixmap locked across a WaitNextEvent
call, because locking the pixels may prevent the system from moving them
around to make room for memory allocated by another application.

For what you are doing, you can safely do the whole
LockPixels/GetBaseAddress thing once, then iterate over all pixels, then
unlock the thing and call WaitNextEvent.

Given the requirements of your application, it might even be that you
can just as well keep the thing locked the whole time (chances are you
won't be running much else, anyway)

> Is there a better way? Seems like there has to be, since programs like
> Photoshop manage it, and at a much higher speed.

How do you know Photoshop uses GWorlds?

Reinder
Not Important - 18 Dec 2005 05:37 GMT
A small correction.

RGBColor getpixel( GWorldPtr pgw, int H, int V )
{
 /* default for out of bounds failure */
 RGBColor    rgb  = { 0x0000, 0x0000, 0x0000 };

 PixMapHandle   hpm  = GetGWorldPixMap( pgw );

 /* 24 bit color pixel : 0xAARRGGBB (Alpha, Red, Green, Blue)*/
 unsigned long  Pixel;
 unsigned long*  PixelBasePtr
           = (unsigned long*)GetPixBaseAddr(hpm);
 long      PixelsPerRow
           = GetPixRowBytes( hpm ) / sizeof(Pixel);
 Rect      rcBounds;

 GetPixBounds( hpm, &rcBounds );

 Locker( pgw );
 
 if (  (H >= rcBounds.left) && (H < rcBounds.right)
   &&  (V >= rcBounds.top) && (V < rcBounds.bottom))
 {
   Pixel = *(PixelBasePtr + (V * PixelsPerRow) + H);

   // components are shorts - so move value to highbyte
   rgb.red    = ((Pixel & 0x00FF0000) >> 0xF) << 0x8;
   rgb.green  = ((Pixel & 0x0000FF00) >> 0x8) << 0x8;
   rgb.blue   = ((Pixel & 0x000000FF) >> 0x0) << 0x8;
 }

 Unlocker( pgw );

 return rgb;
}
Don Bruder - 18 Dec 2005 13:50 GMT
> A small correction.

<snip>

>     // components are shorts - so move value to highbyte
>     rgb.red    = ((Pixel & 0x00FF0000) >> 0xF) << 0x8;
>     rgb.green  = ((Pixel & 0x0000FF00) >> 0x8) << 0x8;
>     rgb.blue   = ((Pixel & 0x000000FF) >> 0x0) << 0x8;

        ???

Erm... Isn't that exactly backwards?

Since the component is a short (two bytes with my compiler settings),
and Macs (at least, the "not-Intel-based" Macs I'm working with...) are
natively big-endian, wouldn't one want the resulting value to land in
the *LOW* byte of the short? Seems to me (without having done anything
more than look at it yet) that your first version, without the trailing
"<< 0x08" operation, would give a correct result, while doing it this
way, I'd expect that what will come out will be an RGB struct with each
component being 256 times whatever the value read from the pixmap
actually was. Unless the machine running the code was little-endian, in
which case, the "<< 0x08" would of course be absolutely vital to getting
the right values back.

Or am I failing to notice/understand something important?

Signature

Don Bruder - dakidd@sonic.net - If your "From:" address isn't on my whitelist,
or the subject of the message doesn't contain the exact text "PopperAndShadow"
somewhere, any message sent to this address will go in the garbage without my
ever knowing it arrived. Sorry... <http://www.sonic.net/~dakidd> for more info

Reinder Verlinde - 18 Dec 2005 14:36 GMT
> >     // components are shorts - so move value to highbyte
> >     rgb.red    = ((Pixel & 0x00FF0000) >> 0xF) << 0x8;
[quoted text clipped - 9 lines]
> natively big-endian, wouldn't one want the resulting value to land in
> the *LOW* byte of the short?

RGBColor stores 16 bits per color component (range: 0x0000 through
0xFFFF), your 24-bit GWorld stores only 8 (range: 0x00 through 0xFF. The
code above compensates for that, but does not map 0xFF to 0xFFFF, as you
probably would want The 'optimal' thing to do is

   rgb.red    = ((Pixel & 0x00FF0000) >> 0xF) * 0x0101;
   ...

or, using bit shifting:

   rgb.red = ((Pixel & 0x00FF0000) >> 0xF);
   rgb.red |= (rgb.red << 8);
   ...

This is a nice linear mapping that maps 0x00 to 0x00, 0xFF to 0xFFFF.

Reinder
Don Bruder - 18 Dec 2005 15:45 GMT
> > >     // components are shorts - so move value to highbyte
> > >     rgb.red    = ((Pixel & 0x00FF0000) >> 0xF) << 0x8;
[quoted text clipped - 12 lines]
> RGBColor stores 16 bits per color component (range: 0x0000 through
> 0xFFFF), your 24-bit GWorld stores only 8 (range: 0x00 through 0xFF.

I'm with you so far...

> The
> code above compensates for that, but does not map 0xFF to 0xFFFF, as you
> probably would want

Why would I want that? Frankly, I couldn't care less about values higher
than 255/0xFF if I were to make a concious effort to do so - The high
byte of such values is going to be "lost" due to being lopped off the
front when getpixel() returns.

What I want is the R, G, and B values that make up the pixel's color in
RAM. Which means I want the three 0x00-0xFF values (plus the
unused/ignored "Alpha" component that I don't much care about, but end
up getting anyway at no extra cost if I should decide to put it to use
somehow) that are actually stored in the pixmap for each pixel's color
components. Since the high bytes of the RGB component values don't exist
in RAM (and according to the docs I'm reading, are ignored by Quicktime
operations that take RGBColor inputs), I'd expect/prefer them to be
filled with zeros when handed back to me, leaving me with only the 8 bit
component values as read from RAM.

> The 'optimal' thing to do is
>
[quoted text clipped - 8 lines]
>
> This is a nice linear mapping that maps 0x00 to 0x00, 0xFF to 0xFFFF.

True enough, I guess, but why do I care what value the (ignored/unused)
high-byte of the component value has? Based on what I can see, that byte
will never come into any calculations - Or will it? Have I missed
something?

Seems to me that worrying about setting the value of the high byte is an
extra step that eats processor time, but does nothing useful -
particularly since the *VERY FIRST* thing I'm going to do with what
comes back once the call to getpixel() completes is lop off the high
byte of the component values in order to get three unsigned 8 bit
numbers between 0 and 255 to use for initializing the R/G/B values that
will be used in my other calculations. (Which *MIGHT* end up having one
or more intermediate steps being calculated in 16 or 32 bits, but whose
final "put it to use" result *WILL* be clamped to the range 0-255)

No, I'm not trying to be argumentative - I simply can't figure out why
it is I should spend machine-cycles setting bytes that, as far as I can
see, are going to be ignored, if not outright discarded. If there's an
actual reason to do so, fine - I'll take the advice and go that route.
But if there isn't (which appears to be the case) it seems to make more
sense to save the machine cycles by not bothering to do anything with
the high byte in the first place. (And do keep in mind that, for reasons
I've covered elsewhere, machine cycles are at a premium here - enough so
that I'm actively considering replacing the whole getpixel/putpixel mess
with a hand-crafted chunk of PPC assembly language to get better speed
out of it.)

Signature

Don Bruder - dakidd@sonic.net - If your "From:" address isn't on my whitelist,
or the subject of the message doesn't contain the exact text "PopperAndShadow"
somewhere, any message sent to this address will go in the garbage without my
ever knowing it arrived. Sorry... <http://www.sonic.net/~dakidd> for more info

Reinder Verlinde - 18 Dec 2005 17:12 GMT
> > RGBColor stores 16 bits per color component (range: 0x0000 through
> > 0xFFFF), your 24-bit GWorld stores only 8 (range: 0x00 through 0xFF.
[quoted text clipped - 16 lines]
> somehow) that are actually stored in the pixmap for each pixel's color
> components.

> Since the high bytes of the RGB component values don't exist
> in RAM

Not in this specific case (24-bit direct color), but generally, they do.
A 8-bit indexed-color GWorld has a color table that defines each color
component in 16 bits.

Also, if ColorSync comes into play, one could say that

> (and according to the docs I'm reading, are ignored by Quicktime operations
> that take RGBColor inputs),

I doubt that that is true. Can you give a link for those docs? I am not
a QuickTime expert, but would guess that those docs are in error, or
that you are misinterpreting them. I also do not see why QuickTime would
pop up in this QuickDraw discussion.

> I'd expect/prefer them to be
> filled with zeros when handed back to me, leaving me with only the 8 bit
> component values as read from RAM.

In that case, I would suggest that you create your own rgb structure,
instead of reusing RGBColor. That will use less memory, and prevent a
bug where, some time in the future, you will inadvertently pass a
RGBColor using your format to a QuickDraw function, resulting in
mostly-black displays.

Reinder
Don Bruder - 18 Dec 2005 19:39 GMT
> > Since the high bytes of the RGB component values don't exist
> > in RAM
>
> Not in this specific case (24-bit direct color), but generally, they do.
> A 8-bit indexed-color GWorld has a color table that defines each color
> component in 16 bits.

Right, I realize that. But I'm not coding to an 8-bit indexed GWorld -
I'm very specifically coding to a 640x480 pixel, "32-bit" (which, in
practice, is really 24-bit stored with a leading byte that gets ignored
under Carbon/9.1) per pixel direct color GWorld. So regardless of how
it's stored in an RGBColor struct or a CLUT entry, or whatever else,
when it hits RAM as part of the 32-bit PixMap, a pixel's color data is
stored as a set of four bytes: #1 is "whatever 8-bit value happens to be
there - we don't care - it's ignored", #2 is the 8-bit value of the red
component, #3 is the 8-bit value of the green component, and #4 is the
8-bit value of the blue component. Since 99% of what I'm doing is
working directly on PixMaps - specifically, "32-bit" direct color
PixMaps - and the data they contain, with RGBColors and CLUTs and such
being used only as "transport containers" to get the 3 useful bytes to
and from my program, well... How important is it, really, to worry about
the distinction?

> Also, if ColorSync comes into play

It doesn't, and at least right now, I have no realistic expectation that
it ever will - I'm not concerned enough with the idea that my colors
might not be displayed accurately to bother writing code to do so. Not
for a motion-detecting webcam/surveillance type gadget, anyway!

> > (and according to the docs I'm reading, are ignored by Quicktime operations
> > that take RGBColor inputs),
[quoted text clipped - 3 lines]
> that you are misinterpreting them. I also do not see why QuickTime would
> pop up in this QuickDraw discussion.

While based in mainly QuickDraw doings right now, the ultimate result is
going to be working *VERY* tightly with QuickTime, which makes extensive
use of GWorlds, PixMaps, and RGBColors. Extensive enough that it's hard
to keep the two "Quicks" from "blurring together" for me unless
something causes them to snap into separate focus.

As for a link, I can't give you that right now. I'll do what I can to
dig up the discussion that gave me that idea - if I can figure out where
it was I ran across it! It's SOMEWHERE on my local drive, but without
going hunting, I can't immediately say which of the dozens of
Apple-supplied Carbon/Quicktime/Quickdraw/MacOS docfiles I've been using
for my references it was in.

> > I'd expect/prefer them to be
> > filled with zeros when handed back to me, leaving me with only the 8 bit
> > component values as read from RAM.
>
> In that case, I would suggest that you create your own rgb structure,
> instead of reusing RGBColor.

That's what the "PixelStruct" (Sorry, didn't notice that wasn't shown in
the posted code - it gets pulled in from an #include file) type is:

typedef struct MyPstruct
  {
     unsigned char UNUSEDALPHA;
     unsigned char Red;
     unsigned char Green;
     unsigned char Blue;
  } PixelStruct;

> That will use less memory,

Yep... 4 bytes per PixelStruct versus 6 per RGBColor - Not a BIG gain as
such things go when considered as a single entity, but it's about half a
meg per image when you start getting into 640x480 blocks of them, and I
am going to be trying to shoehorn this thing into a rig that I'm not
much interested in spending money on to add RAM.

>  and prevent a
> bug where, some time in the future, you will inadvertently pass a
> RGBColor using your format to a QuickDraw function, resulting in
> mostly-black displays.

That's a contributing factor in my decision to write getpixel/putpixel
to deal with things, rather than trying to go directly to the PixMap
each time I want to do something with a pixel. Once I get the kinks
worked out, I intend to simply copy out and return *PixelPtr, rather
than converting it within getpixel() and returning the RGBColor. For
development, using the RGBColor makes things a bit easier to keep an eye
on in the debugger as I step through trying to see just what it is I'm
screwing up THIS time!

Signature

Don Bruder - dakidd@sonic.net - If your "From:" address isn't on my whitelist,
or the subject of the message doesn't contain the exact text "PopperAndShadow"
somewhere, any message sent to this address will go in the garbage without my
ever knowing it arrived. Sorry... <http://www.sonic.net/~dakidd> for more info

Reinder Verlinde - 18 Dec 2005 20:42 GMT
> For development, using the RGBColor makes things a bit easier to keep an eye
> on in the debugger as I step through trying to see just what it is I'm
> screwing up THIS time!

What development environment are you using? Most IDEs should be able to
output your own structures, too.

If you are (sometimes/also/always) working in MacsBug, you should know
that you can tell it what your own frequently used structures look like.
See the section 'Using Templates to Display Memory' in
<http://developer.apple.com/tools/debuggers/MacsBug/Documentation/MacsBug
Ref_6.2.sit.hqx>

Also, you might find some useful stuff in
<http://vision.nyu.edu/VideoToolbox/>, in particular the functions
SetPixelsQuickly and CopyBitsQuickly.

Reinder
Don Bruder - 19 Dec 2005 02:33 GMT
> > For development, using the RGBColor makes things a bit easier to keep an
> > eye
[quoted text clipped - 3 lines]
> What development environment are you using? Most IDEs should be able to
> output your own structures, too.

CW 5
It CAN show them to me, but it takes a tiny bit more effort, and I'm too
lazy to do the conversion for efficiency until after I've managed
something that's at least sorta like functionality.
 
> If you are (sometimes/also/always) working in MacsBug, you should know
> that you can tell it what your own frequently used structures look like.
> See the section 'Using Templates to Display Memory' in
> <http://developer.apple.com/tools/debuggers/MacsBug/Documentation/MacsBug
> Ref_6.2.sit.hqx>

Snarfin' 'em as I learn of their existence... Latest version of the
MacsBug doc I've encountered up to now has been... I think it was
5.something - I want to say 5.1.3.

> Also, you might find some useful stuff in
> <http://vision.nyu.edu/VideoToolbox/>, in particular the functions
> SetPixelsQuickly and CopyBitsQuickly.

Oooh! I LIKE! Too much going on there for a quick look-through to catch
it all, but it's downloading, and I'll definitely be taking a close look
at what it has to offer.

Signature

Don Bruder - dakidd@sonic.net - If your "From:" address isn't on my whitelist,
or the subject of the message doesn't contain the exact text "PopperAndShadow"
somewhere, any message sent to this address will go in the garbage without my
ever knowing it arrived. Sorry... <http://www.sonic.net/~dakidd> for more info

Not Important - 18 Dec 2005 19:14 GMT
> Seems to me that worrying about setting the value of the high
> byte is an extra step that eats processor time, but does nothing
> useful -

You're wanting the results placed in a Color QuickDraw RGBColor
structure.  I have no real idea what you plan o doing with it but
must assume the possibility of use with other Color QuickDraw
routines.  As such I thought it best to conform with the systems
expectations.

See Figure 4-5 Translating a 48-bit RGBColor record to a 32-bit
pixel value on a direct device at:

<http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-1
98.html#MARKER-9-68>

Note: The document is also available in PDF format some where on
the page.
Don Bruder - 18 Dec 2005 19:57 GMT
> > Seems to me that worrying about setting the value of the high
> > byte is an extra step that eats processor time, but does nothing
[quoted text clipped - 5 lines]
> routines.  As such I thought it best to conform with the systems
> expectations.

Ahhh... Got it. What's going to happen with it is I'm going to test it,
adjust it, compare it, or otherwise play with it in various ways before
either cramming it (or a value derived from/related to it in some way)
back into the GWorld (or one much like it) that it came from, or
dropping it on the floor. That's as close as it's ever likely to get to
being passed to a QuickDraw or QuickTime routine.

> See Figure 4-5 Translating a 48-bit RGBColor record to a 32-bit
> pixel value on a direct device at:
[quoted text clipped - 4 lines]
> Note: The document is also available in PDF format some where on
> the page.

Thanks - I'll take a look. (and probably download it for future
reference, if I haven't got it sitting here locally already)

Signature

Don Bruder - dakidd@sonic.net - If your "From:" address isn't on my whitelist,
or the subject of the message doesn't contain the exact text "PopperAndShadow"
somewhere, any message sent to this address will go in the garbage without my
ever knowing it arrived. Sorry... <http://www.sonic.net/~dakidd> for more info

Don Bruder - 18 Dec 2005 05:44 GMT
> > Here's how I'm getting a pixel at the moment:
> >
[quoted text clipped - 14 lines]
>
> Are you sure you need 'Index'? I can't see where you use it.

Ahhh... Another "leftover" I missed - At one point, I was doing the
"which set of bytes should I be looking at" calculation one step at a
time so I could breakpoint through it and be able to see what was what
at any given instant without needing to beg or bribe the debugger into
showing it to me.

> >     PixelStruct   ThePixel = {0, 0, 0, 0};
> >     PixelStruct   *PixelPtr = &ThePixel;
> >     RGBColor      ThePixelColor = {0, 0, 0};
> >     Rect          Bounds = {0,0,0,0};
>
> Is it me, or did you forget to initialize 'Bounds'?

????
There *SHOULD* be a "GetPortBounds(Source, &Bounds);" line in there...
<checks "live" source> Yep, the posted version is missing that line, but
the "production" version has it. I must have "dropped" it when I was
hand-wrapping the comments and otherwise "pretty-izing" the code prior
to posting so that it wouldn't come out the other end of the posting
process looking like it'd been run through a wood chipper.

> >     Locker(Source); // My conditional version of LockPixels()
> >     // Sanity-check the H/V values against Source's bounds Rect.
[quoted text clipped - 13 lines]
> not be sure that Bounds.left and Bounds.top both are zero. For example,
> you can have a 16x16 pixel GWorld with topleft at {30000,-20000}.

You're correct that it doesn't matter for me. I'm (at least currently)
using this code exclusively with 640x480 GWorlds that have their origin
at 0,0, even though as coded (intentionally so), it's easily possible to
pass it a different sized GWorld, or one with its origin someplace other
than 0,0. For my purposes, that's a non-issue, since the only way
something like that is going to happen is if I screw up and somehow
mangle a GWorld before passing it in.

> 2. How large is an int on your system/compiler combination? If it is 2
> bytes, that calculation could easily overflow, returning a PixelPtr that
> points before the BaseAddress.

True. It isn't biting me in this incarnation (probably because I'm
working with GWorlds that are always 640x480 - Although I think I recall
setting up ints to be 4 bytes, as well) but with bigger ones, it could
easily be a problem. Changing H/V to longs instead of ints should cope
with that nicely, regardless of what the int size setting is. Nice
catch! :)

> 3. This code may be correct, but I would write an extra pair of
> parentheses:
[quoted text clipped - 5 lines]
> - rather spend my time on things that matter
> - just prefer writing solid code

Or the fourth option you neglected to mention:
- Like me, you're so anal when you code that you habitually keep a roll
of toilet paper within arm's reach - "Just in case" :)

I often go "overkill" mode on paren use if there's even the slightest
doubt in my mind about ops precedence, but for some reason, this
instance escaped the usual treatment. I'll fix that immediately now that
you've brought it to my attention. :)

> Things may get bad when you keep a pixmap locked across a WaitNextEvent
> call, because locking the pixels may prevent the system from moving them
> around to make room for memory allocated by another application.

Hmmm... That might have only limted relevance for me then, since if this
thing turns out as I envision, it'll likely be the only thing running
(other than the OS) on a machine that would otherwise be sitting in the
closet collecting dust.

> For what you are doing, you can safely do the whole
> LockPixels/GetBaseAddress thing once, then iterate over all pixels, then
> unlock the thing and call WaitNextEvent.

That routine currently gets called from a routine that is in turn  
called from my Timer event handler (I'm using the CarbonEvents event
model) - Still safe in that situation? If so, I could fairly easily move
the "setup" work to the calling routine, lock/get what I need once, then
call it as needed, unlocking only when I'm getting ready to exit the
handler.

> Given the requirements of your application, it might even be that you
> can just as well keep the thing locked the whole time (chances are you
> won't be running much else, anyway)

Well, at the moment, I'm wanting to run it on an older, otherwise
"unloved" rig I'm currently using to keep the closet floor from floating
away. :) It'll end up being pretty much a single-task system, if things
end up the way I plan.

> > Is there a better way? Seems like there has to be, since programs like
> > Photoshop manage it, and at a much higher speed.
>
> How do you know Photoshop uses GWorlds?

I don't, but Photoshop uses something that's at least *SOMEWHAT* like a
GWorld and produces results that would be no different than mine for the
same operation - assuming mine were working properly... Ergo, it has to
be using something that bears at least some functional resemblance to a
GWorld, even if it's working directly in an on-screen window's PixMap or
some sort of custom internal image format.

Signature

Don Bruder - dakidd@sonic.net - If your "From:" address isn't on my whitelist,
or the subject of the message doesn't contain the exact text "PopperAndShadow"
somewhere, any message sent to this address will go in the garbage without my
ever knowing it arrived. Sorry... <http://www.sonic.net/~dakidd> for more info

Reinder Verlinde - 18 Dec 2005 08:55 GMT
> > >         PixelPtr = (PixelStruct *)BaseAddress +
> > >                                   (V * RowBytes) +
[quoted text clipped - 9 lines]
> with that nicely, regardless of what the int size setting is. Nice
> catch! :)

I do not understand why this wouldn't bite you here. 640*480 is more
than nine times as high as the point (32768) where this could happen
(and it is even worse because PixelStruct is more than one byte long)

Reinder
Don Bruder - 18 Dec 2005 12:59 GMT
> > > >         PixelPtr = (PixelStruct *)BaseAddress +
> > > >                                   (V * RowBytes) +
[quoted text clipped - 13 lines]
> than nine times as high as the point (32768) where this could happen
> (and it is even worse because PixelStruct is more than one byte long)

Probably has to do with the fact that my compiler settings have an int
being a 32 bit entity. I thought that was probably the case, but wasn't
certain when I posted the reply. (And worse, I was slipping in and out
of dreamland as I was typing, since the message was posted at my
wake/sleep cycle's rough equivalent of about 3AM) Now that I'm actually
awake, it's verified.)

Signature

Don Bruder - dakidd@sonic.net - If your "From:" address isn't on my whitelist,
or the subject of the message doesn't contain the exact text "PopperAndShadow"
somewhere, any message sent to this address will go in the garbage without my
ever knowing it arrived. Sorry... <http://www.sonic.net/~dakidd> for more info

Not Important - 18 Dec 2005 03:54 GMT
Untested, but if I understood your requirements the following
should work.

RGBColor getpixel( GWorldPtr pgw, int H, int V )
{
 /* default for out of bounds failure */
 RGBColor        rgb = { 0x0000, 0x0000, 0x0000 };

 PixMapHandle    hpm = GetGWorldPixMap( pgw );

 /* 24 bit color pixel : 0xAARRGGBB (Alpha, Red, Green, Blue)*/
 unsigned long   Pixel;
 unsigned long*  PixelBasePtr
                   = (unsigned long*)GetPixBaseAddr(hpm);
 long            PixelsPerRow
                   = GetPixRowBytes( hpm ) / sizeof(Pixel);
 Rect            rcBounds;

 GetPixBounds( hpm, &rcBounds );

 Locker( pgw );
   
 if (    (H >= rcBounds.left) && (H < rcBounds.right)
     &&  (V >= rcBounds.top) && (V < rcBounds.bottom))
 {
     Pixel = *(PixelBasePtr + (V * PixelsPerRow) + H);

     rgb.red     = (Pixel & 0x00FF0000) >> 0xF;
     rgb.green   = (Pixel & 0x0000FF00) >> 0x8;
     rgb.blue    = (Pixel & 0x000000FF) >> 0x0;
 }

 Unlocker( pgw );

 return rgb;
}
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.