2012-10-15 54 views
12

如何将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

转换为位图的处理apimagerep和回图像的3倍:
enter image description here

正如你看到的图像转换为NSBitmapImageRep

后暗每次都使
+0

Hockeyman,你还有完整的解决你的问题?我正在寻找一种方法来识别像素颜色,而不需要太多的过程。也许NSBitmapImageRep可以以某种方式帮助我。谢谢。 – RickON

回答

11

你可以尝试改编自Mike Ash's "Obtaining and Interpreting Image Data" blog post这种方法:

- (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]; 
} 
+0

这个方法有效,但不正确。它返回表示与较暗的图像。我会在我的问题中添加示例。 – hockeyman

+0

如果使用“NSDeviceRGBColorSpace”而不是“NSCalibratedRGBColorSpace”,结果会更好吗? – mrwalker

+0

非常感谢! :) – hockeyman

11

@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是在表示:NSBitmapImageRepNSPDFImageRepNSCGImageSnapshotRep或...

- (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,如果图像包含多个表示形式(例如TIFF文件中的很多NSBitmapImageRep),那么这可能不够好。但是添加一些代码很简单。

+0

作为一个额外的建议,你可能想在迭代中用'ret'替换第二个'[self representations]',因为现在'ret'没有被使用。 –

+0

@布拉德,好建议!谢谢。 –

1

也许迟到了,但是这是从@mrwalker响应雨燕3版本:

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 
    } 
}