Back to getting pixel RGBColor values from a pixmap
|
|
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; }
|
|
|