NSImage для NSBitmapImageRep
Как преобразовать NSImage в NSBitmapImageRep? У меня есть код:
- (NSBitmapImageRep *)bitmapImageRepresentation
{
NSBitmapImageRep *ret = (NSBitmapImageRep *)[self representations];
if(![ret isKindOfClass:[NSBitmapImageRep class]])
{
ret = nil;
for(NSBitmapImageRep *rep in [self representations])
if([rep isKindOfClass:[NSBitmapImageRep class]])
{
ret = rep;
break;
}
}
if(ret == nil)
{
NSSize size = [self size];
size_t width = size.width;
size_t height = size.height;
size_t bitsPerComp = 32;
size_t bytesPerPixel = (bitsPerComp / CHAR_BIT) * 4;
size_t bytesPerRow = bytesPerPixel * width;
size_t totalBytes = height * bytesPerRow;
NSMutableData *data = [NSMutableData dataWithBytesNoCopy:calloc(totalBytes, 1) length:totalBytes freeWhenDone:YES];
CGColorSpaceRef space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGContextRef ctx = CGBitmapContextCreate([data mutableBytes], width, height, bitsPerComp, bytesPerRow, CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), kCGBitmapFloatComponents | kCGImageAlphaPremultipliedLast);
if(ctx != NULL)
{
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:[self isFlipped]]];
[self drawAtPoint:NSZeroPoint fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
[NSGraphicsContext restoreGraphicsState];
CGImageRef img = CGBitmapContextCreateImage(ctx);
ret = [[NSBitmapImageRep alloc] initWithCGImage:img];
[self addRepresentation:ret];
CFRelease(img);
CFRelease(space);
CGContextRelease(ctx);
}
}
return ret;
}
Он работает, но он вызывает утечку памяти. По крайней мере, когда я использую его с ARC. Используя initWithData:[nsimagename TIFFRepresentation]
, он работает неправильно. Некоторые представления изображений не очень хорошие. Я думаю, это зависит от формата и цветового пространства изображения. Есть ли другие способы достичь этого?
Результат с предлагаемым решением mrwalker:
Исходное изображение:
![enter image description here]()
Конвертировано в bitmapimagerep и обратно к изображению 1 раз:
![enter image description here]()
Конвертировано в bitmapimagerep и обратно к изображению 3 раза:
![enter image description here]()
Как вы видите, изображение становится темнее каждый раз после преобразования в NSBitmapImageRep
Ответы
Ответ 1
Вы можете попробовать этот метод, адаптированный из сообщения в блоге Mike Ash "Получение и интерпретация данных изображения" :
- (NSBitmapImageRep *)bitmapImageRepresentation {
int width = [self size].width;
int height = [self size].height;
if(width < 1 || height < 1)
return nil;
NSBitmapImageRep *rep = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes: NULL
pixelsWide: width
pixelsHigh: height
bitsPerSample: 8
samplesPerPixel: 4
hasAlpha: YES
isPlanar: NO
colorSpaceName: NSDeviceRGBColorSpace
bytesPerRow: width * 4
bitsPerPixel: 32];
NSGraphicsContext *ctx = [NSGraphicsContext graphicsContextWithBitmapImageRep: rep];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext: ctx];
[self drawAtPoint: NSZeroPoint fromRect: NSZeroRect operation: NSCompositeCopy fraction: 1.0];
[ctx flushGraphics];
[NSGraphicsContext restoreGraphicsState];
return [rep autorelease];
}
Ответ 2
@Julius: ваш код слишком сложный и содержит несколько ошибок. Я сделаю поправку только для первых строк:
- (NSBitmapImageRep *)bitmapImageRepresentation
{
NSArray *ret =[self representations];
for( NSImageRep *rep in [self representations] )
if( [rep isKindOfClass:[NSBitmapImageRep class]] ) return rep;
return nil;
}
Это выберет первый NSBitmapImageRep
, если он является членом в представлениях или вернет nil, если нет NSBitmapImageRep
. Я дам вам другое решение, которое всегда будет работать независимо от NSImageReps
в представлениях: NSBitmapImageRep
, NSPDFImageRep
или NSCGImageSnapshotRep
или...
- (NSBitmapImageRep *)bitmapImageRepresentation
{
CGImageRef CGImage = [self CGImageForProposedRect:nil context:nil hints:nil];
return [[[NSBitmapImageRep alloc] initWithCGImage:CGImage] autorelease];
}
Или, чтобы избежать подкласса NSImage, вы можете написать:
NSImage *img = [[[NSImage alloc] initWithContentsOfFile:filename] autorelease];
CGImageRef CGImage = [img CGImageForProposedRect:nil context:nil hints:nil];
NSBitmapImageRep *rep = [[[NSBitmapImageRep alloc] initWithCGImage:CGImage] autorelease];
Это приведет только к возврату единственного NSBitmapImageRep
, который может быть недостаточно хорошим, если изображение содержит более одного представления (например, много NSBitmapImageRep
из файлов TIFF). Но добавление кода просто.
Ответ 3
Возможно, поздно на вечеринку, но это версия Swift 3 из ответа @mrwalker:
extension NSImage {
func bitmapImageRepresentation(colorSpaceName: String) -> NSBitmapImageRep? {
let width = self.size.width
let height = self.size.height
if width < 1 || height < 1 {
return nil
}
if let rep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(width), pixelsHigh: Int(height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: colorSpaceName, bytesPerRow: Int(width) * 4, bitsPerPixel: 32)
{
let ctx = NSGraphicsContext.init(bitmapImageRep: rep)
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.setCurrent(ctx)
self.draw(at: NSZeroPoint, from: NSZeroRect, operation: NSCompositingOperation.copy, fraction: 1.0)
ctx?.flushGraphics()
NSGraphicsContext.restoreGraphicsState()
return rep
}
return nil
}
}