开发者

Saving NSBitmapImageRep as NSBMPFileType file. Wrong BMP headers and bitmap content

开发者 https://www.devze.com 2022-12-28 05:25 出处:网络
I save a NSBitmapImageRep to a BMP file (Snow Leopard). It seems ok when i open it on macos. But it makes an error on my multimedia device (which can show any BMP file from internet).I cannot figure o

I save a NSBitmapImageRep to a BMP file (Snow Leopard). It seems ok when i open it on macos. But it makes an error on my multimedia device (which can show any BMP file from internet). I cannot figure out what is wrong, but when i look inside the file (with the cool hexfiend app on macos), 2 things wrong:

  • the header have a wrong value for the biHeight parameter : 4294966216 (hex=C8FBFFFF) the header have a correct biWidth parameter : 1920
  • the first pixel in the bitmap content (after 54 bytes headers in BMP format) correspond to the upper left corner of the original image. In the original BMP file and as specified in the BMP format, it should be the down left corner pixel first.

To explain the full workflow in my app, i have an NSImageView where i can drag a BMP image. This View is bind to an NSImage. After a drag & drop i have an action to save this image (with some text drawing over it) to a BMP file.

Here's the code for saving the new BMP file :

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];

The duneScreenViewdrawSynopsisContentWithDuneFolder method uses CGContextDrawImage to draw the image. The duneScreenViewdrawSynopsis method uses CoreText to draw some text in the same context.

Do you know what's wrong?


I just registered an openid account, so i can not edit my own question. I found a way to manage this problem and wanted to post my solution.

There was 2 problems :

  • wrong biHeight parameter in BMP header
  • vertically flipped data in the bitmap content (start with upper left corner in the place of down left corner first)

For the biHeight parameter, i replaced the biHeight bytes to the good value (1080 for my image)

For the flipped problem, i just flip all rows in the content bitmap bytes.

May be this is not the most elegant solution, but it work fine. Just let me know if you if you have other solutions.

Here's the code :

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);
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号