2012-10-15 22 views
12

Làm thế nào để chuyển đổi NSImage sang NSBitmapImageRep? Tôi có mã:NSImage to 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; 
} 

Nó hoạt động nhưng gây rò rỉ bộ nhớ. Ít nhất là khi tôi đang sử dụng nó với ARC. Sử dụng initWithData:[nsimagename TIFFRepresentation] nó không hoạt động chính xác. Một số đại diện của hình ảnh không tốt. Tôi nghĩ rằng nó phụ thuộc vào định dạng và không gian màu của hình ảnh. Có cách nào khác để đạt được điều đó không?


quả với mrwalker giải pháp đề nghị:

hình ảnh gốc:
enter image description here

Chuyển Đổi Sang bitmapimagerep và trở lại hình ảnh 1 thời gian:
enter image description here

Chuyển Đổi Sang bitm apimagerep và trở lại hình ảnh 3 lần:
enter image description here

Như bạn thấy hình ảnh bị tối hơn mỗi lần sau khi chuyển đổi để NSBitmapImageRep

+0

Hockeyman, bạn vẫn có giải pháp đầy đủ cho câu hỏi của bạn? Tôi đang tìm kiếm một cách để xác định màu sắc pixel mà không có quá nhiều quá trình. Có lẽ NSBitmapImageRep có thể giúp tôi bằng cách nào đó. Cảm ơn. – RickON

Trả lời

11

Bạn có thể thử phương pháp này chuyển thể từ 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

Phương pháp này hoạt động nhưng không chính xác. Nó trả về biểu diễn với hình ảnh tối hơn. Tôi sẽ thêm ví dụ vào câu hỏi của mình. – hockeyman

+0

Kết quả có tốt hơn không nếu bạn sử dụng 'NSDeviceRGBColorSpace' thay vì' NSCalibratedRGBColorSpace'? – mrwalker

+0

Cảm ơn bạn rất nhiều! :) – hockeyman

11

@Julius: Mã của bạn quá phức tạp và chứa nhiều lỗi. Tôi sẽ làm cho một sự điều chỉnh cho chỉ những dòng đầu tiên:

- (NSBitmapImageRep *)bitmapImageRepresentation 
{ 
    NSArray *ret =[self representations]; 
    for(NSImageRep *rep in [self representations]) 
     if([rep isKindOfClass:[NSBitmapImageRep class]]) return rep; 
    return nil; 
} 

này sẽ trích xuất các NSBitmapImageRep đầu tiên nếu nó là thành viên trong cơ quan đại diện hoặc sẽ trở lại con số không, nếu không có NSBitmapImageRep. Tôi sẽ cung cấp cho bạn một giải pháp mà sẽ luôn luôn làm việc bất cứ điều gì NSImageReps đang ở cơ quan đại diện: NSBitmapImageRep, NSPDFImageRep hoặc NSCGImageSnapshotRep hoặc ...

- (NSBitmapImageRep *)bitmapImageRepresentation 
{ 
    CGImageRef CGImage = [self CGImageForProposedRect:nil context:nil hints:nil]; 
    return [[[NSBitmapImageRep alloc] initWithCGImage:CGImage] autorelease]; 
} 

Hoặc để tránh subclassing của NSImage bạn có thể viết:

NSImage *img = [[[NSImage alloc] initWithContentsOfFile:filename] autorelease]; 
CGImageRef CGImage = [img CGImageForProposedRect:nil context:nil hints:nil]; 
NSBitmapImageRep *rep = [[[NSBitmapImageRep alloc] initWithCGImage:CGImage] autorelease]; 

Điều này sẽ chỉ trả về một đơn NSBitmapImageRep có thể không đủ tốt nếu hình ảnh chứa nhiều hơn một biểu diễn (ví dụ: rất nhiều NSBitmapImageRep s từ tệp TIFF). Nhưng thêm một số mã thì đơn giản.

+0

Là một gợi ý bổ sung, bạn có thể muốn thay thế '[tự biểu diễn] thứ hai bằng' ret' trong lần lặp, bởi vì ngay bây giờ 'ret' không được sử dụng. –

+0

@Brad, đề xuất tốt! Cảm ơn. –

1

lẽ muộn để đảng, nhưng đây là phiên bản Swift 3 từ phản ứng @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 
    } 
} 
Các vấn đề liên quan