将NSBitmapImageRep保存为NSBMPFileType文件。错误的BMP标头和位图内容

时间:2010-04-28 08:52:00

标签: objective-c cocoa nsbitmapimagerep

我将NSBitmapImageRep保存到BMP文件(Snow Leopard)。当我在macos上打开它时似乎没问题。但它在我的多媒体设备上出错(可以显示来自互联网的任何BMP文件)。我无法弄清楚出了什么问题,但是当我查看文件内部(使用macos上的炫酷hexfiend应用程序)时,有两件事是错的:

  • 标头的biHeight参数值错误:4294966216(十六进制= C8FBFFFF) 标题有一个正确的biWidth参数:1920
  • 位图内容中的第一个像素(在BMP格式的54个字节标题之后)对应于原始图像的左上角。在原始BMP文件中并按BMP格式指定,它应首先是左下角像素。

为了解释我的应用程序中的完整工作流程,我有一个NSImageView,我可以在其中拖动BMP图像。此视图绑定到NSImage。 经过一段时间的拖累和drop我有一个动作来保存这个图像(用一些文字画在上面)到BMP文件。

以下是保存新BMP文件的代码:

CGColorSpaceRefcolorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGContextRefcontext = CGBitmapContextCreate(NULL, (int)1920, (int)1080, 8, 4*(int)1920, colorSpace, kCGImageAlphaNoneSkipLast);

[duneScreenViewdrawBackgroundWithDuneFolder:self inContext:context inRect:NSMakeRect(0,0,1920,1080) needScale:NO];
if(folderType==DXFolderTypeMovie) {

    [duneScreenViewdrawSynopsisContentWithDuneFolder:self inContext:context inRect:NSMakeRect(0,0,1920,1080) withScale:1.0];
}


CGImageRef backgroundImageRef = CGBitmapContextCreateImage(context);
NSBitmapImageRep*bitmapBackgroundImageRef = [[NSBitmapImageRepalloc] initWithCGImage:backgroundImageRef];


NSData*data = [destinationBitmap representationUsingType:NSBMPFileType properties:nil];
[data writeToFile:[NSStringstringWithFormat:@"%@/%@", folderPath,backgroundPath] atomically: YES];

duneScreenViewdrawSynopsisContentWithDuneFolder方法使用CGContextDrawImage绘制图像。 duneScreenViewdrawSynopsis方法使用CoreText在相同的上下文中绘制一些文本。

你知道什么是错的吗?

1 个答案:

答案 0 :(得分:1)

我刚注册了一个openid帐户,所以我无法编辑自己的问题。我找到了一种方法来管理这个问题,并希望发布我的解决方案。

有两个问题:

  • BMP标题中错误的biHeight参数
  • 在位图内容中垂直翻转数据(从左下角开始左上角开始)

对于biHeight参数,我将biHeight字节替换为良好值(我的图像为1080)

对于翻转的问题,我只是翻转内容位图字节中的所有行。

可能这不是最优雅的解决方案,但它工作正常。如果您有其他解决方案,请告诉我。

以下是代码:

intwidth = 1920;
intheight = 1080;

CGColorSpaceRefcolorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRefcontext = CGBitmapContextCreate(NULL, (int)width, (int)height, 8, 4* (int)width, colorSpace, kCGImageAlphaNoneSkipLast);

[duneScreenViewdrawBackgroundWithDuneFolder:selfinContext:context inRect:NSMakeRect(0,0,width,height) needScale:NO];
if(folderType==DXFolderTypeMovie) {

    [duneScreenViewdrawSynopsisContentWithDuneFolder:selfinContext:context inRect:NSMakeRect(0,0,width,height) withScale:1.0];
}

CGImageRefbackgroundImageRef = CGBitmapContextCreateImage(context);

NSBitmapImageRep*bitmapBackgroundImageRef = [[NSBitmapImageRepalloc] initWithCGImage:backgroundImageRef];

NSData*data = [bitmapBackgroundImageRef representationUsingType:NSBMPFileTypeproperties:nil];

NSMutableData*mutableData = [[NSMutableDataalloc] init];

intbitmapBytesOffset = 54;

//headers
[mutableData appendData:[data subdataWithRange:NSMakeRange(0,bitmapBytesOffset)]];

//bitmap data
intlineIndex=height-1;

while(lineIndex>=0) {

    [mutableData appendData:[data subdataWithRange:NSMakeRange(bitmapBytesOffset+lineIndex*width*3,width*3)]];

    lineIndex--;
}

//force biHeight header parameter to 1080
NSString*biHeightString = @"\x38\x04\x00\x00";
NSData*biHeightData = [biHeightString dataUsingEncoding:NSUTF8StringEncoding];
[mutableData replaceBytesInRange:NSMakeRange(22,4) withBytes:[biHeightData bytes]];

[mutableData writeToFile:[NSStringstringWithFormat:@"%@/%@", folderPath,backgroundPath] atomically: YES];

[mutableData release];


CGImageRelease(backgroundImageRef);
[bitmapBackgroundImageRef release];
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);