2012-10-15 1 views
12

Comment faire pour convertir NSImage en NSBitmapImageRep? J'ai le 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; 
} 

Cela fonctionne, mais il provoque des fuites de mémoire. Au moins quand je l'utilise avec ARC. En utilisant initWithData:[nsimagename TIFFRepresentation] cela ne fonctionne pas correctement. Les représentations de certaines images ne sont pas bonnes. Je pense que cela dépend du format et de l'espace de couleurs de l'image. Y a-t-il d'autres moyens d'y parvenir?


Résultat avec MrWalker solution suggérée:

Image originale:
enter image description here

converti à bitmapimagerep et retour à l'image 1 fois:
enter image description here

converti à bitm apimagerep et retour à l'image 3 fois:
enter image description here

Comme vous le voyez l'image devient plus sombre chaque fois après la conversion en NSBitmapImageRep

+0

Hockeyman, avez-vous toujours la solution complète à votre question? Je cherche un moyen d'identifier les couleurs des pixels sans trop de processus. Peut-être que NSBitmapImageRep pourrait m'aider d'une manière ou d'une autre. Merci. – RickON

Répondre

11

Vous pouvez essayer cette méthode adaptée de 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

Eh bien cette méthode fonctionne mais pas correctement. Il renvoie la représentation avec une image plus sombre. Je vais ajouter un exemple à ma question. – hockeyman

+0

Les résultats sont-ils meilleurs si vous utilisez 'NSDeviceRGBColorSpace' au lieu de' NSCalibratedRGBColorSpace'? – mrwalker

+0

Merci beaucoup! :) – hockeyman

11

@Julius: Votre code est trop compliqué et contient plusieurs bugs. Je vais faire une correction pour que les premières lignes:

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

Cela va extraire la première NSBitmapImageRep si elle est membre dans les représentations ou retournera zéro, s'il n'y a pas NSBitmapImageRep. Je vais vous donner une autre solution qui fonctionnera toujours tout NSImageReps sont dans les représentations: NSBitmapImageRep, NSPDFImageRep ou NSCGImageSnapshotRep ou ...

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

ou pour éviter de subclassing NSImage vous pouvez écrire:

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

Cela ne retournera qu'un seul NSBitmapImageRep, ce qui n'est peut-être pas suffisant si l'image contient plus d'une représentation (par exemple beaucoup de NSBitmapImageRep s des fichiers TIFF). Mais ajouter du code est simple.

+0

En guise de suggestion supplémentaire, vous pouvez remplacer la seconde '[self representations]' par 'ret' dans l'itération, car' ret' est actuellement inutilisé. –

+0

@Brad, bonne suggestion! Merci. –

1

Peut-être tard pour le parti, mais cela est la Swift version 3 de la réponse @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 
    } 
}