2012-10-15 13 views
12

NSImage NSBitmapImageRep nasıl dönüştürülür? Kodum var: 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; 
} 
Çalışıyor, ancak bellek sızıntılarına neden oluyor. En azından ARC ile kullanırken. initWithData:[nsimagename TIFFRepresentation]'u kullanarak düzgün çalışmıyor. Bazı görsellerin temsilleri iyi değildir. Sanırım resmin biçimine ve renk alanına bağlı. Bunu başarmanın başka yolları var mı?


Sonucu mrwalker önerilen çözüm ile:

Orjinal resim: için
enter image description here

Dönüştürülen: bitmapimagerep ve geri resme 1 kez Çevrildi
enter image description here

bitm apimagerep ve sırt görüntüye 3 kez:
enter image description here

görüntü NSBitmapImageRep

dönüştürdükten sonra koyu her zaman alır Gördüğünüz gibi
+0

Hockeyman, hala sorunuzun tam bir çözüm var mı? Çok fazla işlem yapmadan piksel renklerini tanımlamanın bir yolunu arıyorum. Belki de NSBitmapImageRep bana bir şekilde yardımcı olabilir. Teşekkürler. – RickON

cevap

11

Bu yöntem Mike Ash's "Obtaining and Interpreting Image Data" blog post uyarlanmıştır deneyin olabilir:

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

Bu yöntem işe yarar, ancak doğru değil. Koyu görüntü ile temsil eder. Soruma bir örnek ekleyeceğim. – hockeyman

+0

"NSCalibratedRGBColorSpace" yerine "NSDeviceRGBColorSpace" kullanırsanız sonuçlar daha iyi mi? – mrwalker

+0

Çok teşekkür ederim! :) – hockeyman

11

@Julius: Kodunuz çok karmaşık ve çok sayıda hata içeriyor. Ben sadece ilk hatları için bir düzeltme yapacaktır: o temsillerinde üyesidir ya da hiç NSBitmapImageRep varsa, nil dönecektir eğer bu ilk NSBitmapImageRep çıkartacaktır

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

. Eğer yazabilirsiniz NSBitmapImageRep, NSPDFImageRep veya NSCGImageSnapshotRep ya ...

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

Veya NSImage ait subclassing önlemek için:

NSImage *img = [[[NSImage alloc] initWithContentsOfFile:filename] autorelease]; 
CGImageRef CGImage = [img CGImageForProposedRect:nil context:nil hints:nil]; 
NSBitmapImageRep *rep = [[[NSBitmapImageRep alloc] initWithCGImage:CGImage] autorelease]; 
Sana temsiller içinde ne olursa olsun NSImageReps her zaman çalışır başka bir çözüm vereceğiz

Bu, yalnızca görüntüde birden fazla gösterim varsa (örneğin, TIFF dosyalarından çok NSBitmapImageRep s) yeterince iyi olmayan tek bir NSBitmapImageRep döndürecektir. Ancak bazı kodları eklemek basittir.

+0

Başka bir öneri olarak, iterasyonda ikinci '[self represtations]' 'ret' ile değiştirmek isteyebilirsiniz, çünkü şu anda' ret' kullanılmamaktadır. –

+0

@Brad, iyi bir öneri! Teşekkürler. –

1

Belki geç partiye, ancak bu @mrwalker yanıtından Swift 3 versiyonu olan:

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