Objective-C: Display an Array of Floats as an Image
-
22-04-2021 - |
Question
In a Cocoa App I would like to display a 2d array of floats in an NSImageView. To make the code as simple as possible, start off by converting the data from float to NSData:
// dataArray: an Nx by Ny array of floats
NSMutableData *nsdata = [NSMutableData dataWithCapacity:0];
long numPixels = Nx*Ny;
for (int i = 0; i < numPixels; i++) {
[nsdata appendBytes:&dataArray[i] length:sizeof(float)];
}
and now try to display the data (the display is left blank):
[theNSImageView setImage:[[NSImage alloc] initWithData:nsdata]];
Is this the correct approach? Is a CGContext needed first? I was hoping to accomplish this with NSData.
I have noted the earlier Stack posts: 32 bit data, close but in reverse, almost worked but no NSData, color image data here, but not much luck getting variations on these working. Thanks for any suggestions.
Solution 2
Ok got it to work. I had tried the NSBitmapImageRep before (thanks Tim) but the part I was missing was in properly converting my floating point data to a byte array. NSData doesn't do that and returns nil. So the solution was not so much in needing to build up an NSImage float-by-float. In fact, one can similarly build up a bitmapContext (using CGBitmapContextCreate (mentioned by HotLicks above)) and that works too, once the floating point data has been represented properly.
OTHER TIPS
You can use an NSBitmapImageRep
to build up an NSImage
float-by-float.
Interestingly, one of its initialisers has the longest method name in all of Cocoa:
- (id)initWithBitmapDataPlanes:(unsigned char **)planes
pixelsWide:(NSInteger)width
pixelsHigh:(NSInteger)height
bitsPerSample:(NSInteger)bps
samplesPerPixel:(NSInteger)spp
hasAlpha:(BOOL)alpha
isPlanar:(BOOL)isPlanar
colorSpaceName:(NSString *)colorSpaceName
bitmapFormat:(NSBitmapFormat)bitmapFormat
bytesPerRow:(NSInteger)rowBytes
bitsPerPixel:(NSInteger)
It's well documented at least. Once you've built it up by supplying float arrays in planes
you can then get the NSImage
to put in your view:
NSImage *image = [[NSImage alloc] initWithCGImage:[bitmapImageRep CGImage] size:NSMakeSize(width,height)];
Or, slightly cleaner
NSImage *image = [[[NSImage alloc] init] autorelease];
[im addRepresentation:bitmapImageRep];
There is an initialiser which just uses an NSData
container:
+ (id)imageRepWithData:(NSData *)bitmapData
although that depends on your bitmapData
containing one of the correct bitmap formats.