2012-10-15 7 views
12

Wie konvertiert man NSImage in NSBitmapImageRep? Ich habe Code: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; 
} 

Es funktioniert, aber es verursacht Speicherverluste. Zumindest wenn ich es mit ARC benutze. Mit initWithData:[nsimagename TIFFRepresentation] funktioniert es nicht richtig. Die Darstellungen einiger Bilder sind nicht gut. Ich denke, es hängt vom Format und vom Farbraum des Bildes ab. Gibt es andere Möglichkeiten, das zu erreichen?


Ergebnis mit MrWalker vorgeschlagene Lösung:

Originalbild:
enter image description here

Umgewandelt in Bild 1 mal bitmapimagerep und zurück:
enter image description here

Umgerechnet auf Bitm apimagerep und zurück zum Bild 3 mal:
enter image description here

Wie Sie Bild sehen dunkler nach zu NSBitmapImageRep Umwandlung jedes Mal bekommt

+0

Hockeyman, haben Sie immer noch die volle Lösung auf Ihre Frage? Ich suche nach einer Möglichkeit, Pixelfarben ohne zu viel Prozess zu identifizieren. Vielleicht könnte NSBitmapImageRep mir irgendwie helfen. Vielen Dank. – RickON

Antwort

11

Sie diese Methode von Mike Ash's "Obtaining and Interpreting Image Data" blog post angepasst versuchen könnte:

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

Nun, diese Methode funktioniert aber nicht richtig. Es gibt eine Darstellung mit einem dunkleren Bild zurück. Ich füge ein Beispiel zu meiner Frage hinzu. – hockeyman

+0

Sind die Ergebnisse besser, wenn Sie NSDeviceRGBColorSpace anstelle von NSCalibratedRGBColorSpace verwenden? – mrwalker

+0

Vielen Dank! :) – hockeyman

11

@Julius: Ihr Code ist viel zu kompliziert und enthält mehrere Fehler. Ich werde nur für die ersten Zeilen eine Korrektur vorzunehmen:

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

Dies wird die erste NSBitmapImageRep extrahieren, wenn sie Mitglied in den Darstellungen ist oder wird Null zurückgeben, wenn es keine NSBitmapImageRep ist. Ich werde Ihnen eine andere Lösung geben, die immer was NSImageReps sind in den Darstellungen funktioniert: NSBitmapImageRep, NSPDFImageRep oder NSCGImageSnapshotRep oder ...

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

oder Klassifizieren von NSImage vermeiden Sie schreiben können:

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

Dies gibt nur eine einzige NSBitmapImageRep zurück, die möglicherweise nicht gut genug ist, wenn das Bild mehr als eine Darstellung enthält (z. B. viele NSBitmapImageRep s aus TIFF-Dateien). Aber das Hinzufügen von Code ist einfach.

+0

Als zusätzlichen Vorschlag möchten Sie vielleicht die zweite '[Selbstrepräsentation]' durch 'ret' in der Iteration ersetzen, da gerade' ret' unbenutzt ist. –

+0

@Brad, guter Vorschlag! Vielen Dank. –

1

Vielleicht spät zur Party, aber dies ist die Swift 3-Version von der @mrwalker Antwort:

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