0

我需要将 16bpp 灰度位图数据转换为 8bpp。mac os x 不支持我的图像文件格式,因此我将 NSBitmapImageRep 子类化。我已经实现了这个方法imageRepWithData:

+ (id)imageRepWithData:(NSData *)data {
    NSLog(@"imageRepWithData called");
    if (data.length < 2) return nil;
    NSString *magicNumberP5 = @"P5";
    const unsigned char *mnP5 = (const unsigned char *)[magicNumberP5 UTF8String];
    unsigned char headerBuffer[2];
    [data getBytes:headerBuffer length:2];

    if (memcmp(mnP5, headerBuffer, 2) != 0) {
        NSLog(@"It is not supported pgm file format.");
        return nil;
    }

    NSArray *pgmParameters = [self extractPgmHeader:data];

    // width in pixels
    NSInteger width = [[pgmParameters objectAtIndex:0] integerValue];
    // height in pixels
    NSInteger height = [[pgmParameters objectAtIndex:1] integerValue];
    // imageData contains bytes of Bitmap only. Without header
    NSData *imageData = [pgmParameters objectAtIndex:3];
    // Number of bytes in bitmap (length)
    NSUInteger imageLength = [imageData length];

    // calculate number bytes per component
    size_t bytesPerCompontent = imageLength / (width * height) * 8;
    // calculate number of bytes per pixel
    size_t bytesPerPixel = bytesPerCompontent;
    // calculate number of bytes per row
    size_t bytesPerRow = width * (imageLength / (width * height));

    // tmp test
    NSData *eightBitBitmapData = [RWTPGMRep convert16BppTo8BppFromBitmapData:imageData];
    // end of tmp test

    CGDataProviderRef provider =
    CGDataProviderCreateWithCFData((CFDataRef)CFBridgingRetain(imageData));

    CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGrayGamma2_2);
    CGImageRef imageRef = CGImageCreate(width,
                                        height,
                                        bytesPerCompontent,
                                        bytesPerPixel,
                                        bytesPerRow,
                                        colorSpace,
                                        kCGImageAlphaNone,
                                        provider,
                                        NULL,
                                        false,
                                        kCGRenderingIntentDefault);

    CGColorSpaceRelease(colorSpace);
    CGDataProviderRelease(provider);

    if (imageRef == NULL) {
        NSLog(@"CGImageCreate() failed!");
    }
    RWTPGMRep *imageRep = [[RWTPGMRep alloc] initWithCGImage:imageRef];
    if (imageRep == nil) {
        NSLog(@"imageRep is NULL");
    }
    return imageRep;
}

所以我可以显示这个图像,其中像素由 2 个字节编码......

但我需要将此图像转换为 8bpp 为此我写了一个方法convert16BppTo8BppFromBitmapData:

+ (NSData *)convert16BppTo8BppFromBitmapData:(NSData *)sixteenBitBitmapData
{    
    // number of pixels
    NSUInteger size = [sixteenBitBitmapData length] / sizeof(UInt16);

    // allocate memory for 16bpp array
    UInt16 *array16 = malloc(size * sizeof(UInt16));
    UInt16 *array16Ptr = array16;
    // get bytes to array16
    [sixteenBitBitmapData getBytes:array16
                            length:(size * sizeof(UInt16))];

    // allocate memory for 8bpp array (converted values of pixels)
    UInt8 *array8 = malloc(size * sizeof(UInt8));
    UInt8 *array8Ptr = array8;

    // convert 16bpp values to 8bpp values
    NSUInteger i = size;
    while (i--) {
        *array8Ptr++ = (UInt8)((*array16Ptr++) >> 8);
    }

    // pack an array8 into NSData object
    NSData *eightBitBitmapData = [NSData dataWithBytes:array8
                                                length:size];    
    return eightBitBitmapData;
}

我已经检查了该方法,它似乎可以正常工作...仅出于测试目的,我修改了我的imageRepWithData:方法以使用 8bpp 创建 imageRef 并显示转换后的图像...这是我的更改:

// tmp test
NSData *eightBitBitmapData = [RWTPGMRep convert16BppTo8BppFromBitmapData:imageData];
size_t bytesPerCompontent8 = eightBitBitmapData.length / (width * height) * 8;
size_t bytesPerPixel8 = bytesPerCompontent8;
size_t bytesPerRow8 = (width * (eightBitBitmapData.length / (width * height)));


CGDataProviderRef provider =
CGDataProviderCreateWithCFData((CFDataRef)CFBridgingRetain(eightBitBitmapData));

CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGrayGamma2_2);
CGImageRef imageRef = CGImageCreate(width,
                                    height,
                                    bytesPerCompontent8,
                                    bytesPerPixel8,
                                    bytesPerRow8,
                                    colorSpace,
                                    kCGImageAlphaNone,
                                    provider,
                                    NULL,
                                    false,
                                    kCGRenderingIntentDefault);
// end of tmp test

但结果并不像我预期的那样......我显示的 16bpp 图像看起来像:http: //i40.tinypic.com/2isa9tx.png

我的图像转换为 8bb 位图看起来像:http: //i39.tinypic.com/as8c3.png

你知道出了什么问题吗?如果有任何建议,我将不胜感激。

4

0 回答 0