32 bits big endian floating point data to CGImage

970 views Asked by At

I am trying to write an application which read FITS image. FITS stand for Flexible Image Transport format and it is a format wish is primarily used to store scientific data related to astrophysics, and secondarily, it is used by most amator astronomer which take picture of the sky with CCD camera. So FITS file contains images, but they also may contains tables and other kind of data. As I am new in Objectiv-C and cocoa programming (I start this project one year ago, but since I am busy, I almost not touch it for one year !), I started trying to create a library which allow me to convert the image content of the file to a NSImageRep. FITS image binary data may be 8 bit/pix, 16 bit/pix, 32 bit/pix unsigned integer or 32 bit/pix, 64 bit/pix floating point, all in Big endian.

I manage to have image representation for grey scale FITS image in 16 bit/pix, 32 bit/pix unsigned integer but I obtain very weird behaviour when I am looking for 32 bit/pix floating point (and the problem is worth for RGB 32 bit/pix floating points). So far, I haven't test for 8 bits/pix integer data and RGB image based on 16 bit/pix and 32 bit/pix integer data because I haven't yet find example file on the web.

As follow is my code to create a grey scale image form fits file :

-(void) ConstructImgGreyScale
{
CGBitmapInfo     bitmapInfo;
int bytesPerRow;

switch ([self BITPIX])   // BITPIX : Number bits/pixel. Information extracted from the FITS header
{
    case 8:
        bytesPerRow=sizeof(int8_t);
        bitmapInfo = kCGImageAlphaNone ;
        break;
    case 16:
        bytesPerRow=sizeof(int16_t);
        bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrder16Big;
        break;
    case 32:
        bytesPerRow=sizeof(int32_t);
        bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrder32Big;
        break;
    case 64:
        bytesPerRow=sizeof(int64_t);
        bitmapInfo = kCGImageAlphaNone;
        break;
    case -32:
        bytesPerRow=sizeof(Float32);
        bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrder32Big  | kCGBitmapFloatComponents;
    case -64:
        bytesPerRow=sizeof(Float64);
        bitmapInfo = kCGImageAlphaNone  | kCGBitmapFloatComponents;
        break;
    default:
        NSLog(@"Unknown pixel bit size");
        return;
}
[self setBitsPerSample:abs([self BITPIX])];

[self setColorSpaceName:NSCalibratedWhiteColorSpace];

[self setPixelsWide:[self NAXESofAxis:0]]; // <- Size of the X axis. Extracted from FITS header
[self setPixelsHigh:[self NAXESofAxis:1]]; // <- Size of the Y axis. Extracted from FITS header

[self setSize:  NSMakeSize( 2*[self pixelsWide], 2*[self pixelsHigh])];

[self setAlpha: NO];
[self setOpaque:NO];

CGDataProviderRef provider=CGDataProviderCreateWithCFData ((CFDataRef) Img);

CGFloat Scale[2]={0,28};
image = CGImageCreate ([self pixelsWide],
                       [self pixelsHigh],
                       [self bitsPerSample],
                       [self bitsPerSample],
                       [self pixelsWide]*bytesPerRow,
                       [[NSColorSpace deviceGrayColorSpace] CGColorSpace],
                       bitmapInfo,
                       provider,
                       NULL,
                       NO,
                       kCGRenderingIntentDefault
                       );

CGDataProviderRelease(provider);
return;
}  

and here is the snapshot of the result for a 32/bits/pix floating point data : NASA HST picture!

The Image seems to be shift to the left, but what is more annoying is that I get two representation of the same image (upper and lower part of the frame) in the same frame.

And for some other file, the behaviour is more strange : Star Field 1 , (For the other link se the comment, as new user, I can not have more than two link in this text. As well as I can not put directly the image.)

All three star field images are the representation of the same fits file content. I obtain a correct representation of the image in the bottom part of the frame (the star are too much saturated but I haven't yet play with the encoding). But, in the upper part, each time I open the same file I got a different representation of the image. Look like each time I open this file, it do not tack the same sequence of bytes to produce the image representation (at least for the upper part).

Also, I do not know if the image which is duplicated on the bottom contain half of the data and the upper one the other half, or if it is simply a copy of the data.

When I convert the content of my Data in primitive format (human readable number) the number are compatible with what should be in the pixel, at the good position. This let me think the problem is not coming from the data but from the way the CGImage interpret the data i.e. I am wrong somewhere in the argument I pass to the CGImageCreate function.

In case of RGB fits image data, I obtain at the end 18 image into my frame. 6 copy of each R, G and B image. All in gray scale. Note that in case of RGB image, my code is different.

What am I doing wrong ?

1

There are 1 answers

0
William GILLARD On

Ok, I finally find the solution of on of my problem, concerning the duplication of the image. And this was a very stupid mistake and I am not proud of myself not having find it earlier.

In the code, I forget the break in the case -32. Still the question remain about the shift of the picture. I do not see the shift when I am opening 32 bit integer image but it appears on the 32 bit floating points data.

Does any one have an idea of where this shift could come from in my code ? Does it is due to the way I construct the image ? Or it is possible it is du to the way I draw the image ?

Bellow is the piece of code I use to draw the image. Since the image was first upside down, I made a little change of coordinate.

- (bool)draw {
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
if (!context || !image) {
    return NO;
}
NSSize size = [self size];

CGContextTranslateCTM(context, 0, size.height);
CGContextScaleCTM(context, 1, -1);

CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), image);
return YES;
}