views:

212

answers:

2

I have an NSBitmapImageRep that is created like this:

NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] 
                              initWithBitmapDataPlanes:NULL
                                            pixelsWide:waveformSize.width
                                            pixelsHigh:waveformSize.height
                                         bitsPerSample:8
                                       samplesPerPixel:4
                                              hasAlpha:YES
                                              isPlanar:YES
                                        colorSpaceName:NSCalibratedRGBColorSpace
                                           bytesPerRow:0
                                          bitsPerPixel:0];

Now I want to access the pixel data so I get a pointer to the pixel planes using

unsigned char *bitmapData;
[imageRep getBitmapDataPlanes:&bitmapData];

According to the Documentation this returns a C array of five character pointers. But how can it do that? since the type of the argument is unsigned char **, it can only return an array of chars, but not an array of char pointers.

So, this leaves me wondering how to access the individual pixels. Do you have an idea how to do that?

(I know there is the method – setColor:atX:y:, but it seems to be pretty slow if invoked for every single pixel of a big bitmap.)

+1  A: 

If you just want to iterate over the pixels, -bitmapData should be all you need.

smorgan
that only returns a pointer to the first plane. For a planar image this means I only can access the red color values… So you are suggesting to use a nonplanar image instead?
BastiBechtold
OK, it works using a nonplanar image! Thanks!
BastiBechtold
A: 

According to the Documentation this returns a C array of five character pointers. But how can it do that? since the type of the argument is unsigned char **, it can only return an array of chars, but not an array of char pointers.

Incorrect. unsigned char ** is a pointer to at least one pointer to at least one unsigned char.

So, you're supposed to pass a pointer to an array of pointers—that is, a pointer to an array of arrays. Something like this:

unsigned char *buffers[5];
[bitmapImageRep getBitmapDataPlanes:buffers];

If the image rep is planar, then each element of buffers will be a pointer to a component plane; for RGB, buffers[0] is the red plane, buffers[1] is the green plane, buffers[2] is the blue plane, and buffers[3] is the alpha plane. Each plane is, of course, a buffer holding the values for that channel (as unsigned chars).

If the image rep is not planar, then you'll get only one element, which is the RGBA data.

Of particular note is this sentence from the documentation you linked to:

If there are less than five planes, the remaining pointers will be set to NULL.

This means that the code you show contains a buffer overflow: You're passing a pointer to storage for one pointer, but the image rep expects storage for no fewer than five, and it will give you five pointers and/or NULLs, so it will be writing beyond the end of the storage you gave it. This will smash your stack, crash your application, or both.

Peter Hosey
so each whole plain is represented as a single `unsigned char`? That is one mighty `unsigned char` to hold some several thousand pixels. My question is: How is it feasible to save several thousand pixels in eight bit?
BastiBechtold
Paperflyer: No. Re-read the declaration: `unsigned char *buffers[5]` is an array of five pointers, each being a pointer to *at least one* `unsigned char`. Each plane is an array of `unsigned char`s. You get an array of five pointers to up to five arrays.
Peter Hosey